diff --git a/apps/editor/components/build-tab.tsx b/apps/editor/components/build-tab.tsx index bfc8ced4ed..a9b15d7ca4 100644 --- a/apps/editor/components/build-tab.tsx +++ b/apps/editor/components/build-tab.tsx @@ -23,8 +23,9 @@ import { useFloorplanMode, useTerraceDraft, useWallDrawVariant, + withToolShortcut, } from '@pascal-app/editor' -import { useLiquidLineToolOptions } from '@pascal-app/nodes' +import { framingPostToolChoices, useLiquidLineToolOptions } from '@pascal-app/nodes' import { useViewer } from '@pascal-app/viewer' import Image from 'next/image' import { useCallback, useEffect, useRef, useState, useSyncExternalStore } from 'react' @@ -37,6 +38,7 @@ import { import { activateBuildTool, activateFenceFeaturePlacement, + activatePostTool, activateRoofFeatureTool, activateRoofType, activateTerrainSculptMode, @@ -65,6 +67,8 @@ export function BuildTab() { const [kitchenOpen, setKitchenOpen] = useState(false) const [buildSearch, setBuildSearch] = useState('') const activeTool = useEditor((s) => s.tool) + // The column tool placing framing posts lights the Post tile, not Column. + const postArmed = useEditor((s) => framingPostToolChoices(s.toolDefaults.column) !== null) const selectedId = useViewer((s) => s.selection.selectedIds[0]) const selectedFenceFeature = useScene((s) => { const selected = selectedId ? s.nodes[selectedId as AnyNodeId] : undefined @@ -133,6 +137,8 @@ export function BuildTab() { if (type.id === 'roof') return mode === 'build' && (activeTool === 'roof' || isRoofFeatureActive) if (type.id === 'fence' && selectedFence) return true + if (type.kind === 'column') + return mode === 'build' && activeTool === 'column' && (type.id === 'post') === postArmed return mode === 'build' && activeTool === type.kind } @@ -154,6 +160,8 @@ export function BuildTab() { useEditor.getState().setMode('select') } else if (type.id === 'terrace') { startTerraceDraft() + } else if (type.id === 'post') { + activatePostTool() } else if (type.kind) { activateBuildTool(type.kind) } @@ -189,7 +197,7 @@ export function BuildTab() { handleTypeClick(type) }} onMouseEnter={() => triggerSFX('sfx:menu-hover')} - title={i18n._(type.label)} + title={withToolShortcut(i18n._(type.label), type.id)} /> ) const typesIn = (section: NonNullable) => @@ -281,6 +289,10 @@ export function BuildTab() { })} > {advancedTypes.map(renderTile)} + )} diff --git a/apps/editor/components/viewer-toolbar.tsx b/apps/editor/components/viewer-toolbar.tsx index a9ee1183db..451c5e3d97 100644 --- a/apps/editor/components/viewer-toolbar.tsx +++ b/apps/editor/components/viewer-toolbar.tsx @@ -5,17 +5,22 @@ import { type MessageDescriptor, usePascalI18n } from '@pascal-app/core' import { DropdownMenu, DropdownMenuContent, + DropdownMenuGroup, DropdownMenuItem, + DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, + type FloorplanWallDimensionFaces, sceneThemeName, + useCeilingsSetting, useEditor, useFloorplanAnnotationVisibility, useFloorplanMode, useSidebarStore, + useWallsBelowSetting, visibleScene, } from '@pascal-app/editor' import { @@ -26,7 +31,10 @@ import { useViewer, } from '@pascal-app/viewer' import { + ArrowDown, + ArrowUp, Box, + BrickWall, Check, ChevronsLeft, ChevronsRight, @@ -35,10 +43,14 @@ import { EyeOff, Footprints, Grid2X2, + Layers, + Layers2, Layers3, + Link2, Magnet, PenLine, Ruler, + RulerDimensionLine, ScanLine, SlidersHorizontal, Sparkles, @@ -49,6 +61,7 @@ import { import Image from 'next/image' import { type ReactNode, useCallback } from 'react' import { flushSync } from 'react-dom' +import { displayMenuLayout } from '@/lib/display-menu' import { cn } from '@/lib/utils' import { Tooltip, TooltipContent, TooltipTrigger } from './toolbar-tooltip' @@ -197,30 +210,6 @@ const FLOORPLAN_MODE_OPTIONS = [ }, ] as const -const FLOORPLAN_WALL_DIMENSION_REFERENCE_OPTIONS = [ - { - id: 'finished-faces', - name: /* i18n */ { id: 'app.viewerToolbar.finishedFaces', message: 'Finished faces' }, - detail: /* i18n */ { - id: 'app.viewerToolbar.fullWallThickness', - message: 'Full wall thickness', - }, - }, - { - id: 'centerline', - name: /* i18n */ { id: 'app.viewerToolbar.wallCenterline', message: 'Wall centerline' }, - detail: /* i18n */ { id: 'app.viewerToolbar.singleWallAxis', message: 'Single wall axis' }, - }, - { - id: 'stud-faces', - name: /* i18n */ { id: 'app.viewerToolbar.faceOfStud', message: 'Face of stud' }, - detail: /* i18n */ { - id: 'app.viewerToolbar.structuralCoreFace', - message: 'Structural core face', - }, - }, -] as const - function CollapseSidebarButton() { const i18n = usePascalI18n() const isCollapsed = useSidebarStore((state) => state.isCollapsed) @@ -350,8 +339,8 @@ function WallModeToggle() { ) } -// One dropdown that gathers every "how the scene looks" control: grid, shadows, -// camera projection, units, render mode, edges and scene theme. +// One dropdown that gathers every "how the views look" control, grouped by what +// it changes: both views (Show, Dimensions, Editing), the plan, or the 3D scene. const EDGE_OPTIONS = [ { @@ -379,9 +368,102 @@ const EDGE_OPTIONS = [ const SUBMENU_CONTENT_CLASS = 'min-w-56 rounded-xl border-border/45 bg-popover/95 backdrop-blur-xl' +/** Display → Measure walls: the faces wall dimensions measure to, with the line that explains each. */ +const MEASURE_WALLS_OPTIONS = [ + { + id: 'interior', + name: /* i18n */ { id: 'app.viewerToolbar.inside', message: 'Inside' }, + tag: /* i18n */ { + id: 'app.viewerToolbar.id', + message: 'ID', + comment: 'Short for inside dimension: measured between the inside faces of walls.', + }, + detail: /* i18n */ { + id: 'app.viewerToolbar.roomSizesInsideFaceToInsideFace', + message: 'Room sizes, inside face to inside face', + }, + }, + { + id: 'exterior', + name: /* i18n */ { id: 'app.viewerToolbar.outside', message: 'Outside' }, + tag: /* i18n */ { + id: 'app.viewerToolbar.od', + message: 'OD', + comment: 'Short for outside dimension: measured between the outside faces of walls.', + }, + detail: /* i18n */ { + id: 'app.viewerToolbar.overallSizeOutsideFaceToOutsideFace', + message: 'Overall size, outside face to outside face', + }, + }, + { + id: 'both', + name: /* i18n */ { id: 'app.viewerToolbar.both', message: 'Both' }, + tag: /* i18n */ { + id: 'app.viewerToolbar.idOd', + message: 'ID + OD', + comment: 'Inside and outside dimensions together.', + }, + detail: /* i18n */ { + id: 'app.viewerToolbar.roomSizesInsideOverallSizeOutside', + message: 'Room sizes inside, overall size outside', + }, + }, +] as const satisfies readonly { + id: FloorplanWallDimensionFaces + name: MessageDescriptor + tag: MessageDescriptor + detail: MessageDescriptor +}[] + +// Keep the menu open when flipping a toggle. +function keepOpen(event: Event, fn: () => void) { + event.preventDefault() + fn() +} + +/** One titled group of the Display menu; `tag` names the only view it changes. */ +function DisplayGroup({ + label, + tag, + children, +}: { + label: string + tag?: string + children: ReactNode +}) { + return ( + + + {label} + {tag ? ( + + {tag} + + ) : null} + + {children} + + ) +} + +function ShownIcon({ shown }: { shown: boolean }) { + return shown ? ( + + ) : ( + + ) +} + function DisplayMenu() { const i18n = usePascalI18n() - const scene = useEditor(visibleScene) + const layout = displayMenuLayout(useEditor(visibleScene)) + const levelId = useViewer((state) => state.selection.levelId) + const { shown: showCeilings, setShown: setShowCeilings } = useCeilingsSetting(levelId) + // The dashed walls of the levels below and above, on the plan. + const { shown: showWallsBelow, setShown: setShowWallsBelow } = useWallsBelowSetting(levelId) + const showWallsAbove = useEditor((state) => state.showWallsAbove) + const setShowWallsAbove = useEditor((state) => state.setShowWallsAbove) const showGrid = useViewer((state) => state.showGrid) const setShowGrid = useViewer((state) => state.setShowGrid) const showMeasurements = useViewer((state) => state.showMeasurements) @@ -404,11 +486,11 @@ function DisplayMenu() { const setMagneticSnap = useEditor((state) => state.setMagneticSnap) const annotationVisibility = useFloorplanAnnotationVisibility((state) => state.visibility) const setAnnotationCategory = useFloorplanAnnotationVisibility((state) => state.setCategory) - const wallDimensionReference = useFloorplanAnnotationVisibility( - (state) => state.wallDimensionReference, - ) - const setWallDimensionReference = useFloorplanAnnotationVisibility( - (state) => state.setWallDimensionReference, + const showDimensions = useFloorplanAnnotationVisibility((state) => state.showDimensions) + const setShowDimensions = useFloorplanAnnotationVisibility((state) => state.setShowDimensions) + const wallDimensionFaces = useFloorplanAnnotationVisibility((state) => state.wallDimensionFaces) + const setWallDimensionFaces = useFloorplanAnnotationVisibility( + (state) => state.setWallDimensionFaces, ) const floorplanMode = useFloorplanMode((state) => state.mode) const setFloorplanMode = useFloorplanMode((state) => state.setMode) @@ -417,12 +499,31 @@ function DisplayMenu() { SHADING_OPTIONS.find((option) => option.id === shading) ?? SHADING_OPTIONS[0] const activeEdges = EDGE_OPTIONS.find((option) => option.id === edges) ?? EDGE_OPTIONS[0] const activeTheme = getSceneTheme(sceneTheme) - - // Keep the menu open when flipping a toggle. - const keepOpen = (event: Event, fn: () => void) => { - event.preventDefault() - fn() - } + const activeMeasureWalls = + MEASURE_WALLS_OPTIONS.find((option) => option.id === wallDimensionFaces) ?? + MEASURE_WALLS_OPTIONS[2] + const onLabel = i18n._({ id: 'app.viewerToolbar.on', message: 'On' }) + const offLabel = i18n._({ id: 'app.viewerToolbar.off', message: 'Off' }) + const planOnly = i18n._({ id: 'app.viewerToolbar.n2dOnly', message: '2D only' }) + const sceneOnly = i18n._({ id: 'app.viewerToolbar.n3dOnly', message: '3D only' }) + const otherLevelChips = [ + { + id: 'below', + shown: showWallsBelow, + toggle: () => setShowWallsBelow(!showWallsBelow), + icon: ArrowDown, + name: i18n._({ id: 'app.viewerToolbar.below', message: 'Below' }), + label: i18n._({ id: 'editor.actionMenu.viewToggles.wallsBelow', message: 'Walls below' }), + }, + { + id: 'above', + shown: showWallsAbove, + toggle: () => setShowWallsAbove(!showWallsAbove), + icon: ArrowUp, + name: i18n._({ id: 'app.viewerToolbar.above', message: 'Above' }), + label: i18n._({ id: 'editor.actionMenu.viewToggles.wallsAbove', message: 'Walls above' }), + }, + ] return ( @@ -447,69 +548,208 @@ function DisplayMenu() { - keepOpen(e, () => setShowGrid(!showGrid))}> - - {i18n._({ id: 'app.viewerToolbar.grid', message: 'Grid' })} - {showGrid ? ( - - ) : ( - - )} - - {scene === '3d' || scene === 'split' ? ( - keepOpen(e, () => setShowMeasurements(!showMeasurements))} - > - - - {scene === 'split' - ? i18n._({ id: 'app.viewerToolbar.n3dMeasurements', message: '3D measurements' }) - : i18n._({ id: 'app.viewerToolbar.measurements', message: 'Measurements' })} - - {showMeasurements ? ( - - ) : ( - - )} +
+

+ {i18n._({ id: 'app.viewerToolbar.display', message: 'Display' })} +

+

+ + {layout.scope === 'shared' + ? i18n._({ id: 'app.viewerToolbar.sharedBy2dAnd3d', message: 'Shared by 2D and 3D' }) + : layout.scope === '2d' + ? planOnly + : sceneOnly} +

+
+ + + + keepOpen(e, () => setShowGrid(!showGrid))}> + + {i18n._({ id: 'app.viewerToolbar.grid', message: 'Grid' })} + - ) : null} - {scene === '2d' || scene === 'split' ? ( - <> - - - - - {i18n._({ id: 'app.viewerToolbar.floorPlanMode', message: 'Floor plan mode' })} + {layout.otherLevels ? ( +
+ +
+ + {i18n._({ id: 'app.viewerToolbar.otherLevels', message: 'Other levels' })} - - {floorplanMode === 'default' - ? i18n._({ id: 'app.viewerToolbar.default', message: 'Default' }) - : i18n._({ id: 'app.viewerToolbar.expert', message: 'Expert' })} + + {i18n._({ + id: 'app.viewerToolbar.ghostedForReference', + message: 'Ghosted for reference', + })} - - - {FLOORPLAN_MODE_OPTIONS.map((option) => ( - setFloorplanMode(option.id)}> -
- {i18n._(option.name)} - {i18n._(option.detail)} -
- {floorplanMode === option.id ? ( - - ) : null} +
+ {otherLevelChips.map((chip) => ( + keepOpen(e, chip.toggle)} + role="menuitemcheckbox" + > + + {chip.name} + + ))} +
+ ) : null} +
+ + + + keepOpen(e, () => setShowDimensions(!showDimensions))}> + + {i18n._({ id: 'app.viewerToolbar.dimensions', message: 'Dimensions' })} + + +
+
+ + {i18n._({ id: 'app.viewerToolbar.measureWalls', message: 'Measure walls' })} +
+
+ {MEASURE_WALLS_OPTIONS.map((option) => { + const checked = wallDimensionFaces === option.id + return ( + keepOpen(e, () => setWallDimensionFaces(option.id))} + role="menuitemradio" + > + {i18n._(option.name)} + + {i18n._(option.tag)} + - ))} - - - {floorplanMode === 'expert' ? ( - <> + ) + })} +
+

+ {showDimensions + ? i18n._(activeMeasureWalls.detail) + : i18n._({ + id: 'app.viewerToolbar.turnOnDimensionsToShowThem', + message: 'Turn on Dimensions to show them', + })} +

+
+ + + + {i18n._({ id: 'app.viewerToolbar.units', message: 'Units' })} + + {unit === 'imperial' + ? i18n._({ id: 'app.viewerToolbar.feetInches', message: 'Feet & inches' }) + : metricNotation === 'millimeters' + ? i18n._({ id: 'app.viewerToolbar.millimeters', message: 'Millimeters' }) + : i18n._({ id: 'app.viewerToolbar.meters', message: 'Meters' })} + + + + setMetricNotation('meters')}> + + m + + {i18n._({ id: 'app.viewerToolbar.meters', message: 'Meters' })} + {unit === 'metric' && metricNotation === 'meters' ? ( + + ) : null} + + setMetricNotation('millimeters')}> + + mm + + + {i18n._({ id: 'app.viewerToolbar.millimeters', message: 'Millimeters' })} + + {unit === 'metric' && metricNotation === 'millimeters' ? ( + + ) : null} + + setUnit('imperial')}> + + ft + + + {i18n._({ id: 'app.viewerToolbar.feetInches', message: 'Feet & inches' })} + + {unit === 'imperial' ? : null} + + + +
+ + {layout.plan ? ( + <> + + + + + + + {i18n._({ id: 'app.viewerToolbar.floorPlanMode', message: 'Floor plan mode' })} + + + {floorplanMode === 'default' + ? i18n._({ id: 'app.viewerToolbar.default', message: 'Default' }) + : i18n._({ id: 'app.viewerToolbar.expert', message: 'Expert' })} + + + + {FLOORPLAN_MODE_OPTIONS.map((option) => ( + setFloorplanMode(option.id)}> +
+ {i18n._(option.name)} + + {i18n._(option.detail)} + +
+ {floorplanMode === option.id ? ( + + ) : null} +
+ ))} +
+
+ {/* Default draws a fixed clean set: the categories only apply in Expert. */} + {floorplanMode === 'expert' ? ( - + {i18n._({ id: 'app.viewerToolbar.floorPlanAnnotations', @@ -530,226 +770,170 @@ function DisplayMenu() { > {i18n._(option.name)} - {visible ? ( - - ) : ( - - )} +
) })} - - - - - {i18n._({ - id: 'app.viewerToolbar.wallDimensions', - message: 'Wall dimensions', - })} - - - {i18n._( - ( - FLOORPLAN_WALL_DIMENSION_REFERENCE_OPTIONS.find( - (option) => option.id === wallDimensionReference, - ) ?? FLOORPLAN_WALL_DIMENSION_REFERENCE_OPTIONS[0] - ).name, - )} - - - - {FLOORPLAN_WALL_DIMENSION_REFERENCE_OPTIONS.map((option) => ( - - keepOpen(event, () => setWallDimensionReference(option.id)) - } - > + ) : null} + + + ) : null} + + {layout.scene ? ( + <> + + + keepOpen(e, () => setShowCeilings(!showCeilings))}> + + {i18n._({ id: 'app.viewerToolbar.ceilings', message: 'Ceilings' })} + + + keepOpen(e, () => setShowMeasurements(!showMeasurements))} + > + + + {i18n._({ id: 'app.viewerToolbar.measurements', message: 'Measurements' })} + + + + + + + {i18n._({ id: 'app.viewerToolbar.render', message: 'Render' })} + + {i18n._(activeShading.name)} + + + + {SHADING_OPTIONS.map((option) => { + const OptionIcon = option.icon + return ( + setShading(option.id)}> +
{i18n._(option.name)} {i18n._(option.detail)}
- {wallDimensionReference === option.id ? ( + {shading === option.id ? ( ) : null}
- ))} -
-
- - ) : null} + ) + })} +
+
+ + + + {i18n._({ id: 'app.viewerToolbar.edges', message: 'Edges' })} + + {i18n._(activeEdges.name)} + + + + {EDGE_OPTIONS.map((option) => ( + setEdges(option.id)}> +
+ {i18n._(option.name)} + + {i18n._(option.detail)} + +
+ {edges === option.id ? ( + + ) : null} +
+ ))} +
+
+ keepOpen(e, () => setShadows(!shadows))}> + + {i18n._({ id: 'app.viewerToolbar.shadows', message: 'Shadows' })} + + {shadows ? onLabel : offLabel} + + + + keepOpen(e, () => + setCameraMode(cameraMode === 'perspective' ? 'orthographic' : 'perspective'), + ) + } + > + + {i18n._({ id: 'app.viewerToolbar.camera', message: 'Camera' })} + + {cameraMode === 'perspective' + ? i18n._({ id: 'app.viewerToolbar.perspective', message: 'Perspective' }) + : i18n._({ id: 'app.viewerToolbar.orthographic', message: 'Orthographic' })} + + + + + + + {i18n._({ id: 'app.viewerToolbar.sceneTheme', message: 'Scene theme' })} + + + {sceneThemeName(activeTheme.id, activeTheme.name, i18n)} + + + + {SCENE_THEMES.map((theme) => { + const swatches = (['wall', 'roof', 'floor', 'glazing'] as const).map( + (role) => theme.clayTints?.[role] ?? CLAY_PALETTE[role], + ) + return ( + setSceneTheme(theme.id)}> + + {swatches.map((color, index) => ( + + ))} + + + {sceneThemeName(theme.id, theme.name, i18n)} + + {sceneTheme === theme.id ? ( + + ) : null} + + ) + })} + + + ) : null} - keepOpen(e, () => setMagneticSnap(!magneticSnap))}> - - {i18n._({ id: 'app.viewerToolbar.magneticSnap', message: 'Magnetic snap' })} - - {magneticSnap - ? i18n._({ id: 'app.viewerToolbar.on', message: 'On' }) - : i18n._({ id: 'app.viewerToolbar.off', message: 'Off' })} - - - keepOpen(e, () => setShadows(!shadows))}> - - {i18n._({ id: 'app.viewerToolbar.shadows', message: 'Shadows' })} - - {shadows - ? i18n._({ id: 'app.viewerToolbar.on', message: 'On' }) - : i18n._({ id: 'app.viewerToolbar.off', message: 'Off' })} - - - - keepOpen(e, () => - setCameraMode(cameraMode === 'perspective' ? 'orthographic' : 'perspective'), - ) - } - > - - {i18n._({ id: 'app.viewerToolbar.camera', message: 'Camera' })} - - {cameraMode === 'perspective' - ? i18n._({ id: 'app.viewerToolbar.perspective', message: 'Perspective' }) - : i18n._({ id: 'app.viewerToolbar.orthographic', message: 'Orthographic' })} - - - - - - {unit === 'imperial' ? 'ft' : metricNotation === 'millimeters' ? 'mm' : 'm'} - - {i18n._({ id: 'app.viewerToolbar.units', message: 'Units' })} - - {unit === 'imperial' - ? i18n._({ id: 'app.viewerToolbar.feetInches', message: 'Feet & inches' }) - : metricNotation === 'millimeters' - ? i18n._({ id: 'app.viewerToolbar.millimeters', message: 'Millimeters' }) - : i18n._({ id: 'app.viewerToolbar.meters', message: 'Meters' })} - - - - setMetricNotation('meters')}> - - m - - {i18n._({ id: 'app.viewerToolbar.meters', message: 'Meters' })} - {unit === 'metric' && metricNotation === 'meters' ? ( - - ) : null} - - setMetricNotation('millimeters')}> - - mm - - {i18n._({ id: 'app.viewerToolbar.millimeters', message: 'Millimeters' })} - {unit === 'metric' && metricNotation === 'millimeters' ? ( - - ) : null} - - setUnit('imperial')}> - - ft - - - {i18n._({ id: 'app.viewerToolbar.feetInches', message: 'Feet & inches' })} - - {unit === 'imperial' ? : null} - - - - - - - - {i18n._({ id: 'app.viewerToolbar.render', message: 'Render' })} - - {i18n._(activeShading.name)} + + keepOpen(e, () => setMagneticSnap(!magneticSnap))}> + + + {i18n._({ id: 'app.viewerToolbar.magneticSnap', message: 'Magnetic snap' })} - - - {SHADING_OPTIONS.map((option) => { - const OptionIcon = option.icon - return ( - setShading(option.id)}> - -
- {i18n._(option.name)} - {i18n._(option.detail)} -
- {shading === option.id ? ( - - ) : null} -
- ) - })} -
-
- - - - - {i18n._({ id: 'app.viewerToolbar.edges', message: 'Edges' })} - {i18n._(activeEdges.name)} - - - - {EDGE_OPTIONS.map((option) => ( - setEdges(option.id)}> -
- {i18n._(option.name)} - {i18n._(option.detail)} -
- {edges === option.id ? : null} -
- ))} -
-
- - - - - {i18n._({ id: 'app.viewerToolbar.sceneTheme', message: 'Scene theme' })} - - {sceneThemeName(activeTheme.id, activeTheme.name, i18n)} + {magneticSnap ? onLabel : offLabel} - - - {SCENE_THEMES.map((theme) => { - const swatches = (['wall', 'roof', 'floor', 'glazing'] as const).map( - (role) => theme.clayTints?.[role] ?? CLAY_PALETTE[role], - ) - return ( - setSceneTheme(theme.id)}> - - {swatches.map((color, index) => ( - - ))} - - - {sceneThemeName(theme.id, theme.name, i18n)} - - {sceneTheme === theme.id ? ( - - ) : null} - - ) - })} - - + +
) diff --git a/apps/editor/lib/build-palette.test.ts b/apps/editor/lib/build-palette.test.ts new file mode 100644 index 0000000000..b4755b7150 --- /dev/null +++ b/apps/editor/lib/build-palette.test.ts @@ -0,0 +1,22 @@ +import { expect, test } from 'bun:test' +import { registerNode } from '@pascal-app/core' +import { beamDefinition, columnDefinition } from '@pascal-app/nodes' +import { collectBuildTypes } from './build-palette' + +// The beam brings its plan tool; the post is the column tool armed with a framing post. +test('the Build palette lists Beam, and Post beside Column, under Advanced', () => { + registerNode(beamDefinition) + registerNode(columnDefinition) + const types = collectBuildTypes('default') + expect(types.find((type) => type.kind === 'beam')).toMatchObject({ + label: { message: 'Beam' }, + section: 'advanced', + iconSrc: '/icons/beam.svg', + }) + const ids = types.map((type) => type.id) + expect(types.find((type) => type.id === 'post')).toMatchObject({ + kind: 'column', + section: 'advanced', + }) + expect(ids.indexOf('post')).toBe(ids.indexOf('column') + 1) +}) diff --git a/apps/editor/lib/build-palette.ts b/apps/editor/lib/build-palette.ts index 7a3ba56665..af1d540f2e 100644 --- a/apps/editor/lib/build-palette.ts +++ b/apps/editor/lib/build-palette.ts @@ -8,7 +8,7 @@ import { useEditor, useFloorplanMode, } from '@pascal-app/editor' -import { beginFenceFeaturePlacement } from '@pascal-app/nodes' +import { armFramingPostTool, beginFenceFeaturePlacement } from '@pascal-app/nodes' import { useViewer } from '@pascal-app/viewer' import { getRoofFootprintSource, type RoofFootprintSource } from '@/lib/build-tab-state' @@ -110,6 +110,14 @@ export const BASE_BUILD_TYPES: BuildType[] = [ kind: 'column', section: 'advanced', }, + // The column tool armed with a framing post (`activatePostTool`): one family with Column. + { + id: 'post', + label: /* i18n */ { id: 'app.lib.buildPalette.post', message: 'Post' }, + iconSrc: '/icons/post.svg', + kind: 'column', + section: 'advanced', + }, { id: 'shelf', label: /* i18n */ { id: 'app.lib.buildPalette.shelf', message: 'Shelf' }, @@ -253,6 +261,15 @@ export function activateBuildTool(kind: string): void { editor.setTool(kind) } +/** + * The Post tile: the column tool placing treated framing posts that stand up to the beam over + * them, at the size and base last picked (the tool's Place and Base rows). + */ +export function activatePostTool(): void { + activateBuildTool('column') + if (useEditor.getState().tool === 'column') armFramingPostTool() +} + export function activateFenceFeaturePlacement(kind: 'gate' | 'opening'): void { beginFenceFeaturePlacement(kind) } diff --git a/apps/editor/lib/build-panel-model.ts b/apps/editor/lib/build-panel-model.ts index 560e2e31c0..b0cb89faf2 100644 --- a/apps/editor/lib/build-panel-model.ts +++ b/apps/editor/lib/build-panel-model.ts @@ -9,7 +9,7 @@ import { useScene, } from '@pascal-app/core' import { type PanelToolOption, useEditor, useFloorplanMode } from '@pascal-app/editor' -import { useLiquidLineToolOptions } from '@pascal-app/nodes' +import { framingPostToolChoices, useLiquidLineToolOptions } from '@pascal-app/nodes' import { useViewer } from '@pascal-app/viewer' import type { XRWandBuildItem, XRWandBuildModel } from '@webxr/plugin' import { @@ -17,6 +17,7 @@ import { activateFenceFeaturePlacement, activateModularCabinetTool, activatePaintMode, + activatePostTool, activateRoofFeatureTool, activateRoofFootprintSource, activateRoofType, @@ -96,6 +97,7 @@ export function useBuildPanelModel(): XRWandBuildModel { return host?.type === 'fence' ? host : undefined }) const defaults = useEditor((state) => state.toolDefaults.roof) + const postArmed = useEditor((state) => framingPostToolChoices(state.toolDefaults.column) !== null) const floorplanMode = useFloorplanMode((state) => state.mode) useRegistryVersion() const features = collectRoofFeatures() @@ -124,12 +126,15 @@ export function useBuildPanelModel(): XRWandBuildModel { ? mepActive : type.id === 'kitchen' ? kitchenActive - : mode === 'build' && tool === type.kind, + : type.kind === 'column' + ? mode === 'build' && tool === 'column' && (type.id === 'post') === postArmed + : mode === 'build' && tool === type.kind, onSelect: () => { if (type.id === 'fence' && selectedFence) return if (type.mode === 'terrain-sculpt') activateTerrainSculptMode() else if (type.id === 'mep') activateBuildTool('duct-segment') else if (type.id === 'kitchen') activateModularCabinetTool() + else if (type.id === 'post') activatePostTool() else if (type.kind) activateBuildTool(type.kind) }, }), diff --git a/apps/editor/lib/display-menu.test.ts b/apps/editor/lib/display-menu.test.ts new file mode 100644 index 0000000000..fce9d615ce --- /dev/null +++ b/apps/editor/lib/display-menu.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, test } from 'bun:test' +import { displayMenuLayout } from './display-menu' + +describe('Display menu layout', () => { + test('the plan alone shows the Plan group and other levels, not the Scene group', () => { + expect(displayMenuLayout('2d')).toEqual({ + scope: '2d', + otherLevels: true, + plan: true, + scene: false, + viewTags: false, + }) + }) + + test('the 3D view alone shows the Scene group, without other levels', () => { + expect(displayMenuLayout('3d')).toEqual({ + scope: '3d', + otherLevels: false, + plan: false, + scene: true, + viewTags: false, + }) + }) + + test('split shows every group, shared, with the view-only groups tagged', () => { + expect(displayMenuLayout('split')).toEqual({ + scope: 'shared', + otherLevels: true, + plan: true, + scene: true, + viewTags: true, + }) + }) +}) diff --git a/apps/editor/lib/display-menu.ts b/apps/editor/lib/display-menu.ts new file mode 100644 index 0000000000..a614077824 --- /dev/null +++ b/apps/editor/lib/display-menu.ts @@ -0,0 +1,31 @@ +/** The views on screen, as `visibleScene` reports them (`null`: none yet). */ +export type DisplayMenuScene = '2d' | '3d' | 'split' | null + +export type DisplayMenuLayout = { + /** The header's scope line: what the settings apply to. */ + scope: 'shared' | '2d' | '3d' + /** Other levels (walls below / above) draw on the plan only. */ + otherLevels: boolean + /** Plan: floor plan mode and annotations. */ + plan: boolean + /** Scene: ceilings, measurements and the 3D look. */ + scene: boolean + /** With both views up, the view-specific groups say which view they change. */ + viewTags: boolean +} + +/** + * Which groups the Display menu shows for the views on screen. Show, + * Dimensions and Editing apply to both views and are always there. + */ +export function displayMenuLayout(scene: DisplayMenuScene): DisplayMenuLayout { + const plan = scene !== '3d' + const model = scene !== '2d' + return { + scope: plan && model ? 'shared' : plan ? '2d' : '3d', + otherLevels: plan, + plan, + scene: model, + viewTags: plan && model, + } +} diff --git a/apps/editor/public/icons/beam.svg b/apps/editor/public/icons/beam.svg new file mode 100644 index 0000000000..4c35ba1f14 --- /dev/null +++ b/apps/editor/public/icons/beam.svg @@ -0,0 +1 @@ + diff --git a/apps/editor/public/icons/post.svg b/apps/editor/public/icons/post.svg new file mode 100644 index 0000000000..eeea97d10f --- /dev/null +++ b/apps/editor/public/icons/post.svg @@ -0,0 +1 @@ + diff --git a/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_ambientocclusion.webp b/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_ambientocclusion.webp deleted file mode 100644 index f9f720797c..0000000000 Binary files a/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_ambientocclusion.webp and /dev/null differ diff --git a/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_ao_512.ktx2 b/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_ao_512.ktx2 new file mode 100644 index 0000000000..07a9ff2604 Binary files /dev/null and b/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_ao_512.ktx2 differ diff --git a/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_basecolor.webp b/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_basecolor.webp deleted file mode 100644 index 43328559f0..0000000000 Binary files a/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_basecolor.webp and /dev/null differ diff --git a/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_basecolor_512.ktx2 b/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_basecolor_512.ktx2 new file mode 100644 index 0000000000..66bd40019f Binary files /dev/null and b/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_basecolor_512.ktx2 differ diff --git a/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_metallic.webp b/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_metallic.webp deleted file mode 100644 index 824b142ecd..0000000000 Binary files a/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_metallic.webp and /dev/null differ diff --git a/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_metallic_512.ktx2 b/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_metallic_512.ktx2 new file mode 100644 index 0000000000..eb8a4f3320 Binary files /dev/null and b/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_metallic_512.ktx2 differ diff --git a/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_normal.webp b/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_normal.webp deleted file mode 100644 index f30590854f..0000000000 Binary files a/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_normal.webp and /dev/null differ diff --git a/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_normal_512.ktx2 b/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_normal_512.ktx2 new file mode 100644 index 0000000000..1ff8318fd6 Binary files /dev/null and b/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_normal_512.ktx2 differ diff --git a/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_roughness.webp b/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_roughness.webp deleted file mode 100644 index eab36008fe..0000000000 Binary files a/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_roughness.webp and /dev/null differ diff --git a/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_roughness_512.ktx2 b/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_roughness_512.ktx2 new file mode 100644 index 0000000000..266fc8a130 Binary files /dev/null and b/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_roughness_512.ktx2 differ diff --git a/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_thumb.webp b/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_thumb.webp new file mode 100644 index 0000000000..e15ce8d632 Binary files /dev/null and b/apps/editor/public/material/roofing/roof_shingles_classic/roof_shingles_classic_thumb.webp differ diff --git a/apps/editor/public/material/roofing/roof_shingles_grey/roof_shingles_grey_basecolor.webp b/apps/editor/public/material/roofing/roof_shingles_grey/roof_shingles_grey_basecolor.webp deleted file mode 100644 index 4e988c910e..0000000000 Binary files a/apps/editor/public/material/roofing/roof_shingles_grey/roof_shingles_grey_basecolor.webp and /dev/null differ diff --git a/apps/editor/public/material/roofing/roof_shingles_grey/roof_shingles_grey_basecolor_512.ktx2 b/apps/editor/public/material/roofing/roof_shingles_grey/roof_shingles_grey_basecolor_512.ktx2 new file mode 100644 index 0000000000..14ef01337c Binary files /dev/null and b/apps/editor/public/material/roofing/roof_shingles_grey/roof_shingles_grey_basecolor_512.ktx2 differ diff --git a/apps/editor/public/material/roofing/roof_shingles_grey/roof_shingles_grey_basecolor_512.webp b/apps/editor/public/material/roofing/roof_shingles_grey/roof_shingles_grey_basecolor_512.webp deleted file mode 100644 index 3db2655ccf..0000000000 Binary files a/apps/editor/public/material/roofing/roof_shingles_grey/roof_shingles_grey_basecolor_512.webp and /dev/null differ diff --git a/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_ambientocclusion.webp b/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_ambientocclusion.webp deleted file mode 100644 index 95fd2da347..0000000000 Binary files a/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_ambientocclusion.webp and /dev/null differ diff --git a/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_ao_512.ktx2 b/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_ao_512.ktx2 new file mode 100644 index 0000000000..ddc5242e4a Binary files /dev/null and b/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_ao_512.ktx2 differ diff --git a/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_basecolor.webp b/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_basecolor.webp deleted file mode 100644 index 1872a1ccca..0000000000 Binary files a/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_basecolor.webp and /dev/null differ diff --git a/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_basecolor_512.ktx2 b/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_basecolor_512.ktx2 new file mode 100644 index 0000000000..9499156c20 Binary files /dev/null and b/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_basecolor_512.ktx2 differ diff --git a/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_metallic.webp b/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_metallic.webp deleted file mode 100644 index 269e23a789..0000000000 Binary files a/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_metallic.webp and /dev/null differ diff --git a/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_metallic_512.ktx2 b/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_metallic_512.ktx2 new file mode 100644 index 0000000000..eb8a4f3320 Binary files /dev/null and b/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_metallic_512.ktx2 differ diff --git a/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_normal.webp b/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_normal.webp deleted file mode 100644 index e45075a866..0000000000 Binary files a/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_normal.webp and /dev/null differ diff --git a/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_normal_512.ktx2 b/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_normal_512.ktx2 new file mode 100644 index 0000000000..c2d9919250 Binary files /dev/null and b/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_normal_512.ktx2 differ diff --git a/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_roughness.webp b/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_roughness.webp deleted file mode 100644 index d88a07be24..0000000000 Binary files a/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_roughness.webp and /dev/null differ diff --git a/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_roughness_512.ktx2 b/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_roughness_512.ktx2 new file mode 100644 index 0000000000..3c3dbc4fcf Binary files /dev/null and b/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_roughness_512.ktx2 differ diff --git a/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_thumb.webp b/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_thumb.webp new file mode 100644 index 0000000000..ef50aae66d Binary files /dev/null and b/apps/editor/public/material/roofing/roof_shingles_weathered/roof_shingles_weathered_thumb.webp differ diff --git a/apps/editor/public/material/siding/batten_albedo_512.webp b/apps/editor/public/material/siding/batten_albedo_512.webp deleted file mode 100644 index e4a58f6b84..0000000000 Binary files a/apps/editor/public/material/siding/batten_albedo_512.webp and /dev/null differ diff --git a/apps/editor/public/material/siding/batten_ao_512.ktx2 b/apps/editor/public/material/siding/batten_ao_512.ktx2 new file mode 100644 index 0000000000..97d6394809 Binary files /dev/null and b/apps/editor/public/material/siding/batten_ao_512.ktx2 differ diff --git a/apps/editor/public/material/siding/batten_basecolor_512.ktx2 b/apps/editor/public/material/siding/batten_basecolor_512.ktx2 new file mode 100644 index 0000000000..d5ef5444d3 Binary files /dev/null and b/apps/editor/public/material/siding/batten_basecolor_512.ktx2 differ diff --git a/apps/editor/public/material/siding/batten_normal_512.ktx2 b/apps/editor/public/material/siding/batten_normal_512.ktx2 new file mode 100644 index 0000000000..4609e3b993 Binary files /dev/null and b/apps/editor/public/material/siding/batten_normal_512.ktx2 differ diff --git a/apps/editor/public/material/siding/batten_roughness_512.ktx2 b/apps/editor/public/material/siding/batten_roughness_512.ktx2 new file mode 100644 index 0000000000..6814a79ef3 Binary files /dev/null and b/apps/editor/public/material/siding/batten_roughness_512.ktx2 differ diff --git a/apps/editor/public/material/siding/batten_thumb.webp b/apps/editor/public/material/siding/batten_thumb.webp new file mode 100644 index 0000000000..4fcc602b80 Binary files /dev/null and b/apps/editor/public/material/siding/batten_thumb.webp differ diff --git a/apps/editor/public/material/siding/lap_albedo_512.webp b/apps/editor/public/material/siding/lap_albedo_512.webp deleted file mode 100644 index c80920e865..0000000000 Binary files a/apps/editor/public/material/siding/lap_albedo_512.webp and /dev/null differ diff --git a/apps/editor/public/material/siding/lap_ao_512.ktx2 b/apps/editor/public/material/siding/lap_ao_512.ktx2 new file mode 100644 index 0000000000..6c70faffa0 Binary files /dev/null and b/apps/editor/public/material/siding/lap_ao_512.ktx2 differ diff --git a/apps/editor/public/material/siding/lap_basecolor_512.ktx2 b/apps/editor/public/material/siding/lap_basecolor_512.ktx2 new file mode 100644 index 0000000000..497e7fbb35 Binary files /dev/null and b/apps/editor/public/material/siding/lap_basecolor_512.ktx2 differ diff --git a/apps/editor/public/material/siding/lap_normal_512.ktx2 b/apps/editor/public/material/siding/lap_normal_512.ktx2 new file mode 100644 index 0000000000..ae348803d7 Binary files /dev/null and b/apps/editor/public/material/siding/lap_normal_512.ktx2 differ diff --git a/apps/editor/public/material/siding/lap_roughness_512.ktx2 b/apps/editor/public/material/siding/lap_roughness_512.ktx2 new file mode 100644 index 0000000000..e0d5b29f38 Binary files /dev/null and b/apps/editor/public/material/siding/lap_roughness_512.ktx2 differ diff --git a/apps/editor/public/material/siding/lap_thumb.webp b/apps/editor/public/material/siding/lap_thumb.webp new file mode 100644 index 0000000000..889b385eb7 Binary files /dev/null and b/apps/editor/public/material/siding/lap_thumb.webp differ diff --git a/i18n/literal-baseline.json b/i18n/literal-baseline.json index 56a22cba10..ab030ff627 100644 --- a/i18n/literal-baseline.json +++ b/i18n/literal-baseline.json @@ -219,9 +219,6 @@ "Lower the floor", "Raise the floor" ], - "packages/editor/src/components/editor/room-handles.tsx": [ - "Floor" - ], "packages/editor/src/components/editor/snapshot-capture-overlay.tsx": [ " freezes this exact camera angle as a reusable reference for renders & videos.", "Area", @@ -600,18 +597,6 @@ "file…", "running in an open Blender." ], - "packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx": [ - "Camera", - "Direct Manipulation", - "Drawing Tools", - "Editor Navigation", - "Item Placement", - "Keyboard shortcuts", - "Keyboard shortcuts", - "Modes & History", - "Selection", - "Shortcuts are context-aware. Guided constraints are enabled by default; hold Shift during an active gesture to build freely." - ], "packages/editor/src/components/ui/sidebar/panels/settings-panel/load-build-dialog.tsx": [ "Buildings", "Cancel", diff --git a/packages/core/src/agent-operations/__fixtures__/cases.ts b/packages/core/src/agent-operations/__fixtures__/cases.ts index dcef7ba639..1ea366fe3a 100644 --- a/packages/core/src/agent-operations/__fixtures__/cases.ts +++ b/packages/core/src/agent-operations/__fixtures__/cases.ts @@ -27,7 +27,7 @@ import { FIND_BY_TYPE_CASES } from './find-by-type-cases' import { FINISH_CASES } from './finish-cases' import { LOT_INFO_CASES } from './lot-info-cases' import { CREATE_ROOF_CASES, MOVE_ROOFS_CASES } from './roof-cases' -import { ROOM_CASES } from './room-cases' +import { OUTDOOR_ROOM_READ_CASES, ROOM_CASES } from './room-cases' import { CHECK_ROOMS_CASES, VALIDATE_SCENE_CASES } from './scene-check-cases' import { SEARCH_ASSETS_CASES } from './search-assets-cases' import { VIEW_ASSETS_CASES } from './view-assets-cases' @@ -45,6 +45,9 @@ import { ADD_FENCE_CASES, ADD_LEVEL_CASES, ADD_WALL_CASES, + WALL_TYPE_CASES, + FRAMING_POST_CASES, + RAILING_WALL_CASES, CREATE_STAIR_CASES, } from './structure-cases' import { UNIT_CASES } from './unit-cases' @@ -279,7 +282,7 @@ export function finishReadbackScene(): SceneGraph { const wall = scene.nodes.wall_ground as WallNode scene.nodes.wall_ground = { ...wall, - slots: { a: 'library:concrete-drywall' }, + slots: { a: 'library:preset-seattlegrey' }, faceRegions: [{ id: 'wainscot', face: 'a', v1: 0.9, finish: 'library:wood' }], } scene.nodes.wall_side = { @@ -510,8 +513,8 @@ export const GET_WALLS_CASES: AgentToolCase[] = [ resolvedHeight: 2.5, heightIsExplicit: true, wallFaceChains: { - a: { kind: 'default', ref: 'library:concrete-drywall' }, - b: { kind: 'default', ref: 'library:concrete-drywall' }, + a: { kind: 'default', ref: 'library:preset-seattlegrey' }, + b: { kind: 'default', ref: 'library:preset-seattlegrey' }, }, openings: [ { id: 'door_ground', type: 'door' }, @@ -524,8 +527,8 @@ export const GET_WALLS_CASES: AgentToolCase[] = [ resolvedHeight: 2.8, heightIsExplicit: false, wallFaceChains: { - a: { kind: 'default', ref: 'library:concrete-drywall' }, - b: { kind: 'default', ref: 'library:concrete-drywall' }, + a: { kind: 'default', ref: 'library:preset-seattlegrey' }, + b: { kind: 'default', ref: 'library:preset-seattlegrey' }, }, openings: [], }, @@ -581,8 +584,8 @@ export const FINISH_READBACK_CASES: AgentToolCase[] = [ { id: 'wall_ground', wallFaceChains: { - a: { kind: 'ref', ref: 'library:concrete-drywall' }, - b: { kind: 'default', ref: 'library:concrete-drywall' }, + a: { kind: 'ref', ref: 'library:preset-seattlegrey' }, + b: { kind: 'default', ref: 'library:preset-seattlegrey' }, }, }, { @@ -629,8 +632,8 @@ export const FINISH_READBACK_CASES: AgentToolCase[] = [ { id: 'wall_upper', wallFaceChains: { - a: { kind: 'default', ref: 'library:concrete-drywall' }, - b: { kind: 'default', ref: 'library:concrete-drywall' }, + a: { kind: 'default', ref: 'library:preset-seattlegrey' }, + b: { kind: 'default', ref: 'library:preset-seattlegrey' }, }, }, ], @@ -964,12 +967,16 @@ export const AGENT_TOOL_CASES: readonly AgentToolCase[] = [ ...CHECK_ROOMS_CASES, ...DELETE_NODE_CASES, ...ROOM_CASES, + ...OUTDOOR_ROOM_READ_CASES, ...CREATE_ROOM_CASES, ...FURNISH_ROOM_CASES, ...SEARCH_ASSETS_CASES, ...VIEW_ASSETS_CASES, ...DESIGN_BRIEF_CASES, ...ADD_WALL_CASES, + ...WALL_TYPE_CASES, + ...FRAMING_POST_CASES, + ...RAILING_WALL_CASES, ...ADD_FENCE_CASES, ...CREATE_ROOF_CASES, ...MOVE_ROOFS_CASES, diff --git a/packages/core/src/agent-operations/__fixtures__/room-cases.ts b/packages/core/src/agent-operations/__fixtures__/room-cases.ts index 194f290018..2a75978ad5 100644 --- a/packages/core/src/agent-operations/__fixtures__/room-cases.ts +++ b/packages/core/src/agent-operations/__fixtures__/room-cases.ts @@ -1,4 +1,4 @@ -import { createZone, cutFloorOpening, divideZone, structureChangeBatch } from '../../commands/structure' +import { createZone, cutFloorOpening, divideZone, setZoneIntent, structureChangeBatch } from '../../commands/structure' import { reconcileSceneStructure } from '../../lib/structure-reconcile' import { type AnyNode, @@ -511,3 +511,61 @@ export const ROOM_CASES: AgentToolCase[] = [ expect: { result: {}, check: holds({ zone: 2 }) }, }, ] + +function outdoorRoomsScene(patch?: Parameters[1]['patch']): SceneGraph { + const scene = kitchenScene() + let nodes = scene.nodes as Record + let sequence = 0 + const mintId = (kind: string) => kind === 'zone' ? 'zone_outdoor' : `${kind}_outdoor${++sequence}` + const porch = createZone(nodes, { + levelId: 'level_rooms', name: 'Porch', polygon: [[2, 4], [6, 4], [6, 6], [2, 6]], + enclose: false, intent: { roomType: 'porch' }, mintId, + }) + nodes = applySceneChanges(nodes, structureChangeBatch(porch.changes)) + nodes = { ...reconcileSceneStructure({ nodes, mintId }).nodes } as Record + if (patch) { + const before = nodes + nodes = applySceneChanges(nodes, structureChangeBatch(setZoneIntent(nodes, { zoneId: 'zone_outdoor', patch }).changes)) + nodes = { ...reconcileSceneStructure({ nodes, previousNodes: before, mintId }).nodes } as Record + } + return { ...scene, nodes } +} + +export const OUTDOOR_ROOM_READ_CASES: AgentToolCase[] = [ + { + name: 'an ordinary room has roomType room, no step-down and no porch framing', + tool: 'get_zones', scene: kitchenScene, input: { levelId: 'level_rooms' }, + expect: { result: {}, contains: { zones: [{ id: 'zone_kitchen', roomType: 'room', floor: { drop: 0 }, porchFraming: null }] } }, + }, + { + name: 'a covered porch reports its default step-down, automatic framing and existing generated counts', + tool: 'get_zones', scene: () => outdoorRoomsScene(), input: { levelId: 'level_rooms' }, + expect: { result: {}, contains: { zones: [{ id: 'zone_outdoor', roomType: 'porch', floor: { drop: 1.5 * 0.0254 }, porchFraming: { auto: true, postSize: '6x6', postSpacing: 8 * 0.3048, beamSize: '6x8', postCount: 3, beamCount: 3 } }] } }, + }, + { + name: 'hand-edited porch framing reports auto false and counts only its own remaining generated parts', + tool: 'get_zones', scene: () => { + const scene = outdoorRoomsScene({ floor: { drop: 0.05 }, porchFraming: { auto: false, postSize: '4x4', postSpacing: 1.5, beamSize: '6x10' } }) + const part = Object.values(scene.nodes as Record).find((node) => node.type === 'column' && node.metadata?.porchOf === 'zone_outdoor')! + delete scene.nodes[part.id] + ;(scene.nodes.level_rooms as LevelNode).children = (scene.nodes.level_rooms as LevelNode).children.filter((id) => id !== part.id) + return scene + }, input: { levelId: 'level_rooms' }, + expect: { result: {}, contains: { zones: [{ id: 'zone_outdoor', roomType: 'porch', floor: { drop: 0.05 }, porchFraming: { auto: false, postSize: '4x4', postSpacing: 1.5, beamSize: '6x10', postCount: 2, beamCount: 3 } }, { id: 'zone_kitchen', porchFraming: null }] } }, + }, + { + name: 'a deck reports its step-down, default boards and no automatic porch roof framing', + tool: 'get_zones', scene: () => outdoorRoomsScene({ roomType: 'deck' }), input: { levelId: 'level_rooms' }, + expect: { result: {}, contains: { zones: [{ id: 'zone_outdoor', roomType: 'deck', floor: { drop: 0.0254 }, porchFraming: { auto: false, postSize: '6x6', postSpacing: 8 * 0.3048, beamSize: '6x8', postCount: 0, beamCount: 0 }, decking: { boardSize: '5/4x6', gap: 0.0254 / 4, direction: 'parallel' } }] } }, + }, + { + name: 'a patio reports step-down and no automatic porch framing', + tool: 'get_zones', scene: () => outdoorRoomsScene({ roomType: 'patio' }), input: { levelId: 'level_rooms' }, + expect: { result: {}, contains: { zones: [{ id: 'zone_outdoor', roomType: 'patio', floor: { drop: 1.5 * 0.0254 }, porchFraming: { auto: false, postSize: '6x6', postSpacing: 8 * 0.3048, beamSize: '6x8', postCount: 0, beamCount: 0 } }] } }, + }, + { + name: 'custom deck boards and explicitly enabled roof framing use the set_zone_intent names and units', + tool: 'get_zones', scene: () => outdoorRoomsScene({ roomType: 'deck', floor: { drop: 0.02 }, porchFraming: { auto: true, postSize: '8x8' }, decking: { boardSize: 'composite', gap: 0.004, direction: 'diagonal' } }), input: { levelId: 'level_rooms' }, + expect: { result: {}, contains: { zones: [{ id: 'zone_outdoor', roomType: 'deck', floor: { drop: 0.02 }, porchFraming: { auto: true, postSize: '8x8', postSpacing: 8 * 0.3048, beamSize: '6x8', postCount: 3, beamCount: 3 }, decking: { boardSize: 'composite', gap: 0.004, direction: 'diagonal' } }] } }, + }, +] diff --git a/packages/core/src/agent-operations/__fixtures__/structure-cases.ts b/packages/core/src/agent-operations/__fixtures__/structure-cases.ts index f8e73a84d0..f8fff294e9 100644 --- a/packages/core/src/agent-operations/__fixtures__/structure-cases.ts +++ b/packages/core/src/agent-operations/__fixtures__/structure-cases.ts @@ -1,10 +1,13 @@ import { type AnyNode, type AnyNodeId, + BeamNode, + ColumnNode, BuildingNode, CeilingNode, type FenceNode, LevelNode, + railingWallDefaults, SiteNode, SlabNode, WallNode, @@ -12,6 +15,7 @@ import { } from '../../schema' import { FOUNDATION_CONSTRUCTIONS } from '../../lib/foundation-construction' import { foundationWallConstruction } from '../../lib/foundation-wall' +import { WALL_ASSEMBLY_PRESETS, wallAssemblyPatch } from '../../systems/wall/wall-assembly' import { getLevelElevations } from '../../services/storey' import type { AgentToolCase, SceneGraph } from './cases' @@ -1304,3 +1308,201 @@ export const CREATE_STAIR_CASES: AgentToolCase[] = [ expect: { refusal: 'unknown_material', mentions: ['railingMaterial', 'library:brass-rail'] }, }, ] + +const ASSEMBLY_PRESET = WALL_ASSEMBLY_PRESETS.find((entry) => entry.id === 'exterior-2x6-siding')! +const PROJECT_TYPE: { id: string; label: string; assembly: import('../../schema').Assembly } = { + id: 'custom-porch', label: 'Porch wall', + assembly: { face: 'exterior' as const, presetId: 'custom-porch', layers: [ + { id: 'framing', role: 'structure' as const, core: true, material: 'wood', thickness: 0.14 }, + { id: 'interior', role: 'lining' as const, material: 'drywall', thickness: 0.01 }, + ] }, +} +function wallTypesScene(): SceneGraph { + const scene = storeysScene() + const site = SiteNode.parse({ id: 'site_types', children: scene.rootNodeIds, wallTypes: [PROJECT_TYPE] }) + for (const id of scene.rootNodeIds) (scene.nodes[id] as AnyNode).parentId = site.id + scene.nodes[site.id] = site + scene.rootNodeIds = [site.id] + return scene +} + +export const WALL_TYPE_CASES: AgentToolCase[] = [ + ...[ASSEMBLY_PRESET, PROJECT_TYPE].map((type): AgentToolCase => ({ + name: `add wall copies ${type.id} layers and thickness, overriding explicit thickness`, + tool: 'add_wall', scene: wallTypesScene, + input: { levelId: 'level_ground', start: [8, 0], end: [8, 4], type: type.id, thickness: 0.3 }, + expect: { result: { ok: true }, check: (result, nodes) => { + const wall = nodes[result.wallId as string] + const patch = wallAssemblyPatch(type.assembly) + return wall?.type === 'wall' && JSON.stringify(wall) === JSON.stringify(WallNode.parse({ ...wall, ...patch })) && wall.thickness === patch.thickness + ? [] : ['Assembly or thickness differs from the panel patch'] + } }, + })), + { + name: 'an explicit assembly below grade keeps its type without claiming default foundation construction', + tool: 'add_wall', scene: basementHouseScene, + input: { levelId: 'level_base', start: [0, 0], end: [6, 0], type: ASSEMBLY_PRESET.id }, + expect: { result: { ok: true }, check: (result, nodes) => { + const wall = nodes[result.wallId as string] + return wall?.type === 'wall' && wall.assembly?.presetId === ASSEMBLY_PRESET.id && !result.construction + ? [] : ['Explicit wall type was replaced or reported as default foundation construction'] + } }, + }, + ...[ASSEMBLY_PRESET, PROJECT_TYPE].map((type): AgentToolCase => ({ + name: `set wall type copies ${type.id} on existing walls`, + tool: 'set_wall_type', scene: wallTypesScene, + input: { wallIds: ['wall_ground'], type: type.id }, + expect: { result: { ok: true, wallIds: ['wall_ground'], type: type.id }, + after: { wall_ground: wallAssemblyPatch(type.assembly) } }, + })), + ...['add_wall', 'set_wall_type'].map((tool): AgentToolCase => ({ + name: 'unknown assembly ids are refused', tool, scene: wallTypesScene, + input: { levelId: 'level_ground', start: [8, 0], end: [8, 4], wallIds: ['wall_ground'], type: 'missing-type' }, + expect: { refusal: 'unknown_wall_type' }, + })), + { + name: 'every wall must exist before any wall type changes', + tool: 'set_wall_type', scene: wallTypesScene, + input: { wallIds: ['wall_ground', 'wall_missing'], type: PROJECT_TYPE.id }, + expect: { refusal: 'target_not_found' }, + }, + { + name: 'clearing an assembly keeps its thickness', + tool: 'set_wall_type', scene: () => { + const scene = wallTypesScene() + Object.assign(scene.nodes.wall_ground!, wallAssemblyPatch(PROJECT_TYPE.assembly)) + return scene + }, + input: { wallIds: ['wall_ground'], type: null }, + expect: { result: { ok: true }, check: (_result, nodes) => { + const wall = nodes.wall_ground + return wall?.type === 'wall' && !wall.assembly && wall.thickness === wallAssemblyPatch(PROJECT_TYPE.assembly).thickness + ? [] : ['Clearing the assembly changed thickness or retained layers'] + } }, + }, + ...[ASSEMBLY_PRESET, PROJECT_TYPE, null].map((type): AgentToolCase => ({ + name: `get walls reports ${type?.id ?? 'no assembly'} and available types`, + tool: 'get_walls', scene: () => { + const scene = wallTypesScene() + if (type) Object.assign(scene.nodes.wall_ground!, wallAssemblyPatch(type.assembly)) + return scene + }, + input: { levelId: 'level_ground' }, + expect: { result: {}, contains: { + walls: [{ id: 'wall_ground', type: type ? { id: type.id, label: type.label } : null }], + wallTypes: [{ id: PROJECT_TYPE.id, label: PROJECT_TYPE.label }, { id: ASSEMBLY_PRESET.id, label: ASSEMBLY_PRESET.label }], + } }, + })), +] + +export const FRAMING_POST_CASES: AgentToolCase[] = [ + { + name: 'role post uses the Post tile defaults and reaches the beam above it', + tool: 'add_column', scene: () => { + const scene = storeysScene() + const beam = BeamNode.parse({ id: 'beam_post', parentId: 'level_ground', start: [7, 0], end: [10, 0], topElevation: 2.6, depth: 0.2 }) + scene.nodes[beam.id] = beam + ;(scene.nodes.level_ground as LevelNode).children.push(beam.id) + return scene + }, + input: { level: 'level_ground', x: 8, z: 0, role: 'post' }, + expect: { result: { ok: true, width: 5.5 * 0.0254, depth: 5.5 * 0.0254 }, check: (result, nodes) => { + const post = nodes[result.columnId as string] + return post?.type === 'column' && post.role === 'post' && post.crossSection === 'square' && post.postBase === 'none' && post.baseStyle === 'none' && post.capitalStyle === 'none' && post.slots?.shaft === 'library:wood-woodplank19' && Math.abs(post.height - 2.4) < 1e-9 + ? [] : [`Wrong Post tile defaults: ${JSON.stringify(post)}`] + } }, + }, + ...(['4x4', '6x6', '8x8'] as const).map((size, index): AgentToolCase => ({ + name: `post ${size} with ${['none', 'post-base', 'pier'][index]} uses native size and base fields`, + tool: 'add_column', scene: storeysScene, + input: { level: 'level_ground', x: 8, z: 0, role: 'post', postSize: size, postBase: ['none', 'post-base', 'pier'][index], height: '8 ft' }, + expect: { result: { ok: true, height: 2.4384 }, check: (result, nodes) => { + const post = nodes[result.columnId as string] + const side = [3.5, 5.5, 7.25][index]! * 0.0254 + const base = ['none', 'post-base', 'pier'][index] + return post?.type === 'column' && post.width === side && post.depth === side && post.postBase === base && post.baseStyle === (index === 0 ? 'none' : 'simple-square') && post.baseHeight === [0, 1.5 * 0.0254, 8 * 0.0254][index] && (index === 0 || post.slots?.base === ['unused', 'library:metal-steel', 'library:concrete-raw'][index]) + ? [] : ['Post section or base differs from the tile choices'] + } }, + })), + { + name: 'editing a post size and base keeps its authored height, position and shaft finish', + tool: 'add_column', scene: () => { + const scene = storeysScene() + const post = ColumnNode.parse({ id: 'column_post', parentId: 'level_ground', role: 'post', crossSection: 'square', width: 0.1397, depth: 0.1397, height: 1.8, position: [8, 0, 0], slots: { shaft: 'library:preset-white', base: 'library:metal-steel' }, postBase: 'post-base' }) + scene.nodes[post.id] = post + ;(scene.nodes.level_ground as LevelNode).children.push(post.id) + return scene + }, + input: { nodeId: 'column_post', postSize: '8x8', postBase: 'pier' }, + expect: { result: { ok: true }, after: { column_post: { role: 'post', width: 7.25 * 0.0254, depth: 7.25 * 0.0254, height: 1.8, position: [8, 0, 0], postBase: 'pier', baseStyle: 'simple-square', baseHeight: 8 * 0.0254, slots: { shaft: 'library:preset-white', base: 'library:concrete-raw' } } } }, + }, + { + name: 'ordinary columns keep their defaults when no post is requested', + tool: 'add_column', scene: storeysScene, + input: { level: 'level_ground', x: 8, z: 0 }, + expect: { result: { height: 2.5, width: 0.44, depth: 0.44 }, check: (result, nodes) => { + const column = nodes[result.columnId as string] + return column?.type === 'column' && !column.role && !column.postBase && column.crossSection === 'round' ? [] : ['Ordinary column defaults changed'] + } }, + }, + { + name: 'post choices on an ordinary column require role post', + tool: 'add_column', scene: storeysScene, + input: { level: 'level_ground', x: 8, z: 0, postSize: '4x4' }, + expect: { refusal: 'not_a_post' }, + }, +] + +export const RAILING_WALL_CASES: AgentToolCase[] = [ + ...([undefined, 'post-and-rail', 'balusters', 'cable', 'boards', 'glass', 'metal'] as const).map((style): AgentToolCase => ({ + name: `railing ${style ?? 'default'} uses Build panel members and post thickness even below grade`, + tool: 'add_wall', scene: basementHouseScene, + input: { levelId: 'level_base', start: [0, 0], end: [6, 0], wallType: 'railing', thickness: 0.3, ...(style ? { railing: { style } } : {}) }, + expect: { result: { ok: true }, check: (result, nodes) => { + const wall = nodes[result.wallId as string] + const defaults = railingWallDefaults(style) + return wall?.type === 'wall' && wall.wallType === 'railing' && wall.height === defaults.height && wall.thickness === defaults.thickness && !wall.assembly && JSON.stringify(wall.railing) === JSON.stringify(defaults.railing) && !result.construction + ? [] : [`Railing differs from Build defaults: ${JSON.stringify(wall)}`] + } }, + })), + { + name: 'railing accepts every schema setting and a custom guard height in length notation', + tool: 'add_wall', scene: storeysScene, + input: { levelId: 'level_ground', start: [8, 0], end: [8, 4], wallType: 'railing', height: '42 in', thickness: 0.3, + railing: { style: 'cable', postSpacing: '4 ft', postSize: '3 in', infillSize: '0.25 in', infillGap: '2 in', bottomClearance: 0, cap: false } }, + expect: { result: { ok: true }, check: (result, nodes) => { + const wall = nodes[result.wallId as string] + const expected = WallNode.parse({ ...wall, wallType: 'railing', height: 1.0668, thickness: 0.0762, + railing: { style: 'cable', postSpacing: 1.2192, postSize: 0.0762, infillSize: 0.00635, infillGap: 0.0508, bottomClearance: 0, cap: false } }) + return JSON.stringify(wall) === JSON.stringify(expected) ? [] : ['Custom guard settings or height were lost'] + } }, + }, + { + name: 'railing settings require the railing kind', tool: 'add_wall', scene: storeysScene, + input: { levelId: 'level_ground', start: [8, 0], end: [8, 4], railing: { style: 'glass' } }, + expect: { refusal: 'not_a_railing' }, + }, + { + name: 'railings take no assembly type', tool: 'add_wall', scene: storeysScene, + input: { levelId: 'level_ground', start: [8, 0], end: [8, 4], wallType: 'railing', type: ASSEMBLY_PRESET.id }, + expect: { refusal: 'railing_wall' }, + }, + ...(['railing', 'curtain'] as const).map((wallType): AgentToolCase => ({ + name: `existing ${wallType} walls refuse assembly changes`, tool: 'set_wall_type', scene: () => { + const scene = storeysScene() + Object.assign(scene.nodes.wall_ground!, { wallType }) + return scene + }, + input: { wallIds: ['wall_ground'], type: ASSEMBLY_PRESET.id }, + expect: { refusal: `${wallType}_wall` }, + })), + ...([undefined, 'standard', 'railing', 'curtain'] as const).map((wallType): AgentToolCase => ({ + name: `get walls reports wallType ${wallType ?? 'standard for legacy walls'}`, tool: 'get_walls', scene: () => { + const scene = storeysScene() + Object.assign(scene.nodes.wall_ground!, { wallType }) + return scene + }, + input: { levelId: 'level_ground' }, + expect: { result: {}, contains: { walls: [{ id: 'wall_ground', wallType: wallType ?? 'standard' }] } }, + })), +] diff --git a/packages/core/src/agent-operations/add-column.ts b/packages/core/src/agent-operations/add-column.ts index 33672b5288..53af351ce3 100644 --- a/packages/core/src/agent-operations/add-column.ts +++ b/packages/core/src/agent-operations/add-column.ts @@ -1,6 +1,14 @@ import type { z } from 'zod' import type { addColumnTool } from '../agent-tools/columns' import { refuse } from '../agent-tools/refusal' +import { getFloorPlacedElevation } from '../hooks/spatial-grid/floor-placed-elevation' +import { + FRAMING_POST_MIN_HEIGHT, + FRAMING_POST_SIZES, + framingPostBasePatch, + framingPostFields, + framingPostTopAt, +} from '../lib/framing-post' import { matchScriptSlotsToLibrary, requireMeasured, @@ -67,6 +75,10 @@ export const addColumn: AgentOperation = (nodes, input, context) if (compiled) requireMeasured(compiled, { label: input.name, nodeId: input.nodeId, tool: 'add_column' }) const dimensions = compiled ? scriptedSize(compiled.manifest) : undefined + const post = (input.role ?? previous?.role) === 'post' + if (!post && (input.postSize !== undefined || input.postBase !== undefined)) + refuse('not_a_post', 'postSize and postBase require role post or an existing framing post.') + const newPost = post && previous?.role !== 'post' const { nodeId: _, code: _code, @@ -77,14 +89,25 @@ export const addColumn: AgentOperation = (nodes, input, context) y, z, rotation, + postSize, ...fields } = input - const node = ColumnNode.parse({ + let node = ColumnNode.parse({ ...previous, + ...(newPost ? framingPostFields(postSize, input.postBase) : {}), ...fields, + ...(postSize + ? { + width: FRAMING_POST_SIZES[postSize], + depth: FRAMING_POST_SIZES[postSize], + radius: FRAMING_POST_SIZES[postSize] / 2, + } + : {}), ...(compiled?.nodeId ? { id: compiled.nodeId } : {}), name: - input.name ?? previous?.name ?? `Column ${queryNodes(nodes, { type: 'column' }).length + 1}`, + input.name ?? + previous?.name ?? + (post ? 'Post' : `Column ${queryNodes(nodes, { type: 'column' }).length + 1}`), parentId: parent.id, position: [ x ?? previous?.position[0] ?? 0, @@ -107,6 +130,21 @@ export const addColumn: AgentOperation = (nodes, input, context) } : {}), }) + if (post && (newPost || postSize !== undefined || input.postBase !== undefined)) + node = ColumnNode.parse({ + ...node, + ...framingPostBasePatch(node, input.postBase ?? node.postBase ?? 'none'), + }) + if (newPost && input.height === undefined && !compiled) { + const base = + getFloorPlacedElevation({ node, nodes, position: node.position, levelId: parent.id }) + + node.position[1] + const { top } = framingPostTopAt(nodes, parent.id, [node.position[0], node.position[2]], { + baseElevation: base, + side: node.width, + }) + node = { ...node, height: Math.max(FRAMING_POST_MIN_HEIGHT, top - base) } + } const slotIds = new Set(compiled?.manifest.slots.map((slot) => slot.id)) const orphanedSlots = compiled ? Object.keys(previous?.slots ?? {}).filter((id) => !slotIds.has(id)) diff --git a/packages/core/src/agent-operations/add-wall.ts b/packages/core/src/agent-operations/add-wall.ts index a68913c1b0..7b595b17fb 100644 --- a/packages/core/src/agent-operations/add-wall.ts +++ b/packages/core/src/agent-operations/add-wall.ts @@ -7,28 +7,30 @@ import { withFoundationConstruction, } from '../lib/foundation-wall' import { lotOverhang } from '../lib/site-placement' -import { type LevelNode, WallNode } from '../schema' +import { type LevelNode, railingWallDefaults, WallNode } from '../schema' import { normalizeWallCurveOffset } from '../systems/wall/wall-curve' import { WALL_MIN_LENGTH } from '../systems/wall/wall-topology' import { applySceneChanges } from './apply-changes' -import { type LevelTargetInput, targetLevel } from './level-target' +import { targetLevel } from './level-target' import { refuseRoofLevel } from './roof-writes' import { queryNodes } from './scene-queries' import type { AgentOperation } from './types' +import { wallTypePatch } from './wall-type' type Pt = [number, number] -type AddWallInput = LevelTargetInput & { - start: number[] - end: number[] - thickness?: number - height?: number - curveOffset?: number -} +type AddWallInput = z.infer> /** `add_wall`: one wall between two points, named as the editor names walls. */ export const addWall: AgentOperation = (nodes, input, context) => { const level = targetLevel(nodes, input, context) refuseRoofLevel(nodes, level.id, 'a wall') + const railing = input.wallType === 'railing' + if (input.railing && !railing) + refuse('not_a_railing', 'railing settings require wallType railing.') + if (railing && input.type !== undefined) + refuse('railing_wall', 'A railing has no assembly: omit type.') + const guardDefaults = railing ? railingWallDefaults(input.railing?.style) : undefined + const guard = guardDefaults ? { ...guardDefaults.railing, ...input.railing } : undefined const start = input.start as Pt const end = input.end as Pt const length = Math.hypot(end[0] - start[0], end[1] - start[1]) @@ -42,6 +44,7 @@ export const addWall: AgentOperation = (nodes, input, context) => ? normalizeWallCurveOffset({ start, end }, input.curveOffset) : 0 const walls = queryNodes(nodes, { type: 'wall' }).length + const assembly = input.type === undefined ? {} : wallTypePatch(nodes, input.type) const drawn = WallNode.parse({ name: `Wall ${walls + 1}`, parentId: level.id, @@ -50,18 +53,34 @@ export const addWall: AgentOperation = (nodes, input, context) => ...(input.thickness === undefined ? {} : { thickness: input.thickness }), ...(input.height === undefined ? {} : { height: input.height }), ...(curveOffset ? { curveOffset } : {}), + ...assembly, + ...(input.wallType === undefined ? {} : { wallType: input.wallType }), + ...(guardDefaults && guard + ? { + ...guardDefaults, + railing: guard, + height: input.height ?? guardDefaults.height, + thickness: guard.postSize, + } + : {}), }) - const [wall] = withFoundationConstruction( - nodes, - level.id, - [...queryNodes(nodes, { type: 'wall', parentId: level.id }), drawn], - [drawn], - { thickness: input.thickness }, - ) as [WallNode] + const [wall] = railing + ? [drawn] + : (withFoundationConstruction( + nodes, + level.id, + [...queryNodes(nodes, { type: 'wall', parentId: level.id }), drawn], + [drawn], + { thickness: input.thickness, ...assembly }, + ) as [WallNode]) const reading = foundationReadingOfLevel(nodes, level.id) - const foundation = wall.assembly !== undefined + const foundation = input.type === undefined && wall.assembly !== undefined const partition = - !foundation && input.thickness === undefined && levelHoldsFoundationWalls(nodes, level.id) + !railing && + !foundation && + input.type === undefined && + input.thickness === undefined && + levelHoldsFoundationWalls(nodes, level.id) // the wall's mitred band, curve and all: what crosses the lot line, not only its centreline const after = applySceneChanges(nodes, { create: [{ node: wall, parentId: level.id }] }) const site = lotOverhang( @@ -103,3 +122,6 @@ export const addWall: AgentOperation = (nodes, input, context) => changes: { create: [{ node: wall, parentId: level.id }] }, } } + +import type { z } from 'zod' +import type { addWallTool } from '../agent-tools/walls' diff --git a/packages/core/src/agent-operations/author-scene.test.ts b/packages/core/src/agent-operations/author-scene.test.ts index 507924d4ec..a11796a48e 100644 --- a/packages/core/src/agent-operations/author-scene.test.ts +++ b/packages/core/src/agent-operations/author-scene.test.ts @@ -614,6 +614,16 @@ describe('author_scene', () => { expect(outcome.changes?.delete).toEqual(['level_0']) const created = outcome.changes!.create!.map((c) => c.node) const byType = (t: string) => created.filter((n) => n.type === t) + expect(byType('window')[0]).toMatchObject({ + frameThickness: 0.02, + casingFaceA: true, + casingFaceB: true, + }) + expect(byType('door')[0]).toMatchObject({ + frameThickness: 0.02, + casingFaceA: true, + casingFaceB: true, + }) expect(byType('level')).toHaveLength(1) expect(byType('wall')).toHaveLength(4) // Each wall knows which face looks into the room, from the plan: never both the same. @@ -2704,7 +2714,12 @@ describe('author_scene', () => { 'wall glass: a curtain wall has no faces to paint, its color ignored; curtain.frameColor colours its frame', ) const passage = byAuthorId(outcome, 'west/0') - expect(passage).toMatchObject({ type: 'door', openingKind: 'opening', openingShape: 'arch' }) + expect(passage).toMatchObject({ + type: 'door', + frameThickness: 0.02, + openingKind: 'opening', + openingShape: 'arch', + }) expect(outcome.result.passages).toBe(1) expect(outcome.result.defaults).toContain('passage west/0: it has no leaf, its hinge ignored') expect(byAuthorId(outcome, 'west/1')).toMatchObject({ openingShape: 'arch', archHeight: 0.3 }) diff --git a/packages/core/src/agent-operations/author-scene.ts b/packages/core/src/agent-operations/author-scene.ts index 934e119f63..cc10bb4ab0 100644 --- a/packages/core/src/agent-operations/author-scene.ts +++ b/packages/core/src/agent-operations/author-scene.ts @@ -1,6 +1,6 @@ import type { AuthorScenePayload } from '../agent-tools/author-scene' import { refuse } from '../agent-tools/refusal' -import { doorTypeFields } from '../building/door-types' +import { doorTypeFields, NEW_DOOR_FRAME_THICKNESS } from '../building/door-types' import { DOOR_STYLES, type DoorStyle, @@ -9,7 +9,11 @@ import { WINDOW_STYLES, type WindowStyle, } from '../building/opening-style-presets' -import { windowTakesStyle, windowTypeFields } from '../building/window-types' +import { + NEW_WINDOW_FRAME_THICKNESS, + windowTakesStyle, + windowTypeFields, +} from '../building/window-types' import { cutFloorOpening } from '../commands/structure/floor-opening' import { floorRoomFaces } from '../lib/floor-room-faces' import { @@ -1060,6 +1064,8 @@ export function authorScene( visible: true, metadata: { authorScene: { id, color: o.color ?? null } }, wallId: node.id, + casingFaceA: true, + casingFaceB: true, width, height, rotation: [0, 0, 0], @@ -1078,6 +1084,7 @@ export function authorScene( opening = DoorNode.parse({ ...common, type: 'door', + frameThickness: NEW_DOOR_FRAME_THICKNESS, position: [x, height / 2, 0], openingKind: 'opening', }) @@ -1099,6 +1106,7 @@ export function authorScene( opening = DoorNode.parse({ ...common, type: 'door', + frameThickness: NEW_DOOR_FRAME_THICKNESS, position: [x, height / 2, 0], ...(type && isDoorType(type) ? doorTypeFields(type) : {}), ...(style && isDoorStyle(style) ? doorStyleLook(style) : {}), @@ -1127,6 +1135,7 @@ export function authorScene( opening = WindowNode.parse({ ...common, type: 'window', + frameThickness: NEW_WINDOW_FRAME_THICKNESS, position: [x, o.sill + height / 2, 0], ...(windowType ? windowTypeFields(windowType) : {}), ...(style && isWindowStyle(style) && takesStyle ? getWindowStyleOverrides(style) : {}), diff --git a/packages/core/src/agent-operations/create-roof.test.ts b/packages/core/src/agent-operations/create-roof.test.ts index 63ef1bfb39..24199236f1 100644 --- a/packages/core/src/agent-operations/create-roof.test.ts +++ b/packages/core/src/agent-operations/create-roof.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from 'bun:test' import { type AgentRefusal, isAgentRefusal } from '../agent-tools/refusal' -import { BuildingNode, LevelNode, WallNode } from '../schema' +import { BuildingNode, LevelNode, RoofSegmentNode, WallNode } from '../schema' import { planRoofLevel, type RoofLevelPlan } from '../services/roof-level' import { createRoof, grown } from './create-roof' import type { SceneNodes } from './types' @@ -52,6 +52,27 @@ describe('create_roof: a roof outline that stays on the walls', () => { }) }) +describe('create_roof: the heel', () => { + const box: Pt[] = [ + [0, 0], + [8, 0], + [8, 6], + [0, 6], + ] + const heels = (input: Parameters[1]) => + (createRoof(storey(box), input, { activeLevelId: null }).changes?.create ?? []) + .map(({ node }) => node) + .filter((node) => node.type === 'roof-segment') + .map((node) => (node as unknown as { wallHeight: number }).wallHeight) + + test('a new roof starts at the wall tops unless the caller asks for a heel', () => { + expect(heels({})).toEqual([0]) + expect(heels({ wallHeight: 0.4 })).toEqual([0.4]) + // a saved segment with no heel still loads with the schema's 0.5 + expect(RoofSegmentNode.parse({ id: 'rseg_saved' }).wallHeight).toBe(0.5) + }) +}) + describe('create_roof: the level above the covered storey', () => { const house = (above: ReturnType[]) => { const nodes = storey([ diff --git a/packages/core/src/agent-operations/index.ts b/packages/core/src/agent-operations/index.ts index 1383130e58..62d42aa341 100644 --- a/packages/core/src/agent-operations/index.ts +++ b/packages/core/src/agent-operations/index.ts @@ -34,6 +34,7 @@ import { fitStair, measureStairOperation } from './stairs' import type { AgentOperation, AgentOperations } from './types' import { createUnit, listUnits, setUnitMembers } from './units' import { verifyScene } from './verify-scene' +import { setWallType } from './wall-type' export * from './achieved' export * from './add-column' @@ -94,6 +95,7 @@ export * from './wall-face-script' export * from './wall-object-observations' export * from './wall-opening' export * from './wall-skirting' +export * from './wall-type' const SINGLE_OPERATIONS = { measure_stair: measureStairOperation, @@ -111,6 +113,7 @@ const SINGLE_OPERATIONS = { set_checkpoint: setCheckpoint, design_brief: designBrief, add_wall: addWall, + set_wall_type: setWallType, add_fence: addFence, add_corner_window: addCornerWindow, merge_windows: mergeWindowsOperation, diff --git a/packages/core/src/agent-operations/level-reads.ts b/packages/core/src/agent-operations/level-reads.ts index 32ba16477d..b319fcb8e7 100644 --- a/packages/core/src/agent-operations/level-reads.ts +++ b/packages/core/src/agent-operations/level-reads.ts @@ -1,4 +1,7 @@ +import { deckBoardSettings } from '../lib/deck-boards' import { area } from '../lib/polygon-boolean' +import { porchFramingSettings } from '../lib/porch-framing' +import { porchPartOf } from '../lib/porch-framing-sync' import { roomFloorChoices } from '../lib/room-floor-choices' import type { AnyNode, @@ -17,6 +20,7 @@ import { resolveWallEffectiveHeight } from '../systems/wall/wall-top' import { type LevelTargetInput, targetLevel } from './level-target' import { contentCounts, levelIdOf, levelRole, nodesOnLevel, queryNodes } from './scene-queries' import type { AgentOperation, SceneNodes } from './types' +import { wallTypeChoices } from './wall-type' const round2 = (value: number) => Math.round(value * 100) / 100 @@ -48,6 +52,9 @@ export function wallResolvedHeight(nodes: SceneNodes, wall: WallNode): number { } export function wallSummary(nodes: SceneNodes, wall: WallNode) { + const type = wall.assembly?.presetId + ? wallTypeChoices(nodes).find((entry) => entry.id === wall.assembly?.presetId) + : undefined return { id: wall.id, name: wall.name, @@ -58,6 +65,8 @@ export function wallSummary(nodes: SceneNodes, wall: WallNode) { resolvedHeight: wallResolvedHeight(nodes, wall), heightIsExplicit: wall.height !== undefined, thickness: wall.thickness, + wallType: wall.wallType ?? 'standard', + type: type ? { id: type.id, label: type.label } : null, wallFaceChains: { a: resolveWallFaceChain(wall, 'a'), b: resolveWallFaceChain(wall, 'b'), @@ -91,12 +100,29 @@ const unitOf = (nodes: SceneNodes, zoneId: ZoneNode['id']) => { return { unitId: unit?.id ?? null, unit: unit?.name ?? null } } +function zoneFraming(nodes: SceneNodes, zone: ZoneNode) { + const parts = queryNodes(nodes, { type: ['column', 'beam'], parentId: zone.parentId }).filter( + (node) => porchPartOf(node)?.porchOf === zone.id, + ) + if (!zone.roomType && !zone.porchFraming && parts.length === 0) return null + return { + ...porchFramingSettings(zone), + auto: zone.porchFraming?.auto ?? (zone.roomType === 'porch' && zone.hasCeiling !== false), + postCount: parts.filter((node) => node.type === 'column').length, + beamCount: parts.filter((node) => node.type === 'beam').length, + } +} + const zoneSummary = (nodes: SceneNodes, zone: ZoneNode) => ({ id: zone.id, name: zone.name, color: zone.color, polygon: zone.polygon, holes: zone.holes ?? [], + roomType: zone.roomType ?? 'room', + floor: { drop: zone.floor?.drop ?? 0 }, + porchFraming: zoneFraming(nodes, zone), + ...(zone.roomType === 'deck' || zone.decking ? { decking: deckBoardSettings(zone) } : {}), wallMaterial: zone.wallMaterial ?? null, wallOverrides: zone.wallOverrides ?? [], ...unitOf(nodes, zone.id), @@ -196,7 +222,13 @@ export const getLevelSummary: AgentOperation = (nodes, input, export const getWalls: AgentOperation = (nodes, input, context) => { const level = targetLevel(nodes, input, context) const walls = ofType(nodesOnLevel(nodes, level.id), 'wall') - return { result: { levelId: level.id, walls: walls.map((wall) => wallSummary(nodes, wall)) } } + return { + result: { + levelId: level.id, + walls: walls.map((wall) => wallSummary(nodes, wall)), + wallTypes: wallTypeChoices(nodes).map(({ id, label }) => ({ id, label })), + }, + } } /** `get_zones`. */ diff --git a/packages/core/src/agent-operations/wall-opening.test.ts b/packages/core/src/agent-operations/wall-opening.test.ts index 0b6c8a9df6..c5322a7827 100644 --- a/packages/core/src/agent-operations/wall-opening.test.ts +++ b/packages/core/src/agent-operations/wall-opening.test.ts @@ -1,4 +1,5 @@ import { describe, expect, test } from 'bun:test' +import { DOOR_TYPE_SIZES } from '@pascal-app/core/building' import { z } from 'zod' import { addDoorOutput, addWindowOutput } from '../agent-tools' import { OPENING_SCENE, openingScene } from '../building/__fixtures__/wall-opening-cases' @@ -13,26 +14,34 @@ import { addWallOpening } from './wall-opening' const scene = () => openingScene().nodes as unknown as SceneNodes describe('add_door and add_window answer once, for every surface', () => { - test('a door: the node to create, and the result the contract declares', () => { - const nodes = scene() - const { result, changes } = addWallOpening(nodes, { - kind: 'door', - wallId: OPENING_SCENE.main, - t: 0.5, - }) - expect(z.object(addDoorOutput).strict().parse(result)).toEqual(result) - expect(result).toMatchObject({ - ok: true, - wallId: OPENING_SCENE.main, - t: 0.5, - localX: 2, - clamped: false, - coordinateSystem: 'wall-local-meters', - achieved: { created: { door: 1 }, updated: 0, deleted: {} }, - }) - const after = applySceneChanges(nodes as never, changes) as SceneNodes - expect(after[result.doorId!]).toMatchObject({ type: 'door', parentId: OPENING_SCENE.main }) - }) + test.each(Object.keys(DOOR_TYPE_SIZES) as (keyof typeof DOOR_TYPE_SIZES)[])( + 'a %s door: the node to create, and the result the contract declares', + (doorType) => { + const nodes = scene() + const { result, changes } = addWallOpening(nodes, { + kind: 'door', + doorType, + wallId: OPENING_SCENE.main, + t: 0.5, + }) + expect(z.object(addDoorOutput).strict().parse(result)).toEqual(result) + expect(result).toMatchObject({ + ok: true, + wallId: OPENING_SCENE.main, + t: 0.5, + localX: 2, + clamped: false, + coordinateSystem: 'wall-local-meters', + achieved: { created: { door: 1 }, updated: 0, deleted: {} }, + }) + const after = applySceneChanges(nodes as never, changes) as SceneNodes + expect(after[result.doorId!]).toMatchObject({ + type: 'door', + parentId: OPENING_SCENE.main, + frameThickness: 0.02, + }) + }, + ) test('a window says its sill height, centred on the wall by default, in the same shape', () => { const { result } = addWallOpening(scene(), { diff --git a/packages/core/src/agent-operations/wall-skirting.test.ts b/packages/core/src/agent-operations/wall-skirting.test.ts index 539e04fbfe..ec56e06bc7 100644 --- a/packages/core/src/agent-operations/wall-skirting.test.ts +++ b/packages/core/src/agent-operations/wall-skirting.test.ts @@ -94,6 +94,12 @@ describe('setWallSkirting', () => { ]) }) + test('refuses skirting on a railing', () => { + const nodes = room() + nodes.wall_0 = { ...nodes.wall_0, wallType: 'railing' } as WallNode + expect(refusal(() => run(nodes, { wallIds: ['wall_0'], faces: 'both' }))).toBe('railing_wall') + }) + test('refuses a size that is no length, and a node that is no wall', () => { expect(refusal(() => run(room(), { wallIds: ['wall_0'], height: 0 }))).toBe('invalid_size') expect(refusal(() => run(room(), { wallIds: ['level_skirting'] }))).toBe('target_not_found') diff --git a/packages/core/src/agent-operations/wall-skirting.ts b/packages/core/src/agent-operations/wall-skirting.ts index e07770764d..3092f0ea30 100644 --- a/packages/core/src/agent-operations/wall-skirting.ts +++ b/packages/core/src/agent-operations/wall-skirting.ts @@ -70,6 +70,8 @@ export const setWallSkirting: AgentOperation = (nodes, inp }) if (wall.wallType === 'curtain') refuse('curtain_wall', `Wall ${id} is a curtain wall: it has no skirting.`, { target: id }) + if (wall.wallType === 'railing') + refuse('railing_wall', `Wall ${id} is a railing: it has no skirting.`, { target: id }) const faces = input.faces === undefined ? roomFaces(nodes, wall) : getWallTrimFaces(input.faces) const { skirting } = wallTrimPatch(wall, 'skirting', { enabled: input.enabled ?? true, diff --git a/packages/core/src/agent-operations/wall-type.ts b/packages/core/src/agent-operations/wall-type.ts new file mode 100644 index 0000000000..72e6946e75 --- /dev/null +++ b/packages/core/src/agent-operations/wall-type.ts @@ -0,0 +1,49 @@ +import { refuse } from '../agent-tools/refusal' +import { + projectWallTypes, + WALL_ASSEMBLY_PRESETS, + wallAssemblyPatch, +} from '../systems/wall/wall-assembly' +import { queryNodes } from './scene-queries' +import type { AgentOperation, SceneNodes } from './types' + +export function wallTypeChoices(nodes: SceneNodes) { + const sites = queryNodes(nodes, { type: 'site' }).filter((site) => !site.parentId) + return [ + ...WALL_ASSEMBLY_PRESETS, + ...projectWallTypes( + nodes, + sites.map((site) => site.id), + ), + ] +} + +export function wallTypePatch(nodes: SceneNodes, type: string) { + const choice = wallTypeChoices(nodes).find((entry) => entry.id === type) + if (!choice) + refuse('unknown_wall_type', `Unknown wall type: ${type}. Read get_walls.wallTypes.`, { type }) + return wallAssemblyPatch(structuredClone(choice.assembly)) +} + +export const setWallType: AgentOperation<{ wallIds: string[]; type: string | null }> = ( + nodes, + input, +) => { + const data = input.type === null ? { assembly: undefined } : wallTypePatch(nodes, input.type) + const ids = [...new Set(input.wallIds)] + for (const id of ids) { + const wall = nodes[id] + if (wall?.type !== 'wall') + refuse('target_not_found', `${id} is not a wall: nothing was changed.`, { target: id }) + if (wall.wallType === 'curtain' || wall.wallType === 'railing') + refuse( + `${wall.wallType}_wall`, + `Wall ${id} is a ${wall.wallType} wall: it takes no assembly.`, + { target: id }, + ) + } + return { + result: { ok: true, wallIds: ids, type: input.type }, + changes: { update: ids.map((id) => ({ id, data: structuredClone(data) })) }, + } +} diff --git a/packages/core/src/agent-tools/batch.ts b/packages/core/src/agent-tools/batch.ts index 1ec3d52c60..fd54f2fa3a 100644 --- a/packages/core/src/agent-tools/batch.ts +++ b/packages/core/src/agent-tools/batch.ts @@ -17,6 +17,7 @@ export const BATCHABLE_TOOLS = [ 'find_by_type', 'create_roof', 'add_wall', + 'set_wall_type', 'add_fence', 'add_level', 'create_stair', diff --git a/packages/core/src/agent-tools/columns.ts b/packages/core/src/agent-tools/columns.ts index 00102a68c1..7c9e2ddbb2 100644 --- a/packages/core/src/agent-tools/columns.ts +++ b/packages/core/src/agent-tools/columns.ts @@ -8,13 +8,32 @@ export const addColumnTool = { name: 'add_column', title: 'Add column', description: - 'Add a structural or decorative column at (x, z), or rebuild one by nodeId. Supports native fields or optional code using the same module and conventions as add_object, with floor mount and its bottom centre at the support point. Params named height, width and depth drive the native size controls. Only add columns when requested.', + 'Add a structural or decorative column at (x, z), or rebuild one by nodeId. role post makes the Build panel framing post: plain square pressure-treated wood, default 6x6 with no base, reaching the lowest beam above its support or the ceiling plane unless height is given. postSize and postBase use the tile choices. Refused with not_a_post when post choices are given without role post (or an existing post). Supports native fields or optional code using the same module and conventions as add_object, with floor mount and its bottom centre at the support point. Params named height, width and depth drive the native size controls. Only add columns when requested.', input: { x: z.number().optional().describe('X position of the column center (meters)'), z: z.number().optional().describe('Z position of the column center (meters)'), + role: z + .enum(['ornament', 'post']) + .optional() + .describe( + 'post: a framing post; ornament: a decorative column. Omitted keeps existing column behavior.', + ), + postSize: z + .enum(['4x4', '6x6', '8x8']) + .optional() + .describe( + 'Nominal post size; actual square sides 0.0889, 0.1397, 0.18415 m. Default for a new post: 6x6. Overrides native width, depth and radius when supplied.', + ), + postBase: z + .enum(['none', 'post-base', 'pier']) + .optional() + .describe( + 'Post base: none (default for a new post), a steel post base, or a concrete pier. Updates base geometry and finish together.', + ), height: measurement('length', 'm', { positive: true, - description: 'Column height (default: 2.5).', + description: + 'Column height (default: 2.5 m; a new post reaches the beam above or ceiling plane).', }).optional(), radius: measurement('length', 'm', { positive: true, diff --git a/packages/core/src/agent-tools/index.ts b/packages/core/src/agent-tools/index.ts index bbf0ec7116..4d72e69160 100644 --- a/packages/core/src/agent-tools/index.ts +++ b/packages/core/src/agent-tools/index.ts @@ -37,7 +37,7 @@ import { UNIT_TOOL_CONTRACTS } from './units' import { verifySceneTool } from './verify-scene' import { viewSceneTool } from './view-scene' import { addDoorTool, addWindowTool } from './wall-openings' -import { addWallTool } from './walls' +import { addWallTool, setWallTypeTool } from './walls' export * from './achieved' export * from './add-object' @@ -101,6 +101,7 @@ export const AGENT_TOOL_CONTRACTS = [ placeDesignTool, validateDesignTool, addWallTool, + setWallTypeTool, addFenceTool, addCornerWindowTool, mergeWindowsTool, diff --git a/packages/core/src/agent-tools/levels.ts b/packages/core/src/agent-tools/levels.ts index 4d554463e0..98ec8ad6b0 100644 --- a/packages/core/src/agent-tools/levels.ts +++ b/packages/core/src/agent-tools/levels.ts @@ -31,7 +31,7 @@ export const getWallsTool = { name: 'get_walls', title: 'Get walls', description: - 'Get the walls of a level: start and end in metres, length, stored and resolved height, thickness, and their doors and windows. wallFaceChains gives base-chain provenance for geometric faces a (left of start → end) and b (right): ref (authored face slot), legacy (inline spec), or default (declared fallback ref). These are not final rendered finishes: room intent, face paint regions, exterior assembly cladding and reference availability can change appearance. A chosen white or default-matching ref is legitimate; fallback alone is not a defect or a requirement to paint.', + 'Get the walls of a level: start and end in metres, length, stored and resolved height, thickness, wallType (standard, railing or curtain; standard when absent), type ({ id, label } for a known assembly preset or project wall type, null otherwise), and their doors and windows. wallTypes lists available assembly type ids and labels for add_wall.type and set_wall_type. wallFaceChains gives base-chain provenance for geometric faces a (left of start → end) and b (right): ref (authored face slot), legacy (inline spec), or default (declared fallback ref). These are not final rendered finishes: room intent, face paint regions, exterior assembly cladding and reference availability can change appearance. A chosen white or default-matching ref is legitimate; fallback alone is not a defect or a requirement to paint.', input: levelTarget, } @@ -39,7 +39,7 @@ export const getZonesTool = { name: 'get_zones', title: 'Get zones', description: - 'Get the zones (rooms) of a level: name, colour, polygon and holes in metres, area in m² (holes taken out), bounding size, the unit it belongs to (unitId and unit, its name; null: common area), and floor_choices: the floor plates the room can take (key, plateId, name, current; drawn and mezzanine flags). A room shares its floor plate with the rooms next to it unless detached. Persisted authored wall intent is wallMaterial (string, or null when absent) and wallOverrides (records of wallId, geometric face a or b, and finish; [] when absent). This is not a final rendered finish or visual verification: local overrides and face paint can take precedence, and absent room intent is not a defect or a requirement to paint.', + 'Get the zones (rooms) of a level: name, colour, polygon and holes in metres, area in m² (holes taken out), bounding size, roomType (room when absent, porch, deck or patio), floor.drop (step-down in metres, 0 when absent; an explicit floor.elevation takes precedence), porchFraming (auto, postSize, postSpacing in metres, beamSize, postCount and beamCount of existing generated parts; null when no outdoor/framing intent), and decking (boardSize, gap in metres, direction; resolved defaults for decks or when settings exist). auto follows porchFraming.auto; absent, on for a covered porch, off for decks/patios. false leaves framing to hand edits. These names and units match set_zone_intent. Includes the unit it belongs to (unitId and unit, its name; null: common area), and floor_choices: available floor plates (key, plateId, name, current; drawn and mezzanine flags). A room shares its floor plate with adjacent rooms unless detached. Persisted wall intent is wallMaterial (string, null when absent) and wallOverrides (wallId, geometric face a or b, finish; [] when absent), not a final rendered finish: local overrides and face paint can take precedence; absent intent is not a defect or a requirement to paint.', input: levelTarget, } diff --git a/packages/core/src/agent-tools/room-structure.ts b/packages/core/src/agent-tools/room-structure.ts index 07b62b3019..3b7ed24506 100644 --- a/packages/core/src/agent-tools/room-structure.ts +++ b/packages/core/src/agent-tools/room-structure.ts @@ -19,6 +19,25 @@ const zoneIntentPatch = z.strictObject({ elevation: measurement('length', 'm').nullable().optional(), finish: finish.nullable().optional(), regions: paintRegions.nullable().optional(), + drop: measurement('length', 'm', { min: 0 }).nullable().optional(), + }) + .nullable() + .optional(), + roomType: z.enum(['porch', 'deck', 'patio']).nullable().optional(), + porchFraming: z + .strictObject({ + auto: z.boolean().nullable().optional(), + postSize: z.enum(['4x4', '6x6', '8x8']).nullable().optional(), + postSpacing: measurement('length', 'm', { min: 0.6 }).nullable().optional(), + beamSize: z.string().nullable().optional(), + }) + .nullable() + .optional(), + decking: z + .strictObject({ + boardSize: z.enum(['5/4x6', '2x6', '2x4', 'composite']).nullable().optional(), + gap: measurement('length', 'm', { positive: true }).nullable().optional(), + direction: z.enum(['parallel', 'diagonal', 'perpendicular']).nullable().optional(), }) .nullable() .optional(), @@ -195,7 +214,7 @@ export const setZoneIntentTool = { name: 'set_zone_intent', title: 'Set room intent', description: - 'Update room name, floor finish/elevation/regions, floor.footprint ("new" mints a unique floor key tied to this creator room, an existing key joins that floor on this level, null returns to the shared floor). Touching rooms with the same key share a base plate; disconnected pieces share construction settings. Conversion preserves world geometry in one edit and refuses when infeasible. get_zones exposes floor_choices. A keyed floor uses " floor" while the creator remains on that key; otherwise it uses the largest named room. Existing keys such as "own" without a creator use that fallback. A user-given plate name wins; the shared floor stays "Shared floor". Keyed rooms can have raised or sunken floor.elevation, stored as a level-local walking top. Slab thickness, foundation height and edge finish use set_room_floor_construction, updating every piece of the key. Update ceiling paint regions (ceiling.regions: [x, z] polygons with a finish, later wins), step finishes (floorStepFinish for every step of the room; floorStepOverrides: [{ key, step?, finish }] per doorway, key = the door id the step sits under or the lower room id), wall material and construction opt-outs. daylight { artificialLight, mechanicalVentilation } declares a habitable room lit and aired by artificial means (the IRC R303.1 exceptions to daylight; both true), stored in the room\'s metadata; a bedroom, living room or kitchen needs a window to outside or this declaration, above and below grade alike. Absent fields are unchanged; null clears.', + 'Update room name, floor finish/elevation/regions, floor.footprint ("new" mints a unique floor key tied to this creator room, an existing key joins that floor on this level, null returns to the shared floor). Touching rooms with the same key share a base plate; disconnected pieces share construction settings. Conversion preserves world geometry in one edit and refuses when infeasible. get_zones exposes floor_choices. A keyed floor uses " floor" while the creator remains on that key; otherwise it uses the largest named room. Existing keys such as "own" without a creator use that fallback. A user-given plate name wins; the shared floor stays "Shared floor". Keyed rooms can have raised or sunken floor.elevation, stored as a level-local walking top. Slab thickness, foundation height and edge finish use set_room_floor_construction, updating every piece of the key. Update ceiling paint regions (ceiling.regions: [x, z] polygons with a finish, later wins), step finishes (floorStepFinish for every step of the room; floorStepOverrides: [{ key, step?, finish }] per doorway, key = the door id the step sits under or the lower room id), wall material and construction opt-outs. daylight { artificialLight, mechanicalVentilation } declares a habitable room lit and aired by artificial means (the IRC R303.1 exceptions to daylight; both true), stored in the room\'s metadata; a bedroom, living room or kitchen needs a window to outside or this declaration, above and below grade alike. roomType ("porch" | "deck" | "patio", null for a room) makes the room outdoors: a porch is a concrete slab stepped floor.drop (1.5 in) under the house with a ceiling, a deck wood decking 1 in down and framed, a patio concrete and open. porchFraming { auto, postSize "4x4"|"6x6"|"8x8", postSpacing m, beamSize e.g. "6x8" } sets the posts of a covered porch (one at each outside corner, more at most postSpacing apart) and the beam on them under its ceiling; a deck or patio gets them only with auto true (to carry a roof over it). A size or the spacing rebuilds them, auto false leaves them as edited. decking { boardSize "5/4x6"|"2x6"|"2x4"|"composite", gap m (1/8, 3/16 or 1/4 in), direction "parallel"|"diagonal"|"perpendicular" to the house } sets a deck\'s boards (default 5/4x6, 1/4 in apart, along the house); its frame follows: joists 12 in on centre under diagonal 5/4 or composite boards (IRC R507.7), and along the house on beams square to it under boards running out from it. Absent fields are unchanged; null clears.', input: { zoneId: NodeId, patch: zoneIntentPatch }, } diff --git a/packages/core/src/agent-tools/wall-openings.ts b/packages/core/src/agent-tools/wall-openings.ts index eb493159fc..4a64913d96 100644 --- a/packages/core/src/agent-tools/wall-openings.ts +++ b/packages/core/src/agent-tools/wall-openings.ts @@ -58,7 +58,7 @@ export const addDoorTool = { name: 'add_door', title: 'Add door', description: - 'Add a door to an existing straight wall at t (0..1 along it), or a passage with no leaf (openingKind opening: a cased opening, an arch). The door slides to stay on the wall and reports clamped. Refused with a code, as in the editor: curved walls, walls shorter than the door, and overlapping another door, window or wall item unless force is set. Match the reference with the outline (rectangle, rounded, arch), doorType and style; what they cannot express (glass strips, a pattern of lites, carved panels) is written as a script in code, never left as not possible.', + 'Add a door to an existing straight wall at t (0..1 along it), or a passage with no leaf (openingKind opening: a cased opening, an arch). The door slides to stay on the wall and reports clamped. On a railing (wallType railing) it is a gap in the guard as tall as the railing, with no leaf, casing or threshold. Refused with a code, as in the editor: curved walls, walls shorter than the door, and overlapping another door, window or wall item unless force is set. Match the reference with the outline (rectangle, rounded, arch), doorType and style; what they cannot express (glass strips, a pattern of lites, carved panels) is written as a script in code, never left as not possible.', input: { wallId: NodeId.optional().describe('The wall to add the door to.'), nodeId: NodeId.optional().describe( @@ -106,7 +106,7 @@ export const addWindowTool = { name: 'add_window', title: 'Add window', description: - "Add a window to an existing straight wall at t (0..1 along it), centred vertically on the wall, or on sillHeight above the floor when given. It slides to stay on the wall and under the wall's ceiling, and reports clamped. Refused with a code, as in the editor: curved walls, walls shorter than the window, overlapping another door, window or wall item unless force is set, and a style on a window that is not Fixed (style_needs_fixed_window). Match the reference with the outline (rectangle, rounded, arch), windowType and panes (columns × rows, or a style); what they cannot express (glass strips, leaded lites, a feature frame) is written as a script in code, never left as not possible.", + "Add a window to an existing straight wall at t (0..1 along it), centred vertically on the wall, or on sillHeight above the floor when given. It slides to stay on the wall and under the wall's ceiling, and reports clamped. Refused with a code, as in the editor: curved walls, railings (railing_window: a railing takes a door, a gap in its guard), walls shorter than the window, overlapping another door, window or wall item unless force is set, and a style on a window that is not Fixed (style_needs_fixed_window). Match the reference with the outline (rectangle, rounded, arch), windowType and panes (columns × rows, or a style); what they cannot express (glass strips, leaded lites, a feature frame) is written as a script in code, never left as not possible.", input: { wallId: NodeId.optional().describe('The wall to add the window to.'), nodeId: NodeId.optional().describe( diff --git a/packages/core/src/agent-tools/walls.ts b/packages/core/src/agent-tools/walls.ts index ee3aac5f72..248462430b 100644 --- a/packages/core/src/agent-tools/walls.ts +++ b/packages/core/src/agent-tools/walls.ts @@ -2,6 +2,14 @@ import { z } from 'zod' import { FOUNDATION_BY_REGION_NOTE } from '../lib/foundation-construction' import { levelTarget } from './levels' import { measurement } from './measurement' +import { NodeId } from './node-id' + +const wallTypeInput = z + .string() + .min(1) + .describe( + 'Assembly type id from get_walls.wallTypes: a built-in preset or custom- project wall type. Copies its layers and total thickness in metres, overriding thickness. Unknown ids: unknown_wall_type.', + ) /** * A wall's bend: a rounded corner could only be made with apply_patch, its sign documented @@ -19,12 +27,60 @@ export const addWallTool = { name: 'add_wall', title: 'Add wall', description: - 'Add a single wall between two points on a level, straight or, with curveOffset, an arc. Refused with a code: a level that is not a storey (a declared roof level), and a wall shorter than 1 cm. On a level below grade, a wall against the ground (on the outline of the walls of the level) is a foundation wall, ' + + 'Add a single wall between two points on a level, straight or, with curveOffset, an arc. type applies a preset or project wall assembly including its thickness (unknown_wall_type for an unknown id). wallType railing builds the Build panel guard: default post-and-rail, 0.9144 m high, thickness from railing.postSize, no assembly or foundation. Its doors are gaps; windows refuse railing_window, skirting refuses railing_wall. railing settings on a standard wall refuse not_a_railing; type on a railing refuses railing_wall. Refused with a code: a level that is not a storey (a declared roof level), and a wall shorter than 1 cm. On a level below grade, a standard wall against the ground (on the outline of the walls of the level) is a foundation wall, ' + FOUNDATION_BY_REGION_NOTE + '; a partition inside the outline is an ordinary wall; the result says which.', input: { start: planPoint('start'), end: planPoint('end'), + type: wallTypeInput.optional(), + wallType: z + .enum(['standard', 'railing']) + .optional() + .describe( + 'Wall kind (default standard). railing is an open guard with its own height and post-derived thickness.', + ), + railing: z + .object({ + style: z + .enum(['balusters', 'post-and-rail', 'cable', 'boards', 'glass', 'metal']) + .optional() + .describe( + 'Guard style (default post-and-rail); omitted member sizes use the style defaults from the Build panel.', + ), + postSpacing: measurement('length', 'm', { + positive: true, + description: 'Maximum post spacing on centre (default 1.8288 m).', + }).optional(), + postSize: measurement('length', 'm', { + positive: true, + description: + 'Square post side; sets wall thickness, overriding thickness. Default 0.0889 m for wood styles, 0.0508 m cable, 0.0381 m glass/metal.', + }).optional(), + infillSize: measurement('length', 'm', { + positive: true, + description: + 'Baluster/bar square side, cable diameter, board face height or glass thickness. Default by style: post-and-rail 0.0381, balusters 0.03175, cable 0.009525, boards 0.1397, glass 0.0127, metal 0.015875 m.', + }).optional(), + infillGap: measurement('length', 'm', { + min: 0, + description: + 'Clear infill gap. Default 0.0889 m wood styles, 0.066675 m cable, 0 m glass, 0.09525 m metal.', + }).optional(), + bottomClearance: measurement('length', 'm', { + min: 0, + description: + 'Clearance over the floor. Default 0.0889 m post-and-rail/boards, 0.05715 m balusters, 0.06985 m cable, 0.0762 m glass/metal.', + }).optional(), + cap: z + .boolean() + .optional() + .describe('2x6 top cap on post-and-rail/boards styles (default true).'), + }) + .optional() + .describe( + 'Railing settings, only with wallType railing. All lengths in metres; omitted fields follow the selected style.', + ), thickness: measurement('length', 'm', { positive: true, description: @@ -34,9 +90,20 @@ export const addWallTool = { }).optional(), height: measurement('length', 'm', { positive: true, - description: "Wall height (default: the storey's height).", + description: "Wall height (default: the storey's height; a railing 0.9144 m / 36 in).", }).optional(), curveOffset: WALL_CURVE_OFFSET_INPUT.optional(), ...levelTarget, }, } + +export const setWallTypeTool = { + name: 'set_wall_type', + title: 'Set wall type', + description: + 'Apply an assembly type to existing standard walls, copying its layers and total thickness as the wall panel does. type null clears the assembly and keeps thickness. All walls change together. Refused with unknown_wall_type for an unknown type id, target_not_found for a missing wall, curtain_wall or railing_wall for walls that take no assembly.', + input: { + wallIds: z.array(NodeId).min(1), + type: wallTypeInput.nullable(), + }, +} diff --git a/packages/core/src/building/corner-window.test.ts b/packages/core/src/building/corner-window.test.ts index f2b3383953..bbb79d6566 100644 --- a/packages/core/src/building/corner-window.test.ts +++ b/packages/core/src/building/corner-window.test.ts @@ -62,6 +62,11 @@ for (const degrees of [90, 135, 60]) describe(`a corner window at ${degrees}°`, () => { test('one window on each wall, each running to the corner, joined and fused', () => { const { windows } = planCornerWindow(cornerScene(degrees), { corner: [0, 0], width: 1.2 }) + for (const window of windows) { + expect(window.frameThickness).toBe(0.02) + expect(window.casingFaceA).toBe(true) + expect(window.casingFaceB).toBe(true) + } const [onA, onB] = ['wall_a', 'wall_b'].map((id) => windows.find((w) => w.parentId === id)!) // Wall A is 4 m long and ends at the corner; wall B starts there. expect(onA!.position[0]).toBeCloseTo(4 - 0.6, 6) @@ -158,7 +163,9 @@ describe('by hand: wrap, keep in step, unwrap', () => { test('a window ending at a corner wraps it: its partner takes its width, height and sill', () => { const { nodes, window } = plain() - const { create, updates } = wrapCorner(nodes, window.id) + const adjusted = { ...window, frameThickness: 0.035 } + const { create, updates } = wrapCorner({ ...nodes, [window.id]: adjusted }, window.id) + expect(create?.frameThickness).toBe(0.035) expect(create?.parentId).toBe('wall_b') expect([create?.width, create?.height, create?.position[1]]).toEqual([ window.width, @@ -170,6 +177,24 @@ describe('by hand: wrap, keep in step, unwrap', () => { }) }) + test('its partner takes its casing, each face on the same side of the corner', () => { + const { nodes, window } = plain() + const cased = { ...window, casingWidth: 0.1, casingFaceA: true, casingFaceB: false } + const casingOf = (partner: WindowNode | null) => [ + partner?.casingWidth, + partner?.casingFaceA, + partner?.casingFaceB, + ] + // wall_a runs into the corner and wall_b on out of it: their `a` faces are on one side. + const onward = wrapCorner({ ...nodes, [window.id]: cased }, window.id).create + expect(casingOf(onward)).toEqual([0.1, true, false]) + // wall_b drawn back into the corner: its `a` is on the side of wall_a's `b`. + const wallB = nodes.wall_b as WallNode + const reversed = { ...wallB, start: wallB.end, end: wallB.start } + const back = wrapCorner({ ...nodes, wall_b: reversed, [window.id]: cased }, window.id).create + expect(casingOf(back)).toEqual([0.1, false, true]) + }) + // A window a few cm short of the corner still has a Corner section to wrap it. const onWall = (id: string, wall: string, x: number, width = 1.2) => WindowNode.parse({ diff --git a/packages/core/src/building/corner-window.ts b/packages/core/src/building/corner-window.ts index e21ea7cc12..add052838a 100644 --- a/packages/core/src/building/corner-window.ts +++ b/packages/core/src/building/corner-window.ts @@ -129,6 +129,7 @@ const SHARED = [ 'sill', 'sillDepth', 'sillThickness', + 'casingWidth', ] as const /** The partner's update for a change to one side of a corner window; null when nothing shared changed. */ @@ -153,8 +154,8 @@ export function cornerPartnerUpdates( * The editor's Wrap the corner: a window within `CORNER_REACH_M` of a corner where exactly one other * wall ends is slid to the corner and joined to the window waiting there on that wall, adopted * (`mergeWindows`); with none waiting, it gets a partner on that wall, of its width (as far as the - * wall allows), height, sill and type. `create` is the partner to add, if any; `updates` are the - * windows that change, by id. + * wall allows), height, sill, type and casing, each face's casing on its side of the corner. + * `create` is the partner to add, if any; `updates` are the windows that change, by id. */ export function wrapCorner( nodes: Nodes, @@ -210,11 +211,19 @@ export function wrapCorner( }).node as WindowNode const post = fusesAtCorner(window) ? 'none' : 'post' const slidTo = end === 'start' ? window.width / 2 : wallLengthOf(wall) - window.width / 2 + // Casing is kept per wall face. A wall running into the corner and one running on out of it + // have their `a` faces on the same side of it; two meeting end to end or start to start have + // them on opposite sides, so the partner takes the window's faces the other way round. + const swapFaces = end === otherEnd return { create: { ...partner, + frameThickness: window.frameThickness, columnRatios: window.columnRatios, rowRatios: window.rowRatios, + casingWidth: window.casingWidth, + casingFaceA: swapFaces ? window.casingFaceB : window.casingFaceA, + casingFaceB: swapFaces ? window.casingFaceA : window.casingFaceB, corner: { end: otherEnd, partnerId: window.id, post }, } as WindowNode, updates: { diff --git a/packages/core/src/building/door-types.test.ts b/packages/core/src/building/door-types.test.ts index f06c2475e5..4a699fff68 100644 --- a/packages/core/src/building/door-types.test.ts +++ b/packages/core/src/building/door-types.test.ts @@ -20,10 +20,10 @@ describe("the door panel's Type row", () => { }) test('a modern door made sliding stays modern', () => { - const modern = door(doorStyleLook('modern')) + const modern = door({ ...doorStyleLook('modern'), frameThickness: 0.035 }) const sliding = { ...modern, ...doorTypeChange(modern, 'sliding') } as DoorNode expect(doorStylesOf(sliding)).toEqual(['modern']) - expect(sliding).toMatchObject({ trackStyle: 'visible', leafCount: 2 }) + expect(sliding).toMatchObject({ trackStyle: 'visible', leafCount: 2, frameThickness: 0.035 }) }) test('keeps the door on the floor at the new height', () => { diff --git a/packages/core/src/building/door-types.ts b/packages/core/src/building/door-types.ts index b3b3c216db..0683e93fd1 100644 --- a/packages/core/src/building/door-types.ts +++ b/packages/core/src/building/door-types.ts @@ -2,6 +2,9 @@ import type { DoorNode, DoorSegment } from '../schema' import { type DoorType, defaultDoorSegments } from '../schema/nodes/opening-types' import { type DoorStyle, doorStyleLook, doorStylesOf } from './opening-style-presets' +// The schema keeps 0.05 m for saved doors that omit the field (E-003). +export const NEW_DOOR_FRAME_THICKNESS = 0.02 + /** A door type's own size: the door panel's Type row sets it, and add_door takes it when none is given. */ export const DOOR_TYPE_SIZES: Record = { hinged: { width: 0.9, height: 2.1 }, diff --git a/packages/core/src/building/index.ts b/packages/core/src/building/index.ts index ef0afc77ad..72b02113ab 100644 --- a/packages/core/src/building/index.ts +++ b/packages/core/src/building/index.ts @@ -4,6 +4,7 @@ export * from './floor-item-fit' export { buildGroundLevelChanges } from './ground-level' export * from './level-duplication' export { buildLevelBelowChanges } from './level-insertion' +export { buildExteriorWallCopy, levelExteriorWalls } from './level-wall-copy' export * from './merge-windows' export * from './opening-style-presets' export { type RgbaImage, warpImage } from './photo-elevation' diff --git a/packages/core/src/building/level-wall-copy.test.ts b/packages/core/src/building/level-wall-copy.test.ts new file mode 100644 index 0000000000..5a21f87db1 --- /dev/null +++ b/packages/core/src/building/level-wall-copy.test.ts @@ -0,0 +1,181 @@ +import { expect, test } from 'bun:test' +import { createZone } from '../commands/structure/create-zone' +import { structureChangeBatch } from '../commands/structure/shared' +import { FOUNDATION_CONSTRUCTIONS } from '../lib/foundation-construction' +import { foundationWallConstruction } from '../lib/foundation-wall' +import { initSpaceDetectionSync } from '../lib/space-detection' +import { + type AnyNode, + BuildingNode, + generateId, + LevelNode, + type WallNode, + WallNode as WallSchema, + WindowNode, +} from '../schema' +import useScene, { clearSceneHistory } from '../store/use-scene' +import { WALL_ASSEMBLY_PRESETS, wallAssemblyPatch } from '../systems/wall/wall-assembly' +import { buildExteriorWallCopy } from './level-wall-copy' + +test('a new floor copies the exterior walls below in place, and its rooms come from them', async () => { + const previousFrame = globalThis.requestAnimationFrame + const previousCancel = globalThis.cancelAnimationFrame + // A frame that runs in a microtask: a callback run inside the call would let the store + // store the frame id after the flush cleared it, and a later test would cancel that id. + globalThis.requestAnimationFrame = ((callback: FrameRequestCallback) => { + queueMicrotask(() => callback(0)) + return 1 + }) as typeof requestAnimationFrame + globalThis.cancelAnimationFrame = () => {} + const building = BuildingNode.parse({ id: 'building_copy', children: ['level_copy_0'] }) + const ground = LevelNode.parse({ + id: 'level_copy_0', + parentId: building.id, + level: 0, + height: 2.8, + }) + useScene.setState({ + nodes: { [building.id]: building, [ground.id]: ground }, + rootNodeIds: [building.id], + dirtyNodes: new Set(), + readOnly: false, + } as never) + clearSceneHistory() + const stop = initSpaceDetectionSync(useScene, { + getState: () => ({ spaces: {}, setSpaces: () => {} }), + }) + const settle = async () => { + for (let index = 0; index < 6; index++) await Promise.resolve() + } + const nodes = () => useScene.getState().nodes + const walls = (levelId: string) => + Object.values(nodes()).filter( + (node): node is WallNode => node.type === 'wall' && node.parentId === levelId, + ) + try { + const room = createZone(nodes(), { + levelId: ground.id, + polygon: [ + [0, 0], + [8, 0], + [8, 5], + [0, 5], + ], + enclose: true, + mintId: generateId, + }) + useScene.getState().applyNodeChanges(structureChangeBatch(room.changes)) + await settle() + const partition = WallSchema.parse({ parentId: ground.id, start: [4, 0], end: [4, 5] }) + const front = walls(ground.id).find((wall) => wall.start[1] === 0 && wall.end[1] === 0)! + const window = WindowNode.parse({ parentId: front.id, position: [2, 1.2, 0] }) + useScene.getState().applyNodeChanges({ + create: [ + { node: partition, parentId: ground.id }, + { node: window, parentId: front.id }, + ], + }) + await settle() + const upper = LevelNode.parse({ + id: 'level_copy_1', + parentId: building.id, + level: 1, + height: 2.8, + }) + useScene.getState().applyNodeChanges({ create: [{ node: upper, parentId: building.id }] }) + await settle() + + const create = buildExteriorWallCopy({ + nodes: nodes(), + fromLevelId: ground.id, + toLevelId: upper.id, + }) + expect(create).toHaveLength(4) + const before = useScene.temporal.getState().pastStates.length + useScene.getState().applyNodeChanges({ create }) + await settle() + expect(useScene.temporal.getState().pastStates.length).toBe(before + 1) + + const copied = walls(upper.id) + expect(copied).toHaveLength(4) + expect(copied.every((wall) => wall.children.length === 0 && wall.height === undefined)).toBe( + true, + ) + const key = (wall: WallNode) => JSON.stringify([...[wall.start, wall.end].sort()]) + expect(copied.map(key).sort()).toEqual( + walls(ground.id) + .filter((wall) => wall.id !== partition.id) + .map(key) + .sort(), + ) + const rooms = Object.values(nodes()).filter( + (node) => node.type === 'zone' && node.parentId === upper.id && node.spaceRole === 'room', + ) + expect(rooms).toHaveLength(1) + } finally { + stop() + clearSceneHistory() + useScene.getState().unloadScene() + globalThis.requestAnimationFrame = previousFrame + globalThis.cancelAnimationFrame = previousCancel + } +}) + +test('foundation walls copied up from a basement are plain walls, walls copied down get the foundation', () => { + const square: [number, number][] = [ + [-4, -4], + [4, -4], + [4, 4], + [-4, 4], + ] + const building = BuildingNode.parse({ + id: 'building_basement_copy', + children: ['level_basement_copy', 'level_main_copy'], + }) + const basement = LevelNode.parse({ + id: 'level_basement_copy', + parentId: building.id, + level: -1, + baseElevation: -2.5, + height: 2.5, + }) + const main = LevelNode.parse({ + id: 'level_main_copy', + parentId: building.id, + level: 0, + height: 2.5, + }) + const nodes: Record = Object.fromEntries( + [building, basement, main].map((node) => [node.id, node]), + ) + const walls = (levelId: string, construction: Partial) => + square.map((start, at) => + WallSchema.parse({ + id: `wall_${levelId}_${at}`, + parentId: levelId, + start, + end: square[(at + 1) % 4], + ...construction, + }), + ) + const foundation = foundationWallConstruction(Object.values(FOUNDATION_CONSTRUCTIONS)[0]!) + for (const wall of walls(basement.id, foundation)) nodes[wall.id] = wall + const siding = wallAssemblyPatch(structuredClone(WALL_ASSEMBLY_PRESETS[0]!.assembly)) + const up = buildExteriorWallCopy({ nodes, fromLevelId: basement.id, toLevelId: main.id }) + expect(up).toHaveLength(4) + for (const { node } of up) { + expect(node.assembly).toBeUndefined() + expect(node.thickness).toBeUndefined() + } + const above: Record = Object.fromEntries( + [building, basement, main].map((node) => [node.id, node]), + ) + for (const wall of walls(main.id, siding)) above[wall.id] = wall + const down = buildExteriorWallCopy({ + nodes: above, + fromLevelId: main.id, + toLevelId: basement.id, + }) + expect(down).toHaveLength(4) + for (const { node } of down) expect(node.assembly).not.toEqual(siding.assembly) +}) diff --git a/packages/core/src/building/level-wall-copy.ts b/packages/core/src/building/level-wall-copy.ts new file mode 100644 index 0000000000..ae691ee51c --- /dev/null +++ b/packages/core/src/building/level-wall-copy.ts @@ -0,0 +1,84 @@ +import { exteriorWallLoops } from '../lib/exterior-wall-loops' +import { levelHoldsFoundationWalls, withFoundationConstruction } from '../lib/foundation-wall' +import { type AnyNode, type AnyNodeId, generateId, type LevelNode, WallNode } from '../schema' +import { wallFollowsStorey } from '../systems/wall/wall-top' + +/** The visible walls of `levelId` on its outline: the walls a closed circuit's outside runs along. */ +export function levelExteriorWalls(nodes: Record, levelId: string): WallNode[] { + const walls = Object.values(nodes).filter( + (node): node is WallNode => + node.type === 'wall' && node.parentId === levelId && node.visible !== false, + ) + const outline = new Set( + exteriorWallLoops(walls).flatMap((loop) => loop.map((face) => face.wallId)), + ) + return walls.filter((wall) => outline.has(wall.id)) +} + +/** + * Copy a level's exterior walls, in place, onto another level of the building (a floor just added + * above or below it): the same plan positions, thickness, construction and finishes, so the new + * storey's outside lines up with the one it stands on. What belongs to the source storey stays + * there: its doors and windows, its support and terrain settings, and a height that only meant + * "as tall as this storey" (the copy follows its own storey). A copy between a basement and a floor + * over the ground takes the construction of where it lands: walls copied down to a basement get the + * foundation build, and foundation walls copied up are plain walls. Rooms then come from the copied + * walls as from drawn ones. Returns the create entries for `applyNodeChanges`; empty when the + * source has no closed outline. + */ +export function buildExteriorWallCopy({ + nodes, + fromLevelId, + toLevelId, + mintId = () => generateId('wall'), +}: { + nodes: Record + fromLevelId: string + toLevelId: string + mintId?: () => string +}): Array<{ node: WallNode; parentId: AnyNodeId }> { + const from = nodes[fromLevelId] + const to = nodes[toLevelId] + if (from?.type !== 'level' || to?.type !== 'level' || from.id === to.id) return [] + const graph = nodes as Record + const sourceFoundation = levelHoldsFoundationWalls(graph, fromLevelId) + const targetFoundation = levelHoldsFoundationWalls(graph, toLevelId) + const reconstruct = sourceFoundation !== targetFoundation + const storeyHeight = (from as LevelNode).height ?? null + const copies = levelExteriorWalls(nodes, fromLevelId).map((wall) => { + const { + id: _id, + children: _children, + parentId: _parentId, + metadata: _metadata, + supportSlabId: _support, + supportOffset: _offset, + fillToTerrain: _fill, + underpinning: _underpinning, + faceRegions: _regions, + height, + assembly, + thickness, + ...kept + } = wall + return WallNode.parse({ + ...kept, + id: mintId(), + parentId: toLevelId, + children: [], + ...(height !== undefined && !wallFollowsStorey(wall, storeyHeight) ? { height } : {}), + ...(reconstruct ? {} : { assembly, thickness }), + }) + }) + if (!copies.length) return [] + const levelWalls = [ + ...Object.values(nodes).filter( + (node): node is WallNode => node.type === 'wall' && node.parentId === toLevelId, + ), + ...copies, + ] + const built = targetFoundation + ? withFoundationConstruction(graph, toLevelId, levelWalls, copies, {}) + : copies + return built.map((node) => ({ node, parentId: toLevelId as AnyNodeId })) +} diff --git a/packages/core/src/building/merge-windows.test.ts b/packages/core/src/building/merge-windows.test.ts index 07f02cf383..ee79ae3c44 100644 --- a/packages/core/src/building/merge-windows.test.ts +++ b/packages/core/src/building/merge-windows.test.ts @@ -1,6 +1,7 @@ import { describe, expect, test } from 'bun:test' import { type AnyNode, LevelNode, WallNode, WindowNode } from '../schema' import { MERGE_GAP_M, windowMergeOffer } from './merge-windows' +import { planWallOpening } from './wall-openings' // The Merge windows button: offered when exactly two windows are selected, disabled with the // reason when they cannot join, and silent for any other selection. @@ -54,3 +55,23 @@ describe('windowMergeOffer', () => { expect(refusal?.details).toMatchObject({ limit: MERGE_GAP_M }) }) }) + +test('merging newly placed windows keeps their casing and frame width', () => { + const scene = nodes() + const first = planWallOpening(scene, { kind: 'window', wallId: 'wall_m', t: 0.2, width: 1 }).node + const second = planWallOpening(scene, { + kind: 'window', + wallId: 'wall_m', + t: 0.35, + width: 1, + }).node + const placed = { ...scene, [first.id]: first, [second.id]: second } + const offer = windowMergeOffer(placed, [first.id, second.id])! + expect(offer.refusal).toBeNull() + const patch = offer.merge!.changes.update.find((change) => change.id === first.id)!.data + expect({ ...first, ...patch }).toMatchObject({ + casingFaceA: true, + casingFaceB: true, + frameThickness: 0.02, + }) +}) diff --git a/packages/core/src/building/merge-windows.ts b/packages/core/src/building/merge-windows.ts index 637b26e47b..c6d8859e05 100644 --- a/packages/core/src/building/merge-windows.ts +++ b/packages/core/src/building/merge-windows.ts @@ -40,6 +40,7 @@ const SHARED = [ 'sill', 'sillDepth', 'sillThickness', + 'casingWidth', ] as const export type WindowMerge = { diff --git a/packages/core/src/building/wall-openings.test.ts b/packages/core/src/building/wall-openings.test.ts index 7e0adcfc5b..7de398cc62 100644 --- a/packages/core/src/building/wall-openings.test.ts +++ b/packages/core/src/building/wall-openings.test.ts @@ -1,7 +1,8 @@ import { describe, expect, test } from 'bun:test' import { type AgentRefusal, isAgentRefusal } from '../agent-tools/refusal' import { addDoorTool, addWindowTool } from '../agent-tools/wall-openings' -import { openingScene, WALL_OPENING_CASES } from './__fixtures__/wall-opening-cases' +import { type LevelNode, RAILING_GUARD_HEIGHT, railingWallDefaults, WallNode } from '../schema' +import { OPENING_SCENE, openingScene, WALL_OPENING_CASES } from './__fixtures__/wall-opening-cases' import { placedDoorFace, planWallOpening } from './wall-openings' // Layer 1 of 3: the operation both agent surfaces call. The cases are the spec. @@ -27,6 +28,9 @@ describe('planWallOpening', () => { expect(planned.node.position[0]).toBeCloseTo(c.expect.localX, 6) expect(planned.node.position[1]).toBeCloseTo(c.expect.centerY, 6) expect(planned.clamped).toBe(c.expect.clamped) + expect(planned.node.casingFaceA).toBe(true) + expect(planned.node.casingFaceB).toBe(true) + expect(planned.node.frameThickness).toBe(0.02) if (c.expect.glassPanels) expect(JSON.stringify(planned.node)).toContain('"glass"') if (c.expect.node) expect(planned.node).toMatchObject(c.expect.node) }) @@ -80,3 +84,46 @@ describe('the face a door placed by hand takes', () => { expect(placedDoorFace(wallOf('wall_main'), 'front')).toBe('front') }) }) + +// Not a shared case: a railing's openings are gaps in its guard. +describe('an opening on a railing', () => { + const railed = () => { + const { nodes } = openingScene() + const railing = WallNode.parse({ + id: 'wall_railing', + parentId: OPENING_SCENE.levelId, + start: [0, 20], + end: [4, 20], + ...railingWallDefaults(), + }) + const level = nodes[OPENING_SCENE.levelId] as LevelNode + return { + ...nodes, + [railing.id]: railing, + [level.id]: { ...level, children: [...level.children, railing.id] }, + } + } + + test('a door is a gap as tall as the guard, standing on the floor, with no casing or threshold', () => { + const planned = planWallOpening(railed(), { kind: 'door', wallId: 'wall_railing', t: 0.5 }) + expect(planned.node).toMatchObject({ + openingKind: 'opening', + height: RAILING_GUARD_HEIGHT, + threshold: false, + casingFaceA: false, + casingFaceB: false, + }) + expect(planned.node.position[1]).toBeCloseTo(RAILING_GUARD_HEIGHT / 2, 6) + }) + + test('a window is refused: a guard has nothing for it to fill', () => { + let error: unknown + try { + planWallOpening(railed(), { kind: 'window', wallId: 'wall_railing', t: 0.5 }) + } catch (thrown) { + error = thrown + } + expect(isAgentRefusal(error)).toBe(true) + expect((error as AgentRefusal).code).toBe('railing_window') + }) +}) diff --git a/packages/core/src/building/wall-openings.ts b/packages/core/src/building/wall-openings.ts index 4ac793350b..4762a3e4d1 100644 --- a/packages/core/src/building/wall-openings.ts +++ b/packages/core/src/building/wall-openings.ts @@ -20,16 +20,18 @@ import { } from '../schema' import { getCurtainWallConfig } from '../schema/nodes/curtain-wall' import type { DoorType, WindowType } from '../schema/nodes/opening-types' +import { isRailingWall, railingOpeningFields } from '../schema/nodes/railing-wall' import { getWallTop } from '../services/storey' import { resolveWallExteriorSide } from '../systems/wall/wall-assembly' import { getWallCurveLength, isCurvedWall } from '../systems/wall/wall-curve' +import { NEW_DOOR_FRAME_THICKNESS } from './door-types' import { type DoorStyle, doorStyleLook, getWindowStyleOverrides, type WindowStyle, } from './opening-style-presets' -import { windowTakesStyle } from './window-types' +import { NEW_WINDOW_FRAME_THICKNESS, windowTakesStyle } from './window-types' // The placement rules of wall openings, shared by the editor's door and window tools and by // every agent surface: what the editor lets a person do by hand is what an agent may do. @@ -285,6 +287,14 @@ export function planWallOpening(nodes: Nodes, input: WallOpeningInput) { `Wall ${wallId} is curved; doors and windows go on straight walls, as in the editor.`, { wallId }, ) + // A railing's openings are gaps in its guard: a door becomes one, a window has none to fill. + if (kind === 'window' && isRailingWall(wall)) + refuse( + 'railing_window', + `Wall ${wallId} is a railing: it takes a door, which becomes a gap in the guard, not a window.`, + { wallId }, + ) + const railingGap = kind === 'door' && isRailingWall(wall) ? railingOpeningFields(wall) : null const { t, position } = input if (t !== undefined && position !== undefined && Math.abs(t - position) > 1e-9) @@ -316,7 +326,7 @@ export function planWallOpening(nodes: Nodes, input: WallOpeningInput) { if (compiled) requireMeasured(compiled, { label: `A ${kind}`, tool: `add_${kind}` }) const [scriptedWidth, scriptedHeight] = compiled ? scriptedSize(compiled.manifest) : [] const width = scriptedWidth ?? input.width ?? DEFAULTS[kind].width - const height = scriptedHeight ?? input.height ?? DEFAULTS[kind].height + const height = railingGap?.height ?? scriptedHeight ?? input.height ?? DEFAULTS[kind].height const wallLength = lengthOf(wall) if (wallLength < width) refuse( @@ -370,6 +380,8 @@ export function planWallOpening(nodes: Nodes, input: WallOpeningInput) { parentId: wallId, width, height, + casingFaceA: true, + casingFaceB: true, ...(input.openingShape ? { openingShape: input.openingShape } : {}), ...(input.archHeight === undefined ? {} : { archHeight: Math.min(input.archHeight, height) }), ...(input.cornerRadius === undefined ? {} : { cornerRadius: input.cornerRadius }), @@ -384,15 +396,18 @@ export function planWallOpening(nodes: Nodes, input: WallOpeningInput) { kind === 'door' ? DoorNode.parse({ ...base, + frameThickness: NEW_DOOR_FRAME_THICKNESS, ...doorFacing(wall), ...doorHardwareSides(input), swingDirection: input.swingDirection ?? 'inward', ...(input.style ? doorStyleLook(input.style as DoorStyle) : {}), ...(input.doorType ? { doorType: input.doorType } : {}), ...(input.openingKind ? { openingKind: input.openingKind } : {}), + ...railingGap, }) : WindowNode.parse({ ...base, + frameThickness: NEW_WINDOW_FRAME_THICKNESS, ...getWindowStyleOverrides(input.style as WindowStyle | undefined), ...(input.windowType ? { windowType: input.windowType } : {}), ...(input.columns ? { columnRatios: equalRatios(input.columns) } : {}), diff --git a/packages/core/src/building/window-types.ts b/packages/core/src/building/window-types.ts index f41040de99..543f003b7f 100644 --- a/packages/core/src/building/window-types.ts +++ b/packages/core/src/building/window-types.ts @@ -1,6 +1,9 @@ import type { WindowNode } from '../schema' import type { WindowType } from '../schema/nodes/opening-types' +// The schema keeps 0.05 m for saved windows that omit the field (E-003). +export const NEW_WINDOW_FRAME_THICKNESS = 0.02 + /** The window types whose top takes a shape (rounded, arch); the others are rectangular. */ export const SHAPED_WINDOW_TYPES: ReadonlySet = new Set([ 'fixed', diff --git a/packages/core/src/commands/structure/attached-walls.test.ts b/packages/core/src/commands/structure/attached-walls.test.ts new file mode 100644 index 0000000000..1eb28661b8 --- /dev/null +++ b/packages/core/src/commands/structure/attached-walls.test.ts @@ -0,0 +1,95 @@ +import { describe, expect, test } from 'bun:test' +import { extractRooms } from '../../lib/room-graph' +import { type AnyNode, DoorNode, LevelNode, WallNode } from '../../schema' +import { planAttachedWallUpdates } from '../../systems/wall/wall-move' +import { planAttachedWallChanges } from './attached-walls' +import { setWallGeometry } from './set-wall-geometry' +import { applyToScratch, structureChangeBatch } from './shared' + +const LEVEL = 'level_attached' +const wall = (id: string, start: [number, number], end: [number, number]) => + WallNode.parse({ id: `wall_${id}`, parentId: LEVEL, start, end }) + +// A 10 × 6 box whose top wall is one wall, a partition T'd into its middle +// from below and running down to the bottom wall. +function house(): Record { + const nodes: AnyNode[] = [ + LevelNode.parse({ id: LEVEL }), + wall('top', [0, 0], [10, 0]), + wall('right', [10, 0], [10, 6]), + wall('bottom', [10, 6], [0, 6]), + wall('left', [0, 6], [0, 0]), + wall('part', [4, 0], [4, 6]), + ] + return Object.fromEntries(nodes.map((node) => [node.id, node])) +} + +describe('walls T-joined into a moving wall', () => { + test('stretch along their own line to stay on it', () => { + const nodes = house() + const updates = planAttachedWallUpdates( + [nodes.wall_part as WallNode], + [0, 0], + [10, 0], + [0, -1], + [10, -1], + ) + expect(updates).toEqual([{ id: 'wall_part', start: [4, -1], end: [4, 6] }]) + }) + + test('let go when the move carries the join past the wall ends', () => { + const updates = planAttachedWallUpdates( + [wall('part', [4, 0], [4, 6])], + [0, 0], + [10, 0], + [5, -1], + [10, -1], + ) + expect(updates).toEqual([]) + }) + + test('a push of the whole wall takes them along, their doors staying put', () => { + const nodes = house() + // A door 1 m down the partition from the top wall. + const door = DoorNode.parse({ + id: 'door_part', + parentId: 'wall_part', + wallId: 'wall_part', + position: [1, 1.05, 0], + }) + nodes[door.id] = door + nodes.wall_part = { ...nodes.wall_part, children: [door.id] } as AnyNode + const plan = setWallGeometry(nodes, { + wallId: 'wall_top', + start: [0, -1], + end: [10, -1], + mintId: (kind) => `${kind}_new`, + }) + const after = applyToScratch(nodes, structureChangeBatch(plan.changes)) + const part = after.wall_part as WallNode + expect([part.start, part.end]).toEqual([ + [4, -1], + [4, 6], + ]) + // Still 1 m below the old top line, now 2 m from the moved one. + expect((after.door_part as DoorNode).position[0]).toBeCloseTo(2, 9) + }) + + test('a wall whose door the stretch would leave off its end lets go', () => { + const nodes = house() + const door = DoorNode.parse({ + id: 'door_part', + parentId: 'wall_part', + wallId: 'wall_part', + position: [0.5, 1.05, 0], + }) + nodes[door.id] = door + // Pushing the top wall down 1 m would put the door above the partition's start. + expect(planAttachedWallChanges(nodes, 'wall_top', [0, 0], [10, 0], [0, 1], [10, 1])).toEqual([]) + }) +}) + +test('rooms close on a partition T-joined into a wall left whole', () => { + const walls = Object.values(house()).filter((node): node is WallNode => node.type === 'wall') + expect(extractRooms(walls)).toHaveLength(2) +}) diff --git a/packages/core/src/commands/structure/attached-walls.ts b/packages/core/src/commands/structure/attached-walls.ts new file mode 100644 index 0000000000..3383163b04 --- /dev/null +++ b/packages/core/src/commands/structure/attached-walls.ts @@ -0,0 +1,80 @@ +import type { AnyNode, AnyNodeId, SeparatorNode, WallNode } from '../../schema' +import { planAttachedWallUpdates, type WallPlanPoint } from '../../systems/wall/wall-move' +import { planAttachedSeparatorUpdates } from './move-separators' + +/** + * The writes that keep walls T'd into a moving wall on it + * (`planAttachedWallUpdates`): each such wall's new ends and, where its start + * moved, the doors, windows and wall items on it shifted along so they stay + * where they were. A wall whose opening the stretch would leave off its ends + * lets go instead. The invisible walls on it come along too + * (`planAttachedSeparatorUpdates`), so a porch they close off it stays closed. + * `exclude` are walls the move already rewrites. + */ +export function planAttachedWallChanges( + nodes: Readonly>, + movingWallId: string, + originalStart: WallPlanPoint, + originalEnd: WallPlanPoint, + nextStart: WallPlanPoint, + nextEnd: WallPlanPoint, + exclude: ReadonlySet = new Set(), +): Array<{ id: AnyNodeId; data: Partial }> { + const moving = nodes[movingWallId] + if (moving?.type !== 'wall') return [] + const walls = Object.values(nodes).filter( + (node): node is WallNode => + node.type === 'wall' && + node.parentId === moving.parentId && + node.id !== moving.id && + !exclude.has(node.id), + ) + const children = Object.values(nodes).filter( + (node) => 'position' in node && Array.isArray(node.position) && node.parentId, + ) + const changes: Array<{ id: AnyNodeId; data: Partial }> = [] + for (const update of planAttachedWallUpdates( + walls, + originalStart, + originalEnd, + nextStart, + nextEnd, + )) { + const wall = nodes[update.id] as WallNode + const length = Math.hypot(update.end[0] - update.start[0], update.end[1] - update.start[1]) + const ux = (update.end[0] - update.start[0]) / length + const uz = (update.end[1] - update.start[1]) / length + // How far the old start sits along the wall from the new one. + const shift = (wall.start[0] - update.start[0]) * ux + (wall.start[1] - update.start[1]) * uz + const hosted = children.filter((child) => child.parentId === wall.id) + const moved = hosted.map((child) => { + const position = (child as AnyNode & { position: [number, number, number] }).position + return { child, position, x: position[0] + shift } + }) + if (moved.some(({ x }) => x < 0 || x > length)) continue + changes.push({ id: wall.id as AnyNodeId, data: { start: update.start, end: update.end } }) + if (Math.abs(shift) < 1e-9) continue + for (const { child, position, x } of moved) { + changes.push({ + id: child.id as AnyNodeId, + data: { + position: [x, position[1], position[2]], + ...('wallT' in child ? { wallT: x / length } : {}), + } as Partial, + }) + } + } + const separators = Object.values(nodes).filter( + (node): node is SeparatorNode => + node.type === 'separator' && node.parentId === moving.parentId && !exclude.has(node.id), + ) + for (const update of planAttachedSeparatorUpdates( + separators, + originalStart, + originalEnd, + nextStart, + nextEnd, + )) + changes.push({ id: update.id as AnyNodeId, data: { start: update.start, end: update.end } }) + return changes +} diff --git a/packages/core/src/commands/structure/index.ts b/packages/core/src/commands/structure/index.ts index 63456e9c21..06b0d6a737 100644 --- a/packages/core/src/commands/structure/index.ts +++ b/packages/core/src/commands/structure/index.ts @@ -5,6 +5,7 @@ export { resolveZoneTransformHosts, type SupportHostAssignment, } from './apply-zone-transform' +export { planAttachedWallChanges } from './attached-walls' export { type CreateMezzanineInput, createMezzanine } from './create-mezzanine' export { type CreateZoneInput, @@ -29,6 +30,14 @@ export { } from './floor-opening' export { type LockOutsideFacesInput, lockOutsideFaces } from './lock-outside-faces' export { mergeZones } from './merge-zones' +export { + joinedSeparatorIds, + planAttachedSeparatorUpdates, + SEPARATOR_JOIN_REACH, + type SeparatorSpan, + setSeparatorEnd, + translateSeparators, +} from './move-separators' export { type MezzanineStairPlan, planMezzanineStair } from './plan-mezzanine-stair' export { planWallDeletion } from './plan-wall-deletion' export { rebaseFloorReference } from './rebase-floor-reference' @@ -55,3 +64,12 @@ export { structureChangeBatch, } from './shared' export { type TransformZoneInput, transformZone, type ZoneTransformPlan } from './transform-zone' +export { + finishWallEdit, + retypeOutlineBridges, + sameWallConstruction, + trimWallOverlaps, + WALL_CONSTRUCTION_FIELDS, + wallConstructionPatch, + wallsRunAlong, +} from './wall-overlap' diff --git a/packages/core/src/commands/structure/move-separators.test.ts b/packages/core/src/commands/structure/move-separators.test.ts new file mode 100644 index 0000000000..d926735e47 --- /dev/null +++ b/packages/core/src/commands/structure/move-separators.test.ts @@ -0,0 +1,388 @@ +import { describe, expect, test } from 'bun:test' +import { area } from '../../lib/polygon-boolean' +import { reconcileLevelStructure } from '../../lib/structure-kernel' +import { + type AnyNode, + type AnyNodeId, + LevelNode, + railingWallDefaults, + type SeparatorNode, + WallNode, + type ZoneNode, +} from '../../schema' +import { planSeparatorInsertion } from '../../systems/wall/wall-topology' +import { createZone } from './create-zone' +import { setSeparatorEnd, translateSeparators } from './move-separators' +import { setWallGeometry } from './set-wall-geometry' +import { + applyToScratch, + type StructureNodes, + type StructurePlan, + structureChangeBatch, +} from './shared' + +type Point = [number, number] +const LEVEL = 'level_porch' + +function mint() { + let i = 0 + return (kind: string) => `${kind}_moved${++i}` +} + +/** The level's structure settled after an edit, as the live sync does it. */ +function settle(before: StructureNodes, after: StructureNodes) { + let i = 0 + const derived = reconcileLevelStructure({ + levelId: LEVEL, + nodes: after, + previousNodes: before, + mintId: (kind) => { + let id: string + do id = `${kind}_derived${++i}` + while (after[id]) + return id + }, + }) + return applyToScratch(after, structureChangeBatch(derived.patches)) +} + +function apply(nodes: StructureNodes, plan: StructurePlan) { + expect(plan.conflicts).toBeUndefined() + return settle(nodes, applyToScratch(nodes, structureChangeBatch(plan.changes))) +} + +/** + * An 8 × 4 house with a porch off its z = 4 side, closed by invisible walls drawn left, along + * the bottom (one piece, or as `bottom` gives it) and right, and `railed` sides railings instead. + */ +function porch( + bottom: Array<[Point, Point]> = [ + [ + [2, 6], + [6, 6], + ], + ], + railed: ReadonlySet = new Set(), +) { + const level = LevelNode.parse({ id: LEVEL }) + const empty: StructureNodes = { [level.id]: level } + const house = apply( + empty, + createZone(empty, { + levelId: LEVEL, + polygon: [ + [0, 0], + [8, 0], + [8, 4], + [0, 4], + ], + enclose: true, + mintId: mint(), + name: 'Kitchen', + }), + ) + let next = house + const sides: Array<[Point, Point]> = [ + [ + [2, 4], + [2, 6], + ], + ...bottom, + [ + [6, 6], + [6, 4], + ], + ] + sides.forEach(([start, end], index) => { + if (railed.has(index)) { + const railing = WallNode.parse({ + ...railingWallDefaults(), + id: `wall_railing${index}`, + parentId: LEVEL, + start, + end, + }) + next = { ...next, [railing.id]: railing } + return + } + const plan = planSeparatorInsertion(next as Record, { + levelId: LEVEL as AnyNodeId, + start, + end, + joinRadius: 0.05, + mintId: () => `separator_side${index}`, + }) + expect(plan).not.toBeNull() + next = applyToScratch(next, plan!.changes) + }) + return settle(house, next) +} + +const near = (a: Point, b: Point) => Math.hypot(a[0] - b[0], a[1] - b[1]) < 1e-6 +const separators = (nodes: StructureNodes) => + Object.values(nodes).filter((node): node is SeparatorNode => node.type === 'separator') +/** The invisible wall from `a` to `b`, either way round. */ +const between = (nodes: StructureNodes, a: Point, b: Point) => + separators(nodes).find( + (node) => + (near(node.start, a) && near(node.end, b)) || (near(node.start, b) && near(node.end, a)), + ) +const outdoorRoom = (nodes: StructureNodes) => + Object.values(nodes).find( + (node): node is ZoneNode => node.type === 'zone' && node.name !== 'Kitchen', + ) +const roomArea = (zone: ZoneNode | undefined) => + zone ? area([{ outer: zone.polygon, holes: zone.holes }]) : 0 +const whole = (separator: SeparatorNode | undefined) => ({ + separatorId: separator!.id, + t0: 0, + t1: 1, +}) + +describe('a porch closed by invisible walls', () => { + test('its edge pushed out and back in stays a closed porch, the sides stretching with it', () => { + const nodes = porch() + expect(roomArea(outdoorRoom(nodes))).toBeCloseTo(8, 6) + const bottom = between(nodes, [2, 6], [6, 6]) + const out = apply( + nodes, + translateSeparators(nodes, { spans: [whole(bottom)], offset: [0, 1], mintId: mint() }), + ) + // The one moved invisible wall drags both its neighbours; their far ends stay on the house. + expect(between(out, [2, 7], [6, 7])?.id).toBe(bottom!.id) + expect(between(out, [2, 4], [2, 7])).toBeDefined() + expect(between(out, [6, 7], [6, 4])).toBeDefined() + expect(separators(out)).toHaveLength(3) + const porchRoom = outdoorRoom(out) + expect(porchRoom?.roomType).toBe('porch') + expect(roomArea(porchRoom)).toBeCloseTo(12, 6) + expect(porchRoom?.boundarySeparatorIds).toHaveLength(3) + + const back = apply( + out, + translateSeparators(out, { spans: [whole(bottom)], offset: [0, -2], mintId: mint() }), + ) + expect(roomArea(outdoorRoom(back))).toBeCloseTo(4, 6) + expect(between(back, [2, 4], [2, 5])).toBeDefined() + expect(between(back, [6, 5], [6, 4])).toBeDefined() + }) + + test('a side moved along the house slides its end on the house wall and stretches the edge it meets', () => { + const nodes = porch() + const left = between(nodes, [2, 4], [2, 6]) + const after = apply( + nodes, + translateSeparators(nodes, { spans: [whole(left)], offset: [-1, 0], mintId: mint() }), + ) + expect(between(after, [1, 4], [1, 6])?.id).toBe(left!.id) + expect(between(after, [1, 6], [6, 6])).toBeDefined() + expect(between(after, [6, 6], [6, 4])).toBeDefined() + expect(roomArea(outdoorRoom(after))).toBeCloseTo(10, 6) + // The house wall is never moved by its invisible walls. + const walls = (scene: StructureNodes) => + Object.values(scene) + .filter((node) => node.type === 'wall') + .map((node) => JSON.stringify([(node as WallNode).start, (node as WallNode).end])) + .sort() + expect(walls(after)).toEqual(walls(nodes)) + }) + + test('a side carried off the end of the house leaves an invisible wall back to it', () => { + const nodes = porch() + const left = between(nodes, [2, 4], [2, 6]) + const after = apply( + nodes, + translateSeparators(nodes, { spans: [whole(left)], offset: [-3, 0], mintId: mint() }), + ) + expect(between(after, [-1, 4], [-1, 6])).toBeDefined() + // The jog runs back along the house wall's line; the stretch under the wall is absorbed. + expect(between(after, [-1, 4], [0, 4])).toBeDefined() + expect(roomArea(outdoorRoom(after))).toBeCloseTo(14, 6) + }) + + test('an edge drawn in two pieces pushes as one line', () => { + const nodes = porch([ + [ + [2, 6], + [4, 6], + ], + [ + [4, 6], + [6, 6], + ], + ]) + const pieces = [between(nodes, [2, 6], [4, 6]), between(nodes, [4, 6], [6, 6])] + const after = apply( + nodes, + translateSeparators(nodes, { + spans: pieces.map(whole), + offset: [0, 1.5], + mintId: mint(), + }), + ) + expect(between(after, [2, 7.5], [4, 7.5])).toBeDefined() + expect(between(after, [4, 7.5], [6, 7.5])).toBeDefined() + expect(separators(after)).toHaveLength(4) + expect(roomArea(outdoorRoom(after))).toBeCloseTo(14, 6) + }) + + test('part of an edge moves alone, joined back to the rest by a jog', () => { + const nodes = porch() + const bottom = between(nodes, [2, 6], [6, 6])! + const t = bottom.start[0] === 2 ? ([0, 0.5] as const) : ([0.5, 1] as const) + const after = apply( + nodes, + translateSeparators(nodes, { + spans: [{ separatorId: bottom.id, t0: t[0], t1: t[1] }], + offset: [0, 1], + mintId: mint(), + }), + ) + expect(between(after, [2, 7], [4, 7])?.id).toBe(bottom.id) + expect(between(after, [4, 6], [6, 6])).toBeDefined() + expect(between(after, [4, 6], [4, 7])).toBeDefined() + expect(roomArea(outdoorRoom(after))).toBeCloseTo(10, 6) + }) + + test('a corner drawn a little open still moves together, and closes', () => { + const nodes = porch() + const bottom = between(nodes, [2, 6], [6, 6])! + // Drawn by hand 3 cm short of the side: the room still closes there. + const [shortStart, shortEnd] = near(bottom.start, [2, 6]) + ? [[2.03, 6] as Point, bottom.end] + : [bottom.start, [2.03, 6] as Point] + const open = settle(nodes, { + ...nodes, + [bottom.id]: { ...bottom, start: shortStart, end: shortEnd }, + }) + expect(roomArea(outdoorRoom(open))).toBeGreaterThan(7.8) + const after = apply( + open, + translateSeparators(open, { + spans: [whole(open[bottom.id] as SeparatorNode)], + offset: [0, 1], + mintId: mint(), + }), + ) + const left = separators(after).find( + (node) => near(node.start, [2, 4]) || near(node.end, [2, 4]), + )! + const corner = near(left.start, [2, 4]) ? left.end : left.start + expect(corner).toEqual([2.03, 7]) + expect(roomArea(outdoorRoom(after))).toBeGreaterThan(11.8) + }) + + test('an invisible wall T’d into the edge stretches with it', () => { + let nodes = porch() + const divider = planSeparatorInsertion(nodes as Record, { + levelId: LEVEL as AnyNodeId, + start: [4, 4], + end: [4, 6], + joinRadius: 0.05, + mintId: () => 'separator_divider', + }) + nodes = settle(nodes, applyToScratch(nodes, divider!.changes)) + const bottom = between(nodes, [2, 6], [6, 6]) + const after = apply( + nodes, + translateSeparators(nodes, { spans: [whole(bottom)], offset: [0, 1], mintId: mint() }), + ) + expect(between(after, [4, 4], [4, 7])?.id).toBe('separator_divider') + }) + + test('a corner dragged takes the invisible wall joined there with it; Alt leaves it', () => { + const nodes = porch() + const bottom = between(nodes, [2, 6], [6, 6])! + const endpoint = near(bottom.start, [2, 6]) ? 'start' : 'end' + const after = apply( + nodes, + setSeparatorEnd(nodes, { separatorId: bottom.id, endpoint, point: [1, 7] }), + ) + expect(between(after, [1, 7], [6, 6])).toBeDefined() + expect(between(after, [2, 4], [1, 7])).toBeDefined() + expect(roomArea(outdoorRoom(after))).toBeCloseTo(11, 6) + + const detached = setSeparatorEnd(nodes, { + separatorId: bottom.id, + endpoint, + point: [1, 7], + detach: true, + }) + const moved = applyToScratch(nodes, structureChangeBatch(detached.changes)) + expect(between(moved, [2, 4], [2, 6])).toBeDefined() + }) +}) + +test('an end T’d into a slanted wall slides along it', () => { + const level = LevelNode.parse({ id: LEVEL }) + const slanted = WallNode.parse({ + id: 'wall_slanted', + parentId: LEVEL, + start: [0, 0], + end: [10, 5], + }) + const separator = planSeparatorInsertion( + { [level.id]: level, [slanted.id]: slanted } as Record, + { + levelId: LEVEL as AnyNodeId, + start: [4, 2], + end: [4, 8], + joinRadius: 0.05, + mintId: () => 'separator_tee', + }, + )!.separators[0]! + const nodes: StructureNodes = { + [level.id]: level, + [slanted.id]: slanted, + [separator.id]: separator, + } + const plan = translateSeparators(nodes, { + spans: [whole(separator)], + offset: [1, 0], + mintId: mint(), + }) + const after = applyToScratch(nodes, structureChangeBatch(plan.changes)) as StructureNodes + const moved = after[separator.id] as SeparatorNode + expect(moved.start[0]).toBeCloseTo(5, 9) + expect(moved.start[1]).toBeCloseTo(2.5, 9) + expect(moved.end).toEqual([5, 8]) +}) + +describe('a wall pushed with invisible walls on it', () => { + test('carries the porch’s sides T’d into it', () => { + const nodes = porch() + const house = Object.values(nodes).find( + (node): node is WallNode => node.type === 'wall' && node.start[1] === 4 && node.end[1] === 4, + )! + const after = apply( + nodes, + setWallGeometry(nodes, { + wallId: house.id, + start: [house.start[0], 3], + end: [house.end[0], 3], + mintId: mint(), + }), + ) + expect(between(after, [2, 3], [2, 6])).toBeDefined() + expect(between(after, [6, 6], [6, 3])).toBeDefined() + expect(roomArea(outdoorRoom(after))).toBeCloseTo(12, 6) + }) + + test('a railing edge pushed out takes the invisible sides joined at its ends', () => { + const nodes = porch(undefined, new Set([1])) + expect(outdoorRoom(nodes)).toBeDefined() + const railing = nodes.wall_railing1 as WallNode + const after = apply( + nodes, + setWallGeometry(nodes, { + wallId: railing.id, + start: [railing.start[0], 7], + end: [railing.end[0], 7], + mintId: mint(), + }), + ) + expect(between(after, [2, 4], [2, 7])).toBeDefined() + expect(between(after, [6, 7], [6, 4])).toBeDefined() + expect(roomArea(outdoorRoom(after))).toBeCloseTo(12, 6) + }) +}) diff --git a/packages/core/src/commands/structure/move-separators.ts b/packages/core/src/commands/structure/move-separators.ts new file mode 100644 index 0000000000..cb217f1d5c --- /dev/null +++ b/packages/core/src/commands/structure/move-separators.ts @@ -0,0 +1,440 @@ +import { WALL_JUNCTION_TOLERANCE } from '../../lib/room-graph' +import { type AnyNode, SeparatorNode, type WallNode } from '../../schema' +import { isCurvedWall } from '../../systems/wall/wall-curve' +import { + getPlannedLinkedWallUpdates, + planAttachedWallUpdates, + planWallMoveJunctions, + type WallPlanPoint, +} from '../../systems/wall/wall-move' +import { WALL_MIN_LENGTH } from '../../systems/wall/wall-topology' +import { + at, + conflict, + diffStructure, + type Point, + type StructureMintId, + type StructureNodes, + type StructurePlan, +} from './shared' + +/** + * Invisible walls (room separators) move the way walls do, so the rooms they close stay closed: + * a separator joined end to end with a moving one stretches to its moved end (or takes a jog + * where it runs on in line), one T'd into its body slides along its own line to stay on it, and + * an end of the moving one sitting on a wall, a railing or another separator slides along that + * line. Walls never move with them. + */ + +/** A stretch of an invisible wall: `[0, 1]` is all of it. */ +export type SeparatorSpan = { separatorId: string; t0: number; t1: number } + +/** + * How near invisible walls meet: ends this near are one corner and an end this near a line is on + * it, as far as the room graph joins them (`WALL_JUNCTION_TOLERANCE`). A move puts such ends + * exactly together, so a corner drawn a little open closes. + */ +export const SEPARATOR_JOIN_REACH = WALL_JUNCTION_TOLERANCE + +type Line = { start: Point; end: Point } +type Boundary = WallNode | SeparatorNode + +const JOIN = SEPARATOR_JOIN_REACH +const SAME_POINT = 1e-6 +const WHOLE = 1e-4 +// Lines within about 1° of each other run alongside: one end can't slide along the other. +const MIN_SINE = Math.sin(Math.PI / 180) +// The shortest invisible wall a move may leave, as a wall's (`setWallGeometry`). +const MIN_LENGTH = 0.05 + +const distance = (a: Point, b: Point) => Math.hypot(b[0] - a[0], b[1] - a[1]) +const near = (a: Point, b: Point) => distance(a, b) <= JOIN + +/** Where `point` sits along `line` (metres from its start) and how far off its line. */ +function station(point: Point, line: Line) { + const dx = line.end[0] - line.start[0] + const dz = line.end[1] - line.start[1] + const length = Math.hypot(dx, dz) + if (length < 1e-9) return { along: 0, across: distance(point, line.start), length } + return { + along: ((point[0] - line.start[0]) * dx + (point[1] - line.start[1]) * dz) / length, + across: Math.abs((point[1] - line.start[1]) * dx - (point[0] - line.start[0]) * dz) / length, + length, + } +} + +/** Whether `point` is on the segment `line`, its ends included. */ +function onLine(point: Point, line: Line) { + const { along, across, length } = station(point, line) + return length > 1e-9 && across <= JOIN && along >= -JOIN && along <= length + JOIN +} + +/** Where the line through `moving` meets the segment `host`, if it does at a real angle. */ +function meetingOn(moving: Line, host: Line): Point | null { + const r = [moving.end[0] - moving.start[0], moving.end[1] - moving.start[1]] as const + const u = [host.end[0] - host.start[0], host.end[1] - host.start[1]] as const + const hostLength = Math.hypot(u[0], u[1]) + const denominator = r[0] * u[1] - r[1] * u[0] + if (Math.abs(denominator) <= MIN_SINE * Math.hypot(r[0], r[1]) * hostLength) return null + const qp = [host.start[0] - moving.start[0], host.start[1] - moving.start[1]] as const + const t = (qp[0] * r[1] - qp[1] * r[0]) / denominator + if (t * hostLength < -JOIN || t * hostLength > hostLength + JOIN) return null + return [host.start[0] + u[0] * t, host.start[1] + u[1] * t] +} + +/** `separator` with its ends at `point` (within the join reach) put exactly on it. */ +function ontoCorner(separator: SeparatorNode, point: Point): SeparatorNode { + const start = near(separator.start, point) ? point : separator.start + const end = near(separator.end, point) ? point : separator.end + return start === separator.start && end === separator.end + ? separator + : { ...separator, start, end } +} + +/** `separator` with its ends on the body of `line` (clear of its ends) put exactly on it. */ +function ontoBody(separator: SeparatorNode, line: Line): SeparatorNode { + let next = separator + for (const end of ['start', 'end'] as const) { + const { along, across, length } = station(separator[end], line) + if (across > JOIN || along <= JOIN || along >= length - JOIN) continue + next = { ...next, [end]: at(line.start, line.end, along / length) } + } + return next +} + +const touches = (separator: SeparatorNode, line: Line) => + [separator.start, separator.end].some((p) => near(p, line.start) || near(p, line.end)) + +/** How far `other` lies off the line through `from` along `move`: 0 when it runs with the move. */ +function offMove(from: Point, move: Point, other: Point) { + const length = Math.hypot(move[0], move[1]) + if (length < SAME_POINT) return Number.POSITIVE_INFINITY + return Math.abs(move[0] * (other[1] - from[1]) - move[1] * (other[0] - from[0])) / length +} + +/** + * `separator` (joined at a corner of `line`) as the junction rules should read it: one running + * with its corner's move to within the join reach (a side drawn a little out of square, or put + * onto the corner by `ontoCorner`) reads as running exactly with it, so it stretches as a square + * corner's wall does instead of taking a jog. + */ +function squaredForMove(separator: SeparatorNode, line: Line, next: Line) { + let read = { id: separator.id, start: separator.start, end: separator.end } + for (const corner of ['start', 'end'] as const) { + const from = line[corner] + const move: Point = [next[corner][0] - from[0], next[corner][1] - from[1]] + for (const end of ['start', 'end'] as const) { + if (distance(separator[end], from) > SAME_POINT) continue + const far = end === 'start' ? 'end' : 'start' + if (offMove(from, move, separator[far]) > JOIN) continue + const length = Math.hypot(move[0], move[1]) + const along = + ((separator[far][0] - from[0]) * move[0] + (separator[far][1] - from[1]) * move[1]) / length + read = { + ...read, + [far]: [from[0] + (move[0] / length) * along, from[1] + (move[1] / length) * along], + } + } + } + return read +} + +function levelSeparators(nodes: Record, levelId: string | null) { + return Object.values(nodes).filter( + (node): node is SeparatorNode => node.type === 'separator' && node.parentId === levelId, + ) +} + +/** The invisible walls joined at `endpoint` of `separator`: the ones a drag of that end takes. */ +export function joinedSeparatorIds( + nodes: StructureNodes, + separator: SeparatorNode, + endpoint: 'start' | 'end', +): string[] { + const point = separator[endpoint] + return levelSeparators(nodes, separator.parentId).flatMap((node) => + node.id !== separator.id && (near(node.start, point) || near(node.end, point)) ? [node.id] : [], + ) +} + +/** + * Pushes invisible-wall stretches `offset` as one line: a room's edge of separators, a selected + * separator's side arrow. A stretch shorter than its separator is split off first and only it + * moves, the rest staying joined to it by a jog. An end that sat on a wall, a railing or another + * separator slides along it to where the moved line meets it; one the move carries off its end + * leaves a short invisible wall back to where it was, so the room stays closed. Separators joined + * to the moving ones end to end follow the junction rules of a wall move, and those T'd into + * their bodies stretch along their own lines. One plan, one undo step. + */ +export function translateSeparators( + nodes: StructureNodes, + input: { spans: readonly SeparatorSpan[]; offset: Point; mintId: StructureMintId }, +): StructurePlan { + const spans = new Map() + for (const span of input.spans) { + const t0 = Math.max(0, Math.min(span.t0, span.t1)) + const t1 = Math.min(1, Math.max(span.t0, span.t1)) + const held = spans.get(span.separatorId) + spans.set(span.separatorId, { + t0: Math.min(t0, held?.t0 ?? t0), + t1: Math.max(t1, held?.t1 ?? t1), + }) + } + const first = nodes[input.spans[0]?.separatorId ?? ''] + if ( + first?.type !== 'separator' || + [...spans.keys()].some( + (id) => nodes[id]?.type !== 'separator' || nodes[id]?.parentId !== first.parentId, + ) + ) + throw Error('Select an invisible wall.') + const [dx, dz] = input.offset + if (!(Number.isFinite(dx) && Number.isFinite(dz))) throw Error('Invalid move.') + if (Math.hypot(dx, dz) < 1e-9) return { changes: [] } + const levelId = first.parentId + const shift = ([x, z]: Point): Point => [x + dx, z + dz] + const scratch: Record = { ...nodes } + + // The stretches that move, cut out of their separators. + const rest = new Map() + for (const [id, { t0, t1 }] of spans) { + if (t1 - t0 < WHOLE) continue + const separator = scratch[id] as SeparatorNode + const point = (t: number) => at(separator.start, separator.end, t) + for (const [from, to] of [ + [0, t0], + [t1, 1], + ] as const) + if (to - from > WHOLE) { + const remainder = SeparatorNode.parse({ + ...separator, + id: input.mintId('separator'), + start: point(from), + end: point(to), + }) + scratch[remainder.id] = remainder + } + const piece = { start: point(t0), end: point(t1) } + scratch[id] = { ...separator, ...piece } + rest.set(id, piece) + } + if (!rest.size) return { changes: [] } + + const still = Object.values(scratch).filter( + (node): node is Boundary => + node.parentId === levelId && + !rest.has(node.id) && + (node.type === 'separator' || (node.type === 'wall' && !isCurvedWall(node))), + ) + const bridges: Line[] = [] + const moved = new Map() + for (const [id, line] of rest) { + const shifted = { start: shift(line.start), end: shift(line.end) } + const next = { ...shifted } + for (const end of ['start', 'end'] as const) { + const point = line[end] + // A joint inside the moving line moves with it. + if ( + [...rest].some( + ([other, piece]) => other !== id && (near(piece.start, point) || near(piece.end, point)), + ) + ) + continue + // Separators joined here end to end follow the move instead. + const hosts = still.filter( + (node) => + !(node.type === 'separator' && (near(node.start, point) || near(node.end, point))) && + onLine(point, node), + ) + if (!hosts.length) continue + let slid: Point | null = null + for (const host of hosts) { + const meeting = meetingOn(shifted, host) + if (meeting && (!slid || distance(meeting, shifted[end]) < distance(slid, shifted[end]))) + slid = meeting + } + if (slid) next[end] = slid + else if (!still.some((node) => onLine(shifted[end], node))) + bridges.push({ start: point, end: shifted[end] }) + } + if (distance(next.start, next.end) < MIN_LENGTH) + return conflict('invalid-geometry', [id], 'The invisible wall would be too short there.') + moved.set(id, next) + } + + const deleted = new Set() + for (const [id, line] of rest) { + const next = moved.get(id)! + const others = levelSeparators(scratch, levelId).filter( + (node) => !rest.has(node.id) && !deleted.has(node.id), + ) + // Joined end to end: put on the corner exactly, so the junction rules move them. + const joined = others + .filter((node) => touches(node, line)) + .map((node) => ontoCorner(ontoCorner(node, line.start), line.end)) + // T'd into its body: read before the joined ones move, so a moved end never reads as one. + const attached = planAttachedWallUpdates( + others.filter((node) => !touches(node, line)).map((node) => ontoBody(node, line)), + line.start, + line.end, + next.start, + next.end, + ) + const read = joined.map((node) => squaredForMove(node, line, next)) + const junctions = planWallMoveJunctions(read, line.start, line.end, next.start, next.end) + // The rules move the joined ends; each separator keeps its own far end. + const linked = getPlannedLinkedWallUpdates( + junctions, + line.start, + line.end, + next.start, + next.end, + ).map((update) => { + const proxy = read.find((entry) => entry.id === update.id)! + const own = joined.find((entry) => entry.id === update.id)! + return { + id: update.id, + start: update.start === proxy.start ? own.start : update.start, + end: update.end === proxy.end ? own.end : update.end, + } + }) + for (const update of [...linked, ...attached]) { + if (distance(update.start, update.end) < WALL_MIN_LENGTH) { + delete scratch[update.id] + deleted.add(update.id) + } else + scratch[update.id] = { + ...(scratch[update.id] as SeparatorNode), + start: update.start, + end: update.end, + } + } + for (const separator of junctions.wallsToDelete) { + delete scratch[separator.id] + deleted.add(separator.id) + } + for (const bridge of junctions.bridgePlans) + bridges.push({ + start: bridge.originalPoint, + end: bridge.movedEndpoint === 'start' ? next.start : next.end, + }) + scratch[id] = { ...(scratch[id] as SeparatorNode), start: next.start, end: next.end } + } + + const made: Line[] = [] + for (const bridge of bridges) { + if (distance(bridge.start, bridge.end) < WALL_MIN_LENGTH) continue + const same = (a: Point, b: Point) => distance(a, b) <= SAME_POINT + if ( + made.some( + (line) => + (same(line.start, bridge.start) && same(line.end, bridge.end)) || + (same(line.start, bridge.end) && same(line.end, bridge.start)), + ) + ) + continue + made.push(bridge) + const separator = SeparatorNode.parse({ + id: input.mintId('separator'), + parentId: levelId, + start: bridge.start, + end: bridge.end, + }) + scratch[separator.id] = separator + } + return { changes: diffStructure(nodes, scratch) } +} + +/** + * Moves one end of an invisible wall to `point`, as a wall's end drag does: the separators joined + * at that end follow it, stretching and turning about their far ends, and those T'd into its + * body slide along their own lines to stay on it. `detach` (Alt) leaves them where they are. + */ +export function setSeparatorEnd( + nodes: StructureNodes, + input: { separatorId: string; endpoint: 'start' | 'end'; point: Point; detach?: boolean }, +): StructurePlan { + const separator = nodes[input.separatorId] + if (separator?.type !== 'separator') throw Error('Select an invisible wall.') + if (!input.point.every(Number.isFinite)) throw Error('Invalid point.') + const line: Line = { start: separator.start, end: separator.end } + const next: Line = { ...line, [input.endpoint]: input.point } + if (distance(next.start, next.end) < MIN_LENGTH) + return conflict('invalid-geometry', [separator.id], 'The invisible wall would be too short.') + const scratch: Record = { ...nodes } + scratch[separator.id] = { ...separator, start: next.start, end: next.end } + if (!input.detach) { + const from = line[input.endpoint] + const others = levelSeparators(nodes, separator.parentId).filter( + (node) => node.id !== separator.id, + ) + const updates = [ + ...others.flatMap((other) => { + const start = near(other.start, from) ? input.point : other.start + const end = near(other.end, from) ? input.point : other.end + return start === other.start && end === other.end ? [] : [{ id: other.id, start, end }] + }), + ...planAttachedWallUpdates( + others.filter((other) => !touches(other, line)).map((other) => ontoBody(other, line)), + line.start, + line.end, + next.start, + next.end, + ), + ] + for (const update of updates) { + if (distance(update.start, update.end) < WALL_MIN_LENGTH) delete scratch[update.id] + else + scratch[update.id] = { + ...(scratch[update.id] as SeparatorNode), + start: update.start, + end: update.end, + } + } + } + return { changes: diffStructure(nodes, scratch) } +} + +/** + * The invisible walls a moving wall carries along, so the rooms they close stay closed: one T'd + * into its body slides along its own line onto the moved line, as a wall T'd into it does, and + * one joined at a moving end follows that end while the end moves along the separator's own line + * (a corner pushed square). A corner the move turns leaves its separators where they are, on the + * wall it stretched; an end the move would carry off the wall lets go. + */ +export function planAttachedSeparatorUpdates( + separators: readonly SeparatorNode[], + originalStart: WallPlanPoint, + originalEnd: WallPlanPoint, + nextStart: WallPlanPoint, + nextEnd: WallPlanPoint, +): Array<{ id: SeparatorNode['id']; start: WallPlanPoint; end: WallPlanPoint }> { + const line = { start: originalStart, end: originalEnd } + const updates = planAttachedWallUpdates( + separators.filter((separator) => !touches(separator, line)).map((s) => ontoBody(s, line)), + originalStart, + originalEnd, + nextStart, + nextEnd, + ) + const corners = [ + [originalStart, nextStart], + [originalEnd, nextEnd], + ] as const + for (const separator of separators) { + if (!touches(separator, line)) continue + let next: Line | null = null + for (const end of ['start', 'end'] as const) { + const corner = corners.find(([from]) => near(separator[end], from)) + if (!corner) continue + const [from, to] = corner + const other = separator[end === 'start' ? 'end' : 'start'] + if (distance(other, from) < SAME_POINT) continue + if (offMove(from, [to[0] - from[0], to[1] - from[1]], other) > JOIN) continue + next = { ...(next ?? { start: separator.start, end: separator.end }), [end]: to } + } + if (next && distance(next.start, next.end) >= WALL_MIN_LENGTH) + updates.push({ id: separator.id, start: next.start, end: next.end }) + } + return updates +} diff --git a/packages/core/src/commands/structure/set-wall-geometry.ts b/packages/core/src/commands/structure/set-wall-geometry.ts index 2a66fa49bd..5094effd97 100644 --- a/packages/core/src/commands/structure/set-wall-geometry.ts +++ b/packages/core/src/commands/structure/set-wall-geometry.ts @@ -1,6 +1,8 @@ import { type AnyNodeId, WallNode } from '../../schema' import { planWallJustification } from '../../systems/wall/wall-frame' import { getPlannedLinkedWallUpdates, planWallMoveJunctions } from '../../systems/wall/wall-move' +import { WALL_MIN_LENGTH } from '../../systems/wall/wall-topology' +import { planAttachedWallChanges } from './attached-walls' import { applyToScratch, conflict, @@ -10,6 +12,7 @@ import { type StructureNodes, type StructurePlan, } from './shared' +import { retypeOutlineBridges, trimWallOverlaps } from './wall-overlap' export function setWallGeometry( nodes: StructureNodes, @@ -63,22 +66,61 @@ export function setWallGeometry( hosted.map((n) => n.id), 'Moving this junction would remove a wall with hosted objects.', ) + const linkedUpdates = getPlannedLinkedWallUpdates(plan, wall.start, wall.end, start, end) + // A jog shorter than a wall can be (the wall landed on the line it left) + // is no wall: the walls already meet there. + const bridges = plan.bridgePlans.flatMap((bridge) => { + const to = bridge.movedEndpoint === 'start' ? start : end + return Math.hypot(to[0] - bridge.originalPoint[0], to[1] - bridge.originalPoint[1]) < + WALL_MIN_LENGTH + ? [] + : [ + { + node: WallNode.parse({ + ...bridge.wall, + id: input.mintId('wall'), + children: [], + start: bridge.originalPoint, + end: to, + }), + parentId: wall.parentId as AnyNodeId, + }, + ] + }) scratch = applyToScratch(scratch, { - update: getPlannedLinkedWallUpdates(plan, wall.start, wall.end, start, end).map( - ({ id, ...data }) => ({ id, data }), - ), + update: linkedUpdates.map(({ id, ...data }) => ({ id, data })), delete: consumed, - create: plan.bridgePlans.map((bridge) => ({ - node: WallNode.parse({ - ...bridge.wall, - id: input.mintId('wall'), - children: [], - start: bridge.originalPoint, - end: bridge.movedEndpoint === 'start' ? start : end, - }), - parentId: wall.parentId as AnyNodeId, - })), + create: bridges, }) + scratch[wall.id] = next + // Walls T'd into it stay on it, stretched along their own line. + const attached = planAttachedWallChanges( + scratch, + wall.id, + wall.start, + wall.end, + start, + end, + new Set([...consumed, ...linkedUpdates.map(({ id }) => id)]), + ) + scratch = applyToScratch(scratch, { update: attached, delete: [], create: [] }) + // The moved wall, the walls it stretched and its jogs take over any + // stretch of a parallel wall they now run along; jogs left on the outline + // are outside walls. + const bridgeIds = bridges.map(({ node }) => node.id) + retypeOutlineBridges(scratch, wall.id, bridgeIds) + const blocked = trimWallOverlaps( + scratch, + [ + wall.id, + ...linkedUpdates.map(({ id }) => id).filter((id) => scratch[id]), + ...attached.flatMap(({ id }) => (scratch[id]?.type === 'wall' ? [id] : [])), + ...bridgeIds, + ], + () => input.mintId('wall'), + ) + if (blocked) return conflict(blocked.code, blocked.nodeIds, blocked.message) + return { changes: diffStructure(nodes, scratch) } } scratch[wall.id] = next return { changes: diffStructure(nodes, scratch) } diff --git a/packages/core/src/commands/structure/set-zone-intent.ts b/packages/core/src/commands/structure/set-zone-intent.ts index f2f0b8499e..666c9d1d16 100644 --- a/packages/core/src/commands/structure/set-zone-intent.ts +++ b/packages/core/src/commands/structure/set-zone-intent.ts @@ -1,6 +1,12 @@ import { z } from 'zod' import { floorIntentConflicts } from '../../lib/floor-intent-changes' import { floorScriptPaintRefusal } from '../../lib/floor-plate-paint' +import { + isOutdoorRoomDefaultName, + isOutdoorRoomType, + nextOutdoorRoomName, + OUTDOOR_ROOM_DEFAULTS, +} from '../../lib/outdoor-room' import { ownFloorIntentChanges } from '../../lib/own-floor-intent' import { drawnFloorElevationConflict } from '../../lib/room-drawn-floor' import { roundFloorElevation } from '../../lib/room-floor-feasibility' @@ -10,6 +16,7 @@ import { requireZone, type StructureNodes, type StructurePlan } from './shared' const floor = ZoneNode.shape.floor.unwrap() const ceiling = ZoneNode.shape.ceiling.unwrap() +const decking = ZoneNode.shape.decking.unwrap() export const ZoneIntentPatch = z.strictObject({ name: z.string().nullable().optional(), floor: z @@ -19,6 +26,30 @@ export const ZoneIntentPatch = z.strictObject({ elevation: floor.shape.elevation.unwrap().nullable().optional(), finish: floor.shape.finish.unwrap().nullable().optional(), regions: floor.shape.regions.unwrap().nullable().optional(), + drop: floor.shape.drop.unwrap().nullable().optional(), + }) + .nullable() + .optional(), + roomType: ZoneNode.shape.roomType.unwrap().nullable().optional(), + // A porch's posts and beam (`lib/porch-framing`), a deck's or patio's once switched on (`auto` + // true). Choosing a size or the spacing rebuilds them from the settings, automatic again, + // unless the patch says otherwise. + porchFraming: z + .strictObject({ + auto: z.boolean().nullable().optional(), + postSize: z.string().nullable().optional(), + postSpacing: z.number().positive().nullable().optional(), + beamSize: z.string().nullable().optional(), + }) + .nullable() + .optional(), + // A deck's boards (`lib/deck-boards`): the stock, the gap and the way they run; null clears one + // back to its default, a null `decking` all three. + decking: z + .strictObject({ + boardSize: decking.shape.boardSize.unwrap().nullable().optional(), + gap: decking.shape.gap.unwrap().nullable().optional(), + direction: decking.shape.direction.unwrap().nullable().optional(), }) .nullable() .optional(), @@ -44,12 +75,54 @@ export const ZoneIntentPatch = z.strictObject({ }) export type ZoneIntentPatch = z.infer +/** + * The patch with what a change of room type brings (`lib/outdoor-room`): a porch, deck or patio + * steps its floor down from the house's, takes its floor finish, a ceiling or none, and its name + * while the room still has a default one; back to an ordinary room drops them again. What the + * patch sets itself wins. + */ +function withRoomType( + nodes: StructureNodes, + zone: ZoneNode, + patch: ZoneIntentPatch, +): ZoneIntentPatch { + const asked = patch.roomType + if (asked === undefined || (asked ?? undefined) === zone.roomType) return patch + const previous = isOutdoorRoomType(zone.roomType) ? OUTDOOR_ROOM_DEFAULTS[zone.roomType] : null + const next = isOutdoorRoomType(asked) ? OUTDOOR_ROOM_DEFAULTS[asked] : null + // A finish the old type gave the room goes with it; one the user picked stays. + const finish = zone.floor?.finish + const typeFinish = finish === undefined || finish === previous?.finish + const defaultName = /^Room \d+$/.test(zone.name) || isOutdoorRoomDefaultName(zone.name) + const names = Object.values(nodes).flatMap((node) => + node.type === 'zone' && node.parentId === zone.parentId && node.id !== zone.id + ? [node.name] + : [], + ) + return { + ...patch, + ...(patch.name === undefined && next && defaultName + ? { name: nextOutdoorRoomName(asked as keyof typeof OUTDOOR_ROOM_DEFAULTS, names) } + : {}), + ...(patch.hasCeiling === undefined ? { hasCeiling: next ? next.covered : true } : {}), + floor: { + ...patch.floor, + ...(patch.floor?.drop === undefined && patch.floor?.elevation === undefined + ? { drop: next ? next.drop : null } + : {}), + ...(patch.floor?.finish === undefined && typeFinish + ? { finish: next ? next.finish : null } + : {}), + }, + } +} + export function setZoneIntent( nodes: StructureNodes, input: { zoneId: string; patch: ZoneIntentPatch }, ): StructurePlan { const zone = requireZone(nodes, input.zoneId) - const patch = ZoneIntentPatch.parse(input.patch) + const patch = withRoomType(nodes, zone, ZoneIntentPatch.parse(input.patch)) const painted = zone.floor?.script && (patch.floor?.finish ?? patch.floor?.regions) const scripted = painted ? floorScriptPaintRefusal(zone) : undefined if (scripted) @@ -87,6 +160,36 @@ export function setZoneIntent( ? patch.floorStepOverrides : undefined if (patch.name !== undefined) data.name = patch.name ?? '' + if (patch.roomType !== undefined) data.roomType = patch.roomType ?? undefined + if (patch.porchFraming !== undefined) { + const asked = patch.porchFraming + const framing: Record = asked === null ? {} : { ...zone.porchFraming } + if (asked) + for (const key of ['auto', 'postSize', 'postSpacing', 'beamSize'] as const) { + if (asked[key] === null) delete framing[key] + else if (asked[key] !== undefined) framing[key] = asked[key] + } + const resized = + asked && (['postSize', 'postSpacing', 'beamSize'] as const).some((key) => key in asked) + if (resized && asked.auto === undefined) framing.auto = true + // A porch's are automatic by default, stored only when off; a deck's or patio's are off by + // default, stored when switched on. + const roomType = patch.roomType !== undefined ? (patch.roomType ?? undefined) : zone.roomType + if (roomType === 'porch' && framing.auto === true) delete framing.auto + data.porchFraming = Object.keys(framing).length + ? (framing as ZoneNode['porchFraming']) + : undefined + } + if (patch.decking !== undefined) { + const asked = patch.decking + const boards: Record = asked === null ? {} : { ...zone.decking } + if (asked) + for (const key of ['boardSize', 'gap', 'direction'] as const) { + if (asked[key] === null) delete boards[key] + else if (asked[key] !== undefined) boards[key] = asked[key] + } + data.decking = Object.keys(boards).length ? (boards as ZoneNode['decking']) : undefined + } if (patch.wallMaterial !== undefined) data.wallMaterial = patch.wallMaterial ?? undefined for (const key of ['hasFloor', 'hasCeiling'] as const) if (patch[key] !== undefined) data[key] = patch[key] === false ? false : undefined @@ -97,7 +200,14 @@ export function setZoneIntent( if (patch.floor !== undefined) { data.floor = patch.floor === null ? undefined : { ...zone.floor } if (patch.floor) - for (const key of ['elevation', 'finish', 'regions', 'thickness', 'footprint'] as const) { + for (const key of [ + 'elevation', + 'finish', + 'regions', + 'thickness', + 'footprint', + 'drop', + ] as const) { const value = patch.floor[key] if (value === null) delete data.floor![key] else if (value !== undefined) diff --git a/packages/core/src/commands/structure/wall-overlap.test.ts b/packages/core/src/commands/structure/wall-overlap.test.ts new file mode 100644 index 0000000000..fd785a4a38 --- /dev/null +++ b/packages/core/src/commands/structure/wall-overlap.test.ts @@ -0,0 +1,281 @@ +import { describe, expect, test } from 'bun:test' +import { type AnyNode, DoorNode, LevelNode, WallNode, ZoneNode } from '../../schema' +import { planWallInsertion } from '../../systems/wall/wall-topology' +import { setWallGeometry } from './set-wall-geometry' +import { applyToScratch, structureChangeBatch } from './shared' +import { finishWallEdit, retypeOutlineBridges, trimWallOverlaps } from './wall-overlap' + +const LEVEL = 'level_overlap' + +function scene(...nodes: AnyNode[]): Record { + const level = LevelNode.parse({ id: LEVEL }) + return Object.fromEntries( + [level, ...nodes.map((node) => ({ ...node, parentId: node.parentId ?? LEVEL }) as AnyNode)].map( + (node) => [node.id, node], + ), + ) +} +const wall = (id: string, start: [number, number], end: [number, number], extra = {}) => + WallNode.parse({ id: `wall_${id}`, start, end, ...extra }) +function minter() { + let i = 0 + return () => `wall_cut${++i}` +} +const walls = (nodes: Record) => + Object.values(nodes).filter((node): node is WallNode => node.type === 'wall') +const ends = (node: AnyNode | undefined) => { + const w = node as WallNode + return [w.start.map((v) => +v.toFixed(6)), w.end.map((v) => +v.toFixed(6))] +} + +describe('trimWallOverlaps', () => { + test('a wall stretched over the end of a collinear wall cuts it back to meet it', () => { + const nodes = scene(wall('placed', [1, 5], [10, 5]), wall('old', [-2, 5], [3, 5])) + expect(trimWallOverlaps(nodes, ['wall_placed'], minter())).toBeNull() + expect(ends(nodes.wall_old)).toEqual([ + [-2, 5], + [1, 5], + ]) + expect(ends(nodes.wall_placed)).toEqual([ + [1, 5], + [10, 5], + ]) + }) + + test('a wall landing inside a longer one splits it round itself', () => { + const nodes = scene(wall('placed', [3, 0], [5, 0]), wall('long', [0, 0], [10, 0])) + expect(trimWallOverlaps(nodes, ['wall_placed'], minter())).toBeNull() + expect(ends(nodes.wall_long)).toEqual([ + [0, 0], + [3, 0], + ]) + expect(ends(nodes.wall_cut1)).toEqual([ + [5, 0], + [10, 0], + ]) + expect(walls(nodes)).toHaveLength(3) + }) + + test('a wall it covers whole is deleted, its door moved onto the placed wall', () => { + const door = DoorNode.parse({ id: 'door_d', position: [1, 0, 0], width: 0.9 }) + const nodes = scene( + wall('placed', [0, 0], [6, 0]), + { ...wall('short', [4, 0], [2, 0]), children: [door.id] } as AnyNode, + { ...door, parentId: 'wall_short', wallId: 'wall_short' } as AnyNode, + ) + expect(trimWallOverlaps(nodes, ['wall_placed'], minter())).toBeNull() + expect(nodes.wall_short).toBeUndefined() + const moved = nodes.door_d as DoorNode + expect(moved.parentId).toBe('wall_placed') + // 1 m from (4, 0) back toward (2, 0) is x = 3 on the placed wall. + expect(moved.position[0]).toBeCloseTo(3) + expect((nodes.wall_placed as WallNode).children).toContain('door_d') + }) + + test('a door across the cut stops the edit', () => { + const door = DoorNode.parse({ id: 'door_d', position: [3, 0, 0], width: 0.9 }) + const nodes = scene( + wall('placed', [3.2, 0], [10, 0]), + { ...wall('old', [0, 0], [5, 0]), children: [door.id] } as AnyNode, + { ...door, parentId: 'wall_old', wallId: 'wall_old' } as AnyNode, + ) + expect(trimWallOverlaps(nodes, ['wall_placed'], minter())?.code).toBe('hosted-openings') + }) + + test('a thinner wall face-aligned inside a thicker one takes its stretch over', () => { + // Outside 0.2 thick on the line z = 0; a partition 0.1 thick, 5 cm in. + const nodes = scene( + wall('partition', [2, 0.05], [6, 0.05], { thickness: 0.1 }), + wall('outside', [0, 0], [8, 0], { thickness: 0.2 }), + ) + expect(trimWallOverlaps(nodes, ['wall_partition'], minter())).toBeNull() + expect(ends(nodes.wall_outside)).toEqual([ + [0, 0], + [2, 0], + ]) + expect(ends(nodes.wall_cut1)).toEqual([ + [6, 0], + [8, 0], + ]) + }) + + test('walls side by side, face to face, are left alone', () => { + const nodes = scene( + wall('placed', [0, 0], [6, 0], { thickness: 0.1 }), + wall('beside', [0, 0.1], [6, 0.1], { thickness: 0.1 }), + ) + expect(trimWallOverlaps(nodes, ['wall_placed'], minter())).toBeNull() + expect(ends(nodes.wall_beside)).toEqual([ + [0, 0.1], + [6, 0.1], + ]) + }) + + test('rooms that named the cut wall name its pieces and the placed wall', () => { + const zone = ZoneNode.parse({ + id: 'zone_r', + name: 'Room', + polygon: [ + [0, 0], + [10, 0], + [10, 4], + ], + boundaryWallIds: ['wall_long'], + }) + const nodes = scene(wall('placed', [3, 0], [5, 0]), wall('long', [0, 0], [10, 0]), zone) + expect(trimWallOverlaps(nodes, ['wall_placed'], minter())).toBeNull() + expect((nodes.zone_r as ZoneNode).boundaryWallIds).toEqual([ + 'wall_long', + 'wall_cut1', + 'wall_placed', + ]) + }) +}) + +describe('outline jogs', () => { + // A 10 × 6 outline 0.2 thick, a 0.1 partition at x = 5 splitting top and bottom. + const house = () => + scene( + wall('top1', [0, 0], [5, 0], { thickness: 0.2 }), + wall('top2', [5, 0], [10, 0], { thickness: 0.2 }), + wall('right', [10, 0], [10, 6], { thickness: 0.2 }), + wall('bot1', [10, 6], [5, 6], { thickness: 0.2 }), + wall('bot2', [5, 6], [0, 6], { thickness: 0.2 }), + wall('left', [0, 6], [0, 0], { thickness: 0.2 }), + wall('part', [5, 0], [5, 6], { thickness: 0.1 }), + ) + + test('pushing an outside wall out past a partition makes an outside jog', () => { + const nodes = house() + const plan = setWallGeometry(nodes, { + wallId: 'wall_top1', + start: [0, -1], + end: [5, -1], + mintId: (kind) => `${kind}_jog`, + }) + const after = applyToScratch(nodes, structureChangeBatch(plan.changes)) + expect(ends(after.wall_jog)).toEqual([ + [5, 0], + [5, -1], + ]) + expect((after.wall_jog as WallNode).thickness).toBe(0.2) + expect((after.wall_part as WallNode).thickness).toBe(0.1) + }) + + test('a jog inside the house keeps the wall it continues', () => { + const nodes = house() + const inside = wall('jog', [5, 3], [7, 3], { thickness: 0.1 }) + nodes[inside.id] = { ...inside, parentId: LEVEL } as AnyNode + retypeOutlineBridges(nodes, 'wall_top1', ['wall_jog']) + expect((nodes.wall_jog as WallNode).thickness).toBe(0.1) + }) +}) + +describe('setWallGeometry', () => { + test('landing exactly on the line of the wall below leaves no zero-length wall', () => { + // A room's left wall at x = 3 over a wider room below whose top runs from x = 0. + const nodes = scene( + wall('w2', [3, 0], [3, 5]), + wall('topRight', [3, 0], [10, 0]), + wall('belowLeft', [0, 5], [3, 5]), + wall('belowRight', [3, 5], [10, 5]), + wall('w3', [0, 10], [0, 5]), + ) + const plan = setWallGeometry(nodes, { + wallId: 'wall_w2', + start: [0, 0], + end: [0, 5], + mintId: (kind) => `${kind}_new`, + }) + const after = applyToScratch(nodes, structureChangeBatch(plan.changes)) + for (const w of walls(after)) { + expect(Math.hypot(w.end[0] - w.start[0], w.end[1] - w.start[1])).toBeGreaterThan(0.01) + } + expect(after.wall_belowLeft).toBeUndefined() + expect(ends(after.wall_belowRight)).toEqual([ + [0, 5], + [10, 5], + ]) + }) + + test('a wall stretched by a move takes over the collinear wall it now runs along', () => { + const nodes = scene( + wall('w2', [3, 0], [3, 5]), + wall('c', [3, 5], [10, 5]), + wall('e', [-2, 5], [2, 5]), + ) + const plan = setWallGeometry(nodes, { + wallId: 'wall_w2', + start: [1, 0], + end: [1, 5], + mintId: (kind) => `${kind}_new`, + }) + const after = applyToScratch(nodes, structureChangeBatch(plan.changes)) + expect(ends(after.wall_c)).toEqual([ + [1, 5], + [10, 5], + ]) + expect(ends(after.wall_e)).toEqual([ + [-2, 5], + [1, 5], + ]) + }) +}) + +describe('drawing over a wall', () => { + test('a wall drawn along part of another takes that stretch over', () => { + const nodes = scene(wall('old', [0, 0], [4, 0], { thickness: 0.1 })) + const result = planWallInsertion(nodes as never, { + levelId: LEVEL as never, + start: [2, 0], + end: [6, 0], + joinRadius: 0.05, + wallDefaults: { thickness: 0.2 }, + replaceCovered: true, + mintId: minter(), + }) + expect(result.ok).toBe(true) + if (!result.ok) return + const changes = finishWallEdit(nodes as never, result.plan.changes, { + winnerIds: result.plan.insertedWalls.map((w) => w.id), + mintId: minter(), + }) + const after = walls(applyToScratch(nodes as never, changes)) + const covering = after.filter( + (w) => Math.min(w.start[0], w.end[0]) < 4 - 1e-6 && Math.max(w.start[0], w.end[0]) > 2 + 1e-6, + ) + // One wall, the new one, along [2, 4]; the old one keeps [0, 2]. + expect(covering).toHaveLength(1) + expect(covering[0]!.thickness).toBe(0.2) + expect(after).toHaveLength(2) + }) + + test('a wall drawn exactly over another replaces it instead of being refused', () => { + const nodes = scene(wall('old', [0, 0], [4, 0], { thickness: 0.1 })) + const refused = planWallInsertion(nodes as never, { + levelId: LEVEL as never, + start: [0, 0], + end: [4, 0], + joinRadius: 0.05, + }) + expect(refused.ok).toBe(false) + const result = planWallInsertion(nodes as never, { + levelId: LEVEL as never, + start: [0, 0], + end: [4, 0], + joinRadius: 0.05, + wallDefaults: { thickness: 0.2 }, + replaceCovered: true, + mintId: minter(), + }) + expect(result.ok).toBe(true) + if (!result.ok) return + const changes = finishWallEdit(nodes as never, result.plan.changes, { + winnerIds: result.plan.insertedWalls.map((w) => w.id), + mintId: minter(), + }) + const after = walls(applyToScratch(nodes as never, changes)) + expect(after).toHaveLength(1) + expect(after[0]!.thickness).toBe(0.2) + }) +}) diff --git a/packages/core/src/commands/structure/wall-overlap.ts b/packages/core/src/commands/structure/wall-overlap.ts new file mode 100644 index 0000000000..30824ba711 --- /dev/null +++ b/packages/core/src/commands/structure/wall-overlap.ts @@ -0,0 +1,334 @@ +import { enclosedWallIds } from '../../lib/exterior-wall-loops' +import type { AnyNode, AnyNodeId, WallNode } from '../../schema' +import { isCurvedWall } from '../../systems/wall/wall-curve' +import { getWallFaceOffsets } from '../../systems/wall/wall-frame' +import { + WALL_MIN_LENGTH, + type WallTopologyChanges, + wallAttachmentSpan, +} from '../../systems/wall/wall-topology' +import type { StructureConflict } from './shared' +import { rehostWallChild, remapWallReferences, wallSlice } from './zone-wall-merge' + +/** + * A wall placed, moved or stretched over part of a parallel wall takes that + * stretch over: the other wall keeps only what lies past the placed wall's + * ends (cut back, split in two round it, or deleted when covered), so no + * length of wall is doubled. Doors, windows and wall items on the stretch + * taken over move onto the placed wall; rooms that named the cut wall name its + * pieces and the placed wall. + * + * Two walls run along each other when they are parallel and the body centre of + * the thinner lies inside the thicker's body: the same line, or a wall + * face-aligned inside a thicker one. Walls side by side, face to face, are + * left alone. The wall moves, the wall tool and the push arrows all finish + * through here. + */ + +// Walls within about 1° of each other count as parallel. +const PARALLEL_TOLERANCE = Math.sin(Math.PI / 180) +const ON_LINE = 1e-6 +const SPAN_TOLERANCE = 1e-4 + +type Nodes = Record +type Vec = [number, number] + +const dot = (a: Vec, b: Vec) => a[0] * b[0] + a[1] * b[1] +const sub = (a: Vec, b: Vec): Vec => [a[0] - b[0], a[1] - b[1]] + +function straightFrame(wall: WallNode) { + if (isCurvedWall(wall)) return null + const delta = sub(wall.end, wall.start) + const length = Math.hypot(delta[0], delta[1]) + if (length < WALL_MIN_LENGTH) return null + const dir: Vec = [delta[0] / length, delta[1] / length] + return { dir, normal: [-dir[1], dir[0]] as Vec, length } +} + +/** The wall's body across `normal` (a unit vector square to it), from `origin`. */ +function bodyAcross(wall: WallNode, wallNormal: Vec, normal: Vec, origin: Vec): [number, number] { + const { a, b } = getWallFaceOffsets(wall) + const line = dot(sub(wall.start, origin), normal) + const sign = Math.sign(dot(wallNormal, normal)) || 1 + return [line + Math.min(a * sign, b * sign), line + Math.max(a * sign, b * sign)] +} + +/** True when `other` runs along `wall`: parallel, the thinner body centred inside the thicker. */ +function runsAlong(wall: WallNode, other: WallNode) { + const own = straightFrame(wall) + const theirs = straightFrame(other) + if (!(own && theirs)) return false + if (Math.abs(own.dir[0] * theirs.dir[1] - own.dir[1] * theirs.dir[0]) > PARALLEL_TOLERANCE) { + return false + } + const ownBody = bodyAcross(wall, own.normal, theirs.normal, other.start) + const theirBody = bodyAcross(other, theirs.normal, theirs.normal, other.start) + const [thin, thick] = + ownBody[1] - ownBody[0] <= theirBody[1] - theirBody[0] + ? [ownBody, theirBody] + : [theirBody, ownBody] + const middle = (thin[0] + thin[1]) / 2 + return middle > thick[0] + SPAN_TOLERANCE && middle < thick[1] - SPAN_TOLERANCE +} + +/** Where `winner` covers `other`, as `[lo, hi]` of `other`; null under a wall's length. */ +function coveredSpan(winner: WallNode, other: WallNode) { + const frame = straightFrame(other) + if (!frame) return null + const station = (point: Vec) => dot(sub(point, other.start), frame.dir) / frame.length + const s0 = station(winner.start) + const s1 = station(winner.end) + const lo = Math.max(0, Math.min(s0, s1)) + const hi = Math.min(1, Math.max(s0, s1)) + return (hi - lo) * frame.length < WALL_MIN_LENGTH ? null : { frame, s0, s1, lo, hi } +} + +/** The walls on `wall`'s level it runs along for more than a sliver: what it would take over. */ +export function wallsRunAlong(nodes: Readonly, wall: WallNode): WallNode[] { + return Object.values(nodes).filter( + (node): node is WallNode => + node.type === 'wall' && + node.id !== wall.id && + node.parentId === wall.parentId && + runsAlong(wall, node) && + coveredSpan(wall, node) !== null, + ) +} + +function wallAttachments(nodes: Nodes, wall: WallNode) { + return Object.values(nodes).filter( + (node) => node.parentId === wall.id || ('wallId' in node && node.wallId === wall.id), + ) +} + +/** A kept piece of a cut wall: `[t0, t1]` of it, the first keeping its id. */ +type Piece = { id: string; t0: number; t1: number } + +/** + * Cut `winner`'s stretch out of `other` in `nodes` (mutated). Null when done, + * a conflict when an opening straddles a cut. + */ +function cutAlong( + nodes: Nodes, + winner: WallNode, + other: WallNode, + mintId: () => string, +): StructureConflict | null { + const covered = coveredSpan(winner, other) + if (!covered) return null + const { frame, s0, s1, lo, hi } = covered + + // Where the cut wall now ends: on the winner's own end when the two share a + // line, so they meet exactly; else straight across from it on its own line. + const sameLine = + Math.abs(dot(sub(winner.start, other.start), frame.normal)) < ON_LINE && + Math.abs(dot(sub(winner.end, other.start), frame.normal)) < ON_LINE + const pointAt = (t: number): Vec => { + if (t <= 0) return [other.start[0], other.start[1]] + if (t >= 1) return [other.end[0], other.end[1]] + if (sameLine) { + if (Math.abs(s0 - t) * frame.length < ON_LINE) return [winner.start[0], winner.start[1]] + if (Math.abs(s1 - t) * frame.length < ON_LINE) return [winner.end[0], winner.end[1]] + } + return [ + other.start[0] + (other.end[0] - other.start[0]) * t, + other.start[1] + (other.end[1] - other.start[1]) * t, + ] + } + + const spans = [ + [0, lo], + [hi, 1], + ].filter(([t0, t1]) => (t1! - t0!) * frame.length >= WALL_MIN_LENGTH) + const pieces: Piece[] = spans.map(([t0, t1], index) => ({ + id: index === 0 ? other.id : mintId(), + t0: t0!, + t1: t1!, + })) + + // Every attachment goes to the kept piece it sits on, or onto the winner + // when it sits on the stretch taken over; one across a cut stops the edit. + const placed = new Map() + for (const child of wallAttachments(nodes, other)) { + const span = wallAttachmentSpan(child) + if (!span) { + placed.set(child.id, pieces[0] ?? 'winner') + continue + } + const t0 = span.min / frame.length + const t1 = span.max / frame.length + const tolerance = SPAN_TOLERANCE / frame.length + const piece = pieces.find((p) => t0 >= p.t0 - tolerance && t1 <= p.t1 + tolerance) + if (piece) placed.set(child.id, piece) + else if (t0 >= lo - tolerance && t1 <= hi + tolerance) placed.set(child.id, 'winner') + else + return { + code: 'hosted-openings', + nodeIds: [child.id], + message: 'A door or window would sit across where the walls meet.', + } + } + + const slices = pieces.map((piece) => + wallSlice(other, pointAt(piece.t0), pointAt(piece.t1), piece.id, [piece.t0, piece.t1]), + ) + const winnerChildren = new Set(winner.children ?? []) + for (const child of wallAttachments(nodes, other)) { + const target = placed.get(child.id) + if (target === 'winner') { + rehostWallChild(nodes, child, other, winner) + winnerChildren.add(child.id) + continue + } + if (!target) continue + const slice = slices[pieces.indexOf(target)]! + slice.children = [...(slice.children ?? []), child.id] as WallNode['children'] + if (!('position' in child && Array.isArray(child.position))) { + nodes[child.id] = { ...child, parentId: slice.id } as AnyNode + continue + } + const x = child.position[0] - target.t0 * frame.length + const length = (target.t1 - target.t0) * frame.length + nodes[child.id] = { + ...child, + parentId: slice.id, + ...('wallId' in child ? { wallId: slice.id } : {}), + position: [x, child.position[1], child.position[2]], + ...('wallT' in child ? { wallT: length > 1e-6 ? x / length : 0 } : {}), + } as AnyNode + } + nodes[winner.id] = { ...winner, children: [...winnerChildren] } as AnyNode + remapWallReferences(nodes, other, [...slices, nodes[winner.id] as WallNode]) + delete nodes[other.id] + for (const slice of slices) nodes[slice.id] = slice + return null +} + +/** + * Let each wall of `winnerIds` take over the stretches of parallel walls it + * runs along (`nodes` is mutated). Walls among the winners don't cut each + * other. A conflict when an opening would straddle a cut; `nodes` may then + * be half done, so callers work on a copy. + */ +export function trimWallOverlaps( + nodes: Nodes, + winnerIds: readonly string[], + mintId: () => string, +): StructureConflict | null { + const winners = new Set(winnerIds) + for (const id of winnerIds) { + const winner = nodes[id] + if (winner?.type !== 'wall' || !straightFrame(winner)) continue + for (const other of wallsRunAlong(nodes, winner).filter((node) => !winners.has(node.id))) { + const conflict = cutAlong(nodes, nodes[id] as WallNode, other, mintId) + if (conflict) return conflict + } + } + return null +} + +/** + * The fields that make a wall's construction (its wall type): assembly, + * thickness, finishes and trims. Position, support, paint regions, height and + * justification stay with each wall. + */ +export const WALL_CONSTRUCTION_FIELDS = [ + 'thickness', + 'wallType', + 'curtainWall', + 'railing', + 'assembly', + 'material', + 'materialPreset', + 'interiorMaterial', + 'interiorMaterialPreset', + 'exteriorMaterial', + 'exteriorMaterialPreset', + 'slots', + 'legacyFaceMaterials', + 'skirting', + 'crown', + 'chairRail', + 'finishScripts', + 'cap', +] as const satisfies ReadonlyArray + +/** `wall`'s construction as a patch for another wall (unset fields cleared). */ +export function wallConstructionPatch(wall: WallNode): Partial { + const patch: Record = {} + for (const field of WALL_CONSTRUCTION_FIELDS) patch[field] = structuredClone(wall[field]) + return patch as Partial +} + +/** True when two walls are built the same (`WALL_CONSTRUCTION_FIELDS`). */ +export function sameWallConstruction(a: WallNode, b: WallNode): boolean { + return JSON.stringify(wallConstructionPatch(a)) === JSON.stringify(wallConstructionPatch(b)) +} + +/** + * The jog walls a move bridges in (`bridgeIds`) copy the wall they continue — + * often a partition, when an outside wall is pushed out past one. A jog left + * on the outline of the storey, beside a moved wall that is on it too, is an + * outside wall: it takes the moved wall's construction instead (`nodes` is + * mutated). + */ +export function retypeOutlineBridges( + nodes: Nodes, + movedWallId: string, + bridgeIds: readonly string[], +): void { + const moved = nodes[movedWallId] + if (moved?.type !== 'wall' || bridgeIds.length === 0) return + const walls = Object.values(nodes).filter( + (node): node is WallNode => + node.type === 'wall' && node.parentId === moved.parentId && node.visible !== false, + ) + const enclosed = enclosedWallIds(walls) + if (enclosed.has(moved.id)) return + const patch = wallConstructionPatch(moved) + for (const id of bridgeIds) { + const bridge = nodes[id] + if (bridge?.type !== 'wall' || enclosed.has(bridge.id)) continue + nodes[id] = { ...bridge, ...patch } as AnyNode + } +} + +/** + * `changes` (a planned wall edit against `nodes`) with the overlaps its + * `winnerIds` now run along trimmed, and its outline jogs (`bridgeIds`, beside + * `movedWallId`) retyped. The plan unchanged when an opening would straddle a + * cut. + */ +export function finishWallEdit( + nodes: Record, + changes: WallTopologyChanges, + options: { + winnerIds: readonly string[] + movedWallId?: string + bridgeIds?: readonly string[] + mintId: () => string + }, +): WallTopologyChanges { + const scratch: Nodes = { ...nodes } + for (const id of changes.delete) delete scratch[id] + for (const { node, parentId } of changes.create) + scratch[node.id] = { ...node, parentId: parentId ?? node.parentId } as AnyNode + for (const { id, data } of changes.update) + if (scratch[id]) scratch[id] = { ...scratch[id], ...data } as AnyNode + if (options.movedWallId) { + retypeOutlineBridges(scratch, options.movedWallId, options.bridgeIds ?? []) + } + const trimmed = { ...scratch } + const conflict = trimWallOverlaps(trimmed, options.winnerIds, options.mintId) + const after = conflict ? scratch : trimmed + const before = nodes as Nodes + return { + create: Object.values(after) + .filter((node) => !before[node.id]) + .map((node) => ({ node, parentId: node.parentId as AnyNodeId })), + update: Object.values(after) + .filter((node) => before[node.id] && node !== before[node.id]) + .map((node) => ({ id: node.id as AnyNodeId, data: node as Partial })), + delete: Object.keys(before).filter((id) => !after[id]) as AnyNodeId[], + } +} diff --git a/packages/core/src/contracts/reference-inventory.ts b/packages/core/src/contracts/reference-inventory.ts index 204b9908e1..e5752c0b75 100644 --- a/packages/core/src/contracts/reference-inventory.ts +++ b/packages/core/src/contracts/reference-inventory.ts @@ -81,7 +81,10 @@ const MATERIAL_FIELDS = [ 'edgeMaterial', 'exteriorMaterial', 'fasciaMaterial', + 'gableLeftMaterial', + 'gableRightMaterial', 'glassMaterial', + 'heelMaterial', 'interiorMaterial', 'panelMaterial', 'railingMaterial', @@ -660,7 +663,14 @@ export const EXISTING_REFERENCES: readonly ExistingReference[] = [ note: 'Capture provenance: stable across re-capture (R9).', }), ), - ...(['assembly.layers[].src', 'assembly.backing[].src'] as const).map((path) => + ...( + [ + 'assembly.layers[].src', + 'assembly.backing[].src', + 'wallTypes[].assembly.layers[].src', + 'wallTypes[].assembly.backing[].src', + ] as const + ).map((path) => row({ kind: '*', path, @@ -668,7 +678,14 @@ export const EXISTING_REFERENCES: readonly ExistingReference[] = [ note: 'Layer provenance (F2): a preset strips it so it never claims a source element.', }), ), - ...(['assembly.layers[].slot', 'assembly.backing[].slot'] as const).map((path) => + ...( + [ + 'assembly.layers[].slot', + 'assembly.backing[].slot', + 'wallTypes[].assembly.layers[].slot', + 'wallTypes[].assembly.backing[].slot', + ] as const + ).map((path) => row({ kind: '*', path, @@ -676,11 +693,19 @@ export const EXISTING_REFERENCES: readonly ExistingReference[] = [ note: "A key into the host's own `slots`; a missing key falls back to `layer:`, then the role default.", }), ), + ...(['assembly.presetId', 'wallTypes[].assembly.presetId'] as const).map((path) => + row({ + kind: '*', + path, + ...policy('asset', 'content', 'freeze', 'keep'), + note: 'The assembly preset a layer stack was made from.', + }), + ), row({ kind: '*', - path: 'assembly.presetId', + path: 'buildUp.presetId', ...policy('asset', 'content', 'freeze', 'keep'), - note: 'The assembly preset a layer stack was made from.', + note: 'The build-up preset a roof plane or ceiling took its layers from.', }), // ─── Typed provenance (D5) ──────────────────────────────────────── @@ -739,11 +764,23 @@ export const NON_REFERENCES: readonly { kind: string; path: string; reason: stri { kind: 'block', path: 'topology.vertices[].id', reason: 'Defines a topology key.' }, { kind: 'block', path: 'topology.edges[].id', reason: 'Defines a topology key.' }, { kind: 'block', path: 'topology.faces[].id', reason: 'Defines a topology key.' }, - ...(['assembly.layers[].id', 'assembly.backing[].id'] as const).map((path) => ({ + ...( + [ + 'assembly.layers[].id', + 'assembly.backing[].id', + 'wallTypes[].assembly.layers[].id', + 'wallTypes[].assembly.backing[].id', + ] as const + ).map((path) => ({ kind: '*', path, reason: 'Defines an assembly layer key (the `#layer:` address).', })), + { + kind: 'site', + path: 'wallTypes[].id', + reason: "Defines a project wall type's key (what a wall's `assembly.presetId` names).", + }, { kind: 'gutter', path: 'outlets[].id', @@ -961,6 +998,12 @@ export const METADATA_REFERENCES: readonly ExistingReference[] = [ targetKinds: ['slab'], note: 'The deck a balcony railing or deck belongs to.', }), + meta('porchOf', { + ...policy('node', 'internal', 'drop', 'strip'), + targetKinds: ['zone'], + dependents: ['metadata.porchPart', 'metadata.porchSeed'], + note: "The porch room a post or beam was made for by the structure kernel (lib/porch-framing-sync), which part of its framing and its shape as made; a porch gone takes its parts with it, one edited by hand stays the user's own.", + }), ] const described = (reason: string, paths: readonly string[]) => @@ -1000,6 +1043,7 @@ export const METADATA_NON_REFERENCES: readonly { path: string; reason: string }[ 'cabinetAdjacencyRevision', 'cabinetLayoutRevision', 'cabinetPresetNominalWidth', + 'decking', 'deferParentRebuild', 'drawingCoordinationLocked', 'floor', diff --git a/packages/core/src/hooks/spatial-grid/spatial-grid-sync.test.ts b/packages/core/src/hooks/spatial-grid/spatial-grid-sync.test.ts index d5a565748b..3fbe309945 100644 --- a/packages/core/src/hooks/spatial-grid/spatial-grid-sync.test.ts +++ b/packages/core/src/hooks/spatial-grid/spatial-grid-sync.test.ts @@ -4,7 +4,15 @@ import { encodeTerrainField } from '../../lib/terrain-codec' import { applyHeightPatch, createTerrainField, flattenPatch } from '../../lib/terrain-field' import { nodeRegistry, registerNode } from '../../registry' import type { AnyNodeDefinition } from '../../registry/types' -import { type AnyNode, type AnyNodeId, ItemNode, LevelNode, SlabNode, WallNode } from '../../schema' +import { + type AnyNode, + type AnyNodeId, + ItemNode, + LevelNode, + SlabNode, + WallNode, + ZoneNode, +} from '../../schema' import useLiveTerrain from '../../store/use-live-terrain' import useScene, { clearSceneHistory } from '../../store/use-scene' import { spatialGridManager } from './spatial-grid-manager' @@ -536,6 +544,26 @@ describe('spatial-grid sync dirty rules (terrain support)', () => { expect(marked).toEqual(['column_host']) }) + test('terrain changes rebuild a deck room’s plate without plugin tags', () => { + const room = ZoneNode.parse({ + id: 'zone_deck', + name: 'Deck', + polygon: SQUARE, + roomType: 'deck', + }) + const deck = SlabNode.parse({ + id: 'slab_deck', + parentId: 'level_0', + polygon: SQUARE, + zoneIds: [room.id], + plateRole: 'sunken', + }) + const level = makeLevel('level_0', 0, 2.5, [deck.id, room.id]) + const marked: string[] = [] + markTerrainSupportDependents(nodesFor(level, room, deck), (id) => marked.push(id)) + expect(marked).toContain(deck.id) + }) + test('markTerrainSupportDependents includes ground-hosted and terrain-fill structures', () => { const level = makeLevel('level_0', 0, 2.5, [ 'wall_ground', diff --git a/packages/core/src/hooks/spatial-grid/spatial-grid-sync.ts b/packages/core/src/hooks/spatial-grid/spatial-grid-sync.ts index 50db417f90..f64a55252e 100644 --- a/packages/core/src/hooks/spatial-grid/spatial-grid-sync.ts +++ b/packages/core/src/hooks/spatial-grid/spatial-grid-sync.ts @@ -1,3 +1,4 @@ +import { isDeckSlab } from '../../lib/deck-framing' import { resolveLevelId } from '../../lib/node-ancestry' import { isFloorPlate } from '../../lib/plate-surface' import { subtractPolygonsFromPolygon } from '../../lib/polygon-union' @@ -524,6 +525,11 @@ export function markTerrainSupportDependents( for (const node of Object.values(nodes)) { if (node.type === 'slab') { + // A deck's posts run down to the ground under each, on whatever storey it stands. + if (isDeckSlab(node, (id) => nodes[id])) { + markDirty(node.id) + continue + } const level = nodes[resolveLevelId(node, nodes)] if ( node.plateRole === 'base' && diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 678a19007a..ca29d57680 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -132,6 +132,32 @@ export { resolveAssemblyStack, } from './lib/assembly-stack' export { loadAssetUrl, saveAsset } from './lib/asset-storage' +export { + BEAM_MATERIAL_LABELS, + BEAM_MATERIAL_LIBRARY_REFS, + BEAM_TOP_REFERENCE_LABELS, + BEAM_TOP_REFERENCES, + type BeamInput, + type BeamPlan, + type BeamTopReference, + beamBottomElevation, + beamCeilingPlane, + beamOutline, + beamPlan, + beamSizeLabel, + beamSizePreset, + beamSizePresetPatch, + beamsOverPoint, + beamTopElevation, + beamTopReferenceOf, + beamTopReferencePatch, + createBeam, + inchFractionLabel, + type LevelFloorAt, + levelFloorAt, + matchBeamSizePreset, + postStationsAlong, +} from './lib/beam' export { belowGradeFloorY, belowGradeFootprints, @@ -140,6 +166,26 @@ export { GROUND_PIT_PLATE_CLEARANCE, groundPitFloorY, } from './lib/below-grade-footprints' +export { + CEILING_BUILD_UP_PRESETS, + type CeilingBuildUpPreset, + ceilingBuildUpThickness, + ceilingCapLift, + DRYWALL_THICKNESSES, + FRAMING_SPACINGS, + LUMBER_DEPTH, + PANEL_THICKNESSES, + PLASTER_THICKNESS, + ROOF_BUILD_UP_PRESETS, + ROOFING_THICKNESS, + type RoofBuildUpPreset, + roofBuildUpDepths, + roofBuildUpOfDeck, + roofBuildUpPatch, + roofStructureDepth, + UNDERLAYMENT_THICKNESS, + WOOD_PLANK_THICKNESS, +} from './lib/build-up' export { footprintOutline, levelFootprintLoops, @@ -167,6 +213,55 @@ export { } from './lib/corner-snap' export { criticallyDamped } from './lib/critically-damped' export { isCutterName, resolveCutterHost } from './lib/cutter-host' +export { + DECK_BOARD_DIRECTIONS, + DECK_BOARD_GAPS, + DECK_BOARD_JOINT_GAP, + DECK_BOARD_MAX_LENGTH, + DECK_BOARD_SIZES, + DECK_BOARD_STOCK, + DEFAULT_DECK_BOARDS, + type DeckBoardAxes, + type DeckBoardDirection, + type DeckBoardJoists, + type DeckBoardRun, + type DeckBoardSettings, + type DeckBoardSize, + type DeckBoardStock, + deckBoardRun, + deckBoardSettings, + deckBoardThickness, + deckJoistSpacingLimit, + deckSlabBoards, + layoutDeckBoards, +} from './lib/deck-boards' +export { + DECK_BEAM_INSET, + DECK_BOARD_OVERHANG, + DECK_DROPPED_BEAM, + DECK_JOIST_SPANS, + DECK_MIN_POST_HEIGHT, + DECK_POST, + DECK_POST_END_INSET, + DECK_POST_SPACING, + type DeckAxes, + type DeckBeamKind, + type DeckBeamPiece, + type DeckFramingInput, + type DeckFramingPlan, + type DeckHanger, + type DeckJoistPiece, + type DeckJoistSpan, + type DeckLumber, + type DeckPiece, + type DeckPieceRole, + type DeckPostPiece, + type DeckWall, + deckAxes, + deckLedgerEdge, + isDeckSlab, + planDeckFraming, +} from './lib/deck-framing' export { deepestDrawnY, lowestGroundY } from './lib/deepest-drawn' export { clampDoorOperationState, @@ -250,6 +345,24 @@ export { foundationRegionOf, } from './lib/foundation-construction' export { FOUNDATION_STANDARD } from './lib/foundation-standard' +export { + createFramingPost, + DEFAULT_FRAMING_POST_SIZE, + FRAMING_POST_BASE_LABELS, + FRAMING_POST_MATERIAL_REF, + FRAMING_POST_MAX_HEIGHT, + FRAMING_POST_MIN_HEIGHT, + FRAMING_POST_SIZES, + type FramingPostInput, + type FramingPostSize, + type FramingPostTop, + framingPostBasePatch, + framingPostFields, + framingPostHeightLimit, + framingPostSize, + framingPostTopAt, + isFramingPost, +} from './lib/framing-post' export { type FoundationMember, genericFoundation } from './lib/generic-foundation' export { ceilingSeatY, @@ -322,6 +435,18 @@ export { hostedCutterHoles, withHostedCutterHoles, } from './lib/object-cuts' +export { + DEFAULT_OPENING_CASING_WIDTH, + OPENING_CASING_PROUD, + type OpeningCasingBoard, + type OpeningCasingFace, + type OpeningCasingHost, + openingCasingBoards, + openingCasingFaces, + openingCasingWidth, + openingHostFacing, + resolveOpeningCasingHost, +} from './lib/opening-casing' export { getOpeningFloorDatum, getOpeningWallCut, @@ -331,10 +456,21 @@ export { } from './lib/opening-floor-datum' export { isAutoFrameDepth, - OPENING_FRAME_LIP, resolveHostedOpeningFrameDepth, resolveOpeningFrameDepth, } from './lib/opening-frame-depth' +export { + DECK_FLOOR_DROP, + DECKING_THICKNESS, + isOutdoorRoom, + isOutdoorRoomType, + nextOutdoorRoomName, + OUTDOOR_ROOM_DEFAULTS, + OUTDOOR_ROOM_TYPES, + type OutdoorRoomDefaults, + type OutdoorRoomType, + PORCH_FLOOR_DROP, +} from './lib/outdoor-room' export { classifyPlateSideAt, clearPlateSurfaceCaches, @@ -389,6 +525,34 @@ export { subtractPolygonsFromPolygon, unionPolygons, } from './lib/polygon-union' +export { + DEFAULT_PORCH_FRAMING, + PORCH_POST_SETBACK, + PORCH_POST_SPACING, + type PorchBeamPlan, + type PorchFramingPlan, + type PorchFramingSettings, + type PorchPostPlan, + planPorchFraming, + porchFramingSettings, +} from './lib/porch-framing' +export { type PorchPartMetadata, porchPartOf } from './lib/porch-framing-sync' +export { + type EavePoint, + eaveContains, + FASCIA_DROP, + FASCIA_STOCK, + FASCIA_THICKNESS, + type FasciaStock, + fasciaStockFor, + LEVEL_CUT_RUN, + type RoofEaveInput, + type RoofEaveProfile, + roofEaveProfile, + roofSegmentEaveInput, + roofSegmentEaveProfile, + SOFFIT_THICKNESS, +} from './lib/roof-eave' export { compareRoofOverlapIdentity, getRoofPlanBounds, @@ -414,6 +578,7 @@ export { roomFloorElevationFromRelative, roundFloorElevation, } from './lib/room-floor-feasibility' +export { floorPlateRoom } from './lib/room-floor-plate' export type { OpenWallEnd } from './lib/room-graph' export { isAllocatedRoomName } from './lib/room-name' export { @@ -621,6 +786,7 @@ export { getLibraryMaterialIdFromRef, getLibraryMaterialsVersion, getMaterialPresetByRef, + getMaterialSwatch, getMaterialsForCategory, getSceneMaterialIdFromRef, isCommunityMaterialId, @@ -633,6 +799,7 @@ export { type MaterialRef, type MaterialSource, type MaterialSurface, + type MaterialSwatch, materialColorPaint, type ParsedMaterialRef, parseMaterialColor, @@ -836,12 +1003,15 @@ export { isSplineFence, sampleFenceSpline, } from './systems/fence/fence-spline' -export { planOwnedFloorOpenings } from './systems/owned-floor-openings' +export { authorStairOpeningPatches, planOwnedFloorOpenings } from './systems/owned-floor-openings' export { resolveRoofElevation, resolveRoofWallTopElevation } from './systems/roof/roof-elevation' export { RoofElevationSystem } from './systems/roof/roof-elevation-system' export { fitRoofFootprint, + outdoorRoomRoofOutline, type RoofFootprintTarget, + type RoofOutlineEdge, + resolveOutdoorRoomRoofFootprintOnLevel, resolveRoomRoofFootprint, resolveRoomRoofFootprintOnLevel, } from './systems/roof/roof-footprint' @@ -854,6 +1024,7 @@ export { type SlabElevationClamp, type WallSlabSupport, } from './systems/slab/slab-support' +export { stairBaseElevation } from './systems/stair/stair-base-elevation' export { measureStairHeadroom, resolveStairWalkingSurfaces, @@ -932,6 +1103,42 @@ export { planStairSizingEdit, type StairDiagnostic, } from './systems/stair/stair-sizing' +export { + autoStairStringerCount, + DEFAULT_STAIR_NOSING, + formatStairInches, + inferStairStructure, + type ResolvedStairConstruction, + type ResolvedStairStructure, + resolveStairStringerLayout, + resolveStairStructure, + STAIR_CODE, + STAIR_HOUSING_DEPTH, + STAIR_LANDING_JOIST, + STAIR_LANDING_JOIST_SPACING, + STAIR_LANDING_POST, + STAIR_RISER_THICKNESS, + STAIR_STEEL_STRINGER, + STAIR_STRINGER_STOCK, + STAIR_TREAD_STOCK, + type StairFrameBox, + type StairStringerBand, + type StairStringerCut, + type StairStringerFlight, + type StairStringerLayout, + type StairStringerSlice, + type StairStructureHost, + type StairStructureIssue, + stairIsExterior, + stairLandingFrame, + stairStringerCut, + stairStringerEdges, + stairStringerFlight, + stairStringerSlices, + stairStructureConstruction, + stairStructureConstructionOf, + stairStructureDiagnostics, +} from './systems/stair/stair-structure' export { planStairSweepEdit } from './systems/stair/stair-sweep-edit' export { resolveStairWalkingPaths, @@ -946,6 +1153,7 @@ export { type StairWinderPoint, } from './systems/stair/stair-winder' export { + assemblyLayerSlotKey, assemblyThickness, BRICK_AIR_SPACE, BRICK_VENEER, @@ -959,7 +1167,14 @@ export { GYPSUM_SHEATHING, getWallAssemblyPreset, getWallLayerPolylines, + isExteriorWallAssembly, isLegacyWallAssembly, + isWallCladdingProduct, + LGS_STUD_350, + LGS_STUD_550, + LGS_STUD_800, + parseWallTypes, + projectWallTypes, type ResolvedWallAssembly, resolveWallAssembly, resolveWallExteriorSide, @@ -968,23 +1183,32 @@ export { STUCCO_3_COAT, STUD_2X4, STUD_2X6, + STUD_2X8, + STUD_SPACING_16, + STUD_SPACING_24, WALL_ASSEMBLY_PRESETS, WALL_FINISH_LIBRARY_REF, + WALL_TYPE_CORES, type WallAssemblyLayer, type WallAssemblyLayerRole, type WallAssemblyPreset, type WallLayerMiterData, type WallLayerPolyline, + type WallTypeCore, WSP_SHEATHING, wallAssemblyExposedStructure, wallAssemblyExteriorFinish, + wallAssemblyFaceFinish, wallAssemblyFinishRef, wallAssemblyFraming, wallAssemblyFromLegacy, wallAssemblyPatch, wallAssemblyToLegacy, wallAssemblyUnverifiedNote, + wallCladdingProducts, wallLayerBoundaryOffsets, + wallTypeAssembly, + wallTypeCoreOf, } from './systems/wall/wall-assembly' export { constrainWallCurveOffsetToAvoidIntersections, @@ -1062,6 +1286,7 @@ export { getLinkedWallUpdates, getPerpendicularWallMoveAxis, getPlannedLinkedWallUpdates, + planAttachedWallUpdates, planWallMoveJunctions, type WallMoveAxis, type WallMoveBridgePlan, @@ -1087,6 +1312,7 @@ export { export { findOpenWallEnds, planJoinOpenWallEnd, + planSeparatorInsertion, planWallEndRejoins, planWallInsertion, planWallSplitAtPoint, diff --git a/packages/core/src/lib/beam.test.ts b/packages/core/src/lib/beam.test.ts new file mode 100644 index 0000000000..de3f0a9a15 --- /dev/null +++ b/packages/core/src/lib/beam.test.ts @@ -0,0 +1,271 @@ +import { describe, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + AnyNode as AnyNodeSchema, + BEAM_SIZE_PRESETS, + BeamNode, + BuildingNode, + LevelNode, + SiteNode, + SlabNode, +} from '../schema' +import { + beamBottomElevation, + beamCeilingPlane, + beamOutline, + beamSizeLabel, + beamSizePreset, + beamSizePresetPatch, + beamsOverPoint, + beamTopElevation, + beamTopReferenceOf, + beamTopReferencePatch, + createBeam, + inchFractionLabel, + levelFloorAt, + matchBeamSizePreset, + postStationsAlong, +} from './beam' + +const IN = 0.0254 +type Nodes = Record +const keyed = (nodes: AnyNode[]) => Object.fromEntries(nodes.map((n) => [n.id, n])) as Nodes + +/** Two storeys 2.7 m apart; the ground floor's slab tops out 0.05 m over its plane, 0.2 m thick. */ +function house(beams: BeamNode[], above: SlabNode[] = []) { + return keyed([ + SiteNode.parse({ id: 'site_a', children: ['building_a'] }), + BuildingNode.parse({ id: 'building_a', parentId: 'site_a', children: ['level_g', 'level_u'] }), + LevelNode.parse({ + id: 'level_g', + parentId: 'building_a', + level: 0, + height: 2.7, + children: ['slab_g', ...beams.map((b) => b.id)], + }), + LevelNode.parse({ + id: 'level_u', + parentId: 'building_a', + level: 1, + height: 2.7, + children: above.map((s) => s.id), + }), + SlabNode.parse({ + id: 'slab_g', + parentId: 'level_g', + polygon: [ + [0, 0], + [10, 0], + [10, 8], + [0, 8], + ], + elevation: 0.05, + thickness: 0.2, + }), + ...beams, + ...above, + ]) +} + +const beam = (fields: Partial = {}) => + BeamNode.parse({ id: 'beam_a', parentId: 'level_g', start: [2, 4], end: [6, 4], ...fields }) + +describe('beam sizes', () => { + test('the stock sizes carry their dressed sections', () => { + const size = (id: string) => beamSizePreset(id)! + expect(size('4x8').width).toBeCloseTo(3.5 * IN) + expect(size('4x8').depth).toBeCloseTo(7.25 * IN) + expect(size('6x8').width).toBeCloseTo(5.5 * IN) + expect(size('6x8').depth).toBeCloseTo(7.5 * IN) + expect(size('6x12').depth).toBeCloseTo(11.5 * IN) + // a built-up beam is its plies side by side + expect(size('(3)2x10')).toMatchObject({ size: '2x10', plies: 3, label: '(3) 2x10' }) + expect(size('(3)2x10').width).toBeCloseTo(4.5 * IN) + expect(size('(2)lvl-1-3/4x11-7/8').width).toBeCloseTo(3.5 * IN) + expect(size('W8x10').material).toBe('steel') + // a label finds its size as well as an id + expect(beamSizePreset('(2) 2x10')?.id).toBe('(2)2x10') + expect(new Set(BEAM_SIZE_PRESETS.map((preset) => preset.id)).size).toBe( + BEAM_SIZE_PRESETS.length, + ) + }) + + test('a beam reads as a framing plan prints its size', () => { + expect(beamSizeLabel(createBeam({ start: [0, 0], end: [3, 0] }))).toBe('6x8') + expect(beamSizeLabel(createBeam({ start: [0, 0], end: [3, 0], preset: '(2)2x10' }))).toBe( + '(2) 2x10', + ) + expect( + beamSizeLabel( + createBeam({ start: [0, 0], end: [3, 0], preset: '6x8', material: 'pressure-treated' }), + ), + ).toBe('6x8 PT') + expect( + beamSizeLabel(createBeam({ start: [0, 0], end: [3, 0], preset: 'lvl-1-3/4x11-7/8' })), + ).toBe('1-3/4x11-7/8 LVL') + expect(beamSizeLabel(createBeam({ start: [0, 0], end: [3, 0], preset: 'W8x10' }))).toBe('W8x10') + // a section that is no stock size prints its actual inches + expect( + beamSizeLabel(createBeam({ start: [0, 0], end: [3, 0], width: 3.5 * IN, depth: 9 * IN })), + ).toBe('3-1/2x9') + // a schema default is the 6x8 it is sized as, though it names no size + expect(beamSizeLabel(BeamNode.parse({ start: [0, 0], end: [3, 0] }))).toBe('6x8') + }) + + test('inches print in sixteenths, reduced', () => { + expect(inchFractionLabel(3.5 * IN)).toBe('3-1/2') + expect(inchFractionLabel(11.875 * IN)).toBe('11-7/8') + expect(inchFractionLabel(0.75 * IN)).toBe('3/4') + expect(inchFractionLabel(9 * IN)).toBe('9') + }) + + test('a size matches its preset, and switching size keeps a treated beam treated', () => { + const treated = createBeam({ + start: [0, 0], + end: [3, 0], + preset: '(2)2x10', + material: 'pressure-treated', + }) + expect(matchBeamSizePreset(treated)?.id).toBe('(2)2x10') + expect(beamSizePresetPatch(treated, '6x10')).toMatchObject({ + size: '6x10', + plies: 1, + material: 'pressure-treated', + }) + expect(beamSizePresetPatch(treated, 'glulam-5-1/8x12').material).toBe('glulam') + expect(matchBeamSizePreset({ ...treated, width: 2 * IN })).toBeNull() + }) +}) + +describe('createBeam', () => { + test('builds a beam on its level from a centreline and a size', () => { + const made = createBeam({ + start: [1, 2], + end: [5, 2], + preset: '(2) 2x12', + topElevation: 2.4, + levelId: 'level_g', + supportSlabId: 'slab_porch', + }) + expect(made.type).toBe('beam') + expect(made.id).toStartWith('beam_') + expect(made).toMatchObject({ + parentId: 'level_g', + start: [1, 2], + end: [5, 2], + size: '2x12', + plies: 2, + material: 'sawn', + placement: 'dropped', + topElevation: 2.4, + supportSlabId: 'slab_porch', + }) + expect(made.depth).toBeCloseTo(11.25 * IN) + // it is a node the scene's union accepts + expect(AnyNodeSchema.parse(made).type).toBe('beam') + }) + + test('a custom section names no size; an unknown size falls back to the 6x8', () => { + const custom = createBeam({ start: [0, 0], end: [2, 0], width: 0.1, depth: 0.3, plies: 2 }) + expect(custom.size).toBeUndefined() + expect(custom).toMatchObject({ width: 0.1, depth: 0.3, plies: 2 }) + expect(createBeam({ start: [0, 0], end: [2, 0], preset: 'nope' }).size).toBe('6x8') + }) + + test('its plan outline is its width either side of the centreline', () => { + const outline = beamOutline(createBeam({ start: [0, 0], end: [4, 0], preset: '6x8' })) + const half = 2.75 * IN + expect(outline.map(([x, z]) => [x, Number(z.toFixed(6))])).toEqual([ + [0, Number(half.toFixed(6))], + [4, Number(half.toFixed(6))], + [4, Number((-half).toFixed(6))], + [0, Number((-half).toFixed(6))], + ]) + }) +}) + +describe('beam elevation', () => { + test('a dropped beam hangs under the ceiling plane, a flush one sits in the ceiling framing', () => { + const dropped = beam() + const nodes = house([dropped]) + expect(beamCeilingPlane(nodes, dropped)).toBeCloseTo(2.7) + expect(beamTopElevation(nodes, dropped)).toBeCloseTo(2.7) + expect(beamBottomElevation(nodes, dropped)).toBeCloseTo(2.7 - 7.5 * IN) + const flush = beam({ placement: 'flush' }) + expect(beamBottomElevation(house([flush]), flush)).toBeCloseTo(2.7) + }) + + test('a stored top stands, and a slab of the level above lowers the plane over it', () => { + const set = beam({ topElevation: 2.2 }) + expect(beamTopElevation(house([set]), set)).toBe(2.2) + const covered = beam() + const above = SlabNode.parse({ + id: 'slab_u', + parentId: 'level_u', + polygon: [ + [0, 0], + [10, 0], + [10, 8], + [0, 8], + ], + elevation: 0.05, + thickness: 0.3, + }) + // the slab's body reaches 0.25 m under the upper storey's plane + expect(beamTopElevation(house([covered], [above]), covered)).toBeCloseTo(2.45) + }) + + test('the top references set it from the ceiling plane or the floor', () => { + const subject = beam() + const nodes = house([subject]) + expect(levelFloorAt(nodes, 'level_g', [5, 4])).toEqual({ + top: 0.05, + underside: 0.05 - 0.2, + slabId: 'slab_g', + }) + expect(levelFloorAt(nodes, 'level_g', [20, 4]).slabId).toBeNull() + expect(beamTopReferenceOf(nodes, subject)).toBe('ceiling-dropped') + const flushFloor = { ...subject, ...beamTopReferencePatch(nodes, subject, 'floor-flush') } + expect(flushFloor).toMatchObject({ topElevation: 0.05, placement: 'flush' }) + expect(beamTopReferenceOf(nodes, flushFloor)).toBe('floor-flush') + const underFloor = { ...subject, ...beamTopReferencePatch(nodes, subject, 'floor-under') } + expect(underFloor.topElevation).toBeCloseTo(-0.15) + expect(beamTopReferenceOf(nodes, underFloor)).toBe('floor-under') + expect(beamTopReferenceOf(nodes, { ...subject, topElevation: 1.9 })).toBeNull() + expect(beamTopReferencePatch(nodes, flushFloor, 'ceiling-flush')).toEqual({ + topElevation: undefined, + placement: 'flush', + }) + }) +}) + +describe('posts under beams', () => { + test('finds the beams over a point, the lowest first', () => { + const high = beam({ id: 'beam_high' as BeamNode['id'] }) + const low = beam({ id: 'beam_low' as BeamNode['id'], topElevation: 2.2 }) + const nodes = house([high, low]) + expect(beamsOverPoint(nodes, 'level_g', [4, 4]).map((b) => b.id)).toEqual([ + 'beam_low', + 'beam_high', + ]) + // at an end, inside the width + expect(beamsOverPoint(nodes, 'level_g', [6, 4 + 2 * IN])).toHaveLength(2) + // past the end, beside it + expect(beamsOverPoint(nodes, 'level_g', [6.2, 4])).toHaveLength(0) + expect(beamsOverPoint(nodes, 'level_g', [4, 4.2])).toHaveLength(0) + }) + + test('posts stand at both ends and evenly between, no further apart than asked', () => { + expect(postStationsAlong([0, 0], [6, 0], 2.4)).toEqual([ + [0, 0], + [2, 0], + [4, 0], + [6, 0], + ]) + expect(postStationsAlong([0, 0], [2, 0], 2.4)).toEqual([ + [0, 0], + [2, 0], + ]) + }) +}) diff --git a/packages/core/src/lib/beam.ts b/packages/core/src/lib/beam.ts new file mode 100644 index 0000000000..01017a4c1c --- /dev/null +++ b/packages/core/src/lib/beam.ts @@ -0,0 +1,408 @@ +import type { AnyNode, AnyNodeId, LevelNode, SlabNode } from '../schema' +import { + BEAM_SIZE_PRESETS, + type BeamMaterial, + BeamNode, + type BeamPlacement, + type BeamSizePreset, + type BeamSizePresetId, + DEFAULT_BEAM_SIZE_PRESET_ID, +} from '../schema/nodes/beam' +import { DEFAULT_LEVEL_HEIGHT } from '../services/level-height' +import { getWallPlaneTop } from '../services/storey' +import { pointInPolygon, pointOnPolygonBoundary } from '../systems/slab/slab-support' +import { isSiteFlatwork } from './site-flatwork' + +type Nodes = Record +type P = [number, number] + +const INCH = 0.0254 +/** Two sections within this of each other are one size (a 32nd of an inch). */ +const SIZE_TOLERANCE = INCH / 32 + +/** + * The stock size with this id or label (`BEAM_SIZE_PRESETS`): '(2)2x10' and '(2) 2x10' are both + * the two-ply 2x10. + */ +export function beamSizePreset(idOrLabel: string): BeamSizePreset | undefined { + return BEAM_SIZE_PRESETS.find((preset) => preset.id === idOrLabel || preset.label === idOrLabel) +} + +/** Whether a beam of `material` can be a preset of `presetMaterial`: sawn stock comes treated too. */ +function materialFits(material: BeamMaterial, presetMaterial: BeamMaterial): boolean { + if (presetMaterial === 'sawn') return material === 'sawn' || material === 'pressure-treated' + return material === presetMaterial +} + +/** + * The stock size a beam is, if it is one: as many plies of the same nominal size (when it names + * one), the same section, and a material that size comes in. + */ +export function matchBeamSizePreset( + beam: Pick & { size?: string }, +): BeamSizePreset | null { + for (const preset of BEAM_SIZE_PRESETS) { + if (preset.plies !== beam.plies) continue + if (beam.size !== undefined && beam.size !== preset.size) continue + if (!materialFits(beam.material, preset.material)) continue + if (Math.abs(preset.width - beam.width) > SIZE_TOLERANCE) continue + if (Math.abs(preset.depth - beam.depth) > SIZE_TOLERANCE) continue + return preset + } + return null +} + +/** + * A length in inches and sixteenths, as a framing size prints it: 3.5 in reads "3-1/2", 0.75 in + * "3/4", 9 in "9". + */ +export function inchFractionLabel(metres: number, denominator = 16): string { + const total = Math.round((Math.abs(metres) / INCH) * denominator) + const whole = Math.floor(total / denominator) + let numerator = total % denominator + let over = denominator + while (numerator > 0 && numerator % 2 === 0) { + numerator /= 2 + over /= 2 + } + if (numerator === 0) return `${whole}` + return whole > 0 ? `${whole}-${numerator}/${over}` : `${numerator}/${over}` +} + +/** What a plan adds after the size to say what a beam is made of; a W shape is steel by its name. */ +const MATERIAL_SUFFIX: Record = { + sawn: '', + 'pressure-treated': ' PT', + lvl: ' LVL', + glulam: ' GLB', + steel: '', +} + +/** What each material is called in a list or a panel. */ +export const BEAM_MATERIAL_LABELS: Record = { + sawn: 'Sawn lumber', + 'pressure-treated': 'Pressure-treated', + lvl: 'LVL', + glulam: 'Glulam', + steel: 'Steel', +} + +/** + * How each material looks, from the material library: fir for sawn lumber, a weathered grey-brown + * for treated, the pale veneer of an LVL, the warm laminations of a glulam, steel. + */ +export const BEAM_MATERIAL_LIBRARY_REFS: Record = { + sawn: 'library:wood-woodfine2', + 'pressure-treated': 'library:wood-woodplank19', + lvl: 'library:wood-woodfine22', + glulam: 'library:wood-woodfine13', + steel: 'library:metal-steel', +} + +/** + * A beam's size as a framing plan prints it: "6x8", "(2) 2x10", "6x8 PT", "1-3/4x11-7/8 LVL", + * "W8x10"; a section that is no stock size by its actual inches ("3-1/2x9-1/4"). + */ +export function beamSizeLabel( + beam: Pick & { size?: string }, +): string { + const suffix = MATERIAL_SUFFIX[beam.material] + const size = beam.size ?? matchBeamSizePreset(beam)?.size + if (size) return `${beam.plies > 1 ? `(${beam.plies}) ` : ''}${size}${suffix}` + return `${inchFractionLabel(beam.width)}x${inchFractionLabel(beam.depth)}${suffix}` +} + +/** + * The fields that make a beam a stock size. Sawn sizes keep a treated beam treated; any other + * size brings its own material. + */ +export function beamSizePresetPatch( + beam: Pick, + presetId: string, +): Partial { + const preset = beamSizePreset(presetId) + if (!preset) return {} + return { + size: preset.size, + plies: preset.plies, + width: preset.width, + depth: preset.depth, + material: materialFits(beam.material, preset.material) ? beam.material : preset.material, + } +} + +/** What `createBeam` builds a beam from. */ +export type BeamInput = { + /** The centreline, level-local plan points `[x, z]`. */ + start: readonly [number, number] + end: readonly [number, number] + /** + * A stock size by id or label (`BEAM_SIZE_PRESETS`), a 6x8 by default (an unknown one too). + * Ignored when `width` and `depth` are given. + */ + preset?: BeamSizePresetId | (string & {}) + /** A custom section, metres (every ply together across), in place of a stock size. */ + width?: number + depth?: number + /** How many plies a custom section is nailed up from (a stock size brings its own). */ + plies?: number + /** What it is made of; else what the stock size is (sawn lumber for a custom section). */ + material?: BeamMaterial + placement?: BeamPlacement + /** Its top, level-local metres; absent = the level's ceiling plane over it. */ + topElevation?: number + /** The level it goes on: its `parentId`. */ + levelId?: string + /** The slab it belongs to, if any (a porch's or a deck's). */ + supportSlabId?: string + name?: string + metadata?: Record +} + +/** + * A beam node from a centreline and a size, ready for `createNode` on its level: what the beam + * tool draws, and what code that frames a porch or a deck makes. + */ +export function createBeam(input: BeamInput): BeamNode { + const custom = input.width !== undefined && input.depth !== undefined + const preset = custom + ? undefined + : (beamSizePreset(input.preset ?? DEFAULT_BEAM_SIZE_PRESET_ID) ?? + beamSizePreset(DEFAULT_BEAM_SIZE_PRESET_ID)) + return BeamNode.parse({ + start: [input.start[0], input.start[1]], + end: [input.end[0], input.end[1]], + width: custom ? input.width : preset?.width, + depth: custom ? input.depth : preset?.depth, + size: preset?.size, + plies: custom ? (input.plies ?? 1) : preset?.plies, + material: input.material ?? preset?.material ?? 'sawn', + placement: input.placement ?? 'dropped', + ...(input.topElevation !== undefined ? { topElevation: input.topElevation } : {}), + ...(input.levelId ? { parentId: input.levelId } : {}), + ...(input.supportSlabId ? { supportSlabId: input.supportSlabId } : {}), + ...(input.name ? { name: input.name } : {}), + ...(input.metadata ? { metadata: input.metadata } : {}), + }) +} + +/** A beam's plan, level-local: its centreline, run, the way it runs and across it. */ +export type BeamPlan = { + start: P + end: P + length: number + /** Unit vector start → end. */ + direction: P + /** Unit vector to the left of the run (the wall convention's +normal). */ + normal: P + width: number +} + +export function beamPlan(beam: Pick): BeamPlan { + const dx = beam.end[0] - beam.start[0] + const dz = beam.end[1] - beam.start[1] + const length = Math.hypot(dx, dz) + const direction: P = length > 1e-9 ? [dx / length, dz / length] : [1, 0] + return { + start: [beam.start[0], beam.start[1]], + end: [beam.end[0], beam.end[1]], + length, + direction, + normal: [-direction[1], direction[0]], + width: beam.width, + } +} + +/** The beam's outline in plan, level-local: four corners, start's left first. */ +export function beamOutline(beam: Pick): P[] { + const { start, end, normal, width } = beamPlan(beam) + const [nx, nz] = [normal[0] * (width / 2), normal[1] * (width / 2)] + return [ + [start[0] + nx, start[1] + nz], + [end[0] + nx, end[1] + nz], + [end[0] - nx, end[1] - nz], + [start[0] - nx, start[1] - nz], + ] +} + +/** + * The ceiling plane over a beam, level-local: the top of the level's walls there, the storey's + * height or the underside of a slab of the level above that covers the beam (`getWallPlaneTop` + * over the beam's width, as for a wall). + */ +export function beamCeilingPlane( + nodes: Nodes, + beam: Pick, +): number { + if (!beam.parentId) return DEFAULT_LEVEL_HEIGHT + return getWallPlaneTop( + { start: beam.start, end: beam.end, thickness: beam.width }, + beam.parentId, + nodes, + ) +} + +/** + * Where a beam's top is, level-local. A stored `topElevation` stands; without one the beam + * follows the ceiling plane over it: a dropped beam hangs under it, the joists bearing on its + * top, and a flush one sits in the ceiling framing with its underside on it. + */ +export function beamTopElevation( + nodes: Nodes, + beam: Pick< + BeamNode, + 'start' | 'end' | 'width' | 'depth' | 'parentId' | 'placement' | 'topElevation' + >, +): number { + if (beam.topElevation !== undefined) return beam.topElevation + const plane = beamCeilingPlane(nodes, beam) + return beam.placement === 'flush' ? plane + beam.depth : plane +} + +/** Where a beam's underside is, level-local: what a post under it stands up to. */ +export function beamBottomElevation( + nodes: Nodes, + beam: Pick< + BeamNode, + 'start' | 'end' | 'width' | 'depth' | 'parentId' | 'placement' | 'topElevation' + >, +): number { + return beamTopElevation(nodes, beam) - beam.depth +} + +/** The floor at a plan point of a level, level-local: the highest floor slab there, its top and underside. */ +export type LevelFloorAt = { top: number; underside: number; slabId: string | null } + +function slabHolds(slab: SlabNode, [x, z]: P): boolean { + if (!(pointInPolygon(x, z, slab.polygon) || pointOnPolygonBoundary(x, z, slab.polygon))) + return false + for (const hole of slab.holes ?? []) { + if (hole.length >= 3 && pointInPolygon(x, z, hole)) return false + } + return true +} + +/** + * The floor a level stands on at a plan point: the highest of its floor slabs there (not a pit, + * not the site's paving), its top and the underside of its body; the level's own plane, 0, where + * none is. + */ +export function levelFloorAt( + nodes: Nodes, + levelId: string, + point: readonly [number, number], +): LevelFloorAt { + const level = nodes[levelId as LevelNode['id']] + let floor: LevelFloorAt = { top: 0, underside: 0, slabId: null } + if (level?.type !== 'level') return floor + let best: SlabNode | null = null + for (const childId of level.children) { + const child = nodes[childId as AnyNodeId] + if (child?.type !== 'slab' || child.visible === false) continue + if (child.recessed === true || isSiteFlatwork(child) || child.polygon.length < 3) continue + if (!slabHolds(child, [point[0], point[1]])) continue + if (!best || child.elevation > best.elevation) best = child + } + if (best) + floor = { top: best.elevation, underside: best.elevation - best.thickness, slabId: best.id } + return floor +} + +/** + * Where a beam's top is set from, as the panel lists them: under the ceiling plane (a dropped + * beam, the default) or flush in the ceiling framing, both following the plane; flush with the + * floor (its top the floor's) or under the floor's framing (a girder in a crawl space, a deck's + * beam under its joists), both measured at the beam's middle. + */ +export type BeamTopReference = 'ceiling-dropped' | 'ceiling-flush' | 'floor-flush' | 'floor-under' + +export const BEAM_TOP_REFERENCES: readonly BeamTopReference[] = [ + 'ceiling-dropped', + 'ceiling-flush', + 'floor-flush', + 'floor-under', +] + +export const BEAM_TOP_REFERENCE_LABELS: Record = { + 'ceiling-dropped': 'Under ceiling plane', + 'ceiling-flush': 'Flush in ceiling', + 'floor-flush': 'Flush with floor', + 'floor-under': 'Under floor', +} + +function beamFloor(nodes: Nodes, beam: Pick): LevelFloorAt { + if (!beam.parentId) return { top: 0, underside: 0, slabId: null } + const middle: P = [(beam.start[0] + beam.end[0]) / 2, (beam.start[1] + beam.end[1]) / 2] + return levelFloorAt(nodes, beam.parentId, middle) +} + +/** The fields that put a beam's top at `reference`. */ +export function beamTopReferencePatch( + nodes: Nodes, + beam: Pick, + reference: BeamTopReference, +): Pick { + if (reference === 'ceiling-dropped') return { topElevation: undefined, placement: 'dropped' } + if (reference === 'ceiling-flush') return { topElevation: undefined, placement: 'flush' } + const floor = beamFloor(nodes, beam) + return reference === 'floor-flush' + ? { topElevation: floor.top, placement: 'flush' } + : { topElevation: floor.underside, placement: 'dropped' } +} + +/** Which of the references a beam's top is set from now, or null for a top typed in by hand. */ +export function beamTopReferenceOf( + nodes: Nodes, + beam: Pick, +): BeamTopReference | null { + if (beam.topElevation === undefined) + return beam.placement === 'flush' ? 'ceiling-flush' : 'ceiling-dropped' + const floor = beamFloor(nodes, beam) + if (beam.placement === 'flush' && Math.abs(beam.topElevation - floor.top) < 1e-6) + return 'floor-flush' + if (beam.placement === 'dropped' && Math.abs(beam.topElevation - floor.underside) < 1e-6) + return 'floor-under' + return null +} + +/** + * The beams of a level over a plan point, the lowest underside first: those whose outline, + * grown by `margin` all round, holds the point. What a post set there stands up to. + */ +export function beamsOverPoint( + nodes: Nodes, + levelId: string, + point: readonly [number, number], + margin = 0.01, +): BeamNode[] { + const found: { beam: BeamNode; bottom: number }[] = [] + for (const node of Object.values(nodes)) { + if (node?.type !== 'beam' || node.parentId !== levelId || node.visible === false) continue + const { start, length, direction, normal, width } = beamPlan(node) + const rx = point[0] - start[0] + const rz = point[1] - start[1] + const along = rx * direction[0] + rz * direction[1] + const across = rx * normal[0] + rz * normal[1] + if (along < -margin || along > length + margin) continue + if (Math.abs(across) > width / 2 + margin) continue + found.push({ beam: node, bottom: beamBottomElevation(nodes, node) }) + } + return found.sort((a, b) => a.bottom - b.bottom).map(({ beam }) => beam) +} + +/** + * Where posts stand under a beam run: at both ends and evenly between, no two further apart than + * `maxSpacing`. A porch's open edge gets its posts this way. + */ +export function postStationsAlong( + start: readonly [number, number], + end: readonly [number, number], + maxSpacing: number, +): P[] { + const length = Math.hypot(end[0] - start[0], end[1] - start[1]) + const spans = maxSpacing > 0 ? Math.max(1, Math.ceil(length / maxSpacing - 1e-9)) : 1 + return Array.from({ length: spans + 1 }, (_, index) => { + const t = index / spans + return [start[0] + (end[0] - start[0]) * t, start[1] + (end[1] - start[1]) * t] as P + }) +} diff --git a/packages/core/src/lib/build-up.test.ts b/packages/core/src/lib/build-up.test.ts new file mode 100644 index 0000000000..e7f0784fbb --- /dev/null +++ b/packages/core/src/lib/build-up.test.ts @@ -0,0 +1,182 @@ +import { describe, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + BuildingNode, + CEILING_BUILD_UP_PRESETS, + CEILING_CLAMP_MARGIN, + CeilingBuildUp, + CeilingNode, + ceilingBuildUpThickness, + ceilingCapLift, + LevelNode, + ROOF_BUILD_UP_PRESETS, + RoofBuildUp, + RoofSegmentNode, + roofBuildUpDepths, + roofBuildUpPatch, + roofStructureDepth, + SlabNode, +} from '../index' + +const IN = 0.0254 + +const plane = (buildUp: Partial = {}): RoofBuildUp => ({ + roofing: { kind: 'architectural-shingle', thickness: 0.5 * IN }, + sheathing: { kind: 'osb', thickness: (7 / 16) * IN }, + structure: { system: 'rafters', size: '2x10', spacing: 16 * IN }, + ...buildUp, +}) + +describe('roof plane layers', () => { + test('a plane without layers keeps the deck and shingle it always drew', () => { + const old = RoofSegmentNode.parse({ id: 'rseg_old', type: 'roof-segment' }) + expect(old.buildUp).toBeUndefined() + expect([old.deckThickness, old.shingleThickness]).toEqual([0.1, 0.05]) + }) + + test('the deck is structure and sheathing, the covering roofing and underlayment', () => { + const { deck, covering } = roofBuildUpDepths( + plane({ underlayment: { kind: 'synthetic', thickness: 0.02 * IN } }), + ) + expect(deck / IN).toBeCloseTo(9.25 + 7 / 16, 9) + expect(covering / IN).toBeCloseTo(0.52, 9) + }) + + test('cavity insulation fills the rafters, rigid board and an interior finish add to the deck', () => { + const bare = roofBuildUpDepths(plane()).deck + expect(roofBuildUpDepths(plane({ insulation: { kind: 'batt', thickness: 6 * IN } })).deck).toBe( + bare, + ) + expect( + roofBuildUpDepths(plane({ insulation: { kind: 'batt', thickness: 10 * IN } })).deck / IN, + ).toBeCloseTo(10 + 7 / 16, 9) + expect( + roofBuildUpDepths( + plane({ + insulation: { kind: 'rigid', thickness: 2 * IN }, + finish: { kind: 'drywall', thickness: 0.5 * IN }, + }), + ).deck / IN, + ).toBeCloseTo(9.25 + 7 / 16 + 2.5, 9) + }) + + test('setting the layers writes the deck and shingle thickness the plane draws with', () => { + const buildUp = plane({ structure: { system: 'trusses', size: '2x6', spacing: 24 * IN } }) + const node = RoofSegmentNode.parse({ + id: 'rseg_layered', + type: 'roof-segment', + ...roofBuildUpPatch(buildUp), + }) + expect(node.buildUp).toEqual(buildUp) + // a 2x6 top chord on its 2x6 heel + expect(node.deckThickness / IN).toBeCloseTo(2 * 5.5 + 7 / 16, 9) + expect(node.shingleThickness / IN).toBeCloseTo(0.5, 9) + }) + + test('a truss stands its top chord on its heel: two chord depths, where a rafter is one', () => { + expect( + roofStructureDepth({ system: 'rafters', size: '2x8', spacing: 16 * IN }) / IN, + ).toBeCloseTo(7.25, 9) + expect( + roofStructureDepth({ system: 'trusses', size: '2x4', spacing: 24 * IN }) / IN, + ).toBeCloseTo(7, 9) + }) + + test('the default preset is 2x4 trusses on their heel under 7/16 in OSB', () => { + const [first] = ROOF_BUILD_UP_PRESETS + expect(RoofBuildUp.parse(first!.buildUp)).toEqual(first!.buildUp) + expect(roofBuildUpDepths(first!.buildUp).deck / IN).toBeCloseTo(7 + 7 / 16, 9) + for (const preset of ROOF_BUILD_UP_PRESETS) expect(preset.buildUp.presetId).toBe(preset.id) + }) +}) + +describe('ceiling layers', () => { + test('a ceiling without layers has no thickness', () => { + const old = CeilingNode.parse({ id: 'ceiling_old', polygon: [] }) + expect(old.buildUp).toBeUndefined() + }) + + test('the thickness rises from the underside: finish, framing or the fill over it, decking', () => { + expect( + ceilingBuildUpThickness({ + finish: { kind: 'drywall', thickness: 0.5 * IN }, + framing: { system: 'joists', size: '2x6', spacing: 16 * IN }, + }) / IN, + ).toBeCloseTo(6, 9) + expect( + ceilingBuildUpThickness({ + finish: { kind: 'drywall', thickness: 0.625 * IN }, + framing: { system: 'truss-chords', size: '2x4', spacing: 24 * IN }, + insulation: { kind: 'blown', thickness: 12 * IN }, + }) / IN, + ).toBeCloseTo(12.625, 9) + expect( + ceilingBuildUpThickness({ + framing: { system: 'joists', size: '2x8', spacing: 16 * IN }, + decking: { kind: 'plywood', thickness: 0.75 * IN }, + }) / IN, + ).toBeCloseTo(8, 9) + expect(ceilingBuildUpThickness({})).toBe(0) + }) + + test('every preset parses', () => { + for (const preset of CEILING_BUILD_UP_PRESETS) + expect(CeilingBuildUp.parse(preset.buildUp)).toEqual(preset.buildUp) + }) + + const square: [number, number][] = [ + [0, 0], + [4, 0], + [4, 4], + [0, 4], + ] + const joists: CeilingBuildUp = { + finish: { kind: 'drywall', thickness: 0.5 * IN }, + framing: { system: 'joists', size: '2x6', spacing: 16 * IN }, + } + const scene = (ceiling: Partial, floorAbove: boolean) => { + const nodes: AnyNode[] = [ + BuildingNode.parse({ id: 'building_a', children: ['level_0', 'level_1'] }), + LevelNode.parse({ id: 'level_0', level: 0, height: 2.5, parentId: 'building_a' }), + LevelNode.parse({ + id: 'level_1', + level: 1, + height: 2.5, + parentId: 'building_a', + children: floorAbove ? ['slab_above'] : [], + }), + // The floor above as its plate stands: on the walls below, its underside at their top. + SlabNode.parse({ id: 'slab_above', polygon: square, elevation: 0.05, thickness: 0.05 }), + ] + const node = CeilingNode.parse({ + id: 'ceiling_a', + parentId: 'level_0', + polygon: square, + ...ceiling, + }) + return { + node, + nodes: Object.fromEntries([...nodes, node].map((n) => [n.id, n])) as Record< + AnyNodeId, + AnyNode + >, + } + } + + test('the upper face stands on the layers under a roof, and short of the floor above', () => { + const open = scene({ height: 2.4, buildUp: joists }, false) + expect(ceilingCapLift(open.node, open.nodes)).toBeCloseTo(6 * IN, 9) + // the floor above stands on the walls at 2.5 m: that, less the margin, is as high as it goes + const under = scene({ height: 2.4, buildUp: joists }, true) + expect(ceilingCapLift(under.node, under.nodes)).toBeCloseTo(0.1 - CEILING_CLAMP_MARGIN, 9) + const bare = scene({ height: 2.4 }, true) + expect(ceilingCapLift(bare.node, bare.nodes)).toBe(0) + }) +}) + +// A 320 px inspector shows about 26 characters beside "Preset"; longer labels were cut with "…". +test('every layers preset label fits the Preset select uncut', () => { + for (const preset of [...ROOF_BUILD_UP_PRESETS, ...CEILING_BUILD_UP_PRESETS]) + expect(preset.label.length).toBeLessThanOrEqual(26) +}) diff --git a/packages/core/src/lib/build-up.ts b/packages/core/src/lib/build-up.ts new file mode 100644 index 0000000000..7cb5cf5a20 --- /dev/null +++ b/packages/core/src/lib/build-up.ts @@ -0,0 +1,258 @@ +import type { + CeilingBuildUp, + NominalLumber, + RoofBuildUp, + RoofingKind, + RoofStructure, + UnderlaymentKind, +} from '../schema/build-up' +import type { CeilingNode } from '../schema/nodes/ceiling' +import type { AnyNode, AnyNodeId } from '../schema/types' +import { resolveCeilingHeight } from '../services/level-height' +import { CEILING_CLAMP_MARGIN, getCoveringSlabUndersideAt } from '../services/storey' + +const inches = (value: number) => value * 0.0254 + +/** + * Actual depth of dressed lumber (2021 IRC R602.3 / ALSC PS 20): what a + * rafter, truss chord or ceiling joist of that size adds to its layer. + */ +export const LUMBER_DEPTH: Record = { + '2x4': inches(3.5), + '2x6': inches(5.5), + '2x8': inches(7.25), + '2x10': inches(9.25), + '2x12': inches(11.25), +} + +/** + * Typical installed thickness of each roofing, the envelope the plane draws as + * its covering: two courses of shingle at the laps, a tile's profile, a seam's + * height. + */ +export const ROOFING_THICKNESS: Record = { + 'asphalt-3-tab': inches(0.25), + 'architectural-shingle': inches(0.5), + 'standing-seam-metal': inches(1), + 'concrete-tile': inches(2), + 'clay-tile': inches(2.5), + 'wood-shake': inches(0.75), + slate: inches(0.5), +} + +export const UNDERLAYMENT_THICKNESS: Record = { + 'felt-15': inches(0.03), + 'felt-30': inches(0.05), + synthetic: inches(0.02), + 'ice-and-water': inches(0.04), +} + +/** Roof sheathing and attic decking panels, thinnest first. */ +export const PANEL_THICKNESSES: readonly number[] = [ + 7 / 16, + 15 / 32, + 1 / 2, + 19 / 32, + 5 / 8, + 3 / 4, +].map(inches) + +/** Framing spacings on centre: 12, 16, 19.2 and 24 in. */ +export const FRAMING_SPACINGS: readonly number[] = [12, 16, 19.2, 24].map(inches) + +export const DRYWALL_THICKNESSES: readonly number[] = [0.5, 0.625].map(inches) + +/** Three-coat plaster on lath. */ +export const PLASTER_THICKNESS = inches(0.875) +export const WOOD_PLANK_THICKNESS = inches(0.75) + +/** Batt and blown fill the framing cavity (and mound over it when deeper); rigid board adds its own. */ +function framedDepth( + framingDepth: number, + insulation: { kind: string; thickness: number } | undefined, +): number { + if (!insulation) return framingDepth + if (insulation.kind === 'rigid') return framingDepth + insulation.thickness + return Math.max(framingDepth, insulation.thickness) +} + +/** + * How deep a roof plane's structure stands over the plate plane its deck rises + * from: a rafter's depth, its underside on the plates; a truss two chord + * depths, its top chord on the bottom chord at the heel. The heel is plumb, a + * chord's depth times the slope's cosine square to it, so two depths are the + * most it takes: on a pitch θ the top chords sit d(1 − cos θ) under the + * sheathing, never through it. + */ +export function roofStructureDepth(structure: RoofStructure): number { + const depth = LUMBER_DEPTH[structure.size] + return structure.system === 'trusses' ? 2 * depth : depth +} + +/** + * The two thicknesses a roof plane draws with: `deck` (finish, structure, + * insulation and sheathing) and `covering` (roofing and underlayment). + */ +export function roofBuildUpDepths(buildUp: RoofBuildUp): { deck: number; covering: number } { + return { + deck: + (buildUp.finish?.thickness ?? 0) + + framedDepth(roofStructureDepth(buildUp.structure), buildUp.insulation) + + buildUp.sheathing.thickness, + covering: buildUp.roofing.thickness + (buildUp.underlayment?.thickness ?? 0), + } +} + +/** + * The patch that sets a roof plane's layers: the build-up and the deck and + * covering thicknesses it derives, together. A writer never sets one without + * the others. + */ +export function roofBuildUpPatch(buildUp: RoofBuildUp): { + buildUp: RoofBuildUp + deckThickness: number + shingleThickness: number +} { + const { deck, covering } = roofBuildUpDepths(buildUp) + return { buildUp, deckThickness: deck, shingleThickness: covering } +} + +/** + * The layers a plane without any is drawn as: the default preset over the framing its deck + * holds, rafters whose depth with the preset's sheathing makes it (a generated roof's 2x6 + * rafters), else the default preset itself: its trusses on their heel, or the one chord the + * schema's 0.100 m deck held before the heel counted. "Edit layers" writes them, the deck + * unchanged where it matched and deepened by the heel on that old deck; Bones frames such a + * plane by them, so its rafters fit the deck drawn until a roof choice writes the plane layers of + * its own. + */ +export function roofBuildUpOfDeck(deckThickness: number): RoofBuildUp { + const preset = ROOF_BUILD_UP_PRESETS[0]!.buildUp + const framing = deckThickness - preset.sheathing.thickness - (preset.finish?.thickness ?? 0) + if (Math.abs(roofStructureDepth(preset.structure) - framing) < 1e-3) return preset + const size = (Object.keys(LUMBER_DEPTH) as NominalLumber[]).find( + (lumber) => Math.abs(LUMBER_DEPTH[lumber] - framing) < 1e-3, + ) + if (!size || size === preset.structure.size) return preset + const { presetId: _preset, ...layers } = preset + return { ...layers, structure: { system: 'rafters', size, spacing: preset.structure.spacing } } +} + +/** A ceiling's thickness, up from its finished underside. */ +export function ceilingBuildUpThickness(buildUp: CeilingBuildUp): number { + return ( + (buildUp.finish?.thickness ?? 0) + + framedDepth(buildUp.framing ? LUMBER_DEPTH[buildUp.framing.size] : 0, buildUp.insulation) + + (buildUp.decking?.thickness ?? 0) + ) +} + +/** + * How far above its underside a ceiling's upper face stands: its build-up's + * thickness, stopped short of the floor of the level above (a slab covering + * any vertex or the centroid, as the height clamp samples it) so the two + * never share a plane. 0 without a build-up. + */ +export function ceilingCapLift( + ceiling: Pick, + nodes: Record, +): number { + const thickness = ceiling.buildUp ? ceilingBuildUpThickness(ceiling.buildUp) : 0 + if (!(thickness > 0) || typeof ceiling.parentId !== 'string') return Math.max(0, thickness) + const underside = resolveCeilingHeight(ceiling, nodes) + const polygon = ceiling.polygon + let lift = thickness + if (polygon.length > 0) { + const cx = polygon.reduce((sum, [x]) => sum + x, 0) / polygon.length + const cz = polygon.reduce((sum, [, z]) => sum + z, 0) / polygon.length + for (const [x, z] of [...polygon, [cx, cz] as [number, number]]) { + const above = getCoveringSlabUndersideAt(ceiling.parentId, nodes, x, z) + if (above !== null) lift = Math.min(lift, above - CEILING_CLAMP_MARGIN - underside) + } + } + return Math.max(0, lift) +} + +export type RoofBuildUpPreset = { id: string; label: string; buildUp: RoofBuildUp } +export type CeilingBuildUpPreset = { id: string; label: string; buildUp: CeilingBuildUp } + +const roofPreset = (id: string, label: string, buildUp: Omit) => ({ + id, + label, + buildUp: { presetId: id, ...buildUp }, +}) + +const ceilingPreset = (id: string, label: string, buildUp: Omit) => ({ + id, + label, + buildUp: { presetId: id, ...buildUp }, +}) + +const shingles = { + kind: 'architectural-shingle', + thickness: ROOFING_THICKNESS['architectural-shingle'], +} as const +const synthetic = { kind: 'synthetic', thickness: UNDERLAYMENT_THICKNESS.synthetic } as const +const osb = (thickness = inches(7 / 16)) => ({ kind: 'osb', thickness }) as const +const plywood = (thickness: number) => ({ kind: 'plywood', thickness }) as const +const drywall = (thickness = inches(0.5)) => ({ kind: 'drywall', thickness }) as const + +/** + * The first is the default: 2x4 trusses under 7/16 in OSB, a 7-7/16 in deck + * (the top chord on its heel). A roof plane without layers draws the schema's + * 0.100 m, one chord and its sheathing. Labels stay short enough + * for the inspector's Preset select to show uncut; the fields below it name + * every layer. + */ +export const ROOF_BUILD_UP_PRESETS: readonly RoofBuildUpPreset[] = [ + roofPreset('asphalt-trusses-24', 'Asphalt on trusses @ 24"', { + roofing: shingles, + underlayment: synthetic, + sheathing: osb(), + structure: { system: 'trusses', size: '2x4', spacing: inches(24) }, + }), + roofPreset('asphalt-2x10-16', 'Asphalt on 2x10 @ 16"', { + roofing: shingles, + underlayment: synthetic, + sheathing: osb(), + structure: { system: 'rafters', size: '2x10', spacing: inches(16) }, + }), + roofPreset('metal-trusses-24', 'Metal on trusses @ 24"', { + roofing: { kind: 'standing-seam-metal', thickness: ROOFING_THICKNESS['standing-seam-metal'] }, + underlayment: synthetic, + sheathing: osb(), + structure: { system: 'trusses', size: '2x4', spacing: inches(24) }, + }), + roofPreset('tile-2x8-16', 'Tile on 2x8 @ 16"', { + roofing: { kind: 'concrete-tile', thickness: ROOFING_THICKNESS['concrete-tile'] }, + underlayment: { kind: 'felt-30', thickness: UNDERLAYMENT_THICKNESS['felt-30'] }, + sheathing: plywood(inches(15 / 32)), + structure: { system: 'rafters', size: '2x8', spacing: inches(16) }, + }), + roofPreset('cathedral-2x12-16', 'Cathedral 2x12 @ 16"', { + roofing: shingles, + underlayment: { kind: 'ice-and-water', thickness: UNDERLAYMENT_THICKNESS['ice-and-water'] }, + sheathing: plywood(inches(19 / 32)), + structure: { system: 'rafters', size: '2x12', spacing: inches(16) }, + insulation: { kind: 'batt', thickness: LUMBER_DEPTH['2x12'] }, + finish: drywall(), + }), +] + +export const CEILING_BUILD_UP_PRESETS: readonly CeilingBuildUpPreset[] = [ + ceilingPreset('drywall-2x6-16', 'Drywall on 2x6 @ 16"', { + finish: drywall(), + framing: { system: 'joists', size: '2x6', spacing: inches(16) }, + }), + ceilingPreset('trusses-24-blown', 'Truss chords @ 24", blown', { + finish: drywall(inches(0.625)), + framing: { system: 'truss-chords', size: '2x4', spacing: inches(24) }, + insulation: { kind: 'blown', thickness: inches(12) }, + }), + ceilingPreset('storage-2x8-16', 'Attic storage 2x8 @ 16"', { + finish: drywall(), + framing: { system: 'joists', size: '2x8', spacing: inches(16) }, + insulation: { kind: 'batt', thickness: LUMBER_DEPTH['2x8'] }, + decking: plywood(inches(3 / 4)), + }), +] diff --git a/packages/core/src/lib/deck-boards.test.ts b/packages/core/src/lib/deck-boards.test.ts new file mode 100644 index 0000000000..98a5390c02 --- /dev/null +++ b/packages/core/src/lib/deck-boards.test.ts @@ -0,0 +1,248 @@ +import { describe, expect, test } from 'bun:test' +import { setZoneIntent } from '../commands/structure/set-zone-intent' +import { applyToScratch, structureChangeBatch } from '../commands/structure/shared' +import { enclosed } from '../commands/structure/structure.test' +import { type AnyNode, type SlabNode, WallNode, type ZoneNode } from '../schema' +import { railingWallDefaults } from '../schema/nodes/railing-wall' +import { + DECK_BOARD_JOINT_GAP, + DECK_BOARD_MAX_LENGTH, + DECK_BOARD_STOCK, + DEFAULT_DECK_BOARDS, + deckBoardSettings, + deckBoardThickness, + deckSlabBoards, + layoutDeckBoards, +} from './deck-boards' +import { area, difference, type MultiPolygon, type Polygon, union } from './polygon-boolean' +import { reconcileLevelStructure } from './structure-kernel' + +const IN = 0.0254 +const FT = 12 * IN +const LEVEL = 'level_test' + +/** Settle the level's structure as the live sync does after an edit. */ +function settle(before: Record, after: Record) { + let i = 0 + const derived = reconcileLevelStructure({ + levelId: LEVEL, + nodes: after, + previousNodes: before, + mintId: (kind) => { + let id: string + do id = `${kind}_derived${++i}` + while (after[id]) + return id + }, + }) + return applyToScratch(after, structureChangeBatch(derived.patches)) +} + +/** The kitchen (8 × 4) with a deck fenced off its z = 4 side by railings. */ +function withDeck() { + const { nodes } = enclosed() + let next: Record = nodes + const sides: Array<[[number, number], [number, number]]> = [ + [ + [2, 4], + [2, 6], + ], + [ + [2, 6], + [6, 6], + ], + [ + [6, 6], + [6, 4], + ], + ] + sides.forEach(([start, end], index) => { + const railing = WallNode.parse({ + ...railingWallDefaults(), + id: `wall_railing${index}`, + parentId: LEVEL, + start, + end, + }) + next = { ...next, [railing.id]: railing } + }) + return settle(nodes, next) +} + +describe("a deck room's boards", () => { + const deckOf = (nodes: Record) => + Object.values(nodes).find( + (node): node is ZoneNode => node.type === 'zone' && node.roomType === 'deck', + )! + const plateOf = (nodes: Record, zone: ZoneNode) => + Object.values(nodes).find( + (node): node is SlabNode => + node.type === 'slab' && node.plateRole !== 'base' && !!node.zoneIds?.includes(zone.id), + )! + const edit = (nodes: Record, zone: ZoneNode, decking: unknown) => + settle( + nodes, + applyToScratch( + nodes, + structureChangeBatch( + setZoneIntent(nodes, { + zoneId: zone.id, + patch: { decking } as Parameters[1]['patch'], + }).changes, + ), + ), + ) + + test('are kept on the room, cleared by null; its floor plate declares their thickness, the frame under them', () => { + const nodes = withDeck() + const deck = deckOf(nodes) + expect(deck.decking).toBeUndefined() + expect(plateOf(nodes, deck).metadata?.decking).toBeCloseTo(IN, 9) + const set = edit(nodes, deck, { boardSize: '2x6', direction: 'diagonal' }) + expect(deckOf(set).decking).toEqual({ boardSize: '2x6', direction: 'diagonal' }) + expect(plateOf(set, deck).metadata?.decking).toBeCloseTo(1.5 * IN, 9) + const gap = edit(set, deck, { gap: IN / 8, direction: null }) + expect(deckOf(gap).decking).toEqual({ boardSize: '2x6', gap: IN / 8 }) + const cleared = edit(gap, deck, null) + expect(deckOf(cleared).decking).toBeUndefined() + expect(plateOf(cleared, deck).metadata?.decking).toBeCloseTo(IN, 9) + }) +}) +const AXES = { origin: [0, 0] as const, u: [1, 0] as const, v: [0, 1] as const } +const rect = (w: number, d: number): MultiPolygon => [ + { + outer: [ + [0, 0], + [w, 0], + [w, d], + [0, d], + ], + holes: [], + }, +] + +/** A board's extent along and across plan axis `along`. */ +function extent(board: Polygon, along: readonly [number, number]) { + const across: [number, number] = [-along[1], along[0]] + const a = board.outer.map(([x, z]) => x * along[0] + z * along[1]) + const c = board.outer.map(([x, z]) => x * across[0] + z * across[1]) + return { length: Math.max(...a) - Math.min(...a), width: Math.max(...c) - Math.min(...c), a, c } +} + +test('a deck with no settings gets 5/4x6 boards, 1 in by 5 1/2 in, a quarter inch apart, along the house', () => { + expect(deckBoardSettings(undefined)).toEqual(DEFAULT_DECK_BOARDS) + expect(DEFAULT_DECK_BOARDS).toEqual({ boardSize: '5/4x6', gap: IN / 4, direction: 'parallel' }) + expect(deckBoardThickness(DEFAULT_DECK_BOARDS)).toBeCloseTo(IN, 9) + expect(DECK_BOARD_STOCK['5/4x6'].width).toBeCloseTo(5.5 * IN, 9) + expect(DECK_BOARD_STOCK.composite.thickness).toBeCloseTo((15 / 16) * IN, 9) + expect( + deckBoardSettings({ decking: { boardSize: '2x4', gap: IN / 8, direction: 'diagonal' } }), + ).toEqual({ boardSize: '2x4', gap: IN / 8, direction: 'diagonal' }) + // The room's boards win even when the plugin tag declares a different thickness. + const zone = { roomType: 'deck' as const, decking: { boardSize: '2x6' as const } } + const slab = { zoneIds: ['zone_a'], metadata: { floor: 'deck', decking: IN } } + expect(deckSlabBoards(slab, () => zone).boardSize).toBe('2x6') + expect(deckSlabBoards(slab, () => ({ roomType: 'deck' }))).toEqual(DEFAULT_DECK_BOARDS) + expect(deckSlabBoards(slab, () => null)).toEqual(DEFAULT_DECK_BOARDS) +}) + +describe('boards along the house over a 12 × 10 ft deck', () => { + const outline = rect(12 * FT, 10 * FT) + const boards = layoutDeckBoards(outline, AXES, DEFAULT_DECK_BOARDS) + const width = 5.5 * IN + + test('rows of full boards from the outer edge in, a quarter inch apart, the last ripped against the house', () => { + const rows = boards + .map((board) => extent(board, [1, 0])) + .sort((a, b) => Math.max(...b.c) - Math.max(...a.c)) + expect(rows).toHaveLength(Math.ceil((10 * FT + IN / 4) / (width + IN / 4))) + expect(Math.max(...rows[0]!.c)).toBeCloseTo(10 * FT, 4) + for (const row of rows) expect(row.length).toBeCloseTo(12 * FT, 4) + for (const row of rows.slice(0, -1)) expect(row.width).toBeCloseTo(width, 3) + for (let i = 1; i < rows.length; i++) + expect(Math.min(...rows[i - 1]!.c) - Math.max(...rows[i]!.c)).toBeCloseTo(IN / 4, 3) + expect(rows.at(-1)!.width).toBeLessThan(width) + }) + + test('the boards cover the deck but for the gaps, and nothing past its outline', () => { + expect(area(difference(union(boards), outline))).toBeCloseTo(0, 6) + const covered = area(union(boards)) / area(outline) + expect(covered).toBeGreaterThan(0.94) + expect(covered).toBeLessThan(0.97) + }) +}) + +test('diagonal boards run at 45° to the house; boards out from it run square to it', () => { + const outline = rect(10 * FT, 8 * FT) + const diagonal = layoutDeckBoards(outline, AXES, { + ...DEFAULT_DECK_BOARDS, + direction: 'diagonal', + }) + const k = Math.SQRT1_2 + for (const board of diagonal) + expect(extent(board, [k, k]).width).toBeLessThanOrEqual(5.5 * IN + 1e-4) + expect(area(difference(union(diagonal), outline))).toBeCloseTo(0, 6) + const out = layoutDeckBoards(outline, AXES, { + ...DEFAULT_DECK_BOARDS, + direction: 'perpendicular', + }) + for (const board of out) expect(extent(board, [0, 1]).length).toBeCloseTo(8 * FT, 4) +}) + +test('boards are cut along any outline: an L-shaped deck', () => { + const ell: MultiPolygon = [ + { + outer: [ + [0, 0], + [6, 0], + [6, 2], + [2, 2], + [2, 5], + [0, 5], + ], + holes: [], + }, + ] + const boards = layoutDeckBoards(ell, AXES, DEFAULT_DECK_BOARDS) + expect(area(difference(union(boards), ell))).toBeCloseTo(0, 6) + expect(area(union(boards)) / area(ell)).toBeGreaterThan(0.93) + // the long rows stop at the notch + for (const board of boards) { + const { a, c } = extent(board, [1, 0]) + if (Math.min(...c) > 2 + 1e-6) expect(Math.max(...a)).toBeLessThanOrEqual(2 + 1e-6) + } +}) + +test('a run past 16 ft is laid in lengths butted over the joists, the joints of neighbouring rows staggered', () => { + const outline = rect(30 * FT, 4 * FT) + const stations = Array.from({ length: 23 }, (_, i) => 0.75 * IN + i * 16 * IN) + const boards = layoutDeckBoards(outline, AXES, DEFAULT_DECK_BOARDS, { + origin: [0, 0], + axis: [1, 0], + stations, + }) + const rows = new Map>() + for (const board of boards) { + const { a, c } = extent(board, [1, 0]) + const key = Math.max(...c).toFixed(3) + rows.set(key, [...(rows.get(key) ?? []), { from: Math.min(...a), to: Math.max(...a) }]) + } + const joints: number[][] = [] + for (const pieces of rows.values()) { + pieces.sort((p, q) => p.from - q.from) + expect(pieces.length).toBeGreaterThan(1) + for (const piece of pieces) + expect(piece.to - piece.from).toBeLessThanOrEqual(DECK_BOARD_MAX_LENGTH + 1e-6) + const row: number[] = [] + for (let i = 1; i < pieces.length; i++) { + const joint = (pieces[i - 1]!.to + pieces[i]!.from) / 2 + expect(pieces[i]!.from - pieces[i - 1]!.to).toBeCloseTo(DECK_BOARD_JOINT_GAP, 3) + // over a joist + expect(Math.min(...stations.map((s) => Math.abs(s - joint)))).toBeLessThan(1e-4) + row.push(joint) + } + joints.push(row) + } + for (let i = 1; i < joints.length; i++) + expect(joints[i]![0]).not.toBeCloseTo(joints[i - 1]![0]!, 3) +}) diff --git a/packages/core/src/lib/deck-boards.ts b/packages/core/src/lib/deck-boards.ts new file mode 100644 index 0000000000..01509468d4 --- /dev/null +++ b/packages/core/src/lib/deck-boards.ts @@ -0,0 +1,261 @@ +import type { ZoneNode } from '../schema' +import { area, intersection, type MultiPolygon, type Polygon } from './polygon-boolean' + +/** + * A deck's boards (a deck room, `lib/outdoor-room`): their stock, the gap between them and the way + * they run, kept on the room (`decking`, absent = the defaults) and laid by the engine over the + * deck's frame (`lib/deck-framing`). Sections are the boards' actual (dressed) ones: a 5/4x6 is + * 1 in by 5 1/2 in. The boards run along the house (square to the joists), at 45° (the joists + * then closer, IRC Table R507.7) or out from the house (the joists turned to run along it). + */ + +const IN = 0.0254 +const FT = 12 * IN + +type P = readonly [number, number] + +export const DECK_BOARD_SIZES = ['5/4x6', '2x6', '2x4', 'composite'] as const +export type DeckBoardSize = (typeof DECK_BOARD_SIZES)[number] + +export const DECK_BOARD_DIRECTIONS = ['parallel', 'diagonal', 'perpendicular'] as const +/** The boards' run against the house: along it, at 45° to it, or out from it. */ +export type DeckBoardDirection = (typeof DECK_BOARD_DIRECTIONS)[number] + +export type DeckBoardStock = { + label: string + /** Actual section, metres. */ + thickness: number + width: number + /** + * The widest joist spacing the boards may span (IRC Table R507.7): square to the joists, and + * at 45° to them. Composite boards go by their maker's listing (R507.2.2); these are the + * common 16 in and 12 in. + */ + maxJoistSpacing: { square: number; diagonal: number } +} + +export const DECK_BOARD_STOCK: Record = { + '5/4x6': { + label: '5/4x6', + thickness: 1 * IN, + width: 5.5 * IN, + maxJoistSpacing: { square: 16 * IN, diagonal: 12 * IN }, + }, + '2x6': { + label: '2x6', + thickness: 1.5 * IN, + width: 5.5 * IN, + maxJoistSpacing: { square: 24 * IN, diagonal: 16 * IN }, + }, + '2x4': { + label: '2x4', + thickness: 1.5 * IN, + width: 3.5 * IN, + maxJoistSpacing: { square: 24 * IN, diagonal: 16 * IN }, + }, + composite: { + label: 'Composite', + thickness: (15 / 16) * IN, + width: 5.5 * IN, + maxJoistSpacing: { square: 16 * IN, diagonal: 12 * IN }, + }, +} + +/** The gaps boards are laid at, narrowest first: 1/8, 3/16 and 1/4 in. */ +export const DECK_BOARD_GAPS = [IN / 8, (3 * IN) / 16, IN / 4] as const + +/** The longest board laid in one piece (16 ft stock); longer runs butt over a joist. */ +export const DECK_BOARD_MAX_LENGTH = 16 * FT +/** The gap at a butt joint. */ +export const DECK_BOARD_JOINT_GAP = IN / 8 + +export type DeckBoardSettings = { + boardSize: DeckBoardSize + /** Metres between boards. */ + gap: number + direction: DeckBoardDirection +} + +export const DEFAULT_DECK_BOARDS: DeckBoardSettings = { + boardSize: '5/4x6', + gap: IN / 4, + direction: 'parallel', +} + +const isBoardSize = (value: unknown): value is DeckBoardSize => + typeof value === 'string' && (DECK_BOARD_SIZES as readonly string[]).includes(value) +const isDirection = (value: unknown): value is DeckBoardDirection => + typeof value === 'string' && (DECK_BOARD_DIRECTIONS as readonly string[]).includes(value) + +/** A deck's boards: its own settings, else the defaults (an unknown size or run is the default). */ +export function deckBoardSettings( + zone: Pick | null | undefined, +): DeckBoardSettings { + const own = zone?.decking + return { + boardSize: isBoardSize(own?.boardSize) ? own.boardSize : DEFAULT_DECK_BOARDS.boardSize, + gap: typeof own?.gap === 'number' && own.gap > 0 ? own.gap : DEFAULT_DECK_BOARDS.gap, + direction: isDirection(own?.direction) ? own.direction : DEFAULT_DECK_BOARDS.direction, + } +} + +/** The boards on a deck room's floor plate, read from its room's intent. */ +export function deckSlabBoards( + slab: { zoneIds?: readonly string[] }, + zoneOf: (id: string) => Pick | null | undefined, +): DeckBoardSettings { + const zone = slab.zoneIds?.length === 1 ? zoneOf(slab.zoneIds[0]!) : undefined + return zone?.roomType === 'deck' ? deckBoardSettings(zone) : DEFAULT_DECK_BOARDS +} + +/** The boards' thickness: how far under the walking surface the joists' tops stand. */ +export function deckBoardThickness(settings: Pick): number { + return DECK_BOARD_STOCK[settings.boardSize].thickness +} + +/** The widest joist spacing these boards allow, laid as they run (Table R507.7). */ +export function deckJoistSpacingLimit( + settings: Pick, +): number { + const { maxJoistSpacing } = DECK_BOARD_STOCK[settings.boardSize] + return settings.direction === 'diagonal' ? maxJoistSpacing.diagonal : maxJoistSpacing.square +} + +/** The deck's frame axes (`deckAxes`): `u` along the house edge, `v` square to it, into the deck. */ +export type DeckBoardAxes = { origin: P; u: P; v: P } + +export type DeckBoardRun = { + /** The way the boards run, a plan unit vector. */ + along: [number, number] + /** Square to it: the way the rows are laid. */ + across: [number, number] +} + +/** Which way a deck's boards run over its frame. */ +export function deckBoardRun(axes: DeckBoardAxes, direction: DeckBoardDirection): DeckBoardRun { + const { u, v } = axes + if (direction === 'perpendicular') return { along: [v[0], v[1]], across: [u[0], u[1]] } + if (direction === 'diagonal') { + const k = Math.SQRT1_2 + return { + along: [(u[0] + v[0]) * k, (u[1] + v[1]) * k], + across: [(v[0] - u[0]) * k, (v[1] - u[1]) * k], + } + } + return { along: [u[0], u[1]], across: [v[0], v[1]] } +} + +/** + * The joists a long board butts over: their centrelines, the lines where a point's distance + * along `axis` from `origin` is one of `stations`. + */ +export type DeckBoardJoists = { origin: P; axis: P; stations: readonly number[] } + +/** A sliver under this (m²) is not laid. */ +const MIN_BOARD_AREA = 1e-4 +/** No board is cut shorter than this at a butt joint. */ +const MIN_BOARD_PIECE = 2 * FT + +/** + * The boards over `outline` (a deck's top): rows of the board's width, the gap apart, run as the + * settings say and cut along the outline, any shape. Boards running along the house start full at + * its outer edge, the last row ripped against the house; the others are centred, ripped alike at + * both sides. A row longer than 16 ft is laid in lengths butted over the joists (`joists`), the + * joints of neighbouring rows staggered. + */ +export function layoutDeckBoards( + outline: MultiPolygon, + axes: DeckBoardAxes, + settings: DeckBoardSettings, + joists?: DeckBoardJoists, +): Polygon[] { + const { along, across } = deckBoardRun(axes, settings.direction) + const { width } = DECK_BOARD_STOCK[settings.boardSize] + const pitch = width + settings.gap + const [ox, oz] = axes.origin + const alongOf = (p: P) => (p[0] - ox) * along[0] + (p[1] - oz) * along[1] + const acrossOf = (p: P) => (p[0] - ox) * across[0] + (p[1] - oz) * across[1] + const at = (a: number, c: number): [number, number] => [ + ox + along[0] * a + across[0] * c, + oz + along[1] * a + across[1] * c, + ] + let aMin = Number.POSITIVE_INFINITY + let aMax = Number.NEGATIVE_INFINITY + let cMin = Number.POSITIVE_INFINITY + let cMax = Number.NEGATIVE_INFINITY + for (const { outer } of outline) + for (const p of outer) { + aMin = Math.min(aMin, alongOf(p)) + aMax = Math.max(aMax, alongOf(p)) + cMin = Math.min(cMin, acrossOf(p)) + cMax = Math.max(cMax, acrossOf(p)) + } + if (!(cMax - cMin > 1e-6 && aMax - aMin > 1e-6)) return [] + const rows = Math.ceil((cMax - cMin + settings.gap) / pitch - 1e-9) + // Along the house the first row is a full board at the outer edge; otherwise centred. + const first = + settings.direction === 'parallel' + ? cMax - width + : cMin - (rows * pitch - settings.gap - (cMax - cMin)) / 2 + const step = settings.direction === 'parallel' ? -pitch : pitch + const band = (a0: number, a1: number, c0: number, c1: number): Polygon => ({ + outer: [at(a0, c0), at(a1, c0), at(a1, c1), at(a0, c1)], + holes: [], + }) + // A joist's centreline crossing a row's middle, as a distance along the row. + const crossings = (c: number): number[] => { + if (!joists) return [] + const [ax, az] = joists.axis + const dot = along[0] * ax + along[1] * az + if (Math.abs(dot) < 1e-6) return [] + const offset = + (ox - joists.origin[0]) * ax + + (oz - joists.origin[1]) * az + + c * (across[0] * ax + across[1] * az) + return joists.stations.map((s) => (s - offset) / dot).sort((a, b) => a - b) + } + const boards: Polygon[] = [] + for (let row = 0; row < rows; row++) { + const c0 = first + step * row + const pieces = intersection(band(aMin - 1, aMax + 1, c0, c0 + width), outline).filter( + (piece) => area([piece]) >= MIN_BOARD_AREA, + ) + const joints = crossings(c0 + width / 2) + for (const piece of pieces) { + let start = Number.POSITIVE_INFINITY + let end = Number.NEGATIVE_INFINITY + for (const p of piece.outer) { + start = Math.min(start, alongOf(p)) + end = Math.max(end, alongOf(p)) + } + // Butt joints, staggered by row: the first length a third shorter each row in three. + const cuts: number[] = [] + let from = start + let limit = DECK_BOARD_MAX_LENGTH * (1 - (row % 3) / 3) + while (end - from > DECK_BOARD_MAX_LENGTH + 1e-9) { + const joint = joints + .filter( + (a) => a > from + MIN_BOARD_PIECE && a <= from + limit && a < end - MIN_BOARD_PIECE, + ) + .at(-1) + if (joint === undefined) break + cuts.push(joint) + from = joint + limit = DECK_BOARD_MAX_LENGTH + } + if (!cuts.length) { + boards.push(piece) + continue + } + const half = DECK_BOARD_JOINT_GAP / 2 + const bounds = [start - 1, ...cuts.flatMap((a) => [a - half, a + half]), end + 1] + for (let i = 0; i + 1 < bounds.length; i += 2) + boards.push( + ...intersection(band(bounds[i]!, bounds[i + 1]!, c0 - 1, c0 + width + 1), piece).filter( + (part) => area([part]) >= MIN_BOARD_AREA, + ), + ) + } + } + return boards +} diff --git a/packages/core/src/lib/deck-framing.test.ts b/packages/core/src/lib/deck-framing.test.ts new file mode 100644 index 0000000000..304531714e --- /dev/null +++ b/packages/core/src/lib/deck-framing.test.ts @@ -0,0 +1,303 @@ +import { describe, expect, test } from 'bun:test' +import { DECK_BOARD_STOCK } from './deck-boards' +import { + DECK_BEAM_INSET, + DECK_BOARD_OVERHANG, + DECK_POST_SPACING, + type DeckPiece, + type DeckWall, + planDeckFraming, +} from './deck-framing' +import { containsPoint } from './polygon-boolean' + +const IN = 0.0254 +const FT = 12 * IN + +// The house's rear wall runs along x at z = 0; a 16 × 12 ft deck lies behind it, +z. +const WALL: DeckWall = { start: [-1, 0], end: [8, 0], thickness: 0.14 } +const DECK: Array<[number, number]> = [ + [0, 0], + [16 * FT, 0], + [16 * FT, 12 * FT], + [0, 12 * FT], +] +const TOP = 0.6 +const HIGH = TOP - 36 * IN +const LOW = TOP - 18 * IN +const BURIED = TOP - 8 * IN + +const bottomOf = (piece: DeckPiece) => piece.position[1] - piece.dims[1] / 2 +const topOf = (piece: DeckPiece) => piece.position[1] + piece.dims[1] / 2 +/** A piece's plan footprint corners. */ +const corners = (piece: DeckPiece): Array<[number, number]> => { + const [x, , z] = piece.position + const [length, , width] = piece.dims + const c = Math.cos(piece.yaw) + const s = -Math.sin(piece.yaw) + return [ + [-1, -1], + [1, -1], + [1, 1], + [-1, 1], + ].map(([a, b]) => [ + x + (c * a * length - s * b * width) / 2, + z + (s * a * length + c * b * width) / 2, + ]) +} +const within = (outline: Array<[number, number]>, piece: DeckPiece) => + corners(piece).every( + ([x, z]) => + containsPoint([{ outer: outline, holes: [] }], [x, z]) || + outline.some(([px, pz], i) => { + const [qx, qz] = outline[(i + 1) % outline.length]! + const t = Math.max( + 0, + Math.min( + 1, + ((x - px) * (qx - px) + (z - pz) * (qz - pz)) / ((qx - px) ** 2 + (qz - pz) ** 2), + ), + ) + return Math.hypot(x - px - (qx - px) * t, z - pz - (qz - pz) * t) < 1e-6 + }), + ) + +describe('a 16 × 12 ft deck on the house wall, 3 ft over the grade, boards along the house', () => { + const plan = planDeckFraming({ + polygon: DECK, + top: TOP, + decking: IN, + walls: [WALL], + gradeY: HIGH, + }) + const t = plan.joist!.thickness + + test('a ledger on the wall; joists square to it at 16 in from side to side, under the boards; rims set in so the boards overhang them, none at the house', () => { + expect(plan.axes?.ledgerEdge).toBe(0) + expect(plan.ledger?.position[2]).toBeCloseTo(t / 2, 9) + expect(plan.ledger?.dims[0]).toBeCloseTo(16 * FT - 2 * DECK_BOARD_OVERHANG, 9) + const xs = plan.joists.map((joist) => joist.position[0]).sort((a, b) => a - b) + expect(xs[0]).toBeCloseTo(DECK_BOARD_OVERHANG + t / 2, 9) + expect(xs.at(-1)).toBeCloseTo(16 * FT - DECK_BOARD_OVERHANG - t / 2, 9) + for (let i = 1; i < xs.length; i++) + expect(xs[i]! - xs[i - 1]!).toBeLessThanOrEqual(16 * IN + 1e-9) + for (const joist of plan.joists) { + expect(topOf(joist)).toBeCloseTo(TOP - IN, 9) + expect(joist.dims[0]).toBeCloseTo(12 * FT - DECK_BOARD_OVERHANG - 2 * t, 9) + expect(joist.hangers).toHaveLength(1) + } + // the end joists are the side rims + expect(plan.joists.filter((joist) => joist.atRim)).toHaveLength(2) + expect(plan.rims).toHaveLength(3) + const outer = plan.rims.find((rim) => rim.position[2] > 3)! + expect(outer.position[2]).toBeCloseTo(12 * FT - DECK_BOARD_OVERHANG - t / 2, 9) + }) + + test('one 4x8 beam dropped under the joists 16 in in from the outer rim, on 4x4 posts to the grade no more than 8 ft apart', () => { + expect(plan.beam).toBe('dropped') + expect(plan.beams).toHaveLength(1) + const [beam] = plan.beams as [DeckPiece] + expect(beam.size).toBe('4x8') + expect(beam.position[2]).toBeCloseTo(12 * FT - DECK_BOARD_OVERHANG - DECK_BEAM_INSET, 9) + expect(topOf(beam)).toBeCloseTo(TOP - IN - plan.joist!.depth, 9) + const posts = plan.posts.slice().sort((a, b) => a.position[0] - b.position[0]) + expect(posts.length).toBeGreaterThanOrEqual(3) + for (let i = 1; i < posts.length; i++) + expect(posts[i]!.position[0] - posts[i - 1]!.position[0]).toBeLessThanOrEqual( + DECK_POST_SPACING, + ) + for (const post of posts) { + expect(post.size).toBe('4x4') + expect(bottomOf(post)).toBeCloseTo(HIGH, 9) + expect(topOf(post)).toBeCloseTo(bottomOf(beam), 9) + } + }) + + test('every piece lies inside the outline', () => { + for (const piece of [plan.ledger!, ...plan.rims, ...plan.joists, ...plan.beams]) + expect(within(DECK, piece)).toBe(true) + }) +}) + +test('diagonal boards close the joists to 12 in under 5/4 or composite boards; 2x boards span 16 in at 45°', () => { + const at = (boardSize: 'composite' | '2x6') => + planDeckFraming({ + polygon: DECK, + top: TOP, + decking: DECK_BOARD_STOCK[boardSize].thickness, + walls: [WALL], + gradeY: HIGH, + boards: { boardSize, gap: IN / 4, direction: 'diagonal' }, + }) + const diagonal = planDeckFraming({ + polygon: DECK, + top: TOP, + decking: IN, + walls: [WALL], + gradeY: HIGH, + boards: { boardSize: '5/4x6', gap: IN / 4, direction: 'diagonal' }, + }) + expect(diagonal.joistSpacing).toBeCloseTo(12 * IN, 9) + expect(diagonal.spacingForBoards).toBe(true) + const xs = diagonal.joists.map((joist) => joist.position[0]).sort((a, b) => a - b) + for (let i = 1; i < xs.length; i++) + expect(xs[i]! - xs[i - 1]!).toBeLessThanOrEqual(12 * IN + 1e-9) + expect(at('composite').joistSpacing).toBeCloseTo(12 * IN, 9) + expect(at('2x6').joistSpacing).toBeCloseTo(16 * IN, 9) + expect(at('2x6').spacingForBoards).toBe(false) +}) + +test('boards out from the house turn the joists to run along it, on beams square to the house at both sides; the ledger hangs none', () => { + const plan = planDeckFraming({ + polygon: DECK, + top: TOP, + decking: IN, + walls: [WALL], + gradeY: HIGH, + boards: { boardSize: '5/4x6', gap: IN / 4, direction: 'perpendicular' }, + }) + expect(plan.joistsAlongHouse).toBe(true) + for (const joist of plan.joists) { + // along x, the house's run + expect(Math.abs(Math.cos(joist.yaw))).toBeCloseTo(1, 9) + expect(joist.hangers).toEqual([]) + } + const zs = plan.joists.map((joist) => joist.position[2]).sort((a, b) => a - b) + for (let i = 1; i < zs.length; i++) + expect(zs[i]! - zs[i - 1]!).toBeLessThanOrEqual(16 * IN + 1e-9) + expect(plan.beams).toHaveLength(2) + const xs = plan.beams.map((beam) => beam.position[0]).sort((a, b) => a - b) + expect(xs[0]).toBeCloseTo(DECK_BOARD_OVERHANG + DECK_BEAM_INSET, 9) + expect(xs[1]).toBeCloseTo(16 * FT - DECK_BOARD_OVERHANG - DECK_BEAM_INSET, 9) + for (const beam of plan.beams) expect(Math.abs(Math.sin(beam.yaw))).toBeCloseTo(1, 9) + // posts under both beams, both ends of each + expect(plan.posts.length).toBeGreaterThanOrEqual(4) + expect(new Set(plan.posts.map((post) => post.position[0].toFixed(3))).size).toBe(2) + // the joists span between the beams: sized for that, not the deck's width + expect(plan.joist?.size).toBe('2x10') + for (const piece of [plan.ledger!, ...plan.rims, ...plan.joists, ...plan.beams]) + expect(within(DECK, piece)).toBe(true) +}) + +test('a deck too wide for the joists gets a beam between, its joists sized for the shorter span', () => { + const wide: Array<[number, number]> = [ + [0, 0], + [30 * FT, 0], + [30 * FT, 12 * FT], + [0, 12 * FT], + ] + const plan = planDeckFraming({ + polygon: wide, + top: TOP, + decking: IN, + walls: [{ start: [-1, 0], end: [10, 0], thickness: 0.14 }], + gradeY: HIGH, + boards: { boardSize: '5/4x6', gap: IN / 4, direction: 'perpendicular' }, + }) + // 27 ft between the outer beams: two bays of 13 ft 7 in, a 2x10's + expect(plan.beams).toHaveLength(3) + expect(plan.spanPastTable).toBe(false) + expect(plan.joist?.size).toBe('2x10') +}) + +test('a low deck doubles its beam inside the outer rim, the joists hung on it; below grade nothing props it', () => { + const low = planDeckFraming({ polygon: DECK, top: TOP, decking: IN, walls: [WALL], gradeY: LOW }) + expect(low.beam).toBe('flush') + const t = low.joist!.thickness + const [beam] = low.beams as [DeckPiece] + expect(beam.size).toBe(low.joist!.size) + expect(topOf(beam)).toBeCloseTo(TOP - IN, 9) + expect(beam.position[2]).toBeCloseTo(12 * FT - DECK_BOARD_OVERHANG - 1.5 * t, 9) + for (const joist of low.joists) { + expect(joist.dims[0]).toBeCloseTo(12 * FT - DECK_BOARD_OVERHANG - 3 * t, 9) + expect(joist.hangers).toHaveLength(2) + } + for (const post of low.posts) expect(bottomOf(post)).toBeCloseTo(LOW, 9) + const buried = planDeckFraming({ + polygon: DECK, + top: TOP, + decking: IN, + walls: [WALL], + gradeY: BURIED, + }) + expect(buried.beam).toBe('unsupported') + expect(buried.posts).toEqual([]) + expect(buried.joists.length).toBeGreaterThan(0) +}) + +test('an L-shaped deck frames along its outline: a rim on every free edge, a beam under each outer edge, every joist inside', () => { + const ell: Array<[number, number]> = [ + [0, 0], + [20 * FT, 0], + [20 * FT, 8 * FT], + [10 * FT, 8 * FT], + [10 * FT, 14 * FT], + [0, 14 * FT], + ] + const plan = planDeckFraming({ + polygon: ell, + top: TOP, + decking: IN, + walls: [{ start: [-1, 0], end: [22 * FT, 0], thickness: 0.14 }], + gradeY: HIGH, + }) + expect(plan.irregular).toBe(true) + expect(plan.rims).toHaveLength(5) + expect(plan.beams).toHaveLength(2) + for (const piece of [plan.ledger!, ...plan.rims, ...plan.joists, ...plan.beams]) + expect(within(ell, piece)).toBe(true) + const short = plan.joists.filter((joist) => joist.position[0] > 10 * FT + 1) + const long = plan.joists.filter((joist) => joist.position[0] < 10 * FT - 1) + for (const joist of short) expect(joist.position[2] + joist.dims[0] / 2).toBeLessThan(8 * FT) + expect(Math.max(...long.map((joist) => joist.position[2] + joist.dims[0] / 2))).toBeGreaterThan( + 12 * FT, + ) +}) + +test('posts run to the ground under each; posts already standing on a beam line carry it', () => { + const sloped = planDeckFraming({ + polygon: DECK, + top: TOP, + decking: IN, + walls: [WALL], + gradeY: HIGH, + gradeAt: (x) => HIGH - 0.05 * x, + }) + for (const post of sloped.posts) + expect(bottomOf(post)).toBeCloseTo(HIGH - 0.05 * post.position[0], 9) + const line = 12 * FT - DECK_BOARD_OVERHANG - DECK_BEAM_INSET + const carried = planDeckFraming({ + polygon: DECK, + top: TOP, + decking: IN, + walls: [WALL], + gradeY: HIGH, + carriers: [ + [1, line + 0.1], + [16 * FT - 1, line - 0.1], + ], + }) + expect(carried.beams[0]?.carried).toBe(true) + expect(carried.posts).toEqual([]) +}) + +test('a deck with no wall on any edge stands free: rims all round, beams under both ends of the joists', () => { + const free = planDeckFraming({ polygon: DECK, top: TOP, decking: IN, walls: [], gradeY: HIGH }) + expect(free.axes?.ledgerEdge).toBeNull() + expect(free.ledger).toBeNull() + expect(free.rims).toHaveLength(4) + expect(free.beams).toHaveLength(2) + for (const joist of free.joists) expect(joist.hangers).toEqual([]) + const sliver = planDeckFraming({ + polygon: [ + [0, 0], + [0.2, 0], + [0.2, 0.2], + [0, 0.2], + ], + top: TOP, + decking: IN, + walls: [WALL], + gradeY: HIGH, + }) + expect([...sliver.rims, ...sliver.joists, ...sliver.beams, ...sliver.posts]).toEqual([]) +}) diff --git a/packages/core/src/lib/deck-framing.ts b/packages/core/src/lib/deck-framing.ts new file mode 100644 index 0000000000..b0a8212a76 --- /dev/null +++ b/packages/core/src/lib/deck-framing.ts @@ -0,0 +1,697 @@ +import type { AnyNode, AnyNodeId, SlabNode } from '../schema' +import { DEFAULT_DECK_BOARDS, type DeckBoardSettings, deckJoistSpacingLimit } from './deck-boards' +import { floorPlateRoom } from './room-floor-plate' + +/** + * A wood deck's frame, planned once for the engine, which draws it under the deck's boards, and + * for the framing plugin, which books, labels and cites it. Framed to IRC R507: + * + * - a LEDGER on the house edge (the deck edge along a house wall), the joist size; + * - JOISTS at the spacing (closer under diagonal boards, Table R507.7), sized from a span table: + * square to the house under boards that run along it or at 45°, along the house under boards + * that run out from it; + * - RIMS on every other edge, set in so the boards overhang them an inch (none at the house); + * - a BEAM under each edge the joists run out to that is no ledger: DROPPED 16 in in under the + * joists (a 4x8, the joists cantilevering past it) where the deck stands high enough for posts + * under it, else FLUSH, a second joist-size board doubled inside the rim, the joists hung on + * it; more beams between where the joists would span past the table. Joists along the house + * bear on beams square to it at both ends, as joists hung off a ledger cannot run that way; + * - 4x4 POSTS under each beam, at both ends and no more than 8 ft apart, down to the ground under + * each, unless posts already standing there to grade carry it (a porch cover's). + * + * Any outline frames along its edges: an L-shaped deck gets a rim on every edge and a beam under + * each outer edge. Everything is level-local metres; a `yaw` is three.js's (local +x → world + * (cos θ, −sin θ)), a piece's `dims` its length along its run, its height and its thickness. + */ + +const IN = 0.0254 +const FT = 12 * IN +const EPS = 1e-9 + +type P = readonly [number, number] +type V2 = [number, number] + +/** A dropped beam sits this far in from the edge it carries (16 in), the joists cantilevering past it. */ +export const DECK_BEAM_INSET = 16 * IN +/** Posts at both beam ends (2 in in) and no more than 8 ft apart. */ +export const DECK_POST_SPACING = 96 * IN +/** The shortest post worth a post base (Simpson ABU/ABA need it); below this the beam goes flush. */ +export const DECK_MIN_POST_HEIGHT = 6 * IN +/** A post's face stands this far in from its beam's end. */ +export const DECK_POST_END_INSET = 2 * IN +/** The boards overhang the rim this much on a free edge; at the house they stop at the wall. */ +export const DECK_BOARD_OVERHANG = 1 * IN +/** An edge whose midpoint is within this of a wall's face is on the house. */ +const LEDGER_TOLERANCE = 0.3 +/** A post standing within this of a beam's line carries it. */ +const CARRIER_REACH = 12 * IN +const CARRIER_END_REACH = 6 * IN +/** The narrowest deck framed. */ +const MIN_DECK = 12 * IN +/** A post shorter than this is not drawn: the beam sits on the ground there. */ +const MIN_DRAWN_POST = 0.05 +/** A hanger's seat: this far along the joist from its end. */ +const HANGER_SEAT = 0.375 * IN + +/** A stock section: its name, thickness (across) and depth (down), metres. */ +export type DeckLumber = { size: string; thickness: number; depth: number } +/** A joist size and the most it spans. */ +export type DeckJoistSpan = DeckLumber & { span: number } + +/** + * The joists a deck takes by the span they reach, first that spans: SPF #2 at 40 psf live, the + * floor table's arithmetic (R502.3.1(2); IRC R507.6 governs deck joists), as the framing plugin's + * default span table has them. + */ +export const DECK_JOIST_SPANS: readonly DeckJoistSpan[] = [ + { size: '2x8', thickness: 1.5 * IN, depth: 7.25 * IN, span: 12.25 * FT }, + { size: '2x10', thickness: 1.5 * IN, depth: 9.25 * IN, span: 15 * FT }, + { size: '2x12', thickness: 1.5 * IN, depth: 11.25 * IN, span: 17.4 * FT }, +] +/** A dropped beam: a 4x8 (span per Table R507.5(1)). */ +export const DECK_DROPPED_BEAM: DeckLumber = { size: '4x8', thickness: 3.5 * IN, depth: 7.25 * IN } +/** A deck post (Table R507.4). */ +export const DECK_POST: DeckLumber = { size: '4x4', thickness: 3.5 * IN, depth: 3.5 * IN } + +/** A wall a deck edge may bear on: its centreline and thickness. */ +export type DeckWall = { start: P; end: P; thickness: number; curved?: boolean } + +/** A deck room's dedicated floor plate, drawn as boards on a frame. */ +export function isDeckSlab( + slab: Pick, + resolve: (id: AnyNodeId) => AnyNode | undefined, +): boolean { + return !slab.recessed && floorPlateRoom(slab, resolve)?.roomType === 'deck' +} + +const sub = (a: P, b: P): V2 => [a[0] - b[0], a[1] - b[1]] +const dot = (a: P, b: P) => a[0] * b[0] + a[1] * b[1] +const cross = (a: P, b: P) => a[0] * b[1] - a[1] * b[0] + +function distanceToWall(p: P, wall: DeckWall): number { + const [dx, dz] = sub(wall.end, wall.start) + const dd = dx * dx + dz * dz + if (dd < EPS) return Math.hypot(p[0] - wall.start[0], p[1] - wall.start[1]) + const t = Math.max( + 0, + Math.min(1, ((p[0] - wall.start[0]) * dx + (p[1] - wall.start[1]) * dz) / dd), + ) + return Math.hypot(p[0] - (wall.start[0] + dx * t), p[1] - (wall.start[1] + dz * t)) +} + +/** How near edge `i` lies on a wall (parallel within 15°, its midpoint within the tolerance), or null. */ +function wallDistance(polygon: readonly P[], i: number, walls: readonly DeckWall[]): number | null { + const a = polygon[i]! + const b = polygon[(i + 1) % polygon.length]! + const length = Math.hypot(b[0] - a[0], b[1] - a[1]) + if (length < EPS) return null + const along: V2 = [(b[0] - a[0]) / length, (b[1] - a[1]) / length] + const mid: V2 = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2] + let best: number | null = null + for (const wall of walls) { + if (wall.curved) continue + const [dx, dz] = sub(wall.end, wall.start) + const wallLength = Math.hypot(dx, dz) + if (wallLength < EPS) continue + const d = distanceToWall(mid, wall) + if (d > LEDGER_TOLERANCE + wall.thickness / 2) continue + if (Math.abs(cross(along, [dx / wallLength, dz / wallLength])) > Math.sin((15 * Math.PI) / 180)) + continue + if (best === null || d < best) best = d + } + return best +} + +/** The deck edge that lies on a wall (the nearest such), where the ledger goes; null when none does. */ +export function deckLedgerEdge(polygon: readonly P[], walls: readonly DeckWall[]): number | null { + let best: { i: number; d: number } | null = null + for (let i = 0; i < polygon.length; i++) { + const d = wallDistance(polygon, i, walls) + if (d !== null && (!best || d < best.d)) best = { i, d } + } + return best ? best.i : null +} + +/** + * A deck's frame: `u` along its ledger edge (the longest edge of a deck standing free), `v` + * square to it pointing into the deck, from the edge's first corner. + */ +export type DeckAxes = { + /** The deck edge on the house, or null: the deck stands free. */ + ledgerEdge: number | null + /** The edge the frame is squared to: the ledger edge, else the longest. */ + baseEdge: number + origin: V2 + u: V2 + v: V2 +} + +export function deckAxes(polygon: readonly P[], walls: readonly DeckWall[]): DeckAxes | null { + if (polygon.length < 3) return null + const ledgerEdge = deckLedgerEdge(polygon, walls) + let base = ledgerEdge ?? 0 + if (ledgerEdge === null) { + let longest = 0 + for (let i = 0; i < polygon.length; i++) { + const [dx, dz] = sub(polygon[(i + 1) % polygon.length]!, polygon[i]!) + const length = Math.hypot(dx, dz) + if (length > longest) { + longest = length + base = i + } + } + } + const a = polygon[base]! + const [dx, dz] = sub(polygon[(base + 1) % polygon.length]!, a) + const length = Math.hypot(dx, dz) + if (length < EPS) return null + const u: V2 = [dx / length, dz / length] + // the vertex average decides which perpendicular points into the deck + let cx = 0 + let cz = 0 + for (const p of polygon) { + cx += p[0] + cz += p[1] + } + cx /= polygon.length + cz /= polygon.length + let v: V2 = [-u[1], u[0]] + if ((cx - a[0]) * v[0] + (cz - a[1]) * v[1] < 0) v = [u[1], -u[0]] + return { ledgerEdge, baseEdge: base, origin: [a[0], a[1]], u, v } +} + +export type DeckFramingInput = { + /** The deck's outline, plan [x, z]. */ + polygon: readonly P[] + /** Height of the walking surface: the boards' top. */ + top: number + /** The boards' thickness: the joists' tops stand this far under `top`. */ + decking: number + /** Walls a deck edge may lie on (the house's), for the ledger. */ + walls: readonly DeckWall[] + /** How the boards run and what they are (`lib/deck-boards`): the joists follow. */ + boards?: DeckBoardSettings + /** The joist spacing asked for, 16 in unless said; the boards may close it (Table R507.7). */ + joistSpacing?: number + /** The joist sizes, first that spans (the framing plugin's span table): `DECK_JOIST_SPANS` unless said. */ + joists?: readonly DeckJoistSpan[] + /** The ground the beam is chosen against: the grade under the deck's middle. */ + gradeY: number + /** The ground under each post; absent, `gradeY` under every post. */ + gradeAt?: (x: number, z: number) => number + /** Posts already standing to grade (a porch cover's): a beam line two of them stand on gets none of its own. */ + carriers?: readonly P[] + /** How far the boards overhang the rims, `DECK_BOARD_OVERHANG` unless said. */ + overhang?: number +} + +export type DeckPieceRole = 'ledger' | 'joist' | 'rim' | 'beam' | 'post' + +/** One member: its stock, its centre, its `dims` ([run, height, across]) and its yaw. */ +export type DeckPiece = { + role: DeckPieceRole + size: string + position: [number, number, number] + dims: [number, number, number] + yaw: number +} + +/** Where a joist end hangs in a hanger, on the ledger or a flush beam, and the yaw of what it hangs on. */ +export type DeckHanger = { position: [number, number, number]; yaw: number } + +export type DeckJoistPiece = DeckPiece & { + role: 'joist' + /** A joist on a rim's line (the end joist a side rim is): the rim stands in for it where it is drawn. */ + atRim: boolean + hangers: DeckHanger[] +} + +export type DeckBeamPiece = DeckPiece & { + role: 'beam' + /** Posts already standing to grade carry it (`carriers`): it gets none of its own. */ + carried: boolean + /** One between the outer beams, where the joists would span past the table. */ + between: boolean +} + +export type DeckPostPiece = DeckPiece & { + role: 'post' + /** The ground it stands on, where its footing is. */ + bottom: number +} + +export type DeckBeamKind = 'dropped' | 'flush' | 'unsupported' + +export type DeckFramingPlan = { + axes: DeckAxes | null + /** 'dropped' under the joists on posts, 'flush' doubled inside the rim, 'unsupported': no room for a post. */ + beam: DeckBeamKind + joist: DeckJoistSpan | null + /** Even its largest size spans short of the joists. */ + spanPastTable: boolean + joistSpacing: number + /** The spacing is closer than asked, for the boards (Table R507.7). */ + spacingForBoards: boolean + /** The joists run along the house (the boards run out from it). */ + joistsAlongHouse: boolean + /** The outline is no rectangle square to its frame: framed along its edges. */ + irregular: boolean + /** The beam's lumber: a 4x8 dropped, the joist size flush. */ + beamLumber: DeckLumber | null + /** The joists' tops, the beams' and the posts' (under the beams). */ + joistTop: number + beamTop: number + postTop: number + /** The posts' height over `gradeY`: under `DECK_MIN_POST_HEIGHT`, no post fits. */ + postHeight: number + /** The way the joists are laid out, a plan unit vector, and their stations along it from `axes.origin`. */ + stationAxis: V2 | null + stations: number[] + ledger: DeckPiece | null + rims: DeckPiece[] + joists: DeckJoistPiece[] + beams: DeckBeamPiece[] + posts: DeckPostPiece[] +} + +/** The outline with each edge moved in by its offset (signed area kept), or null when that collapses it. */ +function insetEdges(polygon: readonly P[], offsets: readonly number[]): V2[] | null { + const n = polygon.length + let twice = 0 + for (let i = 0; i < n; i++) twice += cross(polygon[i]!, polygon[(i + 1) % n]!) + const sign = twice > 0 ? 1 : -1 + const lines = polygon.map((a, i) => { + const [dx, dz] = sub(polygon[(i + 1) % n]!, a) + const length = Math.hypot(dx, dz) || 1 + const e: V2 = [dx / length, dz / length] + const inward: V2 = sign > 0 ? [-e[1], e[0]] : [e[1], -e[0]] + const d = offsets[i] ?? 0 + return { p: [a[0] + inward[0] * d, a[1] + inward[1] * d] as V2, e } + }) + const inset = polygon.map((_, i): V2 => { + const before = lines[(i - 1 + n) % n]! + const after = lines[i]! + const turn = cross(before.e, after.e) + if (Math.abs(turn) < 1e-9) return after.p + const t = cross(sub(after.p, before.p), after.e) / turn + return [before.p[0] + before.e[0] * t, before.p[1] + before.e[1] * t] + }) + let insetTwice = 0 + for (let i = 0; i < n; i++) insetTwice += cross(inset[i]!, inset[(i + 1) % n]!) + return insetTwice * sign > 0.5 * Math.abs(twice) ? inset : null +} + +/** The outline without repeated corners. */ +function cleanOutline(polygon: readonly P[]): V2[] { + const out: V2[] = [] + for (const p of polygon) { + const last = out.at(-1) + if (!last || Math.hypot(p[0] - last[0], p[1] - last[1]) > 1e-6) out.push([p[0], p[1]]) + } + while ( + out.length > 1 && + Math.hypot(out[0]![0] - out.at(-1)![0], out[0]![1] - out.at(-1)![1]) <= 1e-6 + ) + out.pop() + return out +} + +export function planDeckFraming(input: DeckFramingInput): DeckFramingPlan { + const boards = input.boards ?? DEFAULT_DECK_BOARDS + const asked = input.joistSpacing ?? 16 * IN + const spacing = Math.min(asked, deckJoistSpacingLimit(boards)) + const joistsAlongHouse = boards.direction === 'perpendicular' + const ladder = input.joists?.length ? input.joists : DECK_JOIST_SPANS + const joistTop = input.top - input.decking + const plan: DeckFramingPlan = { + axes: null, + beam: 'unsupported', + joist: null, + spanPastTable: false, + joistSpacing: spacing, + spacingForBoards: spacing < asked - EPS, + joistsAlongHouse, + irregular: false, + beamLumber: null, + joistTop, + beamTop: joistTop, + postTop: joistTop, + postHeight: 0, + stationAxis: null, + stations: [], + ledger: null, + rims: [], + joists: [], + beams: [], + posts: [], + } + const outline = cleanOutline(input.polygon) + if (outline.length < 3) return plan + const axes = deckAxes(outline, input.walls) + if (!axes) return plan + plan.axes = axes + const n = outline.length + const ledgerEdge = axes.ledgerEdge + + // ---- the frame's outline: the free edges in by the boards' overhang ---- + const overhang = input.overhang ?? DECK_BOARD_OVERHANG + const offsets = outline.map((_, i) => + wallDistance(outline, i, input.walls) === null ? overhang : 0, + ) + const frame = insetEdges(outline, offsets) ?? outline + // Frame coordinates: s along the joists' layout (stations), j along the joists. + const S = joistsAlongHouse ? axes.v : axes.u + const J = joistsAlongHouse ? axes.u : axes.v + const [ox, oz] = axes.origin + const toFrame = (p: P): V2 => [ + (p[0] - ox) * S[0] + (p[1] - oz) * S[1], + (p[0] - ox) * J[0] + (p[1] - oz) * J[1], + ] + const toPlan = (s: number, j: number): V2 => [ox + S[0] * s + J[0] * j, oz + S[1] * s + J[1] * j] + const yawOf = (s: number, j: number) => { + const x = S[0] * s + J[0] * j + const z = S[1] * s + J[1] * j + return Math.atan2(-z, x) + } + const yawS = yawOf(1, 0) + const yawJ = yawOf(0, 1) + const fq = frame.map(toFrame) + let twice = 0 + for (let i = 0; i < n; i++) twice += cross(fq[i]!, fq[(i + 1) % n]!) + const ccw = twice > 0 + const edges = fq.map((a, i) => { + const b = fq[(i + 1) % n]! + const length = Math.hypot(b[0] - a[0], b[1] - a[1]) + const e: V2 = length > EPS ? [(b[0] - a[0]) / length, (b[1] - a[1]) / length] : [1, 0] + const inward: V2 = ccw ? [-e[1], e[0]] : [e[1], -e[0]] + // An 'end' edge runs across the joists: they run out to it. A 'side' edge runs with them. + const kind: 'end' | 'side' = Math.abs(e[0]) >= Math.abs(e[1]) ? 'end' : 'side' + return { a, b, e, inward, length, kind } + }) + let sMin = Number.POSITIVE_INFINITY + let sMax = Number.NEGATIVE_INFINITY + let jMin = Number.POSITIVE_INFINITY + let jMax = Number.NEGATIVE_INFINITY + for (const [s, j] of fq) { + sMin = Math.min(sMin, s) + sMax = Math.max(sMax, s) + jMin = Math.min(jMin, j) + jMax = Math.max(jMax, j) + } + if (sMax - sMin < MIN_DECK || jMax - jMin < MIN_DECK) return plan + plan.irregular = + n !== 4 || edges.some((edge) => Math.min(Math.abs(edge.e[0]), Math.abs(edge.e[1])) > 1e-6) + + // ---- the joists: sized for the span between their supports, beams between past the table ---- + // A ledger carries the joists' house ends unless they run along it. + const hung = ledgerEdge !== null && !joistsAlongHouse + const near = hung ? jMin : jMin + DECK_BEAM_INSET + const far = jMax - DECK_BEAM_INSET + const run = Math.max(far - near, 0) + const longest = ladder.at(-1)! + const bays = Math.max(1, Math.ceil(run / longest.span - 1e-9)) + const joist = ladder.find((size) => run / bays <= size.span + EPS) ?? longest + plan.joist = joist + plan.spanPastTable = run / bays > longest.span + EPS + const t = joist.thickness + const d = joist.depth + const centerY = joistTop - d / 2 + + // ---- the beam: dropped where a post fits under a 4x8 under the joists, else flush ---- + const dropped = joistTop - d - DECK_DROPPED_BEAM.depth - input.gradeY >= DECK_MIN_POST_HEIGHT + const beamLumber: DeckLumber = dropped ? DECK_DROPPED_BEAM : joist + const beamTop = dropped ? joistTop - d : joistTop + const postTop = beamTop - beamLumber.depth + const postHeight = postTop - input.gradeY + const canPost = postHeight >= DECK_MIN_POST_HEIGHT + plan.beam = dropped ? 'dropped' : canPost ? 'flush' : 'unsupported' + plan.beamLumber = beamLumber + plan.beamTop = beamTop + plan.postTop = postTop + plan.postHeight = postHeight + + const pieceAt = ( + role: DeckPieceRole, + size: string, + s: number, + j: number, + y: number, + dims: [number, number, number], + yaw: number, + ): DeckPiece => { + const [x, z] = toPlan(s, j) + return { role, size, position: [x, y, z], dims, yaw } + } + // A run along an edge direction, its yaw taken along +s or +j, as the frame's own axes are. + const runYaw = (e: V2) => { + const flip = Math.abs(e[0]) >= Math.abs(e[1]) ? e[0] < 0 : e[1] < 0 + return flip ? yawOf(-e[0], -e[1]) : yawOf(e[0], e[1]) + } + const isConvex = (i: number) => { + const turn = cross(edges[(i - 1 + n) % n]!.e, edges[i]!.e) + return ccw ? turn > 1e-9 : turn < -1e-9 + } + const isReflex = (i: number) => { + const turn = cross(edges[(i - 1 + n) % n]!.e, edges[i]!.e) + return ccw ? turn < -1e-9 : turn > 1e-9 + } + + // ---- the ledger and the rims: one along every edge, a board the joist size inside it ---- + // Where an end edge meets a side edge, the end's board runs to the corner and the side's stops at + // it (at an inside corner the end's runs on past it), so the corners close. + for (let i = 0; i < n; i++) { + const edge = edges[i]! + const prev = edges[(i - 1 + n) % n]! + const next = edges[(i + 1) % n]! + const startTrim = + edge.kind === 'side' && prev.kind === 'end' && isConvex(i) + ? t + : edge.kind === 'end' && prev.kind === 'side' && isReflex(i) + ? -t + : 0 + const j1 = (i + 1) % n + const endTrim = + edge.kind === 'side' && next.kind === 'end' && isConvex(j1) + ? t + : edge.kind === 'end' && next.kind === 'side' && isReflex(j1) + ? -t + : 0 + const length = edge.length - startTrim - endTrim + if (length < t) continue + const mid = startTrim + length / 2 + const s = edge.a[0] + edge.e[0] * mid + edge.inward[0] * (t / 2) + const j = edge.a[1] + edge.e[1] * mid + edge.inward[1] * (t / 2) + const piece = pieceAt( + i === ledgerEdge ? 'ledger' : 'rim', + joist.size, + s, + j, + centerY, + [length, d, t], + runYaw(edge.e), + ) + if (i === ledgerEdge) plan.ledger = piece + else plan.rims.push(piece) + } + + // ---- the beams: under each end edge the joists run out to, and between past the table ---- + type BeamLine = { + /** The beam's centreline, frame coordinates, its full run inside the frame. */ + from: V2 + to: V2 + /** Its own edge, or null for one between. */ + edge: number | null + yaw: number + thickness: number + } + const lines: BeamLine[] = [] + const inset = dropped ? DECK_BEAM_INSET : t + t / 2 + edges.forEach((edge, i) => { + if (edge.kind !== 'end' || i === ledgerEdge) return + const offset: V2 = [edge.inward[0] * inset, edge.inward[1] * inset] + lines.push({ + from: [edge.a[0] + offset[0], edge.a[1] + offset[1]], + to: [edge.b[0] + offset[0], edge.b[1] + offset[1]], + edge: i, + yaw: runYaw(edge.e), + thickness: dropped ? beamLumber.thickness : t, + }) + }) + // The beams between: lines across the frame at even spacing, where it lies across them. + const middles: number[] = [] + if (bays > 1) { + const first = hung ? jMin : jMin + inset + const last = jMax - inset + for (let k = 1; k < bays; k++) middles.push(first + ((last - first) * k) / bays) + } + /** Where the frame lies across the line j = `j`: [s0, s1] runs, with the edges they end on. */ + const across = (j: number) => { + const hits: Array<{ s: number; edge: number }> = [] + edges.forEach((edge, i) => { + const { a, b } = edge + if ((a[1] <= j && j < b[1]) || (b[1] <= j && j < a[1])) + hits.push({ s: a[0] + ((j - a[1]) * (b[0] - a[0])) / (b[1] - a[1]), edge: i }) + }) + hits.sort((p, q) => p.s - q.s) + const runs: Array<[number, number]> = [] + for (let k = 0; k + 1 < hits.length; k += 2) runs.push([hits[k]!.s, hits[k + 1]!.s]) + return runs + } + for (const j of middles) + for (const [s0, s1] of across(j)) + lines.push({ + from: [s0, j], + to: [s1, j], + edge: null, + yaw: yawS, + thickness: dropped ? beamLumber.thickness : 2 * t, + }) + + const carriers = (input.carriers ?? []).map(toFrame) + const endInset = dropped ? DECK_POST_END_INSET : t + for (const line of lines) { + const dir = sub(line.to, line.from) + const full = Math.hypot(dir[0], dir[1]) + if (full < EPS) continue + const e: V2 = [dir[0] / full, dir[1] / full] + const length = full - 2 * endInset + if (length < DECK_POST.thickness) continue + const mid: V2 = [(line.from[0] + line.to[0]) / 2, (line.from[1] + line.to[1]) / 2] + const carried = + carriers.filter((c) => { + const along = dot(sub(c, line.from), e) + return ( + Math.abs(cross(e, sub(c, line.from))) <= CARRIER_REACH && + along >= -CARRIER_END_REACH && + along <= full + CARRIER_END_REACH + ) + }).length >= 2 + const beam = pieceAt( + 'beam', + beamLumber.size, + mid[0], + mid[1], + beamTop - beamLumber.depth / 2, + [length, beamLumber.depth, line.thickness], + line.yaw, + ) as DeckBeamPiece + beam.carried = carried + beam.between = line.edge === null + plan.beams.push(beam) + if (!canPost || carried) continue + const count = Math.max(2, Math.ceil(length / DECK_POST_SPACING) + 1) + const span = length - 2 * DECK_POST_END_INSET + for (let k = 0; k < count; k++) { + const along = -length / 2 + DECK_POST_END_INSET + (span * k) / (count - 1) + const s = mid[0] + e[0] * along + const j = mid[1] + e[1] * along + const [x, z] = toPlan(s, j) + const bottom = input.gradeAt ? input.gradeAt(x, z) : input.gradeY + const height = postTop - bottom + if (!(height >= MIN_DRAWN_POST)) continue + plan.posts.push({ + role: 'post', + size: DECK_POST.size, + position: [x, postTop - height / 2, z], + dims: [DECK_POST.thickness, height, DECK_POST.depth], + yaw: line.yaw, + bottom, + }) + } + } + + // ---- the joists: at the spacing from one side to the other, each run between its supports ---- + const flushEdges = new Set( + dropped ? [] : lines.flatMap((line) => (line.edge === null ? [] : [line.edge])), + ) + const stations: number[] = [] + for (let k = 0; ; k++) { + const s = sMin + t / 2 + k * spacing + if (s > sMax - t / 2 + EPS) break + stations.push(s) + } + if ((stations.at(-1) ?? Number.NEGATIVE_INFINITY) < sMax - t / 2 - EPS) + stations.push(sMax - t / 2) + plan.stationAxis = [S[0], S[1]] + plan.stations = stations + // A station on a side edge's board: the rim (or a ledger along the joists) is that joist. + const sideRims = edges.filter((edge) => edge.kind === 'side' && Math.abs(edge.e[0]) < 1e-6) + for (const s of stations) { + const hits: Array<{ j: number; edge: number }> = [] + edges.forEach((edge, i) => { + const { a, b } = edge + if ((a[0] <= s && s < b[0]) || (b[0] <= s && s < a[0])) + hits.push({ j: a[1] + ((s - a[0]) * (b[1] - a[1])) / (b[0] - a[0]), edge: i }) + }) + hits.sort((p, q) => p.j - q.j) + for (let k = 0; k + 1 < hits.length; k += 2) { + const lo = hits[k]! + const hi = hits[k + 1]! + // in past the board on the edge each end meets: the rim, the ledger, a flush beam's two + const band = (edge: number) => { + const thick = flushEdges.has(edge) ? 2 * t : t + return thick / Math.max(Math.abs(edges[edge]!.inward[1]), 0.3) + } + const hangsOn = (edge: number) => edge === ledgerEdge || flushEdges.has(edge) + const segments: Array<{ + j0: number + j1: number + hung0: boolean + hung1: boolean + yaw0: number + yaw1: number + }> = [ + { + j0: lo.j + band(lo.edge), + j1: hi.j - band(hi.edge), + hung0: hangsOn(lo.edge), + hung1: hangsOn(hi.edge), + yaw0: runYaw(edges[lo.edge]!.e), + yaw1: runYaw(edges[hi.edge]!.e), + }, + ] + // a flush beam between cuts the run: the joists hang on both its faces + if (!dropped) + for (const j of middles) { + const at = segments.findIndex((seg) => j - t > seg.j0 + EPS && j + t < seg.j1 - EPS) + if (at < 0) continue + const seg = segments[at]! + segments.splice( + at, + 1, + { ...seg, j1: j - t, hung1: true, yaw1: yawS }, + { ...seg, j0: j + t, hung0: true, yaw0: yawS }, + ) + } + const atRim = sideRims.some( + (edge) => + Math.abs(s - edge.a[0]) < t - EPS && + Math.max(edge.a[1], edge.b[1]) > lo.j + EPS && + Math.min(edge.a[1], edge.b[1]) < hi.j - EPS, + ) + for (const seg of segments) { + const length = seg.j1 - seg.j0 + if (length < t) continue + const piece = pieceAt( + 'joist', + joist.size, + s, + (seg.j0 + seg.j1) / 2, + centerY, + [length, d, t], + yawJ, + ) as DeckJoistPiece + piece.atRim = atRim + piece.hangers = [] + const hanger = (j: number, yaw: number) => { + const [x, z] = toPlan(s, j) + piece.hangers.push({ position: [x, centerY, z], yaw }) + } + if (seg.hung0) hanger(seg.j0 + HANGER_SEAT, seg.yaw0) + if (seg.hung1) hanger(seg.j1 - HANGER_SEAT, seg.yaw1) + plan.joists.push(piece) + } + } + } + return plan +} diff --git a/packages/core/src/lib/exterior-wall-loops.ts b/packages/core/src/lib/exterior-wall-loops.ts index b90e717e7b..e1bb679890 100644 --- a/packages/core/src/lib/exterior-wall-loops.ts +++ b/packages/core/src/lib/exterior-wall-loops.ts @@ -1,4 +1,5 @@ import type { WallNode } from '../schema' +import { isRailingWall } from '../schema/nodes/railing-wall' import { getWallCurveFrameAt, isCurvedWall } from '../systems/wall/wall-curve' import { dedupeSequentialPoints, @@ -16,7 +17,9 @@ import { distanceToSegment } from './room-topology-index' * The outside of a storey's walls: the unbounded faces of the planar wall * graph, walked the other way round from rooms. Facades fill these loops and * the wall tool selects them. Kept apart from the room kernel (`room-graph`), - * which only ever wants the bounded faces. + * which only ever wants the bounded faces. A railing closes rooms but holds no + * outside back (a deck's guard), so the loops are traced without railings: the + * outline of a house with a deck is its solid walls'. */ type WallFace = { @@ -403,7 +406,10 @@ export function enclosedWallIds( } function outerFaces(walls: WallNode[], joinTolerance: number) { - const loops = exteriorFaces(walls, Math.max(WALL_ENDPOINT_TOLERANCE, joinTolerance)) + const loops = exteriorFaces( + walls.filter((wall) => !isRailingWall(wall)), + Math.max(WALL_ENDPOINT_TOLERANCE, joinTolerance), + ) return loops.filter( (loop, index) => !loops.some((other, otherIndex) => { diff --git a/packages/core/src/lib/floor-plates.ts b/packages/core/src/lib/floor-plates.ts index 0e26bb864d..eb8905934b 100644 --- a/packages/core/src/lib/floor-plates.ts +++ b/packages/core/src/lib/floor-plates.ts @@ -4,6 +4,7 @@ import type { SurfaceHoleMetadata } from '../schema/nodes/surface-hole-metadata' import type { ZoneNode } from '../schema/nodes/zone' import { stairArrivalOpening } from '../systems/stair/stair-footprint' import { omitUndefined } from '../utils/omit-undefined' +import { deckBoardSettings, deckBoardThickness } from './deck-boards' import { automaticFloorHeight, floorPlateHoldsUnderside, @@ -16,8 +17,10 @@ import { exposedIntervals, plateFootprint, roomClearPolygon, + roomRailingFootprints, roomWallFootprints, } from './level-footprints' +import { isOutdoorRoomType, OUTDOOR_ROOM_DEFAULTS } from './outdoor-room' import { area, difference, intersection, type Polygon, union } from './polygon-boolean' import type { TopologyRoom } from './room-topology-index' import { autoRoomVerticalPlacements } from './room-vertical-placement' @@ -427,13 +430,21 @@ export function buildFloorPlates({ const componentOf = (room: PlateRoom) => components.find((component) => component.members.includes(room)) const baseOf = (room: PlateRoom) => componentOf(room)?.elevation ?? DEFAULT_SLAB_ELEVATION - const elevationOf = (room: PlateRoom) => intent.get(room.zone.id) ?? baseOf(room) + // A room stepped down from the floor it shares (a porch, `floor.drop`) follows that floor. + const elevationOf = (room: PlateRoom) => + intent.get(room.zone.id) ?? baseOf(room) - (room.zone.floor?.drop ?? 0) const thresholds = floorOpeningFootprints(grounded, elevationOf, nodes ?? {}) const interiors = new Map( grounded.map((room) => [ room.zone.id, union([ - Math.abs(elevationOf(room) - baseOf(room)) >= 0.001 - 1e-9 ? roomClearPolygon(room) : [], + Math.abs(elevationOf(room) - baseOf(room)) >= 0.001 - 1e-9 + ? // A porch or deck a step down takes its railings: they stand on its own floor, and + // the house's floor stops at the house wall rather than ringing it under them. + isOutdoorRoomType(room.zone.roomType) + ? union([...roomClearPolygon(room), ...roomRailingFootprints(room)]) + : roomClearPolygon(room) + : [], ...(thresholds.get(room.zone.id) ?? []), ]), ]), @@ -894,7 +905,7 @@ export function buildFloorPlates({ })) } if (plate.plateRole === 'base') delete (plate as Partial).fillToTerrain - return omitUndefined(plate) + return omitUndefined(withOutdoorFloorTag(plate, group.members)) }) const plateIds = new Set(plates.map((plate) => plate.id)) const retired = existing.filter((slab) => !used.has(slab.id) && !plateIds.has(slab.id)) @@ -911,6 +922,41 @@ export function buildFloorPlates({ return { plates, retired, remap } } +// The framing plugin's slab kinds an outdoor room's plate is tagged with (`OutdoorRoomDefaults`). +const OUTDOOR_FLOOR_TAGS = new Set(['porch-slab', 'deck']) + +/** + * A plate standing alone under one outdoor room (a porch, deck or patio stepped down from the + * house) is tagged for the framing plugin, as a drawn porch slab or deck is: `metadata.floor` + * (and, for a deck, its boards' thickness in `metadata.decking`, `lib/deck-boards`). Any other + * plate loses a tag it was given that way. These are interop fields for framing plugins + * (including Bones) and the Architect generator; built-in readers use zoneIds and roomType. + */ +function withOutdoorFloorTag(plate: SlabNode, members: readonly PlateRoom[]): SlabNode { + const type = members.length === 1 ? members[0]!.zone.roomType : undefined + const { + floor: tag, + decking: _decking, + ...rest + } = (plate.metadata ?? {}) as Record + const outdoor = plate.plateRole !== 'base' && isOutdoorRoomType(type) + if (!outdoor) { + if (!(typeof tag === 'string' && OUTDOOR_FLOOR_TAGS.has(tag))) return plate + return { ...plate, metadata: rest } + } + const floorTag = OUTDOOR_ROOM_DEFAULTS[type].floorTag + return { + ...plate, + metadata: { + ...rest, + floor: floorTag, + ...(floorTag === 'deck' + ? { decking: deckBoardThickness(deckBoardSettings(members[0]!.zone)) } + : {}), + }, + } +} + const warnedLevels = new Set() export function warnPlateFailure(levelId: string, ids: string[], error: unknown) { if (warnedLevels.has(levelId)) return diff --git a/packages/core/src/lib/framing-post.test.ts b/packages/core/src/lib/framing-post.test.ts new file mode 100644 index 0000000000..01388b1d5a --- /dev/null +++ b/packages/core/src/lib/framing-post.test.ts @@ -0,0 +1,152 @@ +import { describe, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + BeamNode, + BuildingNode, + ColumnNode, + LevelNode, + SiteNode, +} from '../schema' +import { + createFramingPost, + FRAMING_POST_MIN_HEIGHT, + framingPostBasePatch, + framingPostFields, + framingPostHeightLimit, + framingPostSize, + framingPostTopAt, + isFramingPost, +} from './framing-post' + +const IN = 0.0254 +const FT = 12 * IN +type Nodes = Record +const keyed = (nodes: AnyNode[]) => Object.fromEntries(nodes.map((n) => [n.id, n])) as Nodes + +function storey(beams: BeamNode[]) { + return keyed([ + SiteNode.parse({ id: 'site_a', children: ['building_a'] }), + BuildingNode.parse({ id: 'building_a', parentId: 'site_a', children: ['level_g'] }), + LevelNode.parse({ + id: 'level_g', + parentId: 'building_a', + level: 0, + height: 2.7, + children: beams.map((b) => b.id), + }), + ...beams, + ]) +} + +describe('framing posts', () => { + test('a post is a plain square column of its dressed size, pressure-treated, marked a post', () => { + const post = createFramingPost({ position: [3, 4], size: '4x4', height: 2.4 }) + expect(post.type).toBe('column') + expect(post).toMatchObject({ + role: 'post', + postBase: 'none', + style: 'plain', + crossSection: 'square', + position: [3, 0, 4], + height: 2.4, + baseStyle: 'none', + capitalStyle: 'none', + shaftStartScale: 1, + shaftEndScale: 1, + shaftCornerRadius: 0, + edgeSoftness: 0, + slots: { shaft: 'library:wood-woodplank19' }, + }) + expect(post.width).toBeCloseTo(3.5 * IN) + expect(post.depth).toBeCloseTo(3.5 * IN) + expect(isFramingPost(post)).toBe(true) + expect(framingPostSize(post)).toBe('4x4') + // ornamental columns are none of this + const column = ColumnNode.parse({}) + expect(isFramingPost(column)).toBe(false) + expect(column.role).toBeUndefined() + expect(column.postBase).toBeUndefined() + }) + + test('its height comes from its top and foot, never under the least a tool makes', () => { + expect( + createFramingPost({ position: [0, 0], baseElevation: 0.05, topElevation: 2.5 }).height, + ).toBeCloseTo(2.45) + // a deck post on the ground carries the grade as its own y + const deck = createFramingPost({ + position: [0, -0.4, 0], + topElevation: 1.6, + supportSlabId: 'ground', + levelId: 'level_g', + }) + expect(deck).toMatchObject({ + position: [0, -0.4, 0], + supportSlabId: 'ground', + parentId: 'level_g', + }) + expect(deck.height).toBeCloseTo(2) + expect(createFramingPost({ position: [0, 0], height: 0.01 }).height).toBe( + FRAMING_POST_MIN_HEIGHT, + ) + expect(createFramingPost({ position: [0, 0] }).height).toBeCloseTo(8 * FT) + }) + + test('a base is the column base block: a steel post base or a concrete pier', () => { + const pier = createFramingPost({ position: [0, 0], size: '6x6', base: 'pier', height: 2.4 }) + expect(pier).toMatchObject({ + postBase: 'pier', + baseStyle: 'simple-square', + slots: { shaft: 'library:wood-woodplank19', base: 'library:concrete-raw' }, + }) + expect(pier.baseHeight).toBeCloseTo(8 * IN) + expect(pier.width * pier.baseWidthScale).toBeCloseTo(11.5 * IN) + const stood = framingPostBasePatch(pier, 'post-base') + expect(stood).toMatchObject({ postBase: 'post-base', slots: { base: 'library:metal-steel' } }) + expect(stood.baseHeight).toBeCloseTo(1.5 * IN) + // taking the base off keeps the shaft's wood and drops the base's paint + expect(framingPostBasePatch(pier, 'none')).toEqual({ + postBase: 'none', + baseStyle: 'none', + baseHeight: 0, + baseWidthScale: 1, + baseDepthScale: 1, + slots: { shaft: 'library:wood-woodplank19' }, + }) + expect(framingPostFields('8x8').width).toBeCloseTo(7.25 * IN) + }) + + test('a post stands up to the underside of the beam over it, else the ceiling plane', () => { + const header = BeamNode.parse({ + id: 'beam_h', + parentId: 'level_g', + start: [0, 0], + end: [4, 0], + width: 5.5 * IN, + depth: 7.5 * IN, + }) + const nodes = storey([header]) + expect(framingPostTopAt(nodes, 'level_g', [4, 0], { baseElevation: 0.05 })).toEqual({ + top: 2.7 - 7.5 * IN, + beamId: 'beam_h', + }) + expect(framingPostTopAt(nodes, 'level_g', [8, 0])).toEqual({ top: 2.7, beamId: null }) + // a beam under the post's foot is not what it carries + const girder = { ...header, id: 'beam_g' as BeamNode['id'], topElevation: 0 } + const low = storey([girder]) + expect(framingPostTopAt(low, 'level_g', [2, 0], { baseElevation: 0.05 }).beamId).toBeNull() + }) + + test('a post taller than its size may stand on a deck is flagged', () => { + expect( + framingPostHeightLimit(createFramingPost({ position: [0, 0], size: '4x4', height: 9 * FT })), + ).toMatchObject({ + size: '4x4', + limit: expect.closeTo(8 * FT, 6), + }) + expect( + framingPostHeightLimit(createFramingPost({ position: [0, 0], size: '6x6', height: 9 * FT })), + ).toBeNull() + expect(framingPostHeightLimit(ColumnNode.parse({ height: 9 }))).toBeNull() + }) +}) diff --git a/packages/core/src/lib/framing-post.ts b/packages/core/src/lib/framing-post.ts new file mode 100644 index 0000000000..75ad113dfc --- /dev/null +++ b/packages/core/src/lib/framing-post.ts @@ -0,0 +1,250 @@ +import type { AnyNode, AnyNodeId } from '../schema' +import { ColumnNode, type ColumnPostBase } from '../schema/nodes/column' +import { getWallPlaneTop } from '../services/storey' +import { beamBottomElevation, beamsOverPoint } from './beam' + +type Nodes = Record + +const INCH = 0.0254 +const FOOT = 12 * INCH +/** The shortest post the tools make: under that a beam is sitting on the floor. */ +export const FRAMING_POST_MIN_HEIGHT = 0.3 +/** A post's height where nothing says otherwise: a porch's eight-foot post. */ +const DEFAULT_POST_HEIGHT = 8 * FOOT + +/** The square framing posts, by their actual dressed side: 3-1/2, 5-1/2 and 7-1/4 in. */ +export const FRAMING_POST_SIZES = { + '4x4': 3.5 * INCH, + '6x6': 5.5 * INCH, + '8x8': 7.25 * INCH, +} as const + +export type FramingPostSize = keyof typeof FRAMING_POST_SIZES + +export const DEFAULT_FRAMING_POST_SIZE: FramingPostSize = '6x6' + +/** + * The tallest each post may stand on a deck (IRC Table R507.4; the table also turns on the + * species and the area the post carries, so this is the check, not the design). + */ +export const FRAMING_POST_MAX_HEIGHT: Record = { + '4x4': 8 * FOOT, + '6x6': 11 * FOOT, + '8x8': 14 * FOOT, +} + +/** A framing post's wood: pressure-treated, as a post on a slab or the ground must be. */ +export const FRAMING_POST_MATERIAL_REF = 'library:wood-woodplank19' + +/** + * The bases a post stands on, drawn as the column's base block: a steel post base holding the + * wood an inch and a half off the concrete, or a concrete pier 8 in tall and 3 in wider than the + * post all round. + */ +const POST_BASES: Record< + Exclude, + { height: number; margin: number; material: string } +> = { + 'post-base': { height: 1.5 * INCH, margin: 0.25 * INCH, material: 'library:metal-steel' }, + pier: { height: 8 * INCH, margin: 3 * INCH, material: 'library:concrete-raw' }, +} + +export const FRAMING_POST_BASE_LABELS: Record = { + none: 'None', + 'post-base': 'Post base', + pier: 'Concrete pier', +} + +/** Whether a node is a framing post: a column marked `role: 'post'`. */ +export function isFramingPost(node: AnyNode | null | undefined): node is ColumnNode { + return node?.type === 'column' && node.role === 'post' +} + +/** The post size a column's section is, or null when it is none of them (or not square). */ +export function framingPostSize( + column: Pick, +): FramingPostSize | null { + for (const [size, side] of Object.entries(FRAMING_POST_SIZES) as [FramingPostSize, number][]) { + if (Math.abs(column.width - side) < INCH / 16 && Math.abs(column.depth - side) < INCH / 16) + return size + } + return null +} + +/** + * The column fields that set a post's base, the base block and its material together: a post with + * none starts straight off the floor. + */ +export function framingPostBasePatch( + post: Pick & { slots?: Record }, + base: ColumnPostBase, +): Partial { + const { base: _base, ...slots } = post.slots ?? {} + // The base scales stay at 1 with no base: the plan's footprint reads them whatever the style. + if (base === 'none') + return { + postBase: 'none', + baseStyle: 'none', + baseHeight: 0, + baseWidthScale: 1, + baseDepthScale: 1, + slots, + } + const { height, margin, material } = POST_BASES[base] + return { + postBase: base, + baseStyle: 'simple-square', + baseHeight: height, + baseWidthScale: Math.min(3, (post.width + margin * 2) / post.width), + baseDepthScale: Math.min(3, (post.depth + margin * 2) / post.depth), + slots: { ...slots, base: material }, + } +} + +/** + * The column fields that make a framing post: a plain square sawn post of `size`, sharp-cornered, + * its shaft the whole section with no capital, pressure-treated, on `base`. + */ +export function framingPostFields( + size: FramingPostSize = DEFAULT_FRAMING_POST_SIZE, + base: ColumnPostBase = 'none', +): Partial { + const side = FRAMING_POST_SIZES[size] + return { + role: 'post', + style: 'plain', + crossSection: 'square', + supportStyle: 'vertical', + width: side, + depth: side, + radius: side / 2, + edgeSoftness: 0, + shaftProfile: 'straight', + shaftTaper: 0, + shaftBulge: 0, + shaftStartScale: 1, + shaftEndScale: 1, + shaftSegmentCount: 1, + shaftTwistStep: 0, + shaftCornerRadius: 0, + shaftDetail: 'none', + capitalStyle: 'none', + capitalHeight: 0, + // No capital, but the plan's footprint reads its scales: the post's own size. + capitalWidthScale: 1, + capitalDepthScale: 1, + baseRoundBandCount: 0, + ringCount: 0, + fluteCount: 0, + spiralRibCount: 0, + panelCount: 0, + latheRingCount: 0, + carvingLevel: 0, + lowerBandEnabled: false, + dentilCount: 0, + beadCount: 0, + ...framingPostBasePatch( + { width: side, depth: side, slots: { shaft: FRAMING_POST_MATERIAL_REF } }, + base, + ), + } +} + +/** What `createFramingPost` builds a post from. */ +export type FramingPostInput = { + /** + * Where it stands: a level-local plan point `[x, z]`, or the column's `[x, y, z]` with `y` its + * foot over what it stands on (a deck post on the ground carries the grade there). + */ + position: readonly [number, number] | readonly [number, number, number] + size?: FramingPostSize + base?: ColumnPostBase + /** Its height, foot to top. Else `topElevation - baseElevation`, else eight feet. */ + height?: number + /** Its foot, level-local: the top of the slab or the ground it stands on. */ + baseElevation?: number + /** Its top, level-local: the underside of the beam it carries. */ + topElevation?: number + /** The level it goes on: its `parentId`. */ + levelId?: string + /** What it stands on: a slab id, or `'ground'` (`GROUND_SUPPORT_ID`). */ + supportSlabId?: string + rotation?: number + name?: string + metadata?: Record +} + +/** + * A framing post, as a column node ready for `createNode` on its level: what the Post tool places, + * and what code that frames a porch or a deck makes under its beams. + */ +export function createFramingPost(input: FramingPostInput): ColumnNode { + const size = input.size ?? DEFAULT_FRAMING_POST_SIZE + const position: [number, number, number] = + input.position.length === 3 + ? [input.position[0], input.position[1], input.position[2]] + : [input.position[0], 0, input.position[1]] + const height = + input.height ?? + (input.topElevation !== undefined + ? input.topElevation - (input.baseElevation ?? 0) - position[1] + : DEFAULT_POST_HEIGHT) + return ColumnNode.parse({ + name: input.name ?? 'Post', + ...framingPostFields(size, input.base ?? 'none'), + position, + rotation: input.rotation ?? 0, + height: Math.max(FRAMING_POST_MIN_HEIGHT, height), + ...(input.levelId ? { parentId: input.levelId } : {}), + ...(input.supportSlabId ? { supportSlabId: input.supportSlabId } : {}), + ...(input.metadata ? { metadata: input.metadata } : {}), + }) +} + +/** What a post at a plan point stands up to: the beam over it, else the ceiling plane. */ +export type FramingPostTop = { + /** Level-local Y of the post's top. */ + top: number + /** The beam it carries, when one is over it. */ + beamId: string | null +} + +/** + * Where the top of a post standing at a plan point of a level goes: the underside of the lowest + * beam over it that clears its foot (`baseElevation`), else the ceiling plane there (the top of + * the level's walls), as a post under a ceiling with no beam yet stands to it. + */ +export function framingPostTopAt( + nodes: Nodes, + levelId: string, + point: readonly [number, number], + options: { baseElevation?: number; side?: number } = {}, +): FramingPostTop { + const foot = options.baseElevation ?? 0 + for (const beam of beamsOverPoint(nodes, levelId, point)) { + const bottom = beamBottomElevation(nodes, beam) + if (bottom >= foot + FRAMING_POST_MIN_HEIGHT) return { top: bottom, beamId: beam.id } + } + const half = Math.max(options.side ?? FRAMING_POST_SIZES['6x6'], 0.02) / 2 + return { + top: getWallPlaneTop( + { start: [point[0] - half, point[1]], end: [point[0] + half, point[1]], thickness: half * 2 }, + levelId, + nodes, + ), + beamId: null, + } +} + +/** + * A post taller than its size may stand (`FRAMING_POST_MAX_HEIGHT`): the size and the limit, for + * the panel to warn with; null for a post within it or of no post size. + */ +export function framingPostHeightLimit( + post: Pick, +): { size: FramingPostSize; limit: number } | null { + const size = framingPostSize(post) + if (!size) return null + const limit = FRAMING_POST_MAX_HEIGHT[size] + return post.height > limit + 1e-6 ? { size, limit } : null +} diff --git a/packages/core/src/lib/generic-foundation.test.ts b/packages/core/src/lib/generic-foundation.test.ts index de09e2d88a..107892c1ac 100644 --- a/packages/core/src/lib/generic-foundation.test.ts +++ b/packages/core/src/lib/generic-foundation.test.ts @@ -10,6 +10,7 @@ import { LevelNode, nodeType, objectId, + railingWallDefaults, SiteNode, SlabNode, WallNode, @@ -462,3 +463,38 @@ test('the answer is worked out once per scene state', () => { }) afterEach(() => nodeRegistry._reset()) + +/** `house` with a 3 × 4 m deck off its east wall, fenced by three railings. */ +function withRailedDeck(house: Nodes): Nodes { + const corners: Array<[number, number]> = [ + [10, 2], + [13, 2], + [13, 6], + [10, 6], + ] + const railings = corners.slice(1).map((end, index) => + WallNode.parse({ + id: `wall_deck_${index}`, + parentId: 'level_g', + start: corners[index], + end, + ...railingWallDefaults(), + }), + ) + const level = house['level_g' as AnyNodeId] as LevelNode + return keyed([ + ...Object.values(house), + { ...level, children: [...level.children, ...railings.map((wall) => wall.id)] }, + ...railings, + ]) +} + +test('a railing carries no foundation: a deck it fences adds none, a ring of railings stands on none', () => { + const members = genericFoundation(withRailedDeck(flatHouse())) + expect(ofKind(members, 'footing')).toHaveLength(4) + expect(ofKind(members, 'stem')).toHaveLength(4) + expect(Math.max(...members.flatMap((member) => [member.from[0], member.to[0]]))).toBeLessThan( + 10.5, + ) + expect(genericFoundation(flatHouse({ wallExtra: railingWallDefaults() }))).toEqual([]) +}) diff --git a/packages/core/src/lib/level-footprints.ts b/packages/core/src/lib/level-footprints.ts index d5dfaa665c..c64d3d226a 100644 --- a/packages/core/src/lib/level-footprints.ts +++ b/packages/core/src/lib/level-footprints.ts @@ -1,4 +1,5 @@ import type { WallNode } from '../schema' +import { isRailingWall } from '../schema/nodes/railing-wall' import { getWallSurfacePolygon, isCurvedWall } from '../systems/wall/wall-curve' import { calculateLevelMiters, getWallPlanFootprint } from '../systems/wall/wall-footprint' import { getWallFaceLine } from '../systems/wall/wall-frame' @@ -195,6 +196,15 @@ export function roomWallFootprints(rooms: readonly TopologyRoom[]): MultiPolygon return union(boundaryFootprints(rooms).map(({ polygon }) => polygon)) } +/** The footprints of the railings round `room` (a deck's guard): no house wall among them. */ +export function roomRailingFootprints(room: TopologyRoom): MultiPolygon { + return union( + boundaryFootprints([room]) + .filter(({ id }) => isRailingWall(room.context.walls.get(id))) + .map(({ polygon }) => polygon), + ) +} + export function roomClearPolygon(room: TopologyRoom): MultiPolygon { const cached = clearCache.get(room) if (cached) return cached diff --git a/packages/core/src/lib/opening-casing.test.ts b/packages/core/src/lib/opening-casing.test.ts new file mode 100644 index 0000000000..1a38dc8d77 --- /dev/null +++ b/packages/core/src/lib/opening-casing.test.ts @@ -0,0 +1,181 @@ +import { describe, expect, test } from 'bun:test' +import { type AnyNode, DoorNode, RoofSegmentNode, WallNode, WindowNode } from '../schema' +import { + DEFAULT_OPENING_CASING_WIDTH, + OPENING_CASING_PROUD, + type OpeningCasingBoard, + openingCasingBoards, + openingCasingFaces, + resolveOpeningCasingHost, +} from './opening-casing' + +// Casing once sat inside the doors and windows. Now the cutout is the unit's +// own size and the casing is boards on the finished wall faces around it, on +// both faces unless one is turned off, 2 in wide. + +const INCH = 0.0254 +const host = { thickness: 0.2 } + +const window = (values: Record = {}) => + WindowNode.parse({ + id: 'window_c', + position: [2, 1.2, 0], + width: 1.2, + height: 1, + casingFaceA: true, + casingFaceB: true, + ...values, + }) +const door = (values: Record = {}) => + DoorNode.parse({ + id: 'door_c', + position: [2, 1.05, 0], + width: 0.9, + height: 2.1, + casingFaceA: true, + casingFaceB: true, + ...values, + }) + +const parts = (boards: OpeningCasingBoard[], face: 'a' | 'b') => + boards + .filter((board) => board.face === face) + .map((board) => board.part) + .sort() + +/** A board's extent along one axis of the host frame. */ +const span = (board: OpeningCasingBoard, axis: 0 | 1 | 2) => [ + board.center[axis] - board.size[axis] / 2, + board.center[axis] + board.size[axis] / 2, +] + +describe('opening casing schema', () => { + test('a door or window saved before casing loads without casing', () => { + for (const legacy of [ + WindowNode.parse({ id: 'window_old', width: 1.2, height: 1 }), + DoorNode.parse({ id: 'door_old', width: 0.9, height: 2.1 }), + ]) { + expect(legacy.casingFaceA).toBe(false) + expect(legacy.casingFaceB).toBe(false) + expect(openingCasingBoards(legacy, host)).toEqual([]) + expect(legacy.casingWidth).toBeCloseTo(2 * INCH, 12) + } + expect(DEFAULT_OPENING_CASING_WIDTH).toBeCloseTo(2 * INCH, 12) + expect(OPENING_CASING_PROUD).toBeCloseTo(0.75 * INCH, 12) + }) + + test('a casing face turned off stays off', () => { + const parsed = WindowNode.parse({ id: 'window_off', casingFaceA: false, casingWidth: 0.09 }) + expect(parsed.casingFaceA).toBe(false) + expect(parsed.casingFaceB).toBe(false) + expect(parsed.casingWidth).toBe(0.09) + }) +}) + +describe('opening casing boards', () => { + test('a window is a picture frame on each face; a door has no board at the floor', () => { + const windowBoards = openingCasingBoards(window({ sill: false }), host) + expect(parts(windowBoards, 'a')).toEqual(['bottom', 'head', 'leg', 'leg']) + expect(parts(windowBoards, 'b')).toEqual(['bottom', 'head', 'leg', 'leg']) + const doorBoards = openingCasingBoards(door(), host) + expect(parts(doorBoards, 'a')).toEqual(['head', 'leg', 'leg']) + expect(parts(doorBoards, 'b')).toEqual(['head', 'leg', 'leg']) + }) + + test('every board stands on a finished face, outside the opening', () => { + for (const opening of [window(), door()]) { + for (const board of openingCasingBoards(opening, host)) { + const [z0, z1] = span(board, 2) + if (board.face === 'a') { + expect(z0).toBeCloseTo(0.1, 12) + expect(z1).toBeCloseTo(0.1 + OPENING_CASING_PROUD, 12) + } else { + expect(z1).toBeCloseTo(-0.1, 12) + expect(z0).toBeCloseTo(-0.1 - OPENING_CASING_PROUD, 12) + } + const [x0, x1] = span(board, 0) + const [y0, y1] = span(board, 1) + const beside = x0 >= opening.width / 2 - 1e-12 || x1 <= -opening.width / 2 + 1e-12 + const aboveOrBelow = y0 >= opening.height / 2 - 1e-12 || y1 <= -opening.height / 2 + 1e-12 + expect(beside || aboveOrBelow).toBe(true) + } + } + }) + + test('the boards are as wide as the casing, and butt: head and bottom run over the legs', () => { + const boards = openingCasingBoards(window({ casingWidth: 3 * INCH }), host) + const head = boards.find((board) => board.part === 'head')! + const leg = boards.find((board) => board.part === 'leg')! + expect(head.size[1]).toBeCloseTo(3 * INCH, 12) + expect(head.size[0]).toBeCloseTo(1.2 + 6 * INCH, 12) + expect(leg.size[0]).toBeCloseTo(3 * INCH, 12) + expect(leg.size[1]).toBeCloseTo(1, 12) + }) + + test('a face turned off has no boards', () => { + const boards = openingCasingBoards(door({ casingFaceB: false }), host) + expect(boards.length).toBeGreaterThan(0) + expect(boards.every((board) => board.face === 'a')).toBe(true) + expect(openingCasingBoards(door({ casingFaceA: false, casingFaceB: false }), host)).toEqual([]) + }) + + test('an opening off the wall centre still cases the wall faces', () => { + const faces = openingCasingFaces(window({ position: [2, 1.2, 0.05] }), host) + expect(faces).toEqual([ + { face: 'a', plane: 0.05, out: 1 }, + { face: 'b', plane: -0.15000000000000002, out: -1 }, + ]) + }) + + test('a sill takes the bottom board under it, on the window’s own front only', () => { + const drop = 0.03 + for (const [rotationY, front] of [ + [0, 'a'], + [Math.PI, 'b'], + ] as const) { + const boards = openingCasingBoards( + window({ sill: true, sillThickness: drop, rotation: [0, rotationY, 0] }), + host, + ) + const bottomTop = (face: 'a' | 'b') => + span(boards.find((board) => board.face === face && board.part === 'bottom')!, 1)[1] + const back = front === 'a' ? 'b' : 'a' + expect(bottomTop(front)).toBeCloseTo(-0.5 - drop, 12) + expect(bottomTop(back)).toBeCloseTo(-0.5, 12) + expect(parts(boards, front)).toEqual(['bottom', 'foot', 'foot', 'head', 'leg', 'leg']) + } + }) + + test('a corner window has no leg at its corner, and its head stops there', () => { + const boards = openingCasingBoards(window(), { ...host, cornerEnd: 'end' }) + const legs = boards.filter((board) => board.face === 'a' && board.part === 'leg') + expect(legs).toHaveLength(1) + expect(legs[0]!.center[0]).toBeLessThan(0) + const head = boards.find((board) => board.face === 'a' && board.part === 'head')! + expect(span(head, 0)[1]).toBeCloseTo(0.6, 12) + }) +}) + +describe('opening casing host', () => { + const wall = WallNode.parse({ id: 'wall_c', start: [0, 0], end: [4, 0], thickness: 0.15 }) + + test('a wall cases on its own thickness; a curtain wall or a scripted unit takes none', () => { + const nodes = { [wall.id]: wall } as Record + expect(resolveOpeningCasingHost(window({ parentId: wall.id }), nodes)).toEqual({ + thickness: 0.15, + }) + const curtain = { ...wall, wallType: 'curtain' as const } + expect(resolveOpeningCasingHost(window({ parentId: wall.id }), { [wall.id]: curtain })).toBe( + null, + ) + expect(resolveOpeningCasingHost(window(), nodes)).toBe(null) + }) + + test('a gable-end opening cases on the roof segment’s wall', () => { + const segment = RoofSegmentNode.parse({ id: 'rseg_c', wallThickness: 0.18 }) + const opening = window({ roofSegmentId: segment.id, roofFace: 'front', parentId: segment.id }) + expect( + resolveOpeningCasingHost(opening, { [segment.id]: segment } as Record), + ).toEqual({ thickness: 0.18 }) + }) +}) diff --git a/packages/core/src/lib/opening-casing.ts b/packages/core/src/lib/opening-casing.ts new file mode 100644 index 0000000000..4ee90dfe61 --- /dev/null +++ b/packages/core/src/lib/opening-casing.ts @@ -0,0 +1,149 @@ +import type { AnyNode, DoorNode, WallFace, WindowNode } from '../schema' +import { DEFAULT_OPENING_CASING_WIDTH, OPENING_CASING_PROUD } from '../schema/nodes/opening-types' +import { DEFAULT_WALL_THICKNESS, getWallThickness } from '../systems/wall/wall-footprint' +import { cornerPair } from './corner-pair' + +/** + * Door and window casing: flat boards on the finished faces of the host wall + * around the opening, over the drywall or siding. The wall cutout is the unit's + * own width × height and the casing never reaches into it: each board starts at + * the cutout's edge and runs outward, `OPENING_CASING_PROUD` off the face. A + * window gets a picture frame (head, two legs, bottom), a door a head and two + * legs, butted at the corners: the head and bottom run the full width over the + * legs' ends. + * + * Everything here is in the host frame, centred on the opening: x along the + * host toward its end, y up, z across it toward face `a`. The 3D builders turn + * that into the unit's own frame (a unit facing the back is turned half round, + * see `openingHostFacing`); the plan draws it as it is. + */ + +export { DEFAULT_OPENING_CASING_WIDTH, OPENING_CASING_PROUD } + +type CasedOpening = DoorNode | WindowNode +/** From and to along one axis of the host frame (m). */ +type Span = readonly [number, number] + +export type OpeningCasingHost = { + /** The host's total thickness with its finishes: each face is half of it off the mid-plane (m). */ + thickness: number + /** The host end a corner window runs to: no leg there; the head and bottom stop at the opening. */ + cornerEnd?: 'start' | 'end' +} + +export type OpeningCasingFace = { + face: WallFace + /** Across the host, from the opening's centre plane to the finished face (m). */ + plane: number + /** The way the face looks across the host: +1 for `a`, -1 for `b`. */ + out: 1 | -1 +} + +export type OpeningCasingBoard = { + face: WallFace + /** + * `leg` boards stand beside the opening, the part a plan cut shows. A `foot` carries a leg on + * down past a window's sill to the bottom board, which sits under the sill on that face. + */ + part: 'head' | 'leg' | 'foot' | 'bottom' + /** Centre, from the opening's centre in the host frame (m). */ + center: [number, number, number] + /** Along the host, up, across it (m). */ + size: [number, number, number] +} + +/** The face width of an opening's casing boards; a save from before casing has the default. */ +export function openingCasingWidth(opening: Pick): number { + const width = opening.casingWidth + return typeof width === 'number' && width > 0 ? width : DEFAULT_OPENING_CASING_WIDTH +} + +/** + * +1 when the unit faces the host's front (its own +z is face `a`), -1 when it is turned half + * round to face the back, which mirrors its x and z against the host's. + */ +export function openingHostFacing(opening: Pick): 1 | -1 { + return Math.cos(opening.rotation?.[1] ?? 0) >= 0 ? 1 : -1 +} + +/** + * The host an opening is cased on: its wall, or the roof-segment face it is cut into (a gable + * end, whose face `a` is the outside). Null where casing has nowhere to go: a curtain wall, a + * railing (its openings are gaps in the guard), a dormer face, a unit built from a script (its + * script draws its own trim). + */ +export function resolveOpeningCasingHost( + opening: CasedOpening, + nodes: Readonly>, + host: AnyNode | undefined = nodes[opening.roofSegmentId ?? opening.parentId ?? ''], +): OpeningCasingHost | null { + if (opening.source) return null + if (opening.roofSegmentId) { + return host?.type === 'roof-segment' + ? { thickness: host.wallThickness ?? DEFAULT_WALL_THICKNESS } + : null + } + if (host?.type !== 'wall' || host.wallType === 'curtain' || host.wallType === 'railing') + return null + const pair = opening.type === 'window' ? cornerPair(nodes, opening) : null + return { thickness: getWallThickness(host), ...(pair ? { cornerEnd: pair.end } : {}) } +} + +/** The host faces an opening is cased on: both unless turned off (a save from before has both). */ +export function openingCasingFaces( + opening: Pick, + host: OpeningCasingHost, +): OpeningCasingFace[] { + const offset = opening.position[2] ?? 0 + const half = host.thickness / 2 + const faces: OpeningCasingFace[] = [] + if (opening.casingFaceA === true) faces.push({ face: 'a', plane: half - offset, out: 1 }) + if (opening.casingFaceB === true) faces.push({ face: 'b', plane: -half - offset, out: -1 }) + return faces +} + +/** How far a window's sill takes the bottom board down on `face`: its thickness, on its front. */ +function sillDrop(opening: CasedOpening, face: WallFace): number { + if (opening.type !== 'window' || !opening.sill || opening.openingKind === 'opening') return 0 + const front: WallFace = openingHostFacing(opening) === 1 ? 'a' : 'b' + return face === front ? Math.max(opening.sillThickness ?? 0, 0) : 0 +} + +/** The casing boards of a rectangular opening on each face it is cased on, in the host frame. */ +export function openingCasingBoards( + opening: CasedOpening, + host: OpeningCasingHost, +): OpeningCasingBoard[] { + const width = openingCasingWidth(opening) + const proud = OPENING_CASING_PROUD + const halfWidth = opening.width / 2 + const halfHeight = opening.height / 2 + const corner = host.cornerEnd === 'start' ? -1 : host.cornerEnd === 'end' ? 1 : 0 + const left = -halfWidth - (corner === -1 ? 0 : width) + const right = halfWidth + (corner === 1 ? 0 : width) + const legs = ([-1, 1] as const) + .filter((side) => side !== corner) + .map( + (side): Span => + side < 0 ? [-halfWidth - width, -halfWidth] : [halfWidth, halfWidth + width], + ) + const boards: OpeningCasingBoard[] = [] + for (const { face, plane, out } of openingCasingFaces(opening, host)) { + const z = plane + (out * proud) / 2 + const board = (part: OpeningCasingBoard['part'], [x0, x1]: Span, [y0, y1]: Span) => + boards.push({ + face, + part, + center: [(x0 + x1) / 2, (y0 + y1) / 2, z], + size: [x1 - x0, y1 - y0, proud], + }) + board('head', [left, right], [halfHeight, halfHeight + width]) + for (const along of legs) board('leg', along, [-halfHeight, halfHeight]) + if (opening.type !== 'window') continue + const drop = sillDrop(opening, face) + if (drop > 1e-6) + for (const along of legs) board('foot', along, [-halfHeight - drop, -halfHeight]) + board('bottom', [left, right], [-halfHeight - drop - width, -halfHeight - drop]) + } + return boards +} diff --git a/packages/core/src/lib/opening-frame-depth.test.ts b/packages/core/src/lib/opening-frame-depth.test.ts index edd1fc8b64..0396684e30 100644 --- a/packages/core/src/lib/opening-frame-depth.test.ts +++ b/packages/core/src/lib/opening-frame-depth.test.ts @@ -2,19 +2,20 @@ import { expect, test } from 'bun:test' import { DoorNode, WallNode, WindowNode } from '../schema' import { isAutoFrameDepth, - OPENING_FRAME_LIP, resolveHostedOpeningFrameDepth, resolveOpeningFrameDepth, } from './opening-frame-depth' -test('an opening with no frame depth takes its wall thickness plus a lip on each face', () => { +test('auto depth is exactly the wall thickness for doors and windows', () => { const door = DoorNode.parse({ id: 'door_auto', position: [1, 1.05, 0] }) const window = WindowNode.parse({ id: 'window_auto', position: [1, 1.5, 0] }) expect(isAutoFrameDepth(door)).toBe(true) expect(isAutoFrameDepth(window)).toBe(true) - expect(resolveOpeningFrameDepth(door, 0.2)).toBeCloseTo(0.2 + OPENING_FRAME_LIP * 2, 9) - expect(resolveOpeningFrameDepth(window, 0.1)).toBeCloseTo(0.12, 9) - expect(resolveOpeningFrameDepth(door, 0.35)).toBeCloseTo(0.37, 9) + expect(resolveOpeningFrameDepth(door, 0.2)).toBeCloseTo(0.2, 9) + expect(resolveOpeningFrameDepth(window, 0.1)).toBeCloseTo(0.1, 9) + expect(resolveOpeningFrameDepth(window, 0.35)).toBeCloseTo(0.35, 9) + expect(resolveOpeningFrameDepth({ ...window, frameDepth: 0.07 }, 0.35)).toBe(0.07) + expect(resolveOpeningFrameDepth(door, 0.35)).toBeCloseTo(0.35, 9) }) test('an explicit frame depth stays whatever the wall is', () => { @@ -37,15 +38,15 @@ test('a hosted opening resolves against its parent wall, and re-resolves on a th const thick = WallNode.parse({ id: 'wall_thick', start: [0, 4], end: [4, 4], thickness: 0.3 }) const nodes = { [thin.id]: thin, [thick.id]: thick } const door = DoorNode.parse({ id: 'door_hosted', parentId: thin.id, position: [2, 1.05, 0] }) - expect(resolveHostedOpeningFrameDepth(door, nodes)).toBeCloseTo(0.12, 9) - expect(resolveHostedOpeningFrameDepth({ ...door, parentId: thick.id }, nodes)).toBeCloseTo( - 0.32, - 9, - ) + expect(resolveHostedOpeningFrameDepth(door, nodes)).toBeCloseTo(0.1, 9) + expect(resolveHostedOpeningFrameDepth({ ...door, parentId: thick.id }, nodes)).toBeCloseTo(0.3, 9) // Off a wall (a roof face, a preview with no parent) the default wall thickness stands in. expect(resolveHostedOpeningFrameDepth({ ...door, parentId: undefined }, nodes)).toBeCloseTo( - 0.12, + 0.1, 9, ) expect(resolveHostedOpeningFrameDepth({ ...door, frameDepth: 0.07 }, nodes)).toBe(0.07) + const window = WindowNode.parse({ parentId: thin.id }) + expect(resolveHostedOpeningFrameDepth(window, nodes)).toBe(0.1) + expect(resolveHostedOpeningFrameDepth({ ...window, parentId: thick.id }, nodes)).toBe(0.3) }) diff --git a/packages/core/src/lib/opening-frame-depth.ts b/packages/core/src/lib/opening-frame-depth.ts index 84c08704b3..ac6c041a88 100644 --- a/packages/core/src/lib/opening-frame-depth.ts +++ b/packages/core/src/lib/opening-frame-depth.ts @@ -1,9 +1,6 @@ import type { AnyNode, DoorNode, WindowNode } from '../schema' import { DEFAULT_WALL_THICKNESS, getWallThickness } from '../systems/wall/wall-footprint' -/** How far an auto-depth frame stands proud of each wall face. */ -export const OPENING_FRAME_LIP = 0.01 - type FrameDepthOpening = Pick /** An opening without an explicit frame depth follows its host wall. */ @@ -14,14 +11,13 @@ export function isAutoFrameDepth(opening: FrameDepthOpening): boolean { /** * The depth a door's or window's frame runs through its wall. An explicit * `frameDepth` is kept as stored; left out, the frame is the host wall's - * thickness plus a lip on each face, so the wall's cut faces never show - * around it whatever the wall is. + * thickness exactly. */ export function resolveOpeningFrameDepth( opening: FrameDepthOpening, wallThickness: number, ): number { - return opening.frameDepth ?? wallThickness + OPENING_FRAME_LIP * 2 + return opening.frameDepth ?? wallThickness } /** diff --git a/packages/core/src/lib/outdoor-room.test.ts b/packages/core/src/lib/outdoor-room.test.ts new file mode 100644 index 0000000000..0a7791a10d --- /dev/null +++ b/packages/core/src/lib/outdoor-room.test.ts @@ -0,0 +1,554 @@ +import { describe, expect, test } from 'bun:test' +import { setZoneIntent } from '../commands/structure/set-zone-intent' +import { applyToScratch, structureChangeBatch } from '../commands/structure/shared' +import { enclosed } from '../commands/structure/structure.test' +import { type AnyNode, type AnyNodeId, type SlabNode, WallNode, type ZoneNode } from '../schema' +import type { BeamNode } from '../schema/nodes/beam' +import type { ColumnNode } from '../schema/nodes/column' +import { railingWallDefaults } from '../schema/nodes/railing-wall' +import { derivedDeletionIntent } from '../store/derived-node-guard' +import { getWallThickness } from '../systems/wall/wall-footprint' +import { planSeparatorInsertion } from '../systems/wall/wall-topology' +import { beamBottomElevation } from './beam' +import { FRAMING_POST_SIZES } from './framing-post' +import { DECK_FLOOR_DROP, DECKING_THICKNESS, PORCH_FLOOR_DROP } from './outdoor-room' +import { PORCH_POST_SETBACK } from './porch-framing' +import { porchPartOf } from './porch-framing-sync' +import { reconcileLevelStructure } from './structure-kernel' +import { reconcileSceneStructure } from './structure-reconcile' + +const LEVEL = 'level_test' + +/** Settle the level's structure the way the live sync does after an edit. */ +function settle(before: Record, after: Record) { + let i = 0 + const derived = reconcileLevelStructure({ + levelId: LEVEL, + nodes: after, + previousNodes: before, + mintId: (kind) => { + let id: string + do id = `${kind}_derived${++i}` + while (after[id]) + return id + }, + }) + return applyToScratch(after, structureChangeBatch(derived.patches)) +} + +/** The kitchen (an 8 × 4 room) with invisible walls closing off a porch on its z = 4 side. */ +function withPorch() { + const { nodes } = enclosed() + let next: Record = nodes + let n = 0 + for (const [start, end] of [ + [ + [2, 4], + [2, 6], + ], + [ + [2, 6], + [6, 6], + ], + [ + [6, 6], + [6, 4], + ], + ] as Array<[[number, number], [number, number]]>) { + const plan = planSeparatorInsertion(next as Record, { + levelId: LEVEL as AnyNodeId, + start, + end, + joinRadius: 0.05, + mintId: () => `separator_test${++n}`, + }) + expect(plan).not.toBeNull() + next = applyToScratch(next, plan!.changes) + } + return settle(nodes, next) +} + +const zones = (nodes: Record) => + Object.values(nodes).filter((node): node is ZoneNode => node.type === 'zone') +const plates = (nodes: Record) => + Object.values(nodes).filter((node): node is SlabNode => node.type === 'slab') + +describe('a room closed off outside the house by invisible walls', () => { + test('is a porch: concrete, a step down, covered', () => { + const nodes = withPorch() + const porch = zones(nodes).find((zone) => zone.roomType === 'porch')! + expect(porch).toBeDefined() + expect(porch.name).toBe('Porch') + expect(porch.floor?.drop).toBeCloseTo(PORCH_FLOOR_DROP, 9) + expect(porch.hasCeiling).toBeUndefined() + expect(zones(nodes).find((zone) => zone.name === 'Kitchen')?.roomType).toBeUndefined() + }) + + test('its floor plate steps down from the house and is a porch slab', () => { + const nodes = withPorch() + const porch = zones(nodes).find((zone) => zone.roomType === 'porch')! + const base = plates(nodes).find((plate) => plate.plateRole === 'base')! + const own = plates(nodes).find((plate) => plate.zoneIds?.includes(porch.id) && plate !== base)! + expect(own.elevation).toBeCloseTo(base.elevation - PORCH_FLOOR_DROP, 6) + expect(own.metadata?.floor).toBe('porch-slab') + }) + + test('the house wall it faces is an outside wall there, even under its ceiling', () => { + const nodes = withPorch() + const wall = Object.values(nodes).find( + (node): node is WallNode => node.type === 'wall' && node.start[1] === 4 && node.end[1] === 4, + )! + expect([wall.frontSide, wall.backSide].sort()).toEqual(['exterior', 'interior']) + }) + + test('invisible walls never cut the wall they meet', () => { + const nodes = withPorch() + const walls = Object.values(nodes).filter((node) => node.type === 'wall') + expect(walls).toHaveLength(4) + }) +}) + +/** The kitchen with a room off its z = 4 side: railings on `railed` sides, invisible walls on the rest. */ +function withRailings(railed: ReadonlySet) { + const { nodes } = enclosed() + let next: Record = nodes + const sides: Array<[[number, number], [number, number]]> = [ + [ + [2, 4], + [2, 6], + ], + [ + [2, 6], + [6, 6], + ], + [ + [6, 6], + [6, 4], + ], + ] + sides.forEach(([start, end], index) => { + if (railed.has(index)) { + const railing = WallNode.parse({ + ...railingWallDefaults(), + id: `wall_railing${index}`, + parentId: LEVEL, + start, + end, + }) + next = { ...next, [railing.id]: railing } + return + } + const plan = planSeparatorInsertion(next as Record, { + levelId: LEVEL as AnyNodeId, + start, + end, + joinRadius: 0.05, + mintId: () => `separator_rail${index}`, + }) + next = applyToScratch(next, plan!.changes) + }) + return settle(nodes, next) +} + +describe('a room fenced off outside the house by railings', () => { + test('is a deck: boards, 1 in down, no ceiling, framed', () => { + const nodes = withRailings(new Set([0, 1, 2])) + const deck = zones(nodes).find((zone) => zone.roomType === 'deck')! + expect(deck).toBeDefined() + expect(deck.name).toBe('Deck') + expect(deck.hasCeiling).toBe(false) + expect(deck.floor?.drop).toBeCloseTo(DECK_FLOOR_DROP, 9) + expect( + plates(nodes).find((slab) => slab.zoneIds?.includes(deck.id) && slab.plateRole !== 'base') + ?.metadata?.floor, + ).toBe('deck') + expect( + Object.values(nodes).some((node) => node.type === 'ceiling' && node.zoneId === deck.id), + ).toBe(false) + }) + + test("its railings stand on its own floor: the house's floor stops at the house wall", () => { + const nodes = withRailings(new Set([0, 1, 2])) + const deck = zones(nodes).find((zone) => zone.roomType === 'deck')! + const base = plates(nodes).find((plate) => plate.plateRole === 'base')! + const own = plates(nodes).find( + (plate) => plate.plateRole !== 'base' && plate.zoneIds?.includes(deck.id), + )! + const houseWall = Object.values(nodes).find( + (node): node is WallNode => + node.type === 'wall' && + node.wallType !== 'railing' && + node.start[1] === 4 && + node.end[1] === 4, + )! + const railing = railingWallDefaults().thickness + const bounds = (polygon: Array<[number, number]>) => ({ + minX: Math.min(...polygon.map(([x]) => x)), + maxX: Math.max(...polygon.map(([x]) => x)), + minZ: Math.min(...polygon.map(([, z]) => z)), + maxZ: Math.max(...polygon.map(([, z]) => z)), + }) + // No ring of house floor under the railings, and no hole cut for the deck in it. + const face = 4 + getWallThickness(houseWall) / 2 + expect(bounds(base.polygon).maxZ).toBeCloseTo(face, 3) + expect(base.holes).toEqual([]) + // The deck's floor runs from the house wall's face out to the railings' outside faces. + const deckBounds = bounds(own.polygon) + expect(deckBounds.minZ).toBeCloseTo(face, 3) + expect(deckBounds.maxZ).toBeCloseTo(6 + railing / 2, 3) + expect(deckBounds.minX).toBeCloseTo(2 - railing / 2, 3) + expect(deckBounds.maxX).toBeCloseTo(6 + railing / 2, 3) + }) + + test('closed with invisible walls as well, it is a porch, posts and beam along its railings too', () => { + const nodes = withRailings(new Set([0, 2])) + const porch = zones(nodes).find((zone) => zone.roomType === 'porch')! + expect(porch).toBeDefined() + expect( + Object.values(nodes).filter( + (node) => node.type === 'beam' && porchPartOf(node)?.porchOf === porch.id, + ), + ).toHaveLength(3) + }) +}) + +describe('room type', () => { + test('a porch made a deck steps 1 in down, takes boards, loses its ceiling and its name', () => { + const nodes = withPorch() + const porch = zones(nodes).find((zone) => zone.roomType === 'porch')! + const plan = setZoneIntent(nodes, { zoneId: porch.id, patch: { roomType: 'deck' } }) + expect(plan.conflicts).toBeUndefined() + const changed = applyToScratch(nodes, structureChangeBatch(plan.changes)) + const after = settle(nodes, changed) + const deck = after[porch.id] as ZoneNode + expect(deck.roomType).toBe('deck') + expect(deck.name).toBe('Deck') + expect(deck.hasCeiling).toBe(false) + expect(deck.floor?.drop).toBeCloseTo(DECK_FLOOR_DROP, 9) + expect(deck.floor?.finish).toBe('library:wood-woodfine11') + const plate = plates(after).find( + (slab) => slab.zoneIds?.includes(deck.id) && slab.plateRole !== 'base', + )! + expect(plate.metadata?.floor).toBe('deck') + expect(plate.metadata?.decking).toBeCloseTo(DECKING_THICKNESS, 9) + }) + + test('back to an ordinary room drops what the type brought, keeping a picked finish', () => { + const nodes = withPorch() + const porch = zones(nodes).find((zone) => zone.roomType === 'porch')! + const picked = applyToScratch( + nodes, + structureChangeBatch( + setZoneIntent(nodes, { + zoneId: porch.id, + patch: { floor: { finish: 'library:tile-floor1' } }, + }).changes, + ), + ) + const plan = setZoneIntent(picked, { zoneId: porch.id, patch: { roomType: null } }) + const room = applyToScratch(picked, structureChangeBatch(plan.changes))[porch.id] as ZoneNode + expect(room.roomType).toBeUndefined() + expect(room.floor?.drop).toBeUndefined() + expect(room.floor?.finish).toBe('library:tile-floor1') + expect(room.hasCeiling).toBeUndefined() + }) +}) + +describe('planSeparatorInsertion', () => { + test('joins a wall it ends on at its reference line and breaks across a wall it crosses', () => { + const { nodes } = enclosed() + // From inside the kitchen, through its z = 4 wall, to 2 m outside. + const plan = planSeparatorInsertion(nodes as Record, { + levelId: LEVEL as AnyNodeId, + start: [3, 0.03], + end: [3, 6], + joinRadius: 0.05, + })! + expect(plan.resolvedStart).toEqual([3, 0]) + expect(plan.separators.map((separator) => [separator.start, separator.end])).toEqual([ + [ + [3, 0], + [3, 4], + ], + [ + [3, 4], + [3, 6], + ], + ]) + expect(plan.changes.update).toEqual([]) + expect(plan.changes.delete).toEqual([]) + }) + + test('drawn over an invisible wall or along a wall, adds only what is not there', () => { + const nodes = withPorch() as Record + const draw = (start: [number, number], end: [number, number]) => + planSeparatorInsertion(nodes, { levelId: LEVEL as AnyNodeId, start, end, joinRadius: 0.05 }) + expect(draw([2, 6], [6, 6])).toBeNull() + expect(draw([6, 6], [2, 6])).toBeNull() + expect(draw([1, 0], [3, 0])).toBeNull() + expect( + draw([0, 6], [6, 6])!.separators.map((separator) => [separator.start, separator.end]), + ).toEqual([ + [ + [0, 6], + [2, 6], + ], + ]) + }) +}) + +const porchOf = (nodes: Record) => + zones(nodes).find((zone) => zone.roomType === 'porch')! +const posts = (nodes: Record, zoneId: string) => + Object.values(nodes).filter( + (node): node is ColumnNode => node.type === 'column' && porchPartOf(node)?.porchOf === zoneId, + ) +const beams = (nodes: Record, zoneId: string) => + Object.values(nodes).filter( + (node): node is BeamNode => node.type === 'beam' && porchPartOf(node)?.porchOf === zoneId, + ) +const edit = (nodes: Record, id: string, data: Partial) => + ({ ...nodes, [id]: { ...nodes[id], ...data } }) as Record +const intent = ( + nodes: Record, + zoneId: string, + patch: Parameters[1]['patch'], +) => + settle( + nodes, + applyToScratch(nodes, structureChangeBatch(setZoneIntent(nodes, { zoneId, patch }).changes)), + ) +const inset = FRAMING_POST_SIZES['6x6'] / 2 + PORCH_POST_SETBACK + +describe('a covered porch frames itself', () => { + test('posts on its outside corners and between, a beam along each open side', () => { + const nodes = withPorch() + const porch = porchOf(nodes) + const standing = posts(nodes, porch.id) + // The 4 m front: a post at each corner and one between; the 2 m sides need none between. + expect(standing.map((post) => [post.position[0], post.position[2]]).sort()).toEqual( + [ + [2 + inset, 6 - inset], + [4, 6 - inset], + [6 - inset, 6 - inset], + ].map(([x, z]) => [expect.closeTo(x!, 9), expect.closeTo(z!, 9)]) as never, + ) + expect(beams(nodes, porch.id)).toHaveLength(3) + expect( + standing.every((post) => post.role === 'post' && post.width === FRAMING_POST_SIZES['6x6']), + ).toBe(true) + }) + + test('the posts stand on the porch slab, up to the underside of the beam', () => { + const nodes = withPorch() + const porch = porchOf(nodes) + const plate = plates(nodes).find( + (slab) => slab.zoneIds?.includes(porch.id) && slab.plateRole !== 'base', + )! + const front = beams(nodes, porch.id).find((beam) => beam.start[1] === beam.end[1])! + for (const post of posts(nodes, porch.id)) { + expect(post.supportSlabId).toBe(plate.id) + expect(plate.elevation + post.height).toBeCloseTo( + beamBottomElevation(nodes as never, front), + 6, + ) + } + }) + + test('moves with the porch', () => { + const before = withPorch() + const porch = porchOf(before) + let moved: Record = before + for (const node of Object.values(before)) + if (node.type === 'separator') + moved = edit(moved, node.id, { + start: [node.start[0], node.start[1] === 6 ? 6.5 : node.start[1]], + end: [node.end[0], node.end[1] === 6 ? 6.5 : node.end[1]], + } as never) + const after = settle(before, moved) + expect(porchOf(after).id).toBe(porch.id) + expect(posts(after, porch.id).map((post) => post.position[2])).toEqual( + [6.5 - inset, 6.5 - inset, 6.5 - inset].map((z) => expect.closeTo(z, 9)) as never, + ) + expect(new Set(posts(after, porch.id).map((post) => post.id))).toEqual( + new Set(posts(before, porch.id).map((post) => post.id)), + ) + }) + + test('a post moved by hand hands the framing over; Automatic again rebuilds it', () => { + const before = withPorch() + const porch = porchOf(before) + const middle = posts(before, porch.id).find((post) => Math.abs(post.position[0] - 4) < 1e-6)! + const moved = settle( + before, + edit(before, middle.id, { position: [4.5, 0, middle.position[2]] } as never), + ) + expect((moved[porch.id] as ZoneNode).porchFraming?.auto).toBe(false) + expect((moved[middle.id] as ColumnNode).position[0]).toBe(4.5) + const rebuilt = intent(moved, porch.id, { porchFraming: { auto: true } }) + expect((rebuilt[porch.id] as ZoneNode).porchFraming).toBeUndefined() + expect((rebuilt[middle.id] as ColumnNode).position[0]).toBeCloseTo(4, 9) + }) + + test('a post deleted by hand stays deleted', () => { + const before = withPorch() + const porch = porchOf(before) + const middle = posts(before, porch.id).find((post) => Math.abs(post.position[0] - 4) < 1e-6)! + const { [middle.id]: _gone, ...rest } = before + const after = settle(before, rest) + expect((after[porch.id] as ZoneNode).porchFraming?.auto).toBe(false) + expect(posts(after, porch.id)).toHaveLength(2) + }) + + test('closer post spacing and a bigger beam rebuild it', () => { + const before = withPorch() + const porch = porchOf(before) + const after = intent(before, porch.id, { porchFraming: { postSpacing: 1, beamSize: '6x10' } }) + expect(posts(after, porch.id).length).toBeGreaterThan(posts(before, porch.id).length) + expect(beams(after, porch.id).every((beam) => beam.size === '6x10')).toBe(true) + }) + + test('a deck or an uncovered porch has none', () => { + const before = withPorch() + const porch = porchOf(before) + const deck = intent(before, porch.id, { roomType: 'deck' }) + expect(posts(deck, porch.id)).toHaveLength(0) + expect(beams(deck, porch.id)).toHaveLength(0) + const open = intent(before, porch.id, { hasCeiling: false }) + expect(posts(open, porch.id)).toHaveLength(0) + }) +}) + +describe('a deck or patio carries a roof on posts once switched on', () => { + const deckOf = (nodes: Record) => + zones(nodes).find((zone) => zone.roomType === 'deck')! + + test('a deck fenced by railings has none until its posts and beam are on', () => { + const before = withRailings(new Set([0, 1, 2])) + const deck = deckOf(before) + expect(posts(before, deck.id)).toHaveLength(0) + const on = intent(before, deck.id, { porchFraming: { auto: true } }) + expect((on[deck.id] as ZoneNode).porchFraming?.auto).toBe(true) + // The 4 m railing: a post at each outside corner and one between; a beam on each railing. + expect(posts(on, deck.id)).toHaveLength(3) + expect(beams(on, deck.id)).toHaveLength(3) + const plate = plates(on).find( + (slab) => slab.zoneIds?.includes(deck.id) && slab.plateRole !== 'base', + )! + expect(posts(on, deck.id).every((post) => post.supportSlabId === plate.id)).toBe(true) + }) + + test('a size chosen rebuilds them automatically; Off takes them all, edited or not', () => { + const before = withRailings(new Set([0, 1, 2])) + const deck = deckOf(before) + const on = intent(before, deck.id, { porchFraming: { auto: true } }) + const middle = posts(on, deck.id).find((post) => Math.abs(post.position[0] - 4) < 1e-6)! + const moved = settle( + on, + edit(on, middle.id, { position: [4.5, 0, middle.position[2]] } as never), + ) + expect((moved[deck.id] as ZoneNode).porchFraming?.auto).toBe(false) + const resized = intent(moved, deck.id, { porchFraming: { postSize: '4x4' } }) + expect((resized[deck.id] as ZoneNode).porchFraming?.auto).toBe(true) + expect(posts(resized, deck.id).every((post) => post.width === FRAMING_POST_SIZES['4x4'])).toBe( + true, + ) + const handEdited = settle( + resized, + edit(resized, middle.id, { position: [4.5, 0, middle.position[2]] } as never), + ) + const off = intent(handEdited, deck.id, { porchFraming: { auto: null } }) + expect((off[deck.id] as ZoneNode).porchFraming?.auto).toBeUndefined() + expect( + Object.values(off).filter((node) => node.type === 'column' || node.type === 'beam'), + ).toHaveLength(0) + }) + + test('a porch keeps Automatic as its default, stored only when off', () => { + const before = withPorch() + const porch = porchOf(before) + const resized = intent(before, porch.id, { porchFraming: { postSize: '8x8' } }) + expect((resized[porch.id] as ZoneNode).porchFraming?.auto).toBeUndefined() + expect(posts(resized, porch.id).every((post) => post.width === FRAMING_POST_SIZES['8x8'])).toBe( + true, + ) + }) +}) + +describe('deleting a floor plate', () => { + /** The porch off the kitchen's z = 4 side and a deck fenced with railings off its z = 0 side, settled. */ + const withPorchAndDeck = () => { + const porch = withPorch() + const railed: Record = { ...porch } + for (const [index, [start, end]] of ( + [ + [ + [2, 0], + [2, -2], + ], + [ + [2, -2], + [6, -2], + ], + [ + [6, -2], + [6, 0], + ], + ] as Array<[[number, number], [number, number]]> + ).entries()) { + const railing = WallNode.parse({ + ...railingWallDefaults(), + id: `wall_deckrail${index}`, + parentId: LEVEL, + start, + end, + }) + railed[railing.id] = railing + } + return settle(porch, railed) + } + const sceneSync = (before: Record, after: Record) => { + let i = 0 + return reconcileSceneStructure({ + nodes: after, + previousNodes: before, + mintId: (kind) => `${kind}_sync${++i}`, + }).nodes as Record + } + + test("the house's shared plate is not a porch's or a deck's floor: they keep theirs", () => { + const nodes = withPorchAndDeck() + const base = plates(nodes).find((plate) => plate.plateRole === 'base')! + const outdoor = zones(nodes).filter((zone) => zone.roomType) + expect(outdoor.map((zone) => zone.roomType).sort()).toEqual(['deck', 'porch']) + expect(outdoor.every((zone) => base.zoneIds?.includes(zone.id))).toBe(true) + // The store's delete intent and the reconciler's both switch off the kitchen's floor alone. + expect(derivedDeletionIntent(nodes as never, [base.id as AnyNodeId])).toEqual([ + { id: zones(nodes).find((zone) => zone.name === 'Kitchen')!.id, data: { hasFloor: false } }, + ] as never) + const { [base.id]: _gone, ...rest } = nodes + const after = sceneSync(nodes, rest) + for (const zone of outdoor) { + expect((after[zone.id] as ZoneNode).hasFloor).toBeUndefined() + expect( + plates(after).some( + (plate) => plate.plateRole !== 'base' && plate.zoneIds?.includes(zone.id), + ), + ).toBe(true) + } + expect( + (after[zones(nodes).find((zone) => zone.name === 'Kitchen')!.id] as ZoneNode).hasFloor, + ).toBe(false) + }) + + test("a porch's own plate deleted takes the porch's floor only", () => { + const nodes = withPorchAndDeck() + const porch = zones(nodes).find((zone) => zone.roomType === 'porch')! + const own = plates(nodes).find( + (plate) => plate.plateRole !== 'base' && plate.zoneIds?.includes(porch.id), + )! + expect(derivedDeletionIntent(nodes as never, [own.id as AnyNodeId])).toEqual([ + { id: porch.id, data: { hasFloor: false } }, + ] as never) + }) +}) diff --git a/packages/core/src/lib/outdoor-room.ts b/packages/core/src/lib/outdoor-room.ts new file mode 100644 index 0000000000..6bf36c0adb --- /dev/null +++ b/packages/core/src/lib/outdoor-room.ts @@ -0,0 +1,90 @@ +import type { ZoneNode } from '../schema' +import { DEFAULT_DECK_BOARDS, deckBoardThickness } from './deck-boards' + +/** + * Rooms outside the house, the outdoor room types: a porch (a covered floor a step + * down from the house), a deck (a framed floor of boards) and a patio (an uncovered slab). A room + * of one of these types is outdoors whatever covers it, so the house walls it faces are exterior + * walls even under a porch ceiling, and its floor steps down from the house's (`floor.drop`). + * + * A room closed off outside the house by invisible walls starts as a porch: its floor a concrete + * slab 1.5 in under the house's and its ceiling at the house's, both adjustable in its panel. + */ + +const IN = 0.0254 + +export const OUTDOOR_ROOM_TYPES = ['porch', 'deck', 'patio'] as const +export type OutdoorRoomType = (typeof OUTDOOR_ROOM_TYPES)[number] + +/** A porch or patio slab steps down from the house's finish floor by 1.5 in at most. */ +export const PORCH_FLOOR_DROP = 1.5 * IN +/** Deck boards ride 1 in under the threshold so water sheds away from the door. */ +export const DECK_FLOOR_DROP = 1 * IN +/** + * The deck boards on a deck's floor unless its room says otherwise (5/4x6, 1 in: `lib/deck-boards`); + * the framing hangs under them. + */ +export const DECKING_THICKNESS = deckBoardThickness(DEFAULT_DECK_BOARDS) + +export type OutdoorRoomDefaults = { + /** The name a room of the type is given while it has a default name. */ + name: string + drop: number + /** The floor finish it starts with. */ + finish: string + /** Whether it has a ceiling (a covered porch). */ + covered: boolean + /** How the framing plugin reads its floor plate (`metadata.floor`). */ + floorTag: 'porch-slab' | 'deck' +} + +export const OUTDOOR_ROOM_DEFAULTS: Record = { + porch: { + name: 'Porch', + drop: PORCH_FLOOR_DROP, + finish: 'library:concrete-raw', + covered: true, + floorTag: 'porch-slab', + }, + deck: { + name: 'Deck', + drop: DECK_FLOOR_DROP, + finish: 'library:wood-woodfine11', + covered: false, + floorTag: 'deck', + }, + patio: { + name: 'Patio', + drop: PORCH_FLOOR_DROP, + finish: 'library:concrete-raw', + covered: false, + floorTag: 'porch-slab', + }, +} + +export function isOutdoorRoomType(value: unknown): value is OutdoorRoomType { + return typeof value === 'string' && (OUTDOOR_ROOM_TYPES as readonly string[]).includes(value) +} + +/** Whether a room is one of the outdoor room types. */ +export function isOutdoorRoom(zone: Pick): boolean { + return isOutdoorRoomType(zone.roomType) +} + +/** "Porch", "Porch 2", …: the next free name for a room of `type` among `names`. */ +export function nextOutdoorRoomName(type: OutdoorRoomType, names: Iterable): string { + const base = OUTDOOR_ROOM_DEFAULTS[type].name + const taken = new Set(names) + if (!taken.has(base)) return base + for (let n = 2; ; n++) if (!taken.has(`${base} ${n}`)) return `${base} ${n}` +} + +/** Whether `name` is a type's default name ("Deck", "Deck 3"), so a type change may rename it. */ +export function isOutdoorRoomDefaultName(name: string | undefined): boolean { + return ( + typeof name === 'string' && + OUTDOOR_ROOM_TYPES.some((type) => + new RegExp(`^${OUTDOOR_ROOM_DEFAULTS[type].name}( \\d+)?$`).test(name), + ) + ) +} diff --git a/packages/core/src/lib/porch-framing-sync.ts b/packages/core/src/lib/porch-framing-sync.ts new file mode 100644 index 0000000000..9675c0e306 --- /dev/null +++ b/packages/core/src/lib/porch-framing-sync.ts @@ -0,0 +1,282 @@ +import type { AnyNode, AnyNodeId, SlabNode, ZoneNode } from '../schema' +import type { BeamNode } from '../schema/nodes/beam' +import type { ColumnNode } from '../schema/nodes/column' +import { beamBottomElevation, createBeam } from './beam' +import { + createFramingPost, + FRAMING_POST_MIN_HEIGHT, + framingPostFields, + framingPostSize, +} from './framing-post' +import { type PorchFramingPlan, planPorchFraming, porchFramingSettings } from './porch-framing' + +/** + * A porch's posts and beams (`lib/porch-framing`), kept by the structure kernel as it keeps a + * room's floor and ceiling: made when a covered porch has an open side, moved with the porch, + * rebuilt when its framing settings change, removed when it stops being a covered porch. A deck + * or patio gets the same once they are switched on, to carry a roof over it. They are ordinary + * post and beam nodes. Moving, resizing or deleting one hands the room's framing to the user + * (`porchFraming.auto: false`): framing edited by hand stops rebuilding; turning it back on + * rebuilds it. + */ + +type Nodes = Readonly> +type PorchPart = ColumnNode | BeamNode + +/** What the kernel stamps on a porch part: the porch, which part, and what it made it as. */ +export type PorchPartMetadata = { porchOf: string; porchPart: string; porchSeed: string } + +/** The porch a post or beam was made for, when the kernel made it. */ +export function porchPartOf(node: AnyNode | null | undefined): PorchPartMetadata | null { + if (node?.type !== 'column' && node?.type !== 'beam') return null + const metadata = node.metadata as Partial | undefined + return typeof metadata?.porchOf === 'string' && typeof metadata.porchPart === 'string' + ? (metadata as PorchPartMetadata) + : null +} + +/** Keep generated parts linked when reconciliation assigns their room its stable ID. */ +export function remapPorchOwner( + metadata: Record | undefined, + ids: ReadonlyMap, +): Record | undefined { + return typeof metadata?.porchOf === 'string' && ids.has(metadata.porchOf) + ? { ...metadata, porchOf: ids.get(metadata.porchOf) } + : undefined +} + +const round = (value: number) => Math.round(value * 1e6) / 1e6 + +/** A part's shape, as it was made: anything else is a hand edit. */ +function seedOf(part: PorchPart): string { + if (part.type === 'column') + return JSON.stringify( + [part.position[0], part.position[2], part.width, part.depth, part.height, part.rotation].map( + round, + ), + ) + return JSON.stringify([ + ...[...part.start, ...part.end, part.width, part.depth].map(round), + part.topElevation === undefined ? null : round(part.topElevation), + part.placement, + ]) +} + +/** + * A porch part's id and shape, for the structure sync to notice a hand edit or a delete (and run + * the kernel, which hands the porch's framing over); null for any other node. + */ +export function porchPartSignature(node: AnyNode | null | undefined): string | null { + return porchPartOf(node) ? JSON.stringify([node!.id, seedOf(node as PorchPart)]) : null +} + +function edited(part: PorchPart): boolean { + return seedOf(part) !== porchPartOf(part)?.porchSeed +} + +/** + * A room the kernel frames, still closed and its framing automatic: a covered porch (automatic + * unless switched off), or a deck or patio whose posts and beam are switched on (`auto: true`, to + * carry a roof over it; off by default). + */ +function framedPorch(zone: ZoneNode | undefined): boolean { + if (!zone || zone.enclosureStatus === 'open') return false + if (zone.roomType === 'porch') + return zone.hasCeiling !== false && zone.porchFraming?.auto !== false + return coverOptional(zone) && zone.porchFraming?.auto === true +} + +/** A deck or patio: its posts and beam are off until switched on. */ +function coverOptional(zone: Pick): boolean { + return zone.roomType === 'deck' || zone.roomType === 'patio' +} + +/** The floor plate a porch's posts stand on: its own step-down plate, else the one it shares. */ +function porchPlate(zone: ZoneNode, plates: readonly SlabNode[]): SlabNode | undefined { + const holding = plates.filter((plate) => plate.zoneIds?.includes(zone.id)) + return holding.find((plate) => plate.plateRole !== 'base') ?? holding[0] +} + +const yawOf = (start: readonly [number, number], end: readonly [number, number]) => + Math.atan2(-(end[1] - start[1]), end[0] - start[0]) + +function withPorch(node: PorchPart, zone: ZoneNode, key: string): PorchPart { + const metadata: PorchPartMetadata = { porchOf: zone.id, porchPart: key, porchSeed: '' } + const tagged = { ...node, metadata: { ...node.metadata, ...metadata } } as PorchPart + ;(tagged.metadata as PorchPartMetadata).porchSeed = seedOf(tagged) + return tagged +} + +/** The porch's planned parts as nodes, reusing the ids (and the touches) of the ones it has. */ +function buildParts( + zone: ZoneNode, + plan: PorchFramingPlan, + owned: readonly PorchPart[], + plate: SlabNode | undefined, + levelId: string, + nodes: Nodes, + mintId: (kind: 'column' | 'beam') => string, +): PorchPart[] { + const settings = porchFramingSettings(zone) + const byKey = new Map(owned.map((part) => [porchPartOf(part)!.porchPart, part])) + const beams = new Map() + for (const planned of plan.beams) { + const existing = byKey.get(planned.key) + const fresh = createBeam({ + start: planned.start, + end: planned.end, + preset: settings.beamSize, + levelId, + supportSlabId: plate?.id, + name: `${zone.name} beam`, + }) + const beam: BeamNode = + existing?.type === 'beam' + ? { + ...existing, + start: fresh.start, + end: fresh.end, + width: fresh.width, + depth: fresh.depth, + size: fresh.size, + plies: fresh.plies, + material: fresh.material, + placement: 'dropped', + topElevation: undefined, + supportSlabId: plate?.id, + } + : { ...fresh, id: mintId('beam') as BeamNode['id'] } + beams.set(planned.key, withPorch(beam, zone, planned.key) as BeamNode) + } + const foot = plate?.elevation ?? 0 + const posts = plan.posts.map((planned) => { + // Up to the underside of the beam it carries (the lower of two at a corner). + const bottoms = planned.beams.flatMap((key) => { + const beam = beams.get(key) + return beam ? [beamBottomElevation(nodes as never, beam)] : [] + }) + const height = Math.max(FRAMING_POST_MIN_HEIGHT, Math.min(...bottoms) - foot) + const run = plan.beams.find((beam) => beam.key === planned.beams.at(-1)) + const rotation = run ? yawOf(run.start, run.end) : 0 + const existing = byKey.get(planned.key) + const position: [number, number, number] = [planned.position[0], 0, planned.position[1]] + const post: ColumnNode = + existing?.type === 'column' + ? { + ...existing, + ...(framingPostSize(existing) === settings.postSize + ? {} + : framingPostFields(settings.postSize, existing.postBase ?? 'post-base')), + position, + rotation, + height, + supportSlabId: plate?.id, + } + : { + ...createFramingPost({ + position: planned.position, + size: settings.postSize, + base: 'post-base', + height, + levelId, + supportSlabId: plate?.id, + rotation, + name: `${zone.name} post`, + }), + id: mintId('column') as ColumnNode['id'], + } + return withPorch(post, zone, planned.key) + }) + return [...beams.values(), ...posts] +} + +/** + * The kernel's porch framing pass over one level: which posts and beams to put and delete, and + * the porches whose framing a hand edit has handed to the user. `zones` are the level's rooms as + * the pass leaves them, `plates` its floor plates, `current` a node as the pass has it so far; + * `previousNodes` (the scene before the edit) tells a deleted part from one never made. + */ +export function reconcilePorchFraming({ + levelId, + nodes, + previousNodes, + zones, + plates, + current, + mintId, +}: { + levelId: string + nodes: Nodes + previousNodes?: Nodes + zones: readonly ZoneNode[] + plates: readonly SlabNode[] + current: (id: string) => AnyNode | undefined + mintId: (kind: 'column' | 'beam') => string +}): { put: AnyNode[]; delete: AnyNodeId[] } { + const put: AnyNode[] = [] + const remove: AnyNodeId[] = [] + const owned = new Map() + for (const node of Object.values(nodes)) { + const part = porchPartOf(node) + if (!part || node.parentId !== levelId) continue + const latest = (current(node.id) ?? node) as PorchPart + owned.set(part.porchOf, [...(owned.get(part.porchOf) ?? []), latest]) + } + const zonesById = new Map(zones.map((zone) => [zone.id, zone])) + // A porch gone, or no longer a covered one: what it made goes with it; a part edited by hand + // stays, the user's own. A deck's or patio's switched off goes whole, edited or not. + for (const [zoneId, parts] of owned) { + const zone = zonesById.get(zoneId as ZoneNode['id']) + if (framedPorch(zone) || zone?.porchFraming?.auto === false) continue + const switchedOff = !!zone && coverOptional(zone) && zone.porchFraming?.auto === undefined + for (const part of parts) { + if (switchedOff || !edited(part)) remove.push(part.id) + else { + const { + porchOf: _porchOf, + porchPart: _porchPart, + porchSeed: _seed, + ...metadata + } = part.metadata as PorchPartMetadata & Record + put.push({ ...part, metadata } as AnyNode) + } + } + } + for (const zone of zones) { + if (!framedPorch(zone)) continue + const parts = owned.get(zone.id) ?? [] + const before = previousNodes?.[zone.id] + const settingsChanged = + before?.type !== 'zone' || + before.roomType !== zone.roomType || + JSON.stringify(before.porchFraming ?? null) !== JSON.stringify(zone.porchFraming ?? null) + const plan = planPorchFraming(zone, nodes) + if (!settingsChanged) { + // A part of the plan gone since the edit before: deleted by hand. (One the plan dropped + // went with an earlier pass.) + const planned = new Set([...plan.posts, ...plan.beams].map((part) => part.key)) + const deleted = Object.values(previousNodes ?? {}).some((node) => { + const part = porchPartOf(node) + return part?.porchOf === zone.id && planned.has(part.porchPart) && !nodes[node.id] + }) + if (deleted || parts.some(edited)) { + put.push({ ...zone, porchFraming: { ...zone.porchFraming, auto: false } }) + continue + } + } + const built = buildParts( + zone, + plan, + // Settings changed: what a hand made goes too; the porch is rebuilt from its settings. + parts, + porchPlate(zone, plates), + levelId, + nodes, + mintId, + ) + const kept = new Set(built.map((part) => part.id)) + for (const part of parts) if (!kept.has(part.id)) remove.push(part.id) + put.push(...built) + } + return { put, delete: remove } +} diff --git a/packages/core/src/lib/porch-framing.test.ts b/packages/core/src/lib/porch-framing.test.ts new file mode 100644 index 0000000000..149416b353 --- /dev/null +++ b/packages/core/src/lib/porch-framing.test.ts @@ -0,0 +1,82 @@ +import { describe, expect, test } from 'bun:test' +import { type AnyNode, WallNode } from '../schema' +import { FRAMING_POST_SIZES } from './framing-post' +import { PORCH_POST_SETBACK, planPorchFraming } from './porch-framing' + +const LEVEL = 'level_porch' +const wall = (id: string, start: [number, number], end: [number, number]) => + WallNode.parse({ id: `wall_${id}`, parentId: LEVEL, start, end, thickness: 0.15 }) +const nodes = (...walls: WallNode[]): Record => + Object.fromEntries(walls.map((node) => [node.id, node])) + +// A porch in a corner of the house: house walls along z = 0 and x = 0, open on the other two sides. +const corner = { + parentId: LEVEL, + polygon: [ + [0, 0], + [3, 0], + [3, 2.5], + [0, 2.5], + ] as Array<[number, number]>, +} +const house = nodes(wall('south', [0, 0], [6, 0]), wall('west', [0, 6], [0, 0])) +const inset = FRAMING_POST_SIZES['6x6'] / 2 + PORCH_POST_SETBACK + +describe('planPorchFraming', () => { + test('a porch in a corner of the house gets its one corner post', () => { + const { posts } = planPorchFraming(corner, house) + const cornerPost = posts.find((post) => post.key.startsWith('corner:'))! + expect(cornerPost.position[0]).toBeCloseTo(3 - inset, 9) + expect(cornerPost.position[1]).toBeCloseTo(2.5 - inset, 9) + expect(posts.filter((post) => post.key.startsWith('corner:'))).toHaveLength(1) + }) + + test('a side longer than the spacing gets posts between, evenly; none against the house', () => { + const { posts } = planPorchFraming(corner, house) + // The 3 m side reaches 2.8 m from the west wall's face to the corner post: two bays at 8 ft. + const between = posts.filter((post) => post.key.startsWith('side:')) + expect(between).toHaveLength(1) + const start = 0.075 + const end = 3 - inset + expect(between[0]!.position[0]).toBeCloseTo((start + end) / 2, 9) + expect(between[0]!.position[1]).toBeCloseTo(2.5 - inset, 9) + expect(posts.every((post) => post.position[0] > 0.07 && post.position[1] > 0.07)).toBe(true) + }) + + test('a beam runs along each open side, from the house wall face to the corner post', () => { + const { beams } = planPorchFraming(corner, house) + expect(beams).toHaveLength(2) + const east = beams.find((beam) => Math.abs(beam.start[0] - beam.end[0]) < 1e-9)! + expect(east.start[0]).toBeCloseTo(3 - inset, 9) + expect(Math.min(east.start[1], east.end[1])).toBeCloseTo(0.075, 9) + // It reaches the corner post's outside face. + expect(Math.max(east.start[1], east.end[1])).toBeCloseTo( + 2.5 - inset + FRAMING_POST_SIZES['6x6'] / 2, + 9, + ) + }) + + test('closer post spacing adds posts; a walled-in room has none', () => { + const tight = planPorchFraming({ ...corner, porchFraming: { postSpacing: 1 } }, house) + expect(tight.posts.length).toBeGreaterThan(planPorchFraming(corner, house).posts.length) + const closed = planPorchFraming( + corner, + nodes( + wall('south', [0, 0], [3, 0]), + wall('east', [3, 0], [3, 2.5]), + wall('north', [3, 2.5], [0, 2.5]), + wall('west', [0, 2.5], [0, 0]), + ), + ) + expect(closed).toEqual({ posts: [], beams: [] }) + }) + + test('a railing side still carries posts and the beam', () => { + const railing = { + ...wall('rail', [3, 0], [3, 2.5]), + wallType: 'railing', + } as unknown as WallNode + const { beams } = planPorchFraming(corner, nodes(...Object.values(house), railing) as never) + expect(beams).toHaveLength(2) + }) +}) diff --git a/packages/core/src/lib/porch-framing.ts b/packages/core/src/lib/porch-framing.ts new file mode 100644 index 0000000000..6263007f59 --- /dev/null +++ b/packages/core/src/lib/porch-framing.ts @@ -0,0 +1,200 @@ +import type { AnyNode, WallNode, ZoneNode } from '../schema' +import { DEFAULT_BEAM_SIZE_PRESET_ID } from '../schema/nodes/beam' +import { beamSizePreset } from './beam' +import { DEFAULT_FRAMING_POST_SIZE, FRAMING_POST_SIZES, type FramingPostSize } from './framing-post' + +/** + * Where a porch's posts and beam go (a porch room, `lib/outdoor-room`): a post on each outside + * corner, where two open sides meet (a porch in a corner of the house gets its one corner post), + * more along each open side at most `postSpacing` apart, evenly; none where a side meets the house, + * whose wall carries the beam's end. The beam runs along each open side on the posts, dropped + * under the porch ceiling. Pure geometry: the structure kernel turns it into post and beam nodes. + * + * A side is open when no wall stands on it (an invisible wall) or the wall on it is a railing. + */ + +const IN = 0.0254 +const FT = 0.3048 + +/** Post faces sit this far in from the slab edge. */ +export const PORCH_POST_SETBACK = 1.5 * IN +/** Posts no more than 8 ft apart (the porch generator's and DCA 6's limit). */ +export const PORCH_POST_SPACING = 8 * FT + +export type PorchFramingSettings = { + /** A framing post size (`FRAMING_POST_SIZES`). */ + postSize: FramingPostSize + postSpacing: number + /** A stock beam size id (`BEAM_SIZE_PRESETS`). */ + beamSize: string +} + +export const DEFAULT_PORCH_FRAMING: PorchFramingSettings = { + postSize: DEFAULT_FRAMING_POST_SIZE, + postSpacing: PORCH_POST_SPACING, + beamSize: DEFAULT_BEAM_SIZE_PRESET_ID, +} + +const isPostSize = (size: string | undefined): size is FramingPostSize => + !!size && Object.hasOwn(FRAMING_POST_SIZES, size) + +/** A porch's framing settings: its own, else the defaults (an unknown size is the default). */ +export function porchFramingSettings(zone: Pick): PorchFramingSettings { + const own = zone.porchFraming + return { + postSize: isPostSize(own?.postSize) ? own.postSize : DEFAULT_PORCH_FRAMING.postSize, + postSpacing: own?.postSpacing ?? DEFAULT_PORCH_FRAMING.postSpacing, + beamSize: + own?.beamSize && beamSizePreset(own.beamSize) + ? beamSizePreset(own.beamSize)!.id + : DEFAULT_PORCH_FRAMING.beamSize, + } +} + +type P = [number, number] + +export type PorchPostPlan = { + /** Stable within the porch: which corner or side, and which bay. */ + key: string + position: P + /** Actual post width (square). */ + size: number + /** The beams (their keys) it stands under: two at a corner, one along a side. */ + beams: string[] +} + +export type PorchBeamPlan = { + key: string + start: P + end: P + width: number + depth: number +} + +export type PorchFramingPlan = { posts: PorchPostPlan[]; beams: PorchBeamPlan[] } + +const sub = (a: P, b: P): P => [a[0] - b[0], a[1] - b[1]] +const add = (a: P, b: P): P => [a[0] + b[0], a[1] + b[1]] +const scale = (a: P, s: number): P => [a[0] * s, a[1] * s] +const len = (a: P) => Math.hypot(a[0], a[1]) +const unit = (a: P): P => { + const l = len(a) + return l > 1e-12 ? [a[0] / l, a[1] / l] : [0, 0] +} + +/** The wall standing along `a` → `b` (its reference line on the segment), if any. */ +function wallAlong(a: P, b: P, walls: readonly WallNode[]): WallNode | undefined { + const dir = unit(sub(b, a)) + const mid = scale(add(a, b), 0.5) + return walls.find((wall) => { + if ((wall.curveOffset ?? 0) !== 0) return false + const w = sub(wall.end as P, wall.start as P) + const length = len(w) + if (length < 1e-6) return false + const u = scale(w, 1 / length) + if (Math.abs(u[0] * dir[1] - u[1] * dir[0]) > 1e-3) return false + const rel = sub(mid, wall.start as P) + const across = Math.abs(rel[0] * u[1] - rel[1] * u[0]) + const along = rel[0] * u[0] + rel[1] * u[1] + return across < 1e-3 && along > -1e-3 && along < length + 1e-3 + }) +} + +/** Whether a wall is a railing, which a porch's posts and beam still stand along. */ +function isRailing(wall: WallNode): boolean { + return (wall as WallNode & { wallType?: string }).wallType === 'railing' +} + +/** + * The posts and beams for porch `zone` among `nodes` (its level's walls decide which sides are + * open). Empty when no side is open. + */ +export function planPorchFraming( + zone: Pick, + nodes: Readonly>, +): PorchFramingPlan { + const settings = porchFramingSettings(zone) + const postSize = FRAMING_POST_SIZES[settings.postSize] + const beam = beamSizePreset(settings.beamSize)! + const spacing = Math.max(0.6, settings.postSpacing) + const walls = Object.values(nodes).filter( + (node): node is WallNode => node.type === 'wall' && node.parentId === zone.parentId, + ) + const polygon = zone.polygon as P[] + const n = polygon.length + if (n < 3) return { posts: [], beams: [] } + // Inward normals: the polygon's winding decides which side of each edge is inside. + let area = 0 + for (let i = 0; i < n; i++) { + const a = polygon[i]! + const b = polygon[(i + 1) % n]! + area += a[0] * b[1] - b[0] * a[1] + } + const turn = area > 0 ? 1 : -1 + const edges = polygon.map((a, i) => { + const b = polygon[(i + 1) % n]! + const wall = wallAlong(a, b, walls) + const dir = unit(sub(b, a)) + const inward: P = [-dir[1] * turn, dir[0] * turn] + return { a, b, dir, inward, open: !wall || isRailing(wall), wall } + }) + const inset = postSize / 2 + PORCH_POST_SETBACK + const posts: PorchPostPlan[] = [] + const beams: PorchBeamPlan[] = [] + // The post line of an edge: the edge moved in by the inset. + const onLine = (edge: (typeof edges)[number], p: P): P => add(p, scale(edge.inward, inset)) + // The outside corner where open edge i-1 meets open edge i: the two post lines' crossing. + const corner = (i: number): P => { + const prev = edges[(i - 1 + n) % n]! + const next = edges[i]! + const p = onLine(prev, prev.b) + const q = onLine(next, next.a) + const denom = prev.dir[0] * next.dir[1] - prev.dir[1] * next.dir[0] + if (Math.abs(denom) < 1e-9) return q + const t = ((q[0] - p[0]) * next.dir[1] - (q[1] - p[1]) * next.dir[0]) / denom + return add(p, scale(prev.dir, t)) + } + edges.forEach((edge, i) => { + if (!edge.open) return + const prev = edges[(i - 1 + n) % n]! + const next = edges[(i + 1) % n]! + const startCorner = prev.open + const endCorner = next.open + // A side meeting the house starts at the wall's face, where the beam bears. + const startFace = startCorner ? 0 : (prev.wall?.thickness ?? 0.15) / 2 + const endFace = endCorner ? 0 : (next.wall?.thickness ?? 0.15) / 2 + const start = startCorner ? corner(i) : add(onLine(edge, edge.a), scale(edge.dir, startFace)) + const end = endCorner + ? corner((i + 1) % n) + : sub(onLine(edge, edge.b), scale(edge.dir, endFace)) + if (startCorner) + posts.push({ + key: `corner:${i}`, + position: start, + size: postSize, + beams: [`beam:${(i - 1 + n) % n}`, `beam:${i}`], + }) + const run = sub(end, start) + const length = len(run) + if (length < postSize) return + const bays = Math.max(1, Math.ceil(length / spacing - 1e-9)) + for (let k = 1; k < bays; k++) + posts.push({ + key: `side:${i}:${k}`, + position: add(start, scale(run, k / bays)), + size: postSize, + beams: [`beam:${i}`], + }) + // The beam reaches the corner posts' outside faces, so two sides' beams meet over a corner. + const reachStart = startCorner ? postSize / 2 : 0 + const reachEnd = endCorner ? postSize / 2 : 0 + beams.push({ + key: `beam:${i}`, + start: sub(start, scale(edge.dir, reachStart)), + end: add(end, scale(edge.dir, reachEnd)), + width: beam.width, + depth: beam.depth, + }) + }) + return { posts, beams } +} diff --git a/packages/core/src/lib/railing-rooms.test.ts b/packages/core/src/lib/railing-rooms.test.ts new file mode 100644 index 0000000000..9be7b14a9a --- /dev/null +++ b/packages/core/src/lib/railing-rooms.test.ts @@ -0,0 +1,128 @@ +import { describe, expect, test } from 'bun:test' +import { + type AnyNode, + generateId, + LevelNode, + railingWallDefaults, + WallNode, + type ZoneNode, +} from '../schema' +import { railingFencedRoomIds } from './railing-rooms' +import type { BoundarySpan } from './room-topology-index' +import { reconcileSceneStructure } from './structure-reconcile' + +type Point = [number, number] +type Nodes = Record +const LEVEL = 'level_railing' + +const span = (roomId: string, boundaryId: string, face: 'a' | 'b', t0 = 0, t1 = 1) => + ({ roomId, boundaryId, kind: 'wall', face, t0, t1 }) satisfies BoundarySpan + +/** Walls drawn by hand (a railing where `railing` is set), reconciled into rooms. */ +function drawn(edges: { start: Point; end: Point; railing?: boolean }[]): Nodes { + const level = LevelNode.parse({ id: LEVEL, children: [] }) + const nodes: Nodes = {} + for (const { start, end, railing } of edges) { + const wall = WallNode.parse({ + id: generateId('wall'), + parentId: LEVEL, + start, + end, + thickness: 0.2, + ...(railing ? railingWallDefaults() : {}), + }) + nodes[wall.id] = wall + level.children.push(wall.id) + } + nodes[level.id] = level + return reconcileSceneStructure({ nodes, mintId: (kind) => generateId(kind) }).nodes as Nodes +} + +const ring = (corners: Point[], railing = false) => + corners.map((start, index) => ({ start, end: corners[(index + 1) % corners.length]!, railing })) + +const wallOn = (nodes: Nodes, a: Point, b: Point) => + Object.values(nodes).find( + (node): node is WallNode => + node.type === 'wall' && + [node.start, node.end].every((p) => + [a, b].some((q) => Math.hypot(p[0] - q[0], p[1] - q[1]) < 1e-6), + ), + )! + +/** The wall's side toward a point: front is the +normal, perp(end - start) = (-dz, dx). */ +function sideToward(wall: WallNode, [x, z]: Point) { + const [mx, mz] = [(wall.start[0] + wall.end[0]) / 2, (wall.start[1] + wall.end[1]) / 2] + const [nx, nz] = [-(wall.end[1] - wall.start[1]), wall.end[0] - wall.start[0]] + return (x - mx) * nx + (z - mz) * nz > 0 ? wall.frontSide : wall.backSide +} + +describe('rooms a railing fences', () => { + test('a room is fenced where nothing stands behind some stretch of its railing', () => { + const railings = new Set(['wall_rail']) + expect(railingFencedRoomIds([span('deck', 'wall_rail', 'a')], railings)).toEqual( + new Set(['deck']), + ) + // A room behind the whole railing (round a stair well) leaves both inside… + expect( + railingFencedRoomIds( + [span('hall', 'wall_rail', 'a'), span('well', 'wall_rail', 'b')], + railings, + ), + ).toEqual(new Set()) + // …a room behind only part of it does not. + expect( + railingFencedRoomIds( + [span('deck', 'wall_rail', 'a'), span('nook', 'wall_rail', 'b', 0, 0.5)], + railings, + ), + ).toEqual(new Set(['deck'])) + // A solid wall fences nothing. + expect(railingFencedRoomIds([span('hall', 'wall_solid', 'a')], railings)).toEqual(new Set()) + }) + + test("a deck fenced by railings off the house is outside: the house wall's deck face is exterior", () => { + const nodes = drawn([ + ...ring([ + [0, 0], + [6, 0], + [6, 5], + [0, 5], + ]), + { start: [1, 5], end: [1, 7], railing: true }, + { start: [1, 7], end: [4, 7], railing: true }, + { start: [4, 7], end: [4, 5], railing: true }, + ]) + const zones = Object.values(nodes).filter((node): node is ZoneNode => node.type === 'zone') + expect(zones).toHaveLength(2) + const house = wallOn(nodes, [6, 5], [0, 5]) + expect(sideToward(house, [2.5, 6])).toBe('exterior') + expect(sideToward(house, [3, 2])).toBe('interior') + const guard = wallOn(nodes, [1, 7], [4, 7]) + expect([guard.frontSide, guard.backSide]).toEqual(['exterior', 'exterior']) + }) + + test('a railing round a stair well inside a room leaves the room inside', () => { + const nodes = drawn([ + ...ring([ + [0, 0], + [8, 0], + [8, 6], + [0, 6], + ]), + ...ring( + [ + [3, 2], + [5, 2], + [5, 4], + [3, 4], + ], + true, + ), + ]) + const outer = wallOn(nodes, [0, 0], [8, 0]) + expect(sideToward(outer, [4, 1])).toBe('interior') + const guard = wallOn(nodes, [3, 2], [5, 2]) + expect([guard.frontSide, guard.backSide]).toEqual(['interior', 'interior']) + }) +}) diff --git a/packages/core/src/lib/railing-rooms.ts b/packages/core/src/lib/railing-rooms.ts new file mode 100644 index 0000000000..83d163169b --- /dev/null +++ b/packages/core/src/lib/railing-rooms.ts @@ -0,0 +1,47 @@ +import type { WallNode } from '../schema' +import { isRailingWall } from '../schema/nodes/railing-wall' +import type { BoundarySpan } from './room-topology-index' + +/** Span overlap below this (a fraction of the boundary) is a shared endpoint, not a shared edge. */ +const SPAN_OVERLAP = 1e-6 + +/** The ids of the railing walls among `walls`. */ +export function railingWallIds(walls: readonly WallNode[]): Set { + return new Set(walls.flatMap((wall) => (isRailingWall(wall) ? [wall.id] : []))) +} + +/** + * The rooms a railing fences off from the outside: a railing on the room's edge with no room + * standing behind some stretch of it (a deck's or a porch's guard on the storey's outline). A + * railing is a guard, not an enclosure, so such a room is outside whatever covers it, and a wall + * it shares with the house faces outdoors. A railing with rooms on both faces (round a stair well, + * along a loft) leaves them inside. + */ +export function railingFencedRoomIds( + spans: readonly BoundarySpan[], + railingIds: ReadonlySet, +): Set { + const railings = spans.filter((span) => span.kind === 'wall' && railingIds.has(span.boundaryId)) + const fenced = new Set() + for (const span of railings) { + const behind = railings + .filter( + (other) => + other.boundaryId === span.boundaryId && + other.face !== span.face && + Math.min(span.t1, other.t1) - Math.max(span.t0, other.t0) > SPAN_OVERLAP, + ) + .sort((a, b) => a.t0 - b.t0) + let reach = span.t0 + let open = false + for (const other of behind) { + if (other.t0 > reach + SPAN_OVERLAP) { + open = true + break + } + reach = Math.max(reach, other.t1) + } + if (open || reach < span.t1 - SPAN_OVERLAP) fenced.add(span.roomId) + } + return fenced +} diff --git a/packages/core/src/lib/roof-eave.test.ts b/packages/core/src/lib/roof-eave.test.ts new file mode 100644 index 0000000000..137e5eb6b9 --- /dev/null +++ b/packages/core/src/lib/roof-eave.test.ts @@ -0,0 +1,186 @@ +import { describe, expect, test } from 'bun:test' +import { RoofSegmentNode } from '../schema/nodes/roof-segment' +import { LUMBER_DEPTH, ROOF_BUILD_UP_PRESETS, roofBuildUpPatch } from './build-up' +import { + eaveContains, + FASCIA_DROP, + FASCIA_THICKNESS, + fasciaStockFor, + LEVEL_CUT_RUN, + roofEaveProfile, + roofSegmentEaveInput, + roofSegmentEaveProfile, + SOFFIT_THICKNESS, +} from './roof-eave' + +const IN = 0.0254 +const SHEET = (7 / 16) * IN + +/** 2x10 rafters at 6/12 under a 7/16 in sheet, 0.6 m out from the plate line. */ +const input = (cut: 'plumb' | 'square' | 'plumb-level') => ({ + tan: 0.5, + reach: 0.6, + wallOut: 0.075, + tailDepth: LUMBER_DEPTH['2x10'], + tailLift: 0, + deckDepth: LUMBER_DEPTH['2x10'] + SHEET, + cut, +}) + +describe('an eave cut by its rule', () => { + test('plumb: the tails cut plumb at the reach, a plumb 1x over their face from the sheathing to 3/4 in under them', () => { + const eave = roofEaveProfile(input('plumb')) + const cos = 1 / Math.hypot(1, 0.5) + const top = (LUMBER_DEPTH['2x10'] + SHEET) / cos - 0.6 * 0.5 + expect(eave.end).toEqual([ + [0.6, top], + [0.6, -0.3], + ]) + expect(eave.low).toBeCloseTo(-0.3, 9) + const [backTop, frontTop, frontBottom, backBottom] = eave.fascia.corners + expect(backTop).toEqual([0.6, top]) + expect(frontTop[0]).toBeCloseTo(0.6 + FASCIA_THICKNESS, 9) + expect(backBottom[0]).toBeCloseTo(0.6, 9) + // 10.34 in of plumb tail and 0.49 in of sheet: a whole 1x12 drops 0.42 in under it + expect(eave.fascia).toMatchObject({ square: false, stock: '1x12', ripped: false }) + expect(eave.fascia.height).toBeCloseTo(11.25 * IN, 9) + expect(frontBottom[1]).toBeCloseTo(top - 11.25 * IN, 9) + expect(-0.3 - frontBottom[1]).toBeGreaterThan(0.25 * IN) + // a 2x6's 6.64 in takes a whole 1x8, 0.61 in under it + const six = roofEaveProfile({ + ...input('plumb'), + tailDepth: LUMBER_DEPTH['2x6'], + deckDepth: LUMBER_DEPTH['2x6'] + SHEET, + }) + expect(six.fascia).toMatchObject({ stock: '1x8', ripped: false }) + // where no whole 1x drops 1/4 to 3/4 in under the tails, one ripped to drop 3/4 in + const four = roofEaveProfile({ + ...input('plumb'), + tailDepth: LUMBER_DEPTH['2x4'], + deckDepth: LUMBER_DEPTH['2x4'] + SHEET, + }) + expect(four.fascia.corners[2][1]).toBeCloseTo(-0.3 - FASCIA_DROP, 9) + expect(four.fascia).toMatchObject({ stock: '1x6', ripped: true }) + expect(eave.soffit).toBeNull() + }) + + test('square: the tails cut square to the slope through the sheathing edge, the fascia square on them', () => { + const eave = roofEaveProfile(input('square')) + const cos = 1 / Math.hypot(1, 0.5) + const sin = 0.5 * cos + const depth = LUMBER_DEPTH['2x10'] + SHEET + const [corner, foot] = eave.end as [[number, number], [number, number]] + expect(foot[0]).toBeCloseTo(0.6 - depth * sin, 9) + expect(foot[1]).toBeCloseTo(corner[1] - depth * cos, 9) + // on the tails' underside + expect(foot[1]).toBeCloseTo(eave.under(foot[0]), 9) + const [backTop, frontTop, frontBottom, backBottom] = eave.fascia.corners + expect(eave.fascia.square).toBe(true) + expect(eave.fascia.height).toBeCloseTo(depth + FASCIA_DROP, 9) + // its top face in the sheathing's plane, its back on the cut + expect(frontTop[1]).toBeCloseTo(eave.top(frontTop[0]), 9) + expect(backBottom[0] - backTop[0]).toBeCloseTo(-eave.fascia.height * sin, 9) + expect(frontBottom[0] - backBottom[0]).toBeCloseTo(FASCIA_THICKNESS * cos, 9) + // nothing of the tails out past the cut + expect(eaveContains(eave, [0.6, eave.under(0.6) + 0.01])).toBe(false) + expect(eaveContains(eave, [foot[0] - 0.001, foot[1] + 0.002])).toBe(true) + }) + + test('plumb and level: a level cut under the plumb cut, a soffit nailed up to it from the wall out to the fascia', () => { + const eave = roofEaveProfile(input('plumb-level')) + const [, plumbFoot, inner] = eave.end as [[number, number], [number, number], [number, number]] + expect(plumbFoot[0]).toBeCloseTo(0.6, 9) + expect(plumbFoot[1]).toBeCloseTo(-0.3 + LEVEL_CUT_RUN * 0.5, 9) + expect(inner).toEqual([0.6 - LEVEL_CUT_RUN, plumbFoot[1]]) + // the level cut meets the tails' underside + expect(inner[1]).toBeCloseTo(eave.under(inner[0]), 9) + expect(eave.soffit).toEqual({ + y: plumbFoot[1], + thickness: SOFFIT_THICKNESS, + from: 0.075, + to: 0.6, + }) + expect(eave.fascia.corners[2][1]).toBeCloseTo(plumbFoot[1] - FASCIA_DROP, 9) + // the box down to the soffit's underside is the eave's, nothing under it + expect(eaveContains(eave, [0.3, plumbFoot[1] - SOFFIT_THICKNESS + 0.001])).toBe(true) + expect(eaveContains(eave, [0.3, plumbFoot[1] - SOFFIT_THICKNESS - 0.002])).toBe(false) + // a steep 2x4's level cut takes at most half its plumb depth + const steep = roofEaveProfile({ + ...input('plumb-level'), + tan: 1, + tailDepth: LUMBER_DEPTH['2x4'], + }) + const [, foot] = steep.end as [unknown, [number, number]] + expect(foot[1] - steep.under(0.6)).toBeCloseTo((LUMBER_DEPTH['2x4'] * Math.SQRT2) / 2, 9) + }) + + test('a truss tail rides its bottom chord: its underside a chord over the plate, the fascia to 3/4 in under it', () => { + const chord = LUMBER_DEPTH['2x4'] + const eave = roofEaveProfile({ + ...input('plumb'), + tailDepth: chord, + tailLift: chord, + deckDepth: 2 * chord + SHEET, + }) + expect(eave.under(0.6)).toBeCloseTo(chord - 0.3, 9) + const drop = chord - 0.3 - eave.fascia.corners[2][1] + expect(drop).toBeGreaterThanOrEqual(0.25 * IN - 1e-9) + expect(drop).toBeLessThanOrEqual(FASCIA_DROP + 1e-9) + }) + + test('a flat eave and a rising edge are plumb, whatever the plane asks', () => { + expect(roofEaveProfile({ ...input('square'), tan: 0 }).cut).toBe('plumb') + expect(roofEaveProfile({ ...input('plumb-level'), tan: -0.5 }).cut).toBe('plumb') + }) + + test('the 1x a board is cut from: the narrowest as wide, ripped; past a 1x12 a ripped width', () => { + expect(fasciaStockFor(5.5 * IN)).toEqual({ stock: '1x6', ripped: false }) + expect(fasciaStockFor(6 * IN)).toEqual({ stock: '1x8', ripped: true }) + expect(fasciaStockFor(11.25 * IN)).toEqual({ stock: '1x12', ripped: false }) + expect(fasciaStockFor(12 * IN)).toEqual({ stock: null, ripped: true }) + }) +}) + +describe("a roof plane's eave", () => { + const segment = (patch: Partial = {}) => + RoofSegmentNode.parse({ + roofType: 'gable', + width: 8, + depth: 6, + pitch: 26.565, + wallThickness: 0.15, + overhang: 0.6, + ...patch, + }) + + test('its layers name its tails; a truss rides its bottom chord; without layers, rafters under a sheet', () => { + const preset = ROOF_BUILD_UP_PRESETS[0]!.buildUp + const trusses = roofSegmentEaveInput(segment(roofBuildUpPatch(preset))) + expect(trusses.tailDepth).toBeCloseTo(LUMBER_DEPTH['2x4'], 9) + expect(trusses.tailLift).toBeCloseTo(LUMBER_DEPTH['2x4'], 9) + expect(trusses.deckDepth).toBeCloseTo(2 * LUMBER_DEPTH['2x4'] + SHEET, 9) + const bare = roofSegmentEaveInput(segment({ deckThickness: 0.1 })) + expect(bare.tailDepth).toBeCloseTo(0.1 - SHEET, 9) + expect(bare.tailLift).toBe(0) + // the deck's edge, out past the wall's outer face by the overhang along the slope + expect(bare.reach).toBeCloseTo(0.075 + 0.6 * Math.cos(Math.atan(0.5)), 4) + }) + + test('absent, the cut is plumb; a saved plane loads as it was drawn', () => { + expect(segment().eaveCut).toBeUndefined() + expect(roofSegmentEaveProfile(segment()).cut).toBe('plumb') + expect(roofSegmentEaveProfile(segment({ eaveCut: 'square' })).cut).toBe('square') + // a shed's high edge stays plumb + expect( + roofSegmentEaveProfile(segment({ roofType: 'shed', eaveCut: 'square' }), 'high').cut, + ).toBe('plumb') + }) + + test("a flat roof's boards sized on purpose rise over its membrane", () => { + const flat = roofSegmentEaveProfile( + segment({ roofType: 'flat', pitch: 0, fasciaHeight: 0.3, shingleThickness: 0.02 }), + ) + expect(flat.fascia.corners[0][1]).toBeCloseTo(flat.top(flat.reach) + 0.02, 9) + expect(flat.fascia.height).toBe(0.3) + }) +}) diff --git a/packages/core/src/lib/roof-eave.ts b/packages/core/src/lib/roof-eave.ts new file mode 100644 index 0000000000..5097a50b0d --- /dev/null +++ b/packages/core/src/lib/roof-eave.ts @@ -0,0 +1,301 @@ +import { + getRoofSegmentDeckReach, + getSegmentSlopeFrame, + type RoofSegmentNode, +} from '../schema/nodes/roof-segment' +import type { RoofEaveCut } from '../schema/nodes/roof-types' +import { LUMBER_DEPTH } from './build-up' + +const inches = (value: number) => value * 0.0254 + +/** A 1x board's actual thickness: every fascia and rake board is nominal 1x. */ +export const FASCIA_THICKNESS = inches(0.75) +/** How far a fascia or rake board drops below the tails' lowest point, past a soffit's edge. */ +export const FASCIA_DROP = inches(0.75) +/** The least it drops where a 1x then needs no ripping. */ +const FASCIA_DROP_MIN = inches(0.25) +/** The run of a plumb-and-level tail's level cut: a 2x4's width for the soffit's edge to nail to. */ +export const LEVEL_CUT_RUN = inches(3.5) +/** A boxed eave's soffit: a 1/2 in panel nailed up to the level cuts. */ +export const SOFFIT_THICKNESS = inches(0.5) +/** The sheathing a plane without layers is taken to carry over its tails: Bones' 7/16 in. */ +const BARE_SHEATHING = inches(7 / 16) + +export type FasciaStock = '1x6' | '1x8' | '1x10' | '1x12' + +/** The 1x boards a fascia or rake board is cut from, narrowest first, at their actual widths. */ +export const FASCIA_STOCK: readonly { size: FasciaStock; width: number }[] = [ + { size: '1x6', width: inches(5.5) }, + { size: '1x8', width: inches(7.25) }, + { size: '1x10', width: inches(9.25) }, + { size: '1x12', width: inches(11.25) }, +] + +/** + * The 1x a board `width` wide is cut from: the narrowest stock as wide, ripped down to it when + * wider. Past a 1x12 no 1x is wide enough: a ripped width of wider stock (`stock` null). + */ +export function fasciaStockFor(width: number): { stock: FasciaStock | null; ripped: boolean } { + const stock = FASCIA_STOCK.find((candidate) => candidate.width >= width - 1e-4) + if (!stock) return { stock: null, ripped: true } + return { stock: stock.size, ripped: stock.width - width > 1e-3 } +} + +/** + * How wide a board covering `cover` is, `scale` its width per unit of the cover's measure (a rake + * board's, its plumb depth's cosine): `FASCIA_DROP` past it, or a 1x whole where one drops between + * `least` and that, so the board is stock, not ripped. + */ +function boardWidth(cover: number, scale = 1, least = FASCIA_DROP_MIN): number { + const whole = FASCIA_STOCK.find( + ({ width }) => + width >= (cover + least) * scale - 1e-6 && width <= (cover + FASCIA_DROP) * scale + 1e-6, + ) + return whole ? whole.width : (cover + FASCIA_DROP) * scale +} + +/** A point of an eave's section: `s` out from the plate line in plan, `y` up from the plate's plane there. */ +export type EavePoint = readonly [number, number] + +/** The numbers an eave is cut from (`roofEaveProfile`), the roof shell's and Bones' alike. */ +export type RoofEaveInput = { + /** The slope's tangent, falling outward; 0 for a flat roof, negative where it rises (a shed's high edge). */ + tan: number + /** Out from the plate line (the wall's centre line), in plan, to the overhang's end: where the tails are cut. */ + reach: number + /** Out from the plate line to the wall's outer face. */ + wallOut: number + /** The tails' depth square to the slope: a rafter's, or a truss's top chord. */ + tailDepth: number + /** + * How far the tails' underside stands over the plate's plane, plumb: 0 for a rafter, its bottom + * chord's depth for a truss's top chord, which rides it at the heel. + */ + tailLift: number + /** The deck's depth square to the slope, from the plate's plane to the sheathing's top. */ + deckDepth: number + /** Absent, plumb. */ + cut?: RoofEaveCut + /** The fascia's own height (its width as a board) and thickness, where the plane sets them. */ + fasciaHeight?: number + fasciaThickness?: number + /** How far the fascia's top stands over the sheathing's: a flat roof's coping band over its membrane. */ + fasciaRise?: number +} + +/** + * One eave's section, the rule the roof shell's eave edge, fascia and soffit and Bones' rafter tails + * and fascia are all cut by, so the frame never hangs below the shell nor pokes out of it. + */ +export type RoofEaveProfile = { + /** The cut drawn: a flat eave, or an edge rising outward, is plumb whatever the plane asks. */ + cut: RoofEaveCut + tan: number + cos: number + sin: number + reach: number + wallOut: number + /** The sheathing's top at `s`. */ + top: (s: number) => number + /** The tails' underside at `s`. */ + under: (s: number) => number + /** + * The tails' end, from its top corner on the sheathing's top down: a plumb or square cut's two + * ends, or a plumb cut's and then its level cut's inner end. + */ + end: readonly EavePoint[] + /** The tails' lowest point's height. */ + low: number + fascia: { + /** Its section: back top, front top, front bottom, back bottom. */ + corners: readonly [EavePoint, EavePoint, EavePoint, EavePoint] + /** Its width as a board: plumb, its height; square to the slope, its depth along its face. */ + height: number + thickness: number + /** Square to the slope (a `square` cut's), else plumb. */ + square: boolean + stock: FasciaStock | null + ripped: boolean + } + /** A boxed eave's soffit: its top (on the level cuts) and thickness, from the wall's outer face out to the fascia's back. */ + soffit: { y: number; thickness: number; from: number; to: number } | null + /** + * The rake board over a barge rafter on this slope: plumb, its top on the sheathing's top, as deep + * plumb (`height`) as the fascia is at the corner, or over a boxed eave as the barge with the + * fascia's drop; `width` is square to its edges, as a board. + */ + rake: { height: number; width: number; stock: FasciaStock | null; ripped: boolean } +} + +/** + * An eave cut to its plane's rule. The tails reach `reach` out from the plate line along the + * sheathing's top, the deck's full depth under it: + * - plumb: the tails cut plumb there; a plumb 1x fascia covers their face, its top flush with the + * sheathing's top (under the drip edge), its bottom about `FASCIA_DROP` below their lowest point; + * - square: the tails cut square to the slope through the sheathing's outer edge, the fascia square + * to the slope on them, its top face in the sheathing's plane; + * - plumb-level: the plumb cut, and under it a level cut `LEVEL_CUT_RUN` long (at most half the tail's + * plumb depth deep) that a soffit nails up to, run level from the fascia's back to the wall. + * The fascia is as deep as that takes (a whole 1x where one drops at least 1/4 in under the tails, + * else one ripped to it), unless the plane sets its own. + */ +export function roofEaveProfile(input: RoofEaveInput): RoofEaveProfile { + const tan = Number.isFinite(input.tan) ? input.tan : 0 + const cos = 1 / Math.hypot(1, tan) + const sin = tan * cos + const { reach, wallOut, tailLift } = input + const deck = Math.max(0, input.deckDepth) + const top = (s: number) => deck / cos - s * tan + const under = (s: number) => tailLift - s * tan + const thickness = input.fasciaThickness ?? FASCIA_THICKNESS + const cut: RoofEaveCut = tan > 1e-6 ? (input.cut ?? 'plumb') : 'plumb' + const corner: EavePoint = [reach, top(reach)] + let end: EavePoint[] + let low: number + let height: number + let corners: [EavePoint, EavePoint, EavePoint, EavePoint] + let soffit: RoofEaveProfile['soffit'] = null + if (cut === 'square') { + // the sheathing's top to the tails' underside, square to the slope + const depth = deck - tailLift * cos + height = input.fasciaHeight ?? boardWidth(depth) + const down = (d: number): EavePoint => [reach - d * sin, corner[1] - d * cos] + const out = (point: EavePoint): EavePoint => [ + point[0] + thickness * cos, + point[1] - thickness * sin, + ] + const foot = down(depth) + end = [corner, foot] + low = foot[1] + const bottom = down(height) + corners = [corner, out(corner), out(bottom), bottom] + } else { + let foot = under(reach) + if (cut === 'plumb-level') { + const run = Math.min(LEVEL_CUT_RUN, input.tailDepth / cos / (2 * tan)) + foot = under(reach) + run * tan + end = [corner, [reach, foot], [reach - run, foot]] + soffit = { y: foot, thickness: SOFFIT_THICKNESS, from: wallOut, to: reach } + } else end = [corner, [reach, foot]] + low = foot + const topY = corner[1] + (input.fasciaRise ?? 0) + // past a boxed eave's soffit, the fascia drops its whole 3/4 in under the level cuts + height = + input.fasciaHeight ?? + boardWidth( + topY - foot, + 1, + cut === 'plumb-level' ? SOFFIT_THICKNESS + FASCIA_DROP_MIN : FASCIA_DROP_MIN, + ) + corners = [ + [reach, topY], + [reach + thickness, topY], + [reach + thickness, topY - height], + [reach, topY - height], + ] + } + // A rake board meets the eave's fascia flush at the corner: as deep at its foot (plumb, or square + // along the cut), so neither hangs past the other. Over a boxed eave it covers the barge whole, + // held level with the fascia's bottom at the corner. + const rakeHeight = + input.fasciaHeight ?? + (cut === 'plumb' + ? height + : cut === 'square' + ? height / cos + : boardWidth(deck / cos - tailLift, cos) / cos) + return { + cut, + tan, + cos, + sin, + reach, + wallOut, + top, + under, + end, + low, + fascia: { + corners, + height, + thickness, + square: cut === 'square', + ...fasciaStockFor(height), + }, + soffit, + rake: { height: rakeHeight, width: rakeHeight * cos, ...fasciaStockFor(rakeHeight * cos) }, + } +} + +/** + * Whether a point of an eave's section, out past the wall's outer face, lies in the shell's eave + * (`tolerance` either way): under the sheathing's top, inside the tails' end cut, and over their + * underside or a boxed eave's soffit. + */ +export function eaveContains(profile: RoofEaveProfile, [s, y]: EavePoint, tolerance = 0): boolean { + const { reach, cut, cos, sin, top, under, soffit } = profile + if (y > top(s) + tolerance || s > reach + tolerance) return false + const [cs, cy] = profile.end[0] as EavePoint + if (cut === 'square' && (s - cs) * cos - (y - cy) * sin > tolerance) return false + // a boxed eave stands on its soffit: under it the deck is cut away + const floor = soffit ? soffit.y - soffit.thickness : under(s) + return y >= floor - tolerance +} + +type EaveSegment = Pick< + RoofSegmentNode, + 'roofType' | 'pitch' | 'width' | 'depth' | 'wallThickness' | 'overhang' | 'deckThickness' +> & + Partial< + Pick< + RoofSegmentNode, + | 'gableOverhang' + | 'buildUp' + | 'eaveCut' + | 'fasciaHeight' + | 'fasciaDepth' + | 'shingleThickness' + | 'barrelRise' + | 'barrelSegments' + > + > + +/** + * The numbers a roof plane's eaves are cut from (`roofEaveProfile`): its reach and wall, its layers' + * structure and deck, its eave cut and fascia. Its rafters sit on the plate; a truss's top chord on + * its bottom chord at the heel. A plane without layers is taken as rafters under a 7/16 in sheet, + * as deep as its deck. `high`: a shed's high edge, rising outward, cut plumb. + */ +export function roofSegmentEaveInput( + node: EaveSegment, + edge: 'eave' | 'high' = 'eave', +): RoofEaveInput { + const { tanTheta } = getSegmentSlopeFrame(node) + const deck = Math.max(0, node.deckThickness) + const structure = node.buildUp?.structure + const chord = structure ? LUMBER_DEPTH[structure.size] : 0 + const tailDepth = structure ? chord : Math.max(0, deck - Math.min(BARE_SHEATHING, deck / 2)) + return { + tan: edge === 'high' ? -tanTheta : tanTheta, + reach: getRoofSegmentDeckReach(node).z, + wallOut: Math.max(0, node.wallThickness) / 2, + tailDepth, + tailLift: structure?.system === 'trusses' ? chord : 0, + deckDepth: deck, + cut: edge === 'high' ? 'plumb' : (node.eaveCut ?? 'plumb'), + ...(node.fasciaHeight !== undefined ? { fasciaHeight: node.fasciaHeight } : {}), + ...(node.fasciaDepth !== undefined ? { fasciaThickness: node.fasciaDepth } : {}), + // a flat roof's boards sized on purpose rise over its membrane's edge: a coping band + ...(node.roofType === 'flat' && node.fasciaHeight !== undefined + ? { fasciaRise: Math.max(0, node.shingleThickness ?? 0) } + : {}), + } +} + +/** A roof plane's eave (`roofSegmentEaveInput`, `roofEaveProfile`). */ +export function roofSegmentEaveProfile( + node: EaveSegment, + edge: 'eave' | 'high' = 'eave', +): RoofEaveProfile { + return roofEaveProfile(roofSegmentEaveInput(node, edge)) +} diff --git a/packages/core/src/lib/room-floor-plate.ts b/packages/core/src/lib/room-floor-plate.ts index 9baaa233c7..203cfa697f 100644 --- a/packages/core/src/lib/room-floor-plate.ts +++ b/packages/core/src/lib/room-floor-plate.ts @@ -1,6 +1,16 @@ -import type { SlabNode } from '../schema' +import type { AnyNode, AnyNodeId, SlabNode, ZoneNode } from '../schema' export function roomFloorPlate(slabs: readonly SlabNode[], zoneId: string): SlabNode | undefined { const owned = slabs.filter((slab) => slab.zoneIds?.includes(zoneId)) return owned.find((slab) => slab.plateRole !== 'base') ?? owned[0] } + +/** A dedicated plate's room; shared base plates do not inherit one room's outdoor type. */ +export function floorPlateRoom( + slab: Pick, + resolve: (id: AnyNodeId) => AnyNode | undefined, +): ZoneNode | undefined { + if (slab.plateRole === 'base' || slab.zoneIds?.length !== 1) return undefined + const zone = resolve(slab.zoneIds[0]! as AnyNodeId) + return zone?.type === 'zone' ? zone : undefined +} diff --git a/packages/core/src/lib/space-detection.ts b/packages/core/src/lib/space-detection.ts index fc6710f76f..322b3be4d5 100644 --- a/packages/core/src/lib/space-detection.ts +++ b/packages/core/src/lib/space-detection.ts @@ -25,6 +25,8 @@ import { import { getClampedWallCurveOffset } from '../systems/wall/wall-curve' import { changedLevelConstructionDisplacements } from './floor-foundation-stack' import { createFloorOpeningIndex, floorOpeningTargets } from './floor-opening-intent' +import { porchPartOf, porchPartSignature } from './porch-framing-sync' +import { railingFencedRoomIds, railingWallIds } from './railing-rooms' import { type ExtractedRoom, extractRooms, @@ -145,6 +147,9 @@ function zoneGeometrySignature(zone: ZoneNodeType) { zone.wallMaterial, zone.wallOverrides, zone.seed, + // A porch's type and framing settings rebuild its posts and beam. + zone.roomType, + zone.porchFraming, // A drawn zone's outline is intent (it may be adopted); a room's outline is // derived, and an edit to it must be re-derived here as the hosted path does. // The kernel's own write is not a change: the baseline is taken after it. @@ -164,11 +169,19 @@ function levelStructureSnapshots(nodes: Record) { const zonesByLevel = new Map() const slabElevationsByLevel = new Map() const coveringUndersidesByLevel = new Map() + const porchPartsByLevel = new Map() const floorOpenings: Extract[] = [] for (const node of Object.values(nodes)) { if (!(node && typeof node === 'object' && 'parentId' in node && node.parentId)) continue const levelId = (node as any).parentId as string + // A porch's own post or beam moved, resized or deleted by hand hands its framing over. + const porchPart = porchPartSignature(node) + if (porchPart) { + const parts = porchPartsByLevel.get(levelId) ?? [] + parts.push(porchPart) + porchPartsByLevel.set(levelId, parts) + } if (node.type === 'stair' && nodes[node.deckSlabId]?.support === 'open') { const target = nodes[node.deckSlabId].parentId const arrivals = arrivalsByLevel.get(target) ?? [] @@ -271,6 +284,7 @@ function levelStructureSnapshots(nodes: Record) { ...zonesByLevel.keys(), ...separatorsByLevel.keys(), ...openingsByLevel.keys(), + ...porchPartsByLevel.keys(), ]) for (const levelId of levelIds) { const walls = wallsByLevel.get(levelId) ?? [] @@ -284,7 +298,7 @@ function levelStructureSnapshots(nodes: Record) { : '' snapshots.set( levelId, - `${(arrivalsByLevel.get(levelId) ?? []).sort().join('|')}#${(separatorsByLevel.get(levelId) ?? []).sort().join('|')}#${storeyKey}#${levelWallSnapshot(walls, nodes, levelId)}##${zones.map(zoneGeometrySignature).sort().join('||')}##${slabKey}##${aboveSlabKey}##${(ceilingIdsByLevel.get(levelId) ?? []).sort().join('|')}##${(openingsByLevel.get(levelId) ?? []).sort().join('|')}`, + `${(arrivalsByLevel.get(levelId) ?? []).sort().join('|')}#${(separatorsByLevel.get(levelId) ?? []).sort().join('|')}#${storeyKey}#${levelWallSnapshot(walls, nodes, levelId)}##${zones.map(zoneGeometrySignature).sort().join('||')}##${slabKey}##${aboveSlabKey}##${(ceilingIdsByLevel.get(levelId) ?? []).sort().join('|')}##${(openingsByLevel.get(levelId) ?? []).sort().join('|')}##${(porchPartsByLevel.get(levelId) ?? []).sort().join('|')}`, ) } @@ -418,6 +432,10 @@ function fallbackLevelIdsForCandidates( } else if (node.type === 'door' || node.type === 'window') { const wall = nodes[node.parentId] if (wall?.parentId) levelIds.add(wall.parentId) + } else if (porchPartOf(node)) { + // A porch's own post or beam edited by hand: the kernel hands its framing over. + if (porchPartSignature(before[id]) !== porchPartSignature(current[id]) && node.parentId) + levelIds.add(node.parentId) } else if (node.type === 'slab') { const old = before[id], next = current[id] @@ -459,12 +477,12 @@ function detectSpacesFromWalls(levelId: string, boundaries: BoundaryNode[]) { const rooms = extractRooms(boundaries) const walls = boundaries.filter((boundary): boundary is WallNode => boundary.type === 'wall') const roomPolygons = rooms.map((room) => room.polygon) + const spans = rooms.flatMap((room) => room.spans) + // A room a railing fences off from the outside (a deck's guard) is outside. + const fenced = railingFencedRoomIds(spans, railingWallIds(walls)) const wallUpdates: WallSideUpdate[] = walls.map((wall) => ({ wallId: wall.id, - ...classifyWallSides( - wall, - rooms.flatMap((room) => room.spans), - ), + ...classifyWallSides(wall, spans, fenced), })) return { diff --git a/packages/core/src/lib/structure-kernel.ts b/packages/core/src/lib/structure-kernel.ts index fc2c96324f..ddd6350d1f 100644 --- a/packages/core/src/lib/structure-kernel.ts +++ b/packages/core/src/lib/structure-kernel.ts @@ -19,6 +19,7 @@ import { buildFloorPlates, warnPlateFailure } from './floor-plates' import { floorRoomFaces } from './floor-room-faces' import { type FloorStepOverride, remapFloorStepOverrideKeys } from './floor-step-finish' import { newZone } from './new-zone' +import { isOutdoorRoom, nextOutdoorRoomName, OUTDOOR_ROOM_DEFAULTS } from './outdoor-room' import { replacementPlateFor } from './plate-reference' import { area, @@ -30,6 +31,8 @@ import { union, } from './polygon-boolean' import { polygonInteriorPoint } from './polygon-label' +import { reconcilePorchFraming } from './porch-framing-sync' +import { railingFencedRoomIds, railingWallIds } from './railing-rooms' import { pointFromTuple } from './room-graph' import { roomNameAllocator } from './room-name' import type { BoundarySpan } from './room-topology-index' @@ -117,18 +120,50 @@ function equal(a: unknown, b: unknown) { const SPAN_OVERLAP = 1e-6 /** - * The rooms that are outside: without a ceiling, and left without crossing a wall, through a - * separator no room stands behind or into another such room. A porch made a room for its floor - * left its wall with no outside: the front door faced the hall. A room that only lost its - * ceiling is walled in and a kitchen open to a terrace keeps its ceiling, so both stay inside; so - * does a courtyard walled on every side, a limit of this rule. + * The rooms closed off outside the house, and what they are by default: open to the outside across + * invisible walls or railings nothing stands behind, along at least as much of their edge as walls + * close (a porch on the front, or in a corner of the house). Closed with invisible walls, a porch; + * fenced with railings alone, a deck. A room walled on three sides and open on the fourth (a + * kitchen open to a terrace, a recessed porch) is not one of them. `lengthOf` is a wall's or a + * separator's length; `railingIds` the railing walls. */ -export function outdoorRoomIds( - rooms: readonly { spans: readonly BoundarySpan[]; hasCeiling: boolean }[], -): Set { - const separatorSpans = rooms.flatMap((room) => - room.spans.filter((span) => span.kind === 'separator'), - ) +export function outsideRoomTypes( + rooms: readonly { spans: readonly BoundarySpan[] }[], + lengthOf: (boundaryId: string) => number, + railingIds: ReadonlySet = new Set(), +): Map { + const railing = (span: BoundarySpan) => span.kind === 'wall' && railingIds.has(span.boundaryId) + const { exposed } = openLineExposure(rooms, (span) => span.kind === 'separator' || railing(span)) + const spanLength = (span: BoundarySpan) => (span.t1 - span.t0) * lengthOf(span.boundaryId) + const types = new Map() + for (const room of rooms) { + let open = 0 + let walled = 0 + let invisible = false + for (const span of room.spans) { + if (span.kind === 'wall' && !railing(span)) walled += spanLength(span) + else if (exposed(span)) { + open += spanLength(span) + invisible ||= span.kind === 'separator' + } + } + if (room.spans[0] && open > 0 && open >= walled - 1e-6) + types.set(room.spans[0].roomId, invisible ? 'porch' : 'deck') + } + return types +} + +/** Each separator span's spans across it, and whether any stretch of it has none. */ +function separatorExposure(rooms: readonly { spans: readonly BoundarySpan[] }[]) { + return openLineExposure(rooms, (span) => span.kind === 'separator') +} + +/** Each open line's span (`isOpen`): the spans across it, and whether any stretch of it has none. */ +function openLineExposure( + rooms: readonly { spans: readonly BoundarySpan[] }[], + isOpen: (span: BoundarySpan) => boolean, +) { + const separatorSpans = rooms.flatMap((room) => room.spans.filter(isOpen)) const across = (span: BoundarySpan) => separatorSpans .filter( @@ -146,13 +181,35 @@ export function outdoorRoomIds( } return reach < span.t1 - SPAN_OVERLAP } + return { across, exposed } +} + +/** + * The rooms that are outside: a porch, deck or patio (`roomType`, outdoors whatever covers it), and + * a room without a ceiling left without crossing a wall, through a separator no room stands behind + * or into another such room. A porch made a room for its floor left its wall with no outside: the + * front door faced the hall. A room that only lost its ceiling is walled in and a kitchen open to a + * terrace keeps its ceiling, so both stay inside; so does a courtyard walled on every side, a limit + * of this rule. + */ +export function outdoorRoomIds( + rooms: readonly { spans: readonly BoundarySpan[]; hasCeiling: boolean; outdoor?: boolean }[], +): Set { + const { across, exposed } = separatorExposure(rooms) const open = new Map( rooms.flatMap((room) => - !room.hasCeiling && room.spans[0] ? [[room.spans[0].roomId, room.spans] as const] : [], + (!room.hasCeiling || room.outdoor) && room.spans[0] + ? [[room.spans[0].roomId, room.spans] as const] + : [], ), ) + const declared = new Set( + rooms.flatMap((room) => (room.outdoor && room.spans[0] ? [room.spans[0].roomId] : [])), + ) const queue = [...open].flatMap(([id, spans]) => - spans.some((span) => span.kind === 'separator' && exposed(span)) ? [id] : [], + declared.has(id) || spans.some((span) => span.kind === 'separator' && exposed(span)) + ? [id] + : [], ) const outdoor = new Set(queue) for (let id = queue.pop(); id !== undefined; id = queue.pop()) @@ -207,13 +264,14 @@ export function reconcileLevelStructure( function planLevelStructure({ levelId, nodes, + previousNodes, mintId, openingIndex, }: { levelId: string nodes: SceneNodes previousNodes?: SceneNodes - mintId: (kind: 'zone' | 'ceiling' | 'slab' | 'separator') => string + mintId: (kind: 'zone' | 'ceiling' | 'slab' | 'separator' | 'column' | 'beam') => string openingIndex?: FloorOpeningIndex }): { patches: NodePatch[]; snapshot: LevelStructureSnapshot; events: StructureEvent[] } { const snapshot: LevelStructureSnapshot = { levelId, rooms: [] } @@ -309,6 +367,20 @@ function planLevelStructure({ const zoneByFace = new Map() const retiredTo = new Map() const nextRoomName = roomNameAllocator(allZones) + // A new room closed off outside the house is a porch, or a deck when railings fence it + // (`lib/outdoor-room`). + const boundaryLengths = new Map( + [...walls, ...separators].map((boundary) => [ + boundary.id as string, + Math.hypot(boundary.end[0] - boundary.start[0], boundary.end[1] - boundary.start[1]), + ]), + ) + const outsideTypes = outsideRoomTypes( + faces, + (id) => boundaryLengths.get(id) ?? 0, + railingWallIds(walls), + ) + const roomNames = allZones.map((zone) => zone.name) faces.forEach((face, index) => { const rooms = zones .filter((zone) => preferred.get(zone.id) === index && !adoptionFits.has(zone.id)) @@ -333,21 +405,38 @@ function planLevelStructure({ (a, b) => scores.get(b.id)![index]! - scores.get(a.id)![index]! || compareIds(a.id, b.id), )[0] if (source) sourceByFace.set(index, source) + const outside = + !survivor && !source && face.spans[0] ? outsideTypes.get(face.spans[0].roomId) : undefined const zone = survivor ?? - newZone({ - id: mintId('zone'), - parentId: levelId, - name: nextRoomName(), - polygon: face.polygon.outer, - floor: source?.floor, - wallMaterial: source?.wallMaterial, - floorStepFinish: source?.floorStepFinish, - floorStepOverrides: source?.floorStepOverrides, - floorEdgeFinish: source?.floorEdgeFinish, - hasFloor: source?.hasFloor, - hasCeiling: source?.hasCeiling, - }) + (outside + ? newZone({ + id: mintId('zone'), + parentId: levelId, + name: nextOutdoorRoomName(outside, roomNames), + polygon: face.polygon.outer, + roomType: outside, + floor: { + drop: OUTDOOR_ROOM_DEFAULTS[outside].drop, + finish: OUTDOOR_ROOM_DEFAULTS[outside].finish, + }, + ...(OUTDOOR_ROOM_DEFAULTS[outside].covered ? {} : { hasCeiling: false }), + }) + : newZone({ + id: mintId('zone'), + parentId: levelId, + name: nextRoomName(), + polygon: face.polygon.outer, + floor: source?.floor, + wallMaterial: source?.wallMaterial, + floorStepFinish: source?.floorStepFinish, + floorStepOverrides: source?.floorStepOverrides, + floorEdgeFinish: source?.floorEdgeFinish, + hasFloor: source?.hasFloor, + hasCeiling: source?.hasCeiling, + roomType: source?.roomType, + })) + if (outside) roomNames.push(zone.name) const seed = zone.seed && containsPoint([face.polygon], zone.seed) ? zone.seed @@ -596,6 +685,7 @@ function planLevelStructure({ material: template?.material, materialPreset: template?.materialPreset, slots: template?.slots, + buildUp: template?.buildUp, visible: template?.visible, }) const updated: CeilingNode = { @@ -767,13 +857,39 @@ function planLevelStructure({ } for (const components of ceilingComponentsByFace.values()) for (const ceiling of components) ceiling.children = [...new Set(ceiling.children)].sort() + // A covered porch's posts and beam (`lib/porch-framing-sync`). + const porchFraming = reconcilePorchFraming({ + levelId, + nodes, + previousNodes, + zones: [ + ...new Map( + [...allZones, ...next.values()].flatMap((zone) => + zone.type === 'zone' && !deleted.has(zone.id) + ? [[zone.id, (next.get(zone.id) ?? zone) as ZoneNode] as const] + : [], + ), + ).values(), + ], + plates: floorPlan.plates, + current: (id) => next.get(id) ?? nodes[id], + mintId, + }) + for (const node of porchFraming.put) put(node) + for (const id of porchFraming.delete) deleted.add(id) const spans = snapshot.rooms.flatMap((room) => room.spans) const outdoor = outdoorRoomIds( - [...zoneByFace].map(([index, zone]) => ({ - spans: faces[index]!.spans, - hasCeiling: ((next.get(zone.id) ?? zone) as ZoneNode).hasCeiling !== false, - })), + [...zoneByFace].map(([index, zone]) => { + const current = (next.get(zone.id) ?? zone) as ZoneNode + return { + spans: faces[index]!.spans, + hasCeiling: current.hasCeiling !== false, + outdoor: isOutdoorRoom(current), + } + }), ) + // A room a railing fences off from the outside (a deck's guard) is outside too. + for (const id of railingFencedRoomIds(spans, railingWallIds(walls))) outdoor.add(id) for (const wall of walls) put({ ...wall, ...next.get(wall.id), ...classifyWallSides(wall, spans, outdoor) } as WallNode) for (const ceiling of allCeilings) { @@ -890,7 +1006,14 @@ export function createLevelStructurePreview(levelId: string, nodes: SceneNodes) .filter((node): node is WallNode => node.type === 'wall' && node.parentId === levelId) .map((node) => node.id), ) - return (walls: readonly WallNode[]) => { + let separatorIds = new Set( + Object.values(draft) + .filter((node) => node.type === 'separator' && node.parentId === levelId) + .map((node) => node.id), + ) + // `separators`, when given, are the level's invisible walls as the gesture + // leaves them (an invisible-wall push); left out, the stored ones stand. + return (walls: readonly WallNode[], separators?: readonly SeparatorNode[]) => { const currentIds = new Set() for (const wall of walls) { if (wall.parentId !== levelId) continue @@ -900,6 +1023,16 @@ export function createLevelStructurePreview(levelId: string, nodes: SceneNodes) // A level wall left out is one the gesture removes. for (const id of wallIds) if (!currentIds.has(id)) delete draft[id] wallIds = currentIds + if (separators) { + const current = new Set() + for (const separator of separators) { + if (separator.parentId !== levelId) continue + current.add(separator.id) + if (draft[separator.id] !== separator) draft[separator.id] = separator + } + for (const id of separatorIds) if (!current.has(id)) delete draft[id] + separatorIds = current + } let id = 0 // The stored surfaces are the committed reconciliation; only what the // moved walls reshape differs from them. diff --git a/packages/core/src/lib/structure-reconcile.ts b/packages/core/src/lib/structure-reconcile.ts index a92d70a268..559f2f25e2 100644 --- a/packages/core/src/lib/structure-reconcile.ts +++ b/packages/core/src/lib/structure-reconcile.ts @@ -15,8 +15,11 @@ import { type SceneNodes, type StructureEvent, } from './structure-kernel' +import { surfaceIntentZoneIds } from './surface-intent' -export type StructureIdFactory = (kind: 'zone' | 'ceiling' | 'slab' | 'separator') => string +export type StructureIdFactory = ( + kind: 'zone' | 'ceiling' | 'slab' | 'separator' | 'column' | 'beam', +) => string export type SceneStructureInput = { nodes: SceneNodes levelIds?: string[] @@ -126,6 +129,7 @@ export function reconcileSceneStructure({ if (draft[levelId]?.type !== 'level') return const children = levelChildren(draft, levelId) const previousChildren = previousNodes ? levelChildren(previousNodes, levelId) : [] + const plates = children.filter((node) => node.type === 'slab') for (const surface of previousChildren) { if ( (surface.type !== 'ceiling' && surface.type !== 'slab') || @@ -133,8 +137,8 @@ export function reconcileSceneStructure({ draft[surface.id] ) continue - const ids = surface.type === 'ceiling' ? [surface.zoneId] : (surface.zoneIds ?? []) - for (const id of ids) { + // The rooms it was the floor or ceiling of: a porch on a plate of its own keeps its floor. + for (const id of surfaceIntentZoneIds(surface, plates)) { const zone = id ? draft[id] : undefined if (zone?.type === 'zone') draft[zone.id] = { @@ -229,9 +233,10 @@ export function reconcileSceneStructure({ if (metadata?.source !== 'floor-opening') return [{ hole, metadata: metadata ?? { source: 'manual' as const } }] const opening = metadata.openingId ? draft[metadata.openingId] : undefined + // An owner's cut map is complete: a surface it no longer names must heal. return opening?.type === 'floor-opening' && - !opening.legacyPlateCuts?.[surface.id] && - !opening.legacyCeilingCuts?.[surface.id] + !opening.legacyPlateCuts && + !opening.legacyCeilingCuts ? [{ hole, metadata }] : [] }) diff --git a/packages/core/src/lib/surface-intent.ts b/packages/core/src/lib/surface-intent.ts new file mode 100644 index 0000000000..0c5a15f2f4 --- /dev/null +++ b/packages/core/src/lib/surface-intent.ts @@ -0,0 +1,26 @@ +import type { AnyNode, CeilingNode, SlabNode } from '../schema' + +/** + * The rooms whose construction a derived surface IS, among `plates` (the level's floor plates as + * they stand after the edit): a ceiling's room, and the rooms a plate is the floor of. A shared base + * plate also lists the rooms that stand on plates of their own (a porch or deck a step down, a raised + * platform), but it is not their floor, so losing it leaves theirs. Without this, deleting the house's + * plate took every porch and deck floor on the level with it. + */ +export function surfaceIntentZoneIds( + node: SlabNode | CeilingNode, + plates: readonly AnyNode[], +): string[] { + const ids = [ + ...new Set(node.type === 'slab' ? (node.zoneIds ?? []) : node.zoneId ? [node.zoneId] : []), + ] + if (node.type !== 'slab' || node.plateRole !== 'base') return ids + const own = new Set( + plates.flatMap((plate) => + plate.type === 'slab' && plate.id !== node.id && plate.plateRole && plate.plateRole !== 'base' + ? (plate.zoneIds ?? []) + : [], + ), + ) + return ids.filter((id) => !own.has(id)) +} diff --git a/packages/core/src/lib/wall-face-script.ts b/packages/core/src/lib/wall-face-script.ts index 4f0e3f6703..e59df924e7 100644 --- a/packages/core/src/lib/wall-face-script.ts +++ b/packages/core/src/lib/wall-face-script.ts @@ -88,11 +88,14 @@ type FaceFrame = { top: number } -/** A wall whose faces a script can build on: straight, not a curtain wall, standing on a level. */ +/** + * A wall whose faces a script can build on: straight, not a curtain wall or a railing (neither has + * faces), standing on a level. + */ function scriptableWall(nodes: SceneNodes, wallId: string): WallNode | null { const wall = nodes[wallId] if (wall?.type !== 'wall' || !wall.parentId) return null - if (wall.wallType === 'curtain' || isCurvedWall(wall)) return null + if (wall.wallType === 'curtain' || wall.wallType === 'railing' || isCurvedWall(wall)) return null return Math.hypot(wall.end[0] - wall.start[0], wall.end[1] - wall.start[1]) < EPS ? null : wall } diff --git a/packages/core/src/material-kinds.ts b/packages/core/src/material-kinds.ts index 41ca0239dd..1c28004c30 100644 --- a/packages/core/src/material-kinds.ts +++ b/packages/core/src/material-kinds.ts @@ -5,6 +5,7 @@ export const MATERIAL_CATEGORIES = [ 'colors', 'wood', + 'siding', 'stone', 'brick', 'tile', diff --git a/packages/core/src/material-library.test.ts b/packages/core/src/material-library.test.ts index 344cbbb1be..c78953e89b 100644 --- a/packages/core/src/material-library.test.ts +++ b/packages/core/src/material-library.test.ts @@ -1,5 +1,12 @@ import { describe, expect, test } from 'bun:test' -import { getLibraryMaterialIdFromRef, getSceneMaterialIdFromRef } from './material-library' +import { + getCatalogMaterialById, + getLibraryMaterialIdFromRef, + getMaterialSwatch, + getMaterialsForCategory, + getSceneMaterialIdFromRef, + MATERIAL_CATALOG, +} from './index' describe('material references', () => { test('rejects malformed runtime values instead of calling string methods', () => { @@ -11,3 +18,84 @@ describe('material references', () => { } }) }) + +describe('siding', () => { + test('shares complete metre-scale lap and batten profiles across the 18 painted finishes', () => { + const siding = getMaterialsForCategory('siding') + expect(siding).toHaveLength(18) + for (const item of siding) { + const profile = item.id.includes('batten') || item.id.includes('vertical') ? 'batten' : 'lap' + expect(item.preset.maps).toEqual({ + albedoMap: `/material/siding/${profile}_basecolor_512.ktx2`, + normalMap: `/material/siding/${profile}_normal_512.ktx2`, + roughnessMap: `/material/siding/${profile}_roughness_512.ktx2`, + aoMap: `/material/siding/${profile}_ao_512.ktx2`, + }) + expect(item.preset.mapProperties.repeatX).toBe(1) + expect(item.preset.mapProperties.repeatY).toBe(1) + expect(item.preset.mapProperties.flipY).toBe(false) + expect(getMaterialSwatch(item).imageUrl).toBe(item.previewThumbnailUrl!) + expect(getMaterialSwatch(item).tinted).toBe(true) + } + }) + + test('has its own category, apart from wood, under the ids scenes already reference', () => { + const siding = getMaterialsForCategory('siding').map((item) => item.id) + for (const id of ['siding-lap-white', 'siding-lap-cedar', 'siding-batten-charcoal']) { + expect(siding).toContain(id) + expect(getCatalogMaterialById(id)?.category).toBe('siding') + } + expect(siding).toContain('siding-vinyl-white') + expect(getMaterialsForCategory('wood').some((item) => item.id.startsWith('siding-'))).toBe( + false, + ) + }) + + test('a siding swatch is its profile texture tinted by its colour, not a flat chip', () => { + const navy = getCatalogMaterialById('siding-lap-navy')! + expect(getMaterialSwatch(navy)).toEqual({ + color: navy.preset.mapProperties.color, + imageUrl: navy.previewThumbnailUrl!, + tinted: true, + }) + const batten = getMaterialSwatch(getCatalogMaterialById('siding-batten-olive')!) + expect(batten.imageUrl).toContain('batten') + }) + + test('a thumbnail multiplies the material tint instead of its representative preview colour', () => { + const navy = getCatalogMaterialById('siding-lap-navy')! + const item = { + ...navy, + previewThumbnailUrl: '/material/siding/lap_thumb.webp', + previewColor: '#eeeeee', + } + expect(getMaterialSwatch(item)).toEqual({ + color: navy.preset.mapProperties.color, + imageUrl: item.previewThumbnailUrl, + tinted: true, + }) + }) + + test('a white-tinted thumbnail shows as is, and a flat colour stays a colour', () => { + const wood = getCatalogMaterialById('wood-finewood27')! + expect(getMaterialSwatch(wood)).toEqual({ + color: wood.previewColor!, + imageUrl: wood.previewThumbnailUrl!, + tinted: false, + }) + const white = getMaterialSwatch(getCatalogMaterialById('preset-white')!) + expect(white.imageUrl).toBeNull() + }) +}) + +describe('textured catalog materials', () => { + test('uses compressed maps with browser-readable thumbnails in stored orientation', () => { + for (const item of MATERIAL_CATALOG) { + const maps = Object.values(item.preset.maps).filter(Boolean) + if (maps.length === 0) continue + for (const map of maps) expect(map).toMatch(/\.ktx2$/) + expect(item.previewThumbnailUrl).toMatch(/_thumb\.webp$/) + expect(item.preset.mapProperties.flipY).toBe(false) + } + }) +}) diff --git a/packages/core/src/material-library.ts b/packages/core/src/material-library.ts index 77e7e7975c..4ebe238b7c 100644 --- a/packages/core/src/material-library.ts +++ b/packages/core/src/material-library.ts @@ -1926,7 +1926,7 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ previewColor: '#505050', preset: { maps: { - albedoMap: '/material/roofing/roof_shingles_grey/roof_shingles_grey_basecolor_512.webp', + albedoMap: '/material/roofing/roof_shingles_grey/roof_shingles_grey_basecolor_512.ktx2', aoMap: '/material/roofing/roof_shingles_classic/roof_shingles_classic_ao_512.ktx2', metalnessMap: '/material/roofing/roof_shingles_classic/roof_shingles_classic_metallic_512.ktx2', @@ -2165,6 +2165,41 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ }, }, }, + { + // The default interior wall paint (`DEFAULT_INTERIOR_WALL_PAINT`): Light grey's + // colour under its own name. Listed after it, so a nearest-colour snap still + // lands on Light grey. + id: 'preset-seattlegrey', + label: 'Seattle grey', + category: 'colors', + description: 'Cool light grey interior wall paint', + previewColor: '#d8d6d1', + preset: { + maps: {}, + mapProperties: { + color: '#d8d6d1', + roughness: 0.9, + metalness: 0, + repeatX: 1, + repeatY: 1, + rotation: 0, + wrapS: 'Repeat', + wrapT: 'Repeat', + normalScaleX: 1, + normalScaleY: 1, + emissiveIntensity: 1, + displacementScale: 0.02, + transparent: false, + flipY: true, + bumpScale: 1, + emissiveColor: '#000000', + aoMapIntensity: 1, + side: 0, + opacity: 1, + lightMapIntensity: 1, + }, + }, + }, { id: 'preset-greige', label: 'Greige', @@ -4248,18 +4283,24 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ * board-and-batten — so imported exterior walls could be color-true only as * flat paint. One white seamless albedo per profile, * tinted per entry via mapProperties.color (same mechanism the flat color - * presets use), keeps this to two textures for twelve finishes. + * presets use), keeps this to two textures for every finish. Painted wood / + * fiber-cement and vinyl differ by sheen (roughness). The `siding` category + * keeps them apart from wood flooring; ids are stable scene references. */ { id: 'siding-lap-white', label: 'Lap siding — white', - category: 'wood', + category: 'siding', surfaces: ['wall', 'outdoor'], description: 'Exterior clapboard lap siding, painted white', + previewThumbnailUrl: '/material/siding/lap_thumb.webp', previewColor: '#e9e9e9', preset: { maps: { - albedoMap: '/material/siding/lap_albedo_512.webp', + albedoMap: '/material/siding/lap_basecolor_512.ktx2', + normalMap: '/material/siding/lap_normal_512.ktx2', + roughnessMap: '/material/siding/lap_roughness_512.ktx2', + aoMap: '/material/siding/lap_ao_512.ktx2', }, mapProperties: { color: '#e9e9e9', @@ -4273,10 +4314,10 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ normalScaleX: 1, normalScaleY: 1, emissiveIntensity: 1, - displacementScale: 0.02, + displacementScale: 0, bumpScale: 1, transparent: false, - flipY: true, + flipY: false, emissiveColor: '#000000', aoMapIntensity: 1, side: 0, @@ -4288,13 +4329,17 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ { id: 'siding-lap-greige', label: 'Lap siding — greige', - category: 'wood', + category: 'siding', surfaces: ['wall', 'outdoor'], description: 'Exterior clapboard lap siding, painted greige', + previewThumbnailUrl: '/material/siding/lap_thumb.webp', previewColor: '#c8c1b8', preset: { maps: { - albedoMap: '/material/siding/lap_albedo_512.webp', + albedoMap: '/material/siding/lap_basecolor_512.ktx2', + normalMap: '/material/siding/lap_normal_512.ktx2', + roughnessMap: '/material/siding/lap_roughness_512.ktx2', + aoMap: '/material/siding/lap_ao_512.ktx2', }, mapProperties: { color: '#c8c1b8', @@ -4308,10 +4353,10 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ normalScaleX: 1, normalScaleY: 1, emissiveIntensity: 1, - displacementScale: 0.02, + displacementScale: 0, bumpScale: 1, transparent: false, - flipY: true, + flipY: false, emissiveColor: '#000000', aoMapIntensity: 1, side: 0, @@ -4323,13 +4368,17 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ { id: 'siding-lap-gray', label: 'Lap siding — gray', - category: 'wood', + category: 'siding', surfaces: ['wall', 'outdoor'], description: 'Exterior clapboard lap siding, painted gray', + previewThumbnailUrl: '/material/siding/lap_thumb.webp', previewColor: '#8b8a86', preset: { maps: { - albedoMap: '/material/siding/lap_albedo_512.webp', + albedoMap: '/material/siding/lap_basecolor_512.ktx2', + normalMap: '/material/siding/lap_normal_512.ktx2', + roughnessMap: '/material/siding/lap_roughness_512.ktx2', + aoMap: '/material/siding/lap_ao_512.ktx2', }, mapProperties: { color: '#8b8a86', @@ -4343,10 +4392,10 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ normalScaleX: 1, normalScaleY: 1, emissiveIntensity: 1, - displacementScale: 0.02, + displacementScale: 0, bumpScale: 1, transparent: false, - flipY: true, + flipY: false, emissiveColor: '#000000', aoMapIntensity: 1, side: 0, @@ -4358,13 +4407,17 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ { id: 'siding-lap-sage', label: 'Lap siding — sage', - category: 'wood', + category: 'siding', surfaces: ['wall', 'outdoor'], description: 'Exterior clapboard lap siding, painted sage', + previewThumbnailUrl: '/material/siding/lap_thumb.webp', previewColor: '#bcc5b2', preset: { maps: { - albedoMap: '/material/siding/lap_albedo_512.webp', + albedoMap: '/material/siding/lap_basecolor_512.ktx2', + normalMap: '/material/siding/lap_normal_512.ktx2', + roughnessMap: '/material/siding/lap_roughness_512.ktx2', + aoMap: '/material/siding/lap_ao_512.ktx2', }, mapProperties: { color: '#bcc5b2', @@ -4378,10 +4431,10 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ normalScaleX: 1, normalScaleY: 1, emissiveIntensity: 1, - displacementScale: 0.02, + displacementScale: 0, bumpScale: 1, transparent: false, - flipY: true, + flipY: false, emissiveColor: '#000000', aoMapIntensity: 1, side: 0, @@ -4393,13 +4446,17 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ { id: 'siding-lap-cedar', label: 'Lap siding — cedar', - category: 'wood', + category: 'siding', surfaces: ['wall', 'outdoor'], description: 'Exterior clapboard lap siding, stained cedar', + previewThumbnailUrl: '/material/siding/lap_thumb.webp', previewColor: '#b5825a', preset: { maps: { - albedoMap: '/material/siding/lap_albedo_512.webp', + albedoMap: '/material/siding/lap_basecolor_512.ktx2', + normalMap: '/material/siding/lap_normal_512.ktx2', + roughnessMap: '/material/siding/lap_roughness_512.ktx2', + aoMap: '/material/siding/lap_ao_512.ktx2', }, mapProperties: { color: '#b5825a', @@ -4413,10 +4470,10 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ normalScaleX: 1, normalScaleY: 1, emissiveIntensity: 1, - displacementScale: 0.02, + displacementScale: 0, bumpScale: 1, transparent: false, - flipY: true, + flipY: false, emissiveColor: '#000000', aoMapIntensity: 1, side: 0, @@ -4428,13 +4485,17 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ { id: 'siding-lap-forest', label: 'Lap siding — forest', - category: 'wood', + category: 'siding', surfaces: ['wall', 'outdoor'], description: 'Exterior clapboard lap siding, painted forest', + previewThumbnailUrl: '/material/siding/lap_thumb.webp', previewColor: '#4f6b57', preset: { maps: { - albedoMap: '/material/siding/lap_albedo_512.webp', + albedoMap: '/material/siding/lap_basecolor_512.ktx2', + normalMap: '/material/siding/lap_normal_512.ktx2', + roughnessMap: '/material/siding/lap_roughness_512.ktx2', + aoMap: '/material/siding/lap_ao_512.ktx2', }, mapProperties: { color: '#4f6b57', @@ -4448,10 +4509,10 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ normalScaleX: 1, normalScaleY: 1, emissiveIntensity: 1, - displacementScale: 0.02, + displacementScale: 0, bumpScale: 1, transparent: false, - flipY: true, + flipY: false, emissiveColor: '#000000', aoMapIntensity: 1, side: 0, @@ -4463,13 +4524,17 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ { id: 'siding-lap-navy', label: 'Lap siding — navy', - category: 'wood', + category: 'siding', surfaces: ['wall', 'outdoor'], description: 'Exterior clapboard lap siding, painted navy', + previewThumbnailUrl: '/material/siding/lap_thumb.webp', previewColor: '#2f4865', preset: { maps: { - albedoMap: '/material/siding/lap_albedo_512.webp', + albedoMap: '/material/siding/lap_basecolor_512.ktx2', + normalMap: '/material/siding/lap_normal_512.ktx2', + roughnessMap: '/material/siding/lap_roughness_512.ktx2', + aoMap: '/material/siding/lap_ao_512.ktx2', }, mapProperties: { color: '#2f4865', @@ -4483,10 +4548,10 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ normalScaleX: 1, normalScaleY: 1, emissiveIntensity: 1, - displacementScale: 0.02, + displacementScale: 0, bumpScale: 1, transparent: false, - flipY: true, + flipY: false, emissiveColor: '#000000', aoMapIntensity: 1, side: 0, @@ -4498,13 +4563,17 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ { id: 'siding-lap-yellow', label: 'Lap siding — yellow', - category: 'wood', + category: 'siding', surfaces: ['wall', 'outdoor'], description: 'Exterior clapboard lap siding, painted yellow', + previewThumbnailUrl: '/material/siding/lap_thumb.webp', previewColor: '#f2e3b3', preset: { maps: { - albedoMap: '/material/siding/lap_albedo_512.webp', + albedoMap: '/material/siding/lap_basecolor_512.ktx2', + normalMap: '/material/siding/lap_normal_512.ktx2', + roughnessMap: '/material/siding/lap_roughness_512.ktx2', + aoMap: '/material/siding/lap_ao_512.ktx2', }, mapProperties: { color: '#f2e3b3', @@ -4518,10 +4587,10 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ normalScaleX: 1, normalScaleY: 1, emissiveIntensity: 1, - displacementScale: 0.02, + displacementScale: 0, bumpScale: 1, transparent: false, - flipY: true, + flipY: false, emissiveColor: '#000000', aoMapIntensity: 1, side: 0, @@ -4533,13 +4602,17 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ { id: 'siding-lap-nearblack', label: 'Lap siding — nearblack', - category: 'wood', + category: 'siding', surfaces: ['wall', 'outdoor'], description: 'Exterior clapboard lap siding, painted nearblack', + previewThumbnailUrl: '/material/siding/lap_thumb.webp', previewColor: '#232322', preset: { maps: { - albedoMap: '/material/siding/lap_albedo_512.webp', + albedoMap: '/material/siding/lap_basecolor_512.ktx2', + normalMap: '/material/siding/lap_normal_512.ktx2', + roughnessMap: '/material/siding/lap_roughness_512.ktx2', + aoMap: '/material/siding/lap_ao_512.ktx2', }, mapProperties: { color: '#5c5c59', @@ -4553,10 +4626,10 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ normalScaleX: 1, normalScaleY: 1, emissiveIntensity: 1, - displacementScale: 0.02, + displacementScale: 0, bumpScale: 1, transparent: false, - flipY: true, + flipY: false, emissiveColor: '#000000', aoMapIntensity: 1, side: 0, @@ -4568,13 +4641,17 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ { id: 'siding-lap-clay', label: 'Lap siding — clay', - category: 'wood', + category: 'siding', surfaces: ['wall', 'outdoor'], description: 'Exterior clapboard lap siding, painted clay', + previewThumbnailUrl: '/material/siding/lap_thumb.webp', previewColor: '#8f4a2e', preset: { maps: { - albedoMap: '/material/siding/lap_albedo_512.webp', + albedoMap: '/material/siding/lap_basecolor_512.ktx2', + normalMap: '/material/siding/lap_normal_512.ktx2', + roughnessMap: '/material/siding/lap_roughness_512.ktx2', + aoMap: '/material/siding/lap_ao_512.ktx2', }, mapProperties: { color: '#8f4a2e', @@ -4588,10 +4665,10 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ normalScaleX: 1, normalScaleY: 1, emissiveIntensity: 1, - displacementScale: 0.02, + displacementScale: 0, bumpScale: 1, transparent: false, - flipY: true, + flipY: false, emissiveColor: '#000000', aoMapIntensity: 1, side: 0, @@ -4603,13 +4680,17 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ { id: 'siding-batten-cream', label: 'Board & batten — cream', - category: 'wood', + category: 'siding', surfaces: ['wall', 'outdoor'], description: 'Exterior board-and-batten siding, painted cream', + previewThumbnailUrl: '/material/siding/batten_thumb.webp', previewColor: '#efe3cc', preset: { maps: { - albedoMap: '/material/siding/batten_albedo_512.webp', + albedoMap: '/material/siding/batten_basecolor_512.ktx2', + normalMap: '/material/siding/batten_normal_512.ktx2', + roughnessMap: '/material/siding/batten_roughness_512.ktx2', + aoMap: '/material/siding/batten_ao_512.ktx2', }, mapProperties: { color: '#efe3cc', @@ -4623,10 +4704,10 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ normalScaleX: 1, normalScaleY: 1, emissiveIntensity: 1, - displacementScale: 0.02, + displacementScale: 0, bumpScale: 1, transparent: false, - flipY: true, + flipY: false, emissiveColor: '#000000', aoMapIntensity: 1, side: 0, @@ -4638,13 +4719,17 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ { id: 'siding-batten-sand', label: 'Board & batten — sand', - category: 'wood', + category: 'siding', surfaces: ['wall', 'outdoor'], description: 'Exterior board-and-batten siding, painted sand', + previewThumbnailUrl: '/material/siding/batten_thumb.webp', previewColor: '#ddccae', preset: { maps: { - albedoMap: '/material/siding/batten_albedo_512.webp', + albedoMap: '/material/siding/batten_basecolor_512.ktx2', + normalMap: '/material/siding/batten_normal_512.ktx2', + roughnessMap: '/material/siding/batten_roughness_512.ktx2', + aoMap: '/material/siding/batten_ao_512.ktx2', }, mapProperties: { color: '#ddccae', @@ -4658,10 +4743,10 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ normalScaleX: 1, normalScaleY: 1, emissiveIntensity: 1, - displacementScale: 0.02, + displacementScale: 0, bumpScale: 1, transparent: false, - flipY: true, + flipY: false, emissiveColor: '#000000', aoMapIntensity: 1, side: 0, @@ -4673,13 +4758,17 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ { id: 'siding-batten-charcoal', label: 'Board & batten — charcoal', - category: 'wood', + category: 'siding', surfaces: ['wall', 'outdoor'], description: 'Exterior board-and-batten siding, painted charcoal', + previewThumbnailUrl: '/material/siding/batten_thumb.webp', previewColor: '#4e5257', preset: { maps: { - albedoMap: '/material/siding/batten_albedo_512.webp', + albedoMap: '/material/siding/batten_basecolor_512.ktx2', + normalMap: '/material/siding/batten_normal_512.ktx2', + roughnessMap: '/material/siding/batten_roughness_512.ktx2', + aoMap: '/material/siding/batten_ao_512.ktx2', }, mapProperties: { color: '#4e5257', @@ -4693,10 +4782,10 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ normalScaleX: 1, normalScaleY: 1, emissiveIntensity: 1, - displacementScale: 0.02, + displacementScale: 0, bumpScale: 1, transparent: false, - flipY: true, + flipY: false, emissiveColor: '#000000', aoMapIntensity: 1, side: 0, @@ -4708,13 +4797,17 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ { id: 'siding-batten-olive', label: 'Board & batten — olive', - category: 'wood', + category: 'siding', surfaces: ['wall', 'outdoor'], description: 'Exterior board-and-batten siding, painted olive', + previewThumbnailUrl: '/material/siding/batten_thumb.webp', previewColor: '#8d9368', preset: { maps: { - albedoMap: '/material/siding/batten_albedo_512.webp', + albedoMap: '/material/siding/batten_basecolor_512.ktx2', + normalMap: '/material/siding/batten_normal_512.ktx2', + roughnessMap: '/material/siding/batten_roughness_512.ktx2', + aoMap: '/material/siding/batten_ao_512.ktx2', }, mapProperties: { color: '#8d9368', @@ -4728,10 +4821,166 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ normalScaleX: 1, normalScaleY: 1, emissiveIntensity: 1, - displacementScale: 0.02, + displacementScale: 0, bumpScale: 1, transparent: false, - flipY: true, + flipY: false, + emissiveColor: '#000000', + aoMapIntensity: 1, + side: 0, + opacity: 1, + lightMapIntensity: 1, + }, + }, + }, + { + id: 'siding-vinyl-white', + label: 'Vinyl lap siding — white', + category: 'siding', + surfaces: ['wall', 'outdoor'], + description: 'Exterior vinyl lap siding, white, with a low sheen', + previewThumbnailUrl: '/material/siding/lap_thumb.webp', + previewColor: '#ecebe6', + preset: { + maps: { + albedoMap: '/material/siding/lap_basecolor_512.ktx2', + normalMap: '/material/siding/lap_normal_512.ktx2', + roughnessMap: '/material/siding/lap_roughness_512.ktx2', + aoMap: '/material/siding/lap_ao_512.ktx2', + }, + mapProperties: { + color: '#ecebe6', + roughness: 0.55, + metalness: 0, + repeatX: 1, + repeatY: 1, + rotation: 0, + wrapS: 'Repeat', + wrapT: 'Repeat', + normalScaleX: 1, + normalScaleY: 1, + emissiveIntensity: 1, + displacementScale: 0, + bumpScale: 1, + transparent: false, + flipY: false, + emissiveColor: '#000000', + aoMapIntensity: 1, + side: 0, + opacity: 1, + lightMapIntensity: 1, + }, + }, + }, + { + id: 'siding-vinyl-almond', + label: 'Vinyl lap siding — almond', + category: 'siding', + surfaces: ['wall', 'outdoor'], + description: 'Exterior vinyl lap siding, almond, with a low sheen', + previewThumbnailUrl: '/material/siding/lap_thumb.webp', + previewColor: '#ddd2bd', + preset: { + maps: { + albedoMap: '/material/siding/lap_basecolor_512.ktx2', + normalMap: '/material/siding/lap_normal_512.ktx2', + roughnessMap: '/material/siding/lap_roughness_512.ktx2', + aoMap: '/material/siding/lap_ao_512.ktx2', + }, + mapProperties: { + color: '#ddd2bd', + roughness: 0.55, + metalness: 0, + repeatX: 1, + repeatY: 1, + rotation: 0, + wrapS: 'Repeat', + wrapT: 'Repeat', + normalScaleX: 1, + normalScaleY: 1, + emissiveIntensity: 1, + displacementScale: 0, + bumpScale: 1, + transparent: false, + flipY: false, + emissiveColor: '#000000', + aoMapIntensity: 1, + side: 0, + opacity: 1, + lightMapIntensity: 1, + }, + }, + }, + { + id: 'siding-vinyl-gray', + label: 'Vinyl lap siding — gray', + category: 'siding', + surfaces: ['wall', 'outdoor'], + description: 'Exterior vinyl lap siding, gray, with a low sheen', + previewThumbnailUrl: '/material/siding/lap_thumb.webp', + previewColor: '#a3a6a4', + preset: { + maps: { + albedoMap: '/material/siding/lap_basecolor_512.ktx2', + normalMap: '/material/siding/lap_normal_512.ktx2', + roughnessMap: '/material/siding/lap_roughness_512.ktx2', + aoMap: '/material/siding/lap_ao_512.ktx2', + }, + mapProperties: { + color: '#a3a6a4', + roughness: 0.55, + metalness: 0, + repeatX: 1, + repeatY: 1, + rotation: 0, + wrapS: 'Repeat', + wrapT: 'Repeat', + normalScaleX: 1, + normalScaleY: 1, + emissiveIntensity: 1, + displacementScale: 0, + bumpScale: 1, + transparent: false, + flipY: false, + emissiveColor: '#000000', + aoMapIntensity: 1, + side: 0, + opacity: 1, + lightMapIntensity: 1, + }, + }, + }, + { + id: 'siding-vinyl-vertical-white', + label: 'Vinyl vertical siding — white', + category: 'siding', + surfaces: ['wall', 'outdoor'], + description: 'Exterior vinyl board-and-batten style vertical siding, white, with a low sheen', + previewThumbnailUrl: '/material/siding/batten_thumb.webp', + previewColor: '#ecebe6', + preset: { + maps: { + albedoMap: '/material/siding/batten_basecolor_512.ktx2', + normalMap: '/material/siding/batten_normal_512.ktx2', + roughnessMap: '/material/siding/batten_roughness_512.ktx2', + aoMap: '/material/siding/batten_ao_512.ktx2', + }, + mapProperties: { + color: '#ecebe6', + roughness: 0.55, + metalness: 0, + repeatX: 1, + repeatY: 1, + rotation: 0, + wrapS: 'Repeat', + wrapT: 'Repeat', + normalScaleX: 1, + normalScaleY: 1, + emissiveIntensity: 1, + displacementScale: 0, + bumpScale: 1, + transparent: false, + flipY: false, emissiveColor: '#000000', aoMapIntensity: 1, side: 0, @@ -4797,6 +5046,36 @@ export function getMaterialsForCategory(category: MaterialCategory): MaterialCat return items } +/** How a catalog material reads as a small flat swatch (a tile, a chip, a cursor badge). */ +export type MaterialSwatch = { + color: string + imageUrl: string | null + /** + * The image is a neutral thumbnail or albedo the colour tints, as the 3D material does + * (`mapProperties.color` × map): draw it multiplied over `color`. + */ + tinted: boolean +} + +const BROWSER_IMAGE = /\.(?:webp|png|jpe?g|avif|gif)(?:[?#]|$)/i + +/** + * A catalog material's swatch: its thumbnail or browser-readable albedo, + * multiplied by the material's colour; else its flat preview colour. + */ +export function getMaterialSwatch(item: MaterialCatalogItem): MaterialSwatch { + const tint = item.preset.mapProperties.color + const color = item.previewColor ?? tint ?? '#f3f4f6' + const albedo = item.preset.maps.albedoMap + const imageUrl = + item.previewThumbnailUrl ?? (albedo && BROWSER_IMAGE.test(albedo) ? albedo : null) + if (imageUrl) { + const tinted = !!tint && !/^#(?:fff|ffffff)$/i.test(tint) + return { color: tinted ? tint : color, imageUrl, tinted } + } + return { color, imageUrl: null, tinted: false } +} + /** A community material's id (`mtl_…`, as the host's database mints them), well formed. */ export function isCommunityMaterialId(id: string): boolean { return /^mtl_[\w-]+$/.test(id) diff --git a/packages/core/src/node-slots/door.ts b/packages/core/src/node-slots/door.ts index 0a9eae7193..7080bf5a61 100644 --- a/packages/core/src/node-slots/door.ts +++ b/packages/core/src/node-slots/door.ts @@ -1,6 +1,6 @@ import type { SlotDeclaration } from '../registry/types' -export type DoorSlotId = 'panel' | 'frame' | 'glass' | 'hardware' +export type DoorSlotId = 'panel' | 'frame' | 'casing-a' | 'casing-b' | 'glass' | 'hardware' // Picker swatches. Rendering falls back to the live body/glass/hardware defaults // (which already track shading + theme), so these are just the indicator colours. @@ -11,14 +11,15 @@ const GLASS_DEFAULT = 'library:preset-glass' const HARDWARE_DEFAULT = 'library:metal-chrome' /** - * A door exposes four paintable slots: `panel` (leaf faces), `frame`, `glass`, - * and `hardware` (handle / hinges / closer / panic bar). The opening reveal - * keeps its own material. + * A door exposes its panel, frame, glass, hardware and casing on each host-wall + * face. The opening reveal keeps its own material. */ export function doorSlots(): SlotDeclaration[] { return [ { slotId: 'panel', label: 'Panel', default: PANEL_DEFAULT }, { slotId: 'frame', label: 'Frame', default: FRAME_DEFAULT }, + { slotId: 'casing-a', label: 'Casing A', default: FRAME_DEFAULT }, + { slotId: 'casing-b', label: 'Casing B', default: FRAME_DEFAULT }, { slotId: 'glass', label: 'Glass', default: GLASS_DEFAULT }, { slotId: 'hardware', label: 'Hardware', default: HARDWARE_DEFAULT }, ] diff --git a/packages/core/src/node-slots/wall.ts b/packages/core/src/node-slots/wall.ts index 2316efcd5a..a48c0f2ce3 100644 --- a/packages/core/src/node-slots/wall.ts +++ b/packages/core/src/node-slots/wall.ts @@ -1,6 +1,7 @@ import type { SlotDeclaration } from '../registry/types' import { getCurtainWallConfig } from '../schema/nodes/curtain-wall' -import { WALL_SURFACE_SLOT_DEFAULTS, type WallNode } from '../schema/nodes/wall' +import { getRailingWallConfig, railingWallSlotDefault } from '../schema/nodes/railing-wall' +import { getWallFaceDefault, WALL_SURFACE_SLOT_DEFAULTS, type WallNode } from '../schema/nodes/wall' /** * A wall exposes two paintable faces — `a` (left of start → end) and `b` — @@ -19,9 +20,26 @@ export function wallSlots(node?: WallNode): SlotDeclaration[] { { slotId: 'curtain-solid', label: 'Solid panels', default: config.solidColor }, ] } + // A railing has no faces: it paints its posts and rails, and its infill. + if (node?.wallType === 'railing') { + const { style } = getRailingWallConfig(node) + return [ + { + slotId: 'railing-frame', + label: 'Posts & rails', + default: railingWallSlotDefault(style, 'railing-frame'), + }, + { + slotId: 'railing-infill', + label: style === 'glass' ? 'Glass' : 'Infill', + default: railingWallSlotDefault(style, 'railing-infill'), + }, + ] + } + // A face's default follows its side: the interior paint, raw drywall outside. return [ - { slotId: 'a', label: 'Side A', default: WALL_SURFACE_SLOT_DEFAULTS.a }, - { slotId: 'b', label: 'Side B', default: WALL_SURFACE_SLOT_DEFAULTS.b }, + { slotId: 'a', label: 'Side A', default: getWallFaceDefault(node ?? {}, 'a') }, + { slotId: 'b', label: 'Side B', default: getWallFaceDefault(node ?? {}, 'b') }, { slotId: 'aSkirting', label: 'Skirting (side A)', diff --git a/packages/core/src/node-slots/window.ts b/packages/core/src/node-slots/window.ts index 7675253d96..fa9281e4b8 100644 --- a/packages/core/src/node-slots/window.ts +++ b/packages/core/src/node-slots/window.ts @@ -1,16 +1,18 @@ import type { SlotDeclaration } from '../registry/types' -export type WindowSlotId = 'frame' | 'glass' +export type WindowSlotId = 'frame' | 'casing-a' | 'casing-b' | 'glass' // Picker swatches. Rendering falls back to the live frame/glass defaults (which // already track shading + theme), so these are just the indicator colours. const FRAME_DEFAULT = 'library:preset-softwhite' const GLASS_DEFAULT = 'library:preset-glass' -/** A window exposes two paintable slots: the joinery frame and the glass. */ +/** A window exposes its frame, glass and casing on each host-wall face. */ export function windowSlots(): SlotDeclaration[] { return [ { slotId: 'frame', label: 'Frame', default: FRAME_DEFAULT }, + { slotId: 'casing-a', label: 'Casing A', default: FRAME_DEFAULT }, + { slotId: 'casing-b', label: 'Casing B', default: FRAME_DEFAULT }, { slotId: 'glass', label: 'Glass', default: GLASS_DEFAULT }, ] } diff --git a/packages/core/src/registry/index.ts b/packages/core/src/registry/index.ts index cb8d9acafc..51af894b22 100644 --- a/packages/core/src/registry/index.ts +++ b/packages/core/src/registry/index.ts @@ -149,6 +149,8 @@ export type { PaintPatchArgs, PaintPreviewArgs, PaintResolveArgs, + PaintScopeId, + PaintSurfaceScopes, ParamAction, ParametricDescriptor, ParamField, diff --git a/packages/core/src/registry/types.ts b/packages/core/src/registry/types.ts index f7f51ae749..d05aacf375 100644 --- a/packages/core/src/registry/types.ts +++ b/packages/core/src/registry/types.ts @@ -656,6 +656,16 @@ export type FloorplanGeometry = */ affordance?: string payload?: unknown + /** The arrow this many times its usual size (a big outline's side push); 1 by default. */ + scale?: number + /** + * `pull`: a wall end's "pull to continue" grip — a screen-sized arrow a + * few pixels past `point` (the wall end) along `angle`, in its own colour, + * so it reads apart from the end's move grip. + */ + variant?: 'pull' + /** Tooltip shown while the pointer rests on the arrow. */ + title?: string } /** * Curved two-headed rotation arrow — the 2D counterpart of the 3D @@ -685,6 +695,8 @@ export type FloorplanGeometry = * already compute the pivot to place the handle should pass it through. */ pivot?: FloorplanPoint + /** Size against the default icon (1), for a node far larger than the handle, like a roof. */ + scale?: number } /** * Centered length / distance label. Renders as a small rounded @@ -968,13 +980,13 @@ export type FloorplanMoveTarget = (args: { /** * A plugin-contributed section for the floating node inspector card. - * When a node whose `type` is in `kinds` is selected, the inspector header - * shows the extension's `icon` as a button. Clicking it swaps the card - * body to ONLY this extension's `component` (inside a section titled - * `title`) — extension mode and the kind's own controls are EITHER/OR, - * never appended together. Clicking the (highlighted) icon again, or the - * chevron, returns to the regular controls. The mobile sheet has no - * header icons, so it appends the section after the kind's controls + * When a node whose `type` is in `kinds` is selected, the node's action + * menu shows the extension's `icon` as a button, `title` as its tooltip. + * Clicking it opens the inspector card on ONLY this extension's `component` + * (inside a section titled `title`) — extension mode and the kind's own + * controls are EITHER/OR, never appended together. The card's chevron + * returns to the regular controls. The mobile sheet has no action-menu + * buttons for it, so it appends the section after the kind's controls * instead. * * `component` is lazy-loaded on first expand and receives the selected @@ -995,9 +1007,9 @@ export type InspectorExtension = { pluginId: string /** Node kinds whose inspector card grows this section. */ kinds: string[] - /** Header-button icon (16px box). */ + /** The icon of its action-menu button (16px box). */ icon: IconRef - /** Section title, e.g. `Engineering`. */ + /** Section title and its action-menu tooltip, e.g. `Engineering`. */ title: string /** Lazy section body; receives `{ node }` (the selected node). */ component: LazyComponent @@ -1950,6 +1962,17 @@ export type SlotDeclaration = { default?: string } +/** How far one paint click spreads: the editor's painter application scopes. */ +export type PaintScopeId = 'single' | 'object' | 'matching' | 'room' + +/** A surface's own scope set — see `PaintCapability.scopes`. */ +export type PaintSurfaceScopes = { + scopes: PaintScopeId[] + labels?: Partial> + /** The role a click paints under `scope`; the hovered role when omitted. */ + roleFor?: (scope: PaintScopeId) => string +} + export type PaintCapability = { /** * Material-picker target represented by this paint capability. Omit when @@ -1975,6 +1998,15 @@ export type PaintCapability = { * back to the user as the raw id. Return `null` to keep the derived label. */ roleLabel?: (node: AnyNode, role: string) => string | null + /** + * Optional: the application scopes a surface offers itself, in place of the + * derived set (`single`, plus `object` / `matching` / `room` from the node's + * slots, asset and `roomScope`). `labels` names a scope over its generic + * label; `roleFor` is the role a click paints under a wider scope (a roof + * gable's `matching` paints every gable of the roof). Return `null` to keep + * the derived set. + */ + scopes?: (node: AnyNode, role: string) => PaintSurfaceScopes | null /** * Build the node-update patch that applies the new material at * `role`. Returned partial is merged into the node by the editor. @@ -2453,6 +2485,8 @@ export type SnappableConfig = { export type SnapPointKind = 'start' | 'end' | 'midpoint' | 'center' | 'corners' export type SurfacesConfig = { + /** False makes hosted openings gaps without leaf, frame or threshold; defaults to true. */ + renderOpeningContent?: (node: AnyNode) => boolean hosting?: SurfaceProvider | false top?: { /** Height above the node origin; point, when supplied, is in the parent XZ frame. */ @@ -2986,6 +3020,15 @@ export type ParamField = min?: number max?: number step?: number + /** Shown when the node omits the key (an optional field with a schema-level fallback). */ + default?: number + /** + * The nodes the field edits. A multi-selection shows it while any selected + * node qualifies and reads and writes only those; a single node that does + * not qualify hides it. Unlike `visibleIf`, one non-qualifying node does + * not hide it for the whole selection. + */ + appliesTo?: (n: N) => boolean visibleIf?: (n: N) => boolean customEditor?: ComponentType } diff --git a/packages/core/src/schema/__fixtures__/node-fixtures.ts b/packages/core/src/schema/__fixtures__/node-fixtures.ts index 4883f01cb0..4be280e6ea 100644 --- a/packages/core/src/schema/__fixtures__/node-fixtures.ts +++ b/packages/core/src/schema/__fixtures__/node-fixtures.ts @@ -12,6 +12,7 @@ import { AnyNode, type AnyNodeType, nodeKindOf } from '../types' /** Fields a kind requires beyond the defaults its own schema fills in. */ export const NODE_REQUIRED_FIELDS: Record> = { + beam: { start: [0, 0], end: [4, 0] }, ceiling: { polygon: [ [0, 0], diff --git a/packages/core/src/schema/assembly.ts b/packages/core/src/schema/assembly.ts index 510d6a2e30..4ae27ec3ed 100644 --- a/packages/core/src/schema/assembly.ts +++ b/packages/core/src/schema/assembly.ts @@ -51,6 +51,8 @@ export const AssemblyLayer = z.object({ thickness: z.number().finite().nonnegative(), /** Body only, at most one: the structural layer (framing, block), the one generators frame. */ core: z.literal(true).optional(), + /** The core layer's framing members on centre, metres (studs at 16 in); absent = the framer's own. */ + spacing: z.number().finite().positive().optional(), /** * What the layer is built of, as a construction-material kind * (`stucco`, `siding`, `osb`, `wood`, `cmu`, `drywall`, …). A label for @@ -122,6 +124,17 @@ export const Assembly = z }) } + for (const [list, layers] of lists) { + layers.forEach((layer, index) => { + if (layer.spacing !== undefined && !layer.core) { + ctx.addIssue({ + code: 'custom', + message: 'Only the core layer has a framing spacing', + path: [list, index, 'spacing'], + }) + } + }) + } assembly.layers.forEach((layer, index) => { if (layer.core && !STRUCTURAL_ROLES.has(layer.role)) { ctx.addIssue({ diff --git a/packages/core/src/schema/build-up.ts b/packages/core/src/schema/build-up.ts new file mode 100644 index 0000000000..be9a33cb9a --- /dev/null +++ b/packages/core/src/schema/build-up.ts @@ -0,0 +1,106 @@ +import { z } from 'zod' + +/** + * Typed layer build-ups for roof planes and ceilings: each layer is a product + * choice (a roofing, a sheathing, a framing size at a spacing) rather than an + * F2 layer list, so framing tools read the structure they frame and the + * inspector edits choices, not strings. Thicknesses are metres; spacings are + * metres on centre. + */ + +const Thickness = z.number().finite().nonnegative() +/** What the person calls a layer's material where the kind's own name won't do ("Brazilian cherry"). */ +const LayerName = z.string().trim().min(1).max(60).optional() + +/** Nominal dimensional lumber, by its actual depth (`LUMBER_DEPTH`). */ +export const NominalLumber = z.enum(['2x4', '2x6', '2x8', '2x10', '2x12']) +export type NominalLumber = z.infer + +export const RoofingKind = z.enum([ + 'asphalt-3-tab', + 'architectural-shingle', + 'standing-seam-metal', + 'concrete-tile', + 'clay-tile', + 'wood-shake', + 'slate', +]) +export type RoofingKind = z.infer + +export const UnderlaymentKind = z.enum(['felt-15', 'felt-30', 'synthetic', 'ice-and-water']) +export type UnderlaymentKind = z.infer + +/** Structural panels: roof sheathing and attic decking. */ +export const PanelKind = z.enum(['osb', 'plywood']) +export type PanelKind = z.infer + +/** Batt and blown fill the framing cavity; rigid board runs continuous over the framing. */ +export const InsulationKind = z.enum(['batt', 'blown', 'rigid']) +export type InsulationKind = z.infer + +export const InteriorFinishKind = z.enum(['drywall', 'plaster', 'wood-plank']) +export type InteriorFinishKind = z.infer + +export const RoofingLayer = z.object({ kind: RoofingKind, thickness: Thickness, name: LayerName }) +export const UnderlaymentLayer = z.object({ + kind: UnderlaymentKind, + thickness: Thickness, + name: LayerName, +}) +export const PanelLayer = z.object({ kind: PanelKind, thickness: Thickness, name: LayerName }) +export const InsulationLayer = z.object({ + kind: InsulationKind, + thickness: Thickness, + name: LayerName, +}) +export const InteriorFinishLayer = z.object({ + kind: InteriorFinishKind, + thickness: Thickness, + name: LayerName, +}) + +/** For trusses, `size` is the top chord: the depth the roof plane's deck carries. */ +export const RoofStructure = z.object({ + system: z.enum(['rafters', 'trusses']), + size: NominalLumber, + spacing: z.number().finite().positive(), +}) +export type RoofStructure = z.infer + +/** `truss-chords`: the ceiling hangs from the roof trusses' bottom chords, `size` deep. */ +export const CeilingFraming = z.object({ + system: z.enum(['joists', 'truss-chords']), + size: NominalLumber, + spacing: z.number().finite().positive(), +}) +export type CeilingFraming = z.infer + +/** + * A roof plane, outside in. Absent optional layers are none. The plane's + * `deckThickness` and `shingleThickness` derive from it (`roofBuildUpPatch`). + */ +export const RoofBuildUp = z.object({ + presetId: z.string().optional(), + roofing: RoofingLayer, + underlayment: UnderlaymentLayer.optional(), + sheathing: PanelLayer, + structure: RoofStructure, + insulation: InsulationLayer.optional(), + /** Under the structure, the room-facing face of a cathedral ceiling. */ + finish: InteriorFinishLayer.optional(), +}) +export type RoofBuildUp = z.infer + +/** + * A ceiling, bottom up from its stored height (the finished underside). + * Absent layers are none. + */ +export const CeilingBuildUp = z.object({ + presetId: z.string().optional(), + finish: InteriorFinishLayer.optional(), + framing: CeilingFraming.optional(), + /** Over the framing, for attic storage. */ + decking: PanelLayer.optional(), + insulation: InsulationLayer.optional(), +}) +export type CeilingBuildUp = z.infer diff --git a/packages/core/src/schema/host-children.test.ts b/packages/core/src/schema/host-children.test.ts index f6263387e1..8326ee75cc 100644 --- a/packages/core/src/schema/host-children.test.ts +++ b/packages/core/src/schema/host-children.test.ts @@ -41,7 +41,8 @@ test('frozen pre-slice corpus covers every kind predating separators', () => { kind !== 'separator' && kind !== 'floor-opening' && kind !== 'fence-gate' && - kind !== 'fence-opening', + kind !== 'fence-opening' && + kind !== 'beam', ).sort(), ) }) @@ -53,7 +54,14 @@ test.each(baseline)( saved.type === 'zone' ? { ...expected, boundarySeparatorIds: [], holes: [] } : saved.type === 'door' || saved.type === 'window' - ? { ...expected, floorThresholdVersion: 1 } + ? { + ...expected, + floorThresholdVersion: 1, + // Saved before casing: no casing. + casingFaceA: false, + casingFaceB: false, + casingWidth: 0.0508, + } : saved.type === 'fence' ? { ...expected, diff --git a/packages/core/src/schema/index.ts b/packages/core/src/schema/index.ts index 7091c47b54..d551a199cd 100644 --- a/packages/core/src/schema/index.ts +++ b/packages/core/src/schema/index.ts @@ -20,6 +20,24 @@ export { parseAllowedOrigins, } from './asset-url' export { BaseNode, generateId, Material, nodeType, objectId } from './base' +// Roof-plane and ceiling layer build-ups +export { + CeilingBuildUp, + CeilingFraming, + InsulationKind, + InsulationLayer, + InteriorFinishKind, + InteriorFinishLayer, + NominalLumber, + PanelKind, + PanelLayer, + RoofBuildUp, + RoofingKind, + RoofingLayer, + RoofStructure, + UnderlaymentKind, + UnderlaymentLayer, +} from './build-up' // Camera export { CameraSchema } from './camera' // Collections @@ -81,6 +99,15 @@ export { planAutomaticDownspouts, resolveAutomaticDownspoutLength, } from './nodes/automatic-downspout' +export { + BEAM_SIZE_PRESETS, + BeamMaterial, + BeamNode, + BeamPlacement, + type BeamSizePreset, + type BeamSizePresetId, + DEFAULT_BEAM_SIZE_PRESET_ID, +} from './nodes/beam' export { BlockEdge, BlockFace, @@ -115,6 +142,7 @@ export { ColumnCrossSection, ColumnNode, ColumnPanelShape, + ColumnPostBase, type ColumnPresetId, ColumnRingPlacement, ColumnShaftDetail, @@ -269,6 +297,24 @@ export { export { PipeFittingNode } from './nodes/pipe-fitting' export { PipeSegmentNode } from './nodes/pipe-segment' export { PipeTrapNode } from './nodes/pipe-trap' +export { + DEFAULT_RAILING_WALL, + getRailingWallConfig, + getRailingWallHeight, + isRailingWall, + RAILING_GUARD_HEIGHT, + RAILING_GUARD_HEIGHT_TALL, + RAILING_MAX_POST_SPACING, + RAILING_SPHERE_LIMIT, + RAILING_STYLE_DEFAULTS, + RailingWallConfig, + type RailingWallPatch, + type RailingWallSlotId, + RailingWallStyle, + railingOpeningFields, + railingWallDefaults, + railingWallSlotDefault, +} from './nodes/railing-wall' // Nodes export { createDefaultRidgeVentsForSegment, @@ -311,6 +357,7 @@ export type { RoofSegmentSurfaceMaterialRole, RoofSegmentSurfaceMaterialSpec, RoofSegmentVisibleTopBounds, + RoofWallBand, SegmentSlopeFrame, } from './nodes/roof-segment' export { @@ -323,6 +370,7 @@ export { getRoofSegmentEndReach, getRoofSegmentSurfaceY, getRoofSegmentVisibleTopBounds, + getRoofWallBandMaterial, getSegmentFasciaMaterial, getSegmentSlopeFrame, hasSegmentMaterialOverride, @@ -330,10 +378,13 @@ export { MIN_ROOF_SEGMENT_TRIM_SPAN, normalizeRoofSegmentTrim, ROOF_SHAPE_DEFAULTS, + ROOF_WALL_BANDS, + RoofEaveCut, RoofSegmentNode, RoofSegmentTrim, RoofType, roofTypeHasRakes, + roofWallBandFields, } from './nodes/roof-segment' export { getRoofSegmentResizePatch } from './nodes/roof-segment-resize' export type { @@ -407,6 +458,14 @@ export { } from './nodes/stair' export { StairConstruction } from './nodes/stair-construction' export { AttachmentSide, StairSegmentNode, StairSegmentType } from './nodes/stair-segment' +export { + STAIR_STRINGER_SPACINGS_IN, + StairStringerStock, + StairStringerType, + StairStructure, + StairStructureType, + StairTreadStock, +} from './nodes/stair-structure' export { StructuralGridNode } from './nodes/structural-grid' export { SurfaceHoleMetadata } from './nodes/surface-hole-metadata' export { SurfacePaintRegion } from './nodes/surface-paint-region' @@ -422,8 +481,11 @@ export type { WallTrimSlotId, } from './nodes/wall' export { + DEFAULT_EXTERIOR_WALL_FINISH, + DEFAULT_INTERIOR_WALL_PAINT, getEffectiveWallFaceMaterial, getEffectiveWallSurfaceMaterial, + getWallFaceDefault, getWallSurfaceMaterialSignature, getWallTrimFaces, getWallTrimSlotId, @@ -504,3 +566,9 @@ export type { } from './types' // Union types export { AnyNode, nodeKindOf } from './types' +export { + CUSTOM_WALL_TYPE_PREFIX, + newWallTypeId, + WallTypeDefinition, + WallTypeDefinitionId, +} from './wall-type' diff --git a/packages/core/src/schema/nodes/beam.ts b/packages/core/src/schema/nodes/beam.ts new file mode 100644 index 0000000000..829fba2945 --- /dev/null +++ b/packages/core/src/schema/nodes/beam.ts @@ -0,0 +1,175 @@ +import dedent from 'dedent' +import { z } from 'zod' +import { BaseNode, nodeType, objectId } from '../base' + +const INCH = 0.0254 +const PlanPoint = z.tuple([z.number(), z.number()]) + +/** + * What a beam is made of: sawn lumber (a solid timber or 2x plies nailed up), the same + * pressure-treated for ground contact and the weather, LVL, glulam, or a steel W shape. + */ +export const BeamMaterial = z.enum(['sawn', 'pressure-treated', 'lvl', 'glulam', 'steel']) +export type BeamMaterial = z.infer + +/** + * How the joists it carries meet the beam (under the joists, or among them): a + * dropped beam is under them, its top the plane they bear on; a flush beam is among them, the + * joists hung from its sides. + */ +export const BeamPlacement = z.enum(['dropped', 'flush']) +export type BeamPlacement = z.infer + +/** One stock beam: a nominal size, how many plies of it, its actual section and what it is. */ +export type BeamSizePreset = { + id: string + /** The size as a framing plan prints it: "6x8", "(2) 2x10", "1-3/4x11-7/8 LVL". */ + label: string + /** Nominal size of one ply. */ + size: string + plies: number + /** Actual width of the whole member (every ply), metres. */ + width: number + /** Actual depth, metres. */ + depth: number + material: BeamMaterial +} + +/** A sawn stock size: one timber, or `plies` of a 2x nailed up (`width` is one ply's, inches). */ +function sawn( + id: Id, + size: string, + width: number, + depth: number, + plies = 1, +) { + return { + id, + label: plies > 1 ? `(${plies}) ${size}` : size, + size, + plies, + width: width * plies * INCH, + depth: depth * INCH, + material: 'sawn' as const, + } +} + +/** + * The stock sizes a beam is picked from, at their actual dressed sizes: a sawn 4x is 3-1/2 in + * wide and a 6x 5-1/2 in; a 2x ply 1-1/2 in; LVL 1-3/4 in a ply; glulam 5-1/8 in; a W8x10 is + * 3.94 in across its flanges and 7.89 in deep. + */ +export const BEAM_SIZE_PRESETS = [ + sawn('4x6', '4x6', 3.5, 5.5), + sawn('4x8', '4x8', 3.5, 7.25), + sawn('4x10', '4x10', 3.5, 9.25), + sawn('4x12', '4x12', 3.5, 11.25), + sawn('6x6', '6x6', 5.5, 5.5), + sawn('6x8', '6x8', 5.5, 7.5), + sawn('6x10', '6x10', 5.5, 9.5), + sawn('6x12', '6x12', 5.5, 11.5), + sawn('(2)2x8', '2x8', 1.5, 7.25, 2), + sawn('(2)2x10', '2x10', 1.5, 9.25, 2), + sawn('(2)2x12', '2x12', 1.5, 11.25, 2), + sawn('(3)2x10', '2x10', 1.5, 9.25, 3), + sawn('(3)2x12', '2x12', 1.5, 11.25, 3), + { + id: 'lvl-1-3/4x9-1/4', + label: '1-3/4x9-1/4 LVL', + size: '1-3/4x9-1/4', + plies: 1, + width: 1.75 * INCH, + depth: 9.25 * INCH, + material: 'lvl', + }, + { + id: 'lvl-1-3/4x11-7/8', + label: '1-3/4x11-7/8 LVL', + size: '1-3/4x11-7/8', + plies: 1, + width: 1.75 * INCH, + depth: 11.875 * INCH, + material: 'lvl', + }, + { + id: '(2)lvl-1-3/4x11-7/8', + label: '(2) 1-3/4x11-7/8 LVL', + size: '1-3/4x11-7/8', + plies: 2, + width: 3.5 * INCH, + depth: 11.875 * INCH, + material: 'lvl', + }, + { + id: 'glulam-5-1/8x9', + label: '5-1/8x9 GLB', + size: '5-1/8x9', + plies: 1, + width: 5.125 * INCH, + depth: 9 * INCH, + material: 'glulam', + }, + { + id: 'glulam-5-1/8x12', + label: '5-1/8x12 GLB', + size: '5-1/8x12', + plies: 1, + width: 5.125 * INCH, + depth: 12 * INCH, + material: 'glulam', + }, + { + id: 'W8x10', + label: 'W8x10', + size: 'W8x10', + plies: 1, + width: 3.94 * INCH, + depth: 7.89 * INCH, + material: 'steel', + }, +] as const satisfies readonly BeamSizePreset[] + +export type BeamSizePresetId = (typeof BEAM_SIZE_PRESETS)[number]['id'] + +/** A new beam's size: a 6x8, the header a porch's posts carry. */ +export const DEFAULT_BEAM_SIZE_PRESET_ID = '6x8' satisfies BeamSizePresetId + +export const BeamNode = BaseNode.extend({ + id: objectId('beam'), + type: nodeType('beam'), + start: PlanPoint, + end: PlanPoint, + width: z + .number() + .positive() + .default(5.5 * INCH), + depth: z + .number() + .positive() + .default(7.5 * INCH), + size: z.string().optional(), + plies: z.number().int().min(1).max(5).default(1), + material: BeamMaterial.default('sawn'), + placement: BeamPlacement.default('dropped'), + topElevation: z.number().optional(), + // A slab the beam belongs to (a porch's or a deck's): a reference for what builds and frames + // around it, never its height. + supportSlabId: z.string().optional(), +}).describe( + dedent` + Beam node - a horizontal framing member drawn by hand: a header over a porch's posts, a deck's + beam, a girder under a floor, a beam across an open span + - start/end: the beam's centreline, level-local plan points like a wall's + - width/depth: the actual section, metres (every ply together across) + - size: the nominal size of one ply as printed ("6x8", "2x10", "1-3/4x11-7/8"); absent = a + custom section, labelled by its actual size + - plies: how many plies of size are nailed up side by side + - material: sawn, pressure-treated, lvl, glulam or steel + - placement: dropped (the joists bear on its top) or flush (the joists hang from its sides) + - topElevation: its top, level-local metres; absent = the level's ceiling plane over it (the + top of the walls), a dropped beam hanging under it, a flush one in the ceiling framing + - supportSlabId: the slab it belongs to, if any (a porch or a deck) + `, +) + +export type BeamNode = z.infer diff --git a/packages/core/src/schema/nodes/ceiling.ts b/packages/core/src/schema/nodes/ceiling.ts index 180d7b7322..151d485302 100644 --- a/packages/core/src/schema/nodes/ceiling.ts +++ b/packages/core/src/schema/nodes/ceiling.ts @@ -1,6 +1,7 @@ import dedent from 'dedent' import { z } from 'zod' import { BaseNode, nodeType, objectId } from '../base' +import { CeilingBuildUp } from '../build-up' import { MaterialSchema } from '../material' import { ItemNode } from './item' import { SurfaceHoleMetadata } from './surface-hole-metadata' @@ -26,6 +27,9 @@ export const CeilingNode = BaseNode.extend({ // − CEILING_CLAMP_MARGIN (see `resolveCeilingHeight`). Present = an // explicit custom height, still write-clamped under that bound. height: z.number().optional(), + // Layers bottom up from `height`, the finished underside: the ceiling's + // thickness rises from there (`ceilingBuildUpThickness`). Absent = no thickness. + buildUp: CeilingBuildUp.optional(), // Painted parts of a manual ceiling (later wins). An automatic ceiling draws // its room's `zone.ceiling.regions` instead: it is rebuilt from the room. regions: z.array(SurfacePaintRegion).optional(), @@ -39,6 +43,7 @@ export const CeilingNode = BaseNode.extend({ - holes: array of polygons representing holes in the ceiling - holeMetadata: metadata parallel to holes, used to preserve manual and auto-managed cutouts - height: explicit height in meters; absent = follows the level top automatically + - buildUp: layers bottom up from the underside (finish, framing, decking, insulation) - regions: painted parts of a manual ceiling ([x, z] polygons, later wins) - autoFromWalls: whether the ceiling is automatically generated from a closed wall loop `, diff --git a/packages/core/src/schema/nodes/column.ts b/packages/core/src/schema/nodes/column.ts index ff12f55382..889cda5c45 100644 --- a/packages/core/src/schema/nodes/column.ts +++ b/packages/core/src/schema/nodes/column.ts @@ -57,6 +57,12 @@ export const ColumnRingPlacement = z.enum(['ends', 'even', 'top', 'bottom']) export const ColumnCarvingPlacement = z.enum(['shaft', 'base', 'capital', 'all']) +/** + * What a framing post (`role: 'post'`) stands on: straight on the floor, a steel post base + * holding it off the concrete, or a concrete pier above the floor or the grade. + */ +export const ColumnPostBase = z.enum(['none', 'post-base', 'pier']) + export const ColumnSupportStyle = z.enum([ 'vertical', 'a-frame', @@ -81,6 +87,7 @@ export type ColumnCapitalStyle = z.infer export type ColumnRingPlacement = z.infer export type ColumnCarvingPlacement = z.infer export type ColumnSupportStyle = z.infer +export type ColumnPostBase = z.infer export const ColumnNode = BaseNode.extend({ id: objectId('column'), @@ -165,7 +172,10 @@ export const ColumnNode = BaseNode.extend({ braceTopSpread: z.number().min(0).default(0.12), bracePlateEnabled: z.boolean().default(true), // A declaration consumed by the selected shared support checker; old columns stay unchanged. - role: z.enum(['ornament']).optional(), + // 'post' marks a framing post (core `createFramingPost`): a square sawn post under a beam. + role: z.enum(['ornament', 'post']).optional(), + // A framing post's base, drawn by the base fields (`framingPostBasePatch` sets both). + postBase: ColumnPostBase.optional(), material: MaterialSchema.optional(), materialPreset: z.string().optional(), // Unified paint-slot refs (`scene:`/`library:` MaterialRef per slot id), @@ -184,6 +194,8 @@ export const ColumnNode = BaseNode.extend({ - baseHeight/capitalHeight: bottom and top block proportions - ring/flute/spiral/panel/lathe/carving fields: procedural detail controls - supportStyle/brace fields: vertical column or procedural support assembly + - role: 'post' for a framing post (a square sawn post carrying a beam), 'ornament' for decoration + - postBase: a framing post's base: none, a steel post base, or a concrete pier `) export const COLUMN_PRESETS = { diff --git a/packages/core/src/schema/nodes/door.ts b/packages/core/src/schema/nodes/door.ts index 7c16701dd5..915e34f57c 100644 --- a/packages/core/src/schema/nodes/door.ts +++ b/packages/core/src/schema/nodes/door.ts @@ -3,7 +3,12 @@ import { z } from 'zod' import { BaseNode, nodeType, objectId } from '../base' import { GeometryScriptSource } from '../geometry-source' import { MaterialSchema } from '../material' -import { DEFAULT_DOOR_CONTENT_PADDING, DoorType, defaultDoorSegments } from './opening-types' +import { + DEFAULT_DOOR_CONTENT_PADDING, + DEFAULT_OPENING_CASING_WIDTH, + DoorType, + defaultDoorSegments, +} from './opening-types' export { DoorType } from './opening-types' @@ -130,11 +135,20 @@ export const DoorNode = BaseNode.extend({ .number() .optional() .describe( - "Frame depth through the wall; left out, the frame follows its wall: the wall's thickness plus a 1 cm lip on each face.", + "Frame depth through the wall; left out, the frame is exactly the host wall's thickness.", ), threshold: z.boolean().default(true), thresholdHeight: z.number().default(0.02), + // Casing: flat boards on the finished faces of the host wall around the + // opening (head and both legs, none at the floor), never inside it, so the + // wall cutout stays width × height. The faces are the host's `a` / `b` + // (WallFace), not the door's front and back, so flipping the swing leaves + // the casing where it is. Absent casing fields keep saved openings uncased. + casingFaceA: z.boolean().default(false), + casingFaceB: z.boolean().default(false), + casingWidth: z.number().positive().default(DEFAULT_OPENING_CASING_WIDTH), + // Swing hingesSide: z.enum(['left', 'right']).default('left'), swingDirection: z.enum(['inward', 'outward']).default('inward'), @@ -163,11 +177,15 @@ export const DoorNode = BaseNode.extend({ panicBarHeight: z.number().default(1.0), }).describe(dedent`Door node - a parametric door placed on a wall - position: center of the door in wall-local coordinate system (Y = height/2, always at floor) + - width/height: overall outer dimensions, which are also the wall cutout - doorCategory/doorType: explicit operation family, defaulting old doors to interior hinged - openingKind/openingShape: hinged door or frameless wall opening shape - segments: rows stacked top to bottom, each defining its own columnRatios - type 'empty' = no leaf fill for that segment, 'panel' = raised/recessed panel, 'glass' = glazed - hingesSide/swingDirection/swingAngle: which way the door opens and how far it is currently open + - frameThickness: width of the frame members (new doors use 0.020 m; absent in saved doors keeps 0.05 m) + - casingFaceA/casingFaceB: casing (head and legs) on the host wall's face a / b, around the cutout (absent means off; new openings enable both) + - casingWidth: face width of the casing boards (2 in by default) - doorCloser/panicBar: commercial and emergency hardware options `) diff --git a/packages/core/src/schema/nodes/level.ts b/packages/core/src/schema/nodes/level.ts index b6a0ce436a..564b7a3788 100644 --- a/packages/core/src/schema/nodes/level.ts +++ b/packages/core/src/schema/nodes/level.ts @@ -2,6 +2,7 @@ import dedent from 'dedent' import { z } from 'zod' import type { ProceduralItemNode } from '../../procedural-items/node' import { BaseNode, nodeType, objectId } from '../base' +import type { BeamNode } from './beam' import type { BlockNode } from './block' import type { CeilingNode } from './ceiling' import type { ColumnNode } from './column' @@ -38,6 +39,7 @@ type CoreLevelChildId = | FloorOpeningNode['id'] | FenceNode['id'] | ColumnNode['id'] + | BeamNode['id'] | ConstructionDimensionNode['id'] | BlockNode['id'] | StructuralGridNode['id'] diff --git a/packages/core/src/schema/nodes/opening-types.ts b/packages/core/src/schema/nodes/opening-types.ts index ca65de92bb..c78b1256ef 100644 --- a/packages/core/src/schema/nodes/opening-types.ts +++ b/packages/core/src/schema/nodes/opening-types.ts @@ -39,6 +39,14 @@ export const defaultDoorSegments = () => [ /** A new door's leaf margin [x, y] (m). */ export const DEFAULT_DOOR_CONTENT_PADDING: [number, number] = [0.04, 0.04] +const INCH = 0.0254 + +/** A door's or window's casing face width when none is given: 2 in boards (m). */ +export const DEFAULT_OPENING_CASING_WIDTH = 2 * INCH + +/** How far casing stands proud of the finished wall face: 3/4 in stock, like skirting (m). */ +export const OPENING_CASING_PROUD = 0.75 * INCH + export const WindowType = z.enum([ 'fixed', 'sliding', diff --git a/packages/core/src/schema/nodes/railing-wall.test.ts b/packages/core/src/schema/nodes/railing-wall.test.ts new file mode 100644 index 0000000000..fe35fc81e3 --- /dev/null +++ b/packages/core/src/schema/nodes/railing-wall.test.ts @@ -0,0 +1,110 @@ +import { wallSlots } from '../../node-slots/wall' +import { + DEFAULT_RAILING_WALL, + getRailingWallConfig, + getRailingWallHeight, + isRailingWall, + RAILING_GUARD_HEIGHT, + RAILING_GUARD_HEIGHT_TALL, + RAILING_SPHERE_LIMIT, + RAILING_STYLE_DEFAULTS, + railingOpeningFields, + railingWallDefaults, +} from './railing-wall' +import { WallNode } from './wall' + +const IN = 0.0254 + +describe('railing wall defaults', () => { + test('the default railing is the DCA 6 deck guard: 4x4 posts at most 6 ft apart, 2x2 balusters 3½ in clear on a rail 3½ in up, a 2x6 cap', () => { + expect(DEFAULT_RAILING_WALL).toEqual({ + style: 'post-and-rail', + postSpacing: 72 * IN, + postSize: 3.5 * IN, + infillSize: 1.5 * IN, + infillGap: 3.5 * IN, + bottomClearance: 3.5 * IN, + cap: true, + }) + expect(RAILING_GUARD_HEIGHT).toBeCloseTo(0.9144, 9) + expect(RAILING_GUARD_HEIGHT_TALL).toBeCloseTo(1.0668, 9) + }) + + test('every style starts with openings a 4 in sphere cannot pass', () => { + for (const members of Object.values(RAILING_STYLE_DEFAULTS)) { + expect(members.infillGap).toBeLessThan(RAILING_SPHERE_LIMIT) + expect(members.bottomClearance).toBeLessThan(RAILING_SPHERE_LIMIT) + } + }) + + test('a drawn railing is a 36 in guard of its style, as thick as its posts, with no assembly', () => { + const patch = railingWallDefaults() + expect(patch).toEqual({ + wallType: 'railing', + thickness: 3.5 * IN, + height: RAILING_GUARD_HEIGHT, + railing: DEFAULT_RAILING_WALL, + assembly: undefined, + }) + const cable = railingWallDefaults('cable') + expect(cable.railing.style).toBe('cable') + expect(cable.railing.postSize).toBeCloseTo(2 * IN, 9) + expect(cable.thickness).toBe(cable.railing.postSize) + + const wall = WallNode.parse({ start: [0, 0], end: [4, 0], ...patch }) + expect(isRailingWall(wall)).toBe(true) + expect(wall.height).toBe(RAILING_GUARD_HEIGHT) + expect(wall.assembly).toBeUndefined() + }) +}) + +describe('railing wall config', () => { + test('a partial config reads over the defaults; a wall saved before railings parses as it was', () => { + const wall = WallNode.parse({ + start: [0, 0], + end: [4, 0], + wallType: 'railing', + railing: { style: 'glass' }, + }) + expect(wall.railing).toEqual({ ...DEFAULT_RAILING_WALL, style: 'glass' }) + expect(getRailingWallConfig({ railing: { postSpacing: 1.2 } })).toEqual({ + ...DEFAULT_RAILING_WALL, + postSpacing: 1.2, + }) + + const plain = WallNode.parse({ start: [0, 0], end: [4, 0] }) + expect(plain.railing).toBeUndefined() + expect(isRailingWall(plain)).toBe(false) + expect(getRailingWallConfig(plain)).toBe(DEFAULT_RAILING_WALL) + }) + + test('a railing never follows the storey: with no height of its own it is a 36 in guard', () => { + expect(getRailingWallHeight({})).toBe(RAILING_GUARD_HEIGHT) + expect(getRailingWallHeight({ height: RAILING_GUARD_HEIGHT_TALL })).toBe( + RAILING_GUARD_HEIGHT_TALL, + ) + }) + + test('a door on a railing is a gap as tall as the guard, with no casing or threshold', () => { + expect(railingOpeningFields({ height: RAILING_GUARD_HEIGHT_TALL })).toEqual({ + openingKind: 'opening', + height: RAILING_GUARD_HEIGHT_TALL, + threshold: false, + casingFaceA: false, + casingFaceB: false, + }) + }) + + test('a railing paints its posts and rails and its infill, not two faces', () => { + const wood = WallNode.parse({ start: [0, 0], end: [4, 0], ...railingWallDefaults() }) + expect(wallSlots(wood)).toEqual([ + { slotId: 'railing-frame', label: 'Posts & rails', default: 'library:preset-white' }, + { slotId: 'railing-infill', label: 'Infill', default: 'library:preset-white' }, + ]) + const glass = WallNode.parse({ start: [0, 0], end: [4, 0], ...railingWallDefaults('glass') }) + expect(wallSlots(glass).map((slot) => [slot.slotId, slot.default])).toEqual([ + ['railing-frame', 'library:metal-steel'], + ['railing-infill', 'library:preset-glass'], + ]) + }) +}) diff --git a/packages/core/src/schema/nodes/railing-wall.ts b/packages/core/src/schema/nodes/railing-wall.ts new file mode 100644 index 0000000000..64341768d4 --- /dev/null +++ b/packages/core/src/schema/nodes/railing-wall.ts @@ -0,0 +1,189 @@ +import { z } from 'zod' +import { StairRailingStyle } from './stair-types' + +/** + * A railing wall (`WallNode.wallType: 'railing'`): drawn and joined + * like any wall, and like any wall it closes rooms (a deck or a porch its railings fence is a + * room), but it stands as an open guard instead of a framed body: posts at its ends and equally + * spaced between them, rails, and the infill its style sets. Its doors are gaps in the guard (a + * doorway: no leaf, casing or threshold), with a post either side. It takes no finishes, assembly, + * framing or foundation, and it keeps its own height rather than following the storey. + */ + +const INCH = 0.0254 + +/** A guard's height over the floor, IRC R312.1.2: 36 in where the drop is more than 30 in. */ +export const RAILING_GUARD_HEIGHT = 36 * INCH +/** The taller guard the IBC (1015.3) and some local codes ask for: 42 in. */ +export const RAILING_GUARD_HEIGHT_TALL = 42 * INCH +/** The largest sphere a guard's openings may pass, IRC R312.1.3: 4 in. */ +export const RAILING_SPHERE_LIMIT = 4 * INCH +/** Guard posts on centre at most this far apart: 6 ft, the AWC Deck Construction Guide (DCA 6). */ +export const RAILING_MAX_POST_SPACING = 72 * INCH + +/** The railing styles: the stair guards' vocabulary (`StairRailingStyle`). */ +export const RailingWallStyle = StairRailingStyle +export type RailingWallStyle = z.infer + +/** + * How a railing wall is built, metres. The guard's height is the wall's own `height`; its + * `thickness` follows `postSize`, so the plan outline and the room it closes run along the posts. + * - `postSpacing`: the most the posts stand apart on centre; they are equally spaced between the + * run's ends (each end, and each side of an opening, has its post). + * - `postSize`: the posts' square section. + * - `infillSize`: a baluster's (picket's, bar's) square section, a cable's diameter, a board's + * face height, a glass pane's thickness. + * - `infillGap`: the clear space between the infill members (keep it under the 4 in sphere). + * - `bottomClearance`: the clear space under the bottom rail (or the lowest infill) over the floor. + * - `cap`: a 2x6 cap laid flat over the top rail (the post-and-rail and boards styles). + */ +export const RailingWallConfig = z.object({ + style: RailingWallStyle.default('post-and-rail'), + postSpacing: z.number().finite().positive().default(RAILING_MAX_POST_SPACING), + postSize: z + .number() + .finite() + .positive() + .default(3.5 * INCH), + infillSize: z + .number() + .finite() + .positive() + .default(1.5 * INCH), + infillGap: z + .number() + .finite() + .nonnegative() + .default(3.5 * INCH), + bottomClearance: z + .number() + .finite() + .nonnegative() + .default(3.5 * INCH), + cap: z.boolean().default(true), +}) +export type RailingWallConfig = z.infer + +/** + * The default railing: the DCA 6 deck guard — 4x4 posts at most 6 ft apart, a 2x6 cap over a + * 2x4 top rail, a 2x4 bottom rail 3½ in off the floor, and 2x2 balusters 3½ in clear. + */ +export const DEFAULT_RAILING_WALL: RailingWallConfig = RailingWallConfig.parse({}) + +/** + * The members each style is drawn with when picked: its posts' section, its infill's section and + * clear gap, and its clearance over the floor (the stair guards' members, `nodes/stair/*-guard`). + */ +export const RAILING_STYLE_DEFAULTS: Record< + RailingWallStyle, + Pick +> = { + // DCA 6: 4x4 posts, 2x2 balusters 3½ in clear on a 2x4 bottom rail 3½ in up. + 'post-and-rail': { + postSize: 3.5 * INCH, + infillSize: 1.5 * INCH, + infillGap: 3.5 * INCH, + bottomClearance: 3.5 * INCH, + }, + // Joinery: newels, 1¼ in square balusters between a handrail and a shoe rail. + balusters: { + postSize: 3.5 * INCH, + infillSize: 1.25 * INCH, + infillGap: 3.5 * INCH, + bottomClearance: 2.25 * INCH, + }, + // 2 in posts, ⅜ in cables 3 in on centre under a flat cap. + cable: { + postSize: 2 * INCH, + infillSize: 0.375 * INCH, + infillGap: 2.625 * INCH, + bottomClearance: 2.75 * INCH, + }, + // 4x4 posts, 1x6 boards on the flat 3½ in apart under a 2x6 cap. + boards: { + postSize: 3.5 * INCH, + infillSize: 5.5 * INCH, + infillGap: 3.5 * INCH, + bottomClearance: 3.5 * INCH, + }, + // 1½ in posts and one ½ in tempered pane per bay. + glass: { + postSize: 1.5 * INCH, + infillSize: 0.5 * INCH, + infillGap: 0, + bottomClearance: 3 * INCH, + }, + // 1½ in steel posts on baseplates, ⅝ in square bars between two flat rails. + metal: { + postSize: 1.5 * INCH, + infillSize: 0.625 * INCH, + infillGap: 3.75 * INCH, + bottomClearance: 3 * INCH, + }, +} + +/** A railing wall's config with every field present: its own over the defaults. */ +export function getRailingWallConfig(wall: { railing?: Partial }) { + return wall.railing ? { ...DEFAULT_RAILING_WALL, ...wall.railing } : DEFAULT_RAILING_WALL +} + +/** Whether a node is a railing wall. */ +export function isRailingWall(node: { type?: string; wallType?: string } | null | undefined) { + return node?.type === 'wall' && node.wallType === 'railing' +} + +/** A railing's height: its own, else the 36 in guard (a railing never follows the storey). */ +export function getRailingWallHeight(wall: { height?: number }): number { + return wall.height ?? RAILING_GUARD_HEIGHT +} + +export type RailingWallPatch = { + wallType: 'railing' + thickness: number + height: number + railing: RailingWallConfig + assembly: undefined +} + +/** + * What a newly drawn railing wall is (the Build panel's Railing): a railing of `style` with that + * style's members, as thick as its posts, 36 in tall, and no assembly (a railing has no layers). + */ +export function railingWallDefaults(style: RailingWallStyle = 'post-and-rail'): RailingWallPatch { + const railing = { ...DEFAULT_RAILING_WALL, ...RAILING_STYLE_DEFAULTS[style], style } + return { + wallType: 'railing', + thickness: railing.postSize, + height: RAILING_GUARD_HEIGHT, + railing, + assembly: undefined, + } +} + +/** + * What a door placed on a railing becomes: a gap in the guard as tall as the guard, with no leaf, + * casing or threshold. The guard stands a post either side of it. + */ +export function railingOpeningFields(wall: { height?: number }) { + return { + openingKind: 'opening' as const, + height: getRailingWallHeight(wall), + threshold: false, + casingFaceA: false, + casingFaceB: false, + } +} + +/** A railing wall's paint slots: its posts and rails, and its infill. */ +export type RailingWallSlotId = 'railing-frame' | 'railing-infill' + +const WOOD_STYLES: ReadonlySet = new Set(['post-and-rail', 'balusters', 'boards']) + +/** + * What an unpainted railing shows: a wood guard painted white, a metal one steel, and glass + * panes glass. + */ +export function railingWallSlotDefault(style: RailingWallStyle, slot: RailingWallSlotId): string { + if (slot === 'railing-infill' && style === 'glass') return 'library:preset-glass' + return WOOD_STYLES.has(style) ? 'library:preset-white' : 'library:metal-steel' +} diff --git a/packages/core/src/schema/nodes/roof-segment.ts b/packages/core/src/schema/nodes/roof-segment.ts index 5c0408521e..b64eea2d2d 100644 --- a/packages/core/src/schema/nodes/roof-segment.ts +++ b/packages/core/src/schema/nodes/roof-segment.ts @@ -1,13 +1,14 @@ import dedent from 'dedent' import { z } from 'zod' import { BaseNode, nodeType, objectId } from '../base' +import { RoofBuildUp } from '../build-up' import type { MaterialSchema as MaterialSchemaType } from '../material' import { MaterialSchema } from '../material' import { getBarrelRoofProfile } from './barrel-roof' import { RoofGlazing, RoofSystemType } from './roof-glazing' -import { RoofType } from './roof-types' +import { RoofEaveCut, RoofType } from './roof-types' -export { RoofType } from './roof-types' +export { RoofEaveCut, RoofType } from './roof-types' export const MIN_ROOF_SEGMENT_TRIM_SPAN = 0.1 const DEFAULT_ROOF_SEGMENT_WIDTH = 8 const DEFAULT_ROOF_SEGMENT_DEPTH = 6 @@ -142,6 +143,9 @@ export const RoofSegmentNode = BaseNode.extend({ // gambrel's ends, a shed's sides). Absent, as far as the eaves reach (`overhang` is along the slope). gableOverhang: z.number().min(0).optional(), shingleThickness: z.number().default(0.05), + // The plane's layers, outside in. Present, `deckThickness` and `shingleThickness` are derived + // from it and written with it (`roofBuildUpPatch`); absent, they are the plane's own. + buildUp: RoofBuildUp.optional(), arc: z .object({ centerX: z.number(), @@ -172,20 +176,32 @@ export const RoofSegmentNode = BaseNode.extend({ managedByParent: z.boolean().default(false), wallShell: z.enum(['auto', 'include', 'omit']).default('auto'), shedInsetEndPanels: z.boolean().default(false), - // Plumb 1x8 fascia and rake boards on the eaves and rakes (gable, hip, - // shed, flat), built from the segment itself so they follow its pitch, - // size, overhang and type. + // Fascia and rake boards on the eaves and rakes (gable, hip, shed, flat), built from the segment + // itself so they follow its pitch, size, overhang, layers and eave cut (core's `roofEaveProfile`). fascia: z.boolean().optional(), + // How the rafter tails are cut at the eaves, the fascia with them (`RoofEaveCut`); absent, plumb. + eaveCut: RoofEaveCut.optional(), // Shed only: the board on the high edge. Off when that edge meets a wall // (a porch cover on a ledger); a lean-to never has one. fasciaHighEdge: z.boolean().optional(), - // The boards' height and thickness; a 1x8 (0.184 × 0.019 m) when absent. With a height set, a - // flat roof's boards rise to the roof's top: a coping band over the deck and membrane edges. + // The boards' height and thickness; absent, a 1x as deep as the tails need (`roofEaveProfile`). + // With a height set, a flat roof's boards rise to the roof's top: a coping band over the deck and + // membrane edges. fasciaHeight: z.number().positive().optional(), fasciaDepth: z.number().positive().optional(), // The boards' and rakes' own finish; absent, they take the wall role's, as they always did. fasciaMaterial: MaterialSchema.optional(), fasciaMaterialPreset: z.string().optional(), + // The wall band between the top plate and the eaves (a raised heel) is wall, not trim: its own + // finish; absent, the roof's, then the walls' below it. + heelMaterial: MaterialSchema.optional(), + heelMaterialPreset: z.string().optional(), + // Each gable end's own finish (−x is the left, +x the right, as `getRoofSegmentWallFaces` names + // them); absent, the edge role's, as every gable took before they could be painted apart. + gableLeftMaterial: MaterialSchema.optional(), + gableLeftMaterialPreset: z.string().optional(), + gableRightMaterial: MaterialSchema.optional(), + gableRightMaterialPreset: z.string().optional(), // Shape-specific ratios. Only the pair matching `roofType` is read; the // rest are inert. Defined on every segment so the panel can flip // roofType without losing the previous shape's tuning. @@ -257,10 +273,14 @@ export const RoofSegmentNode = BaseNode.extend({ - overhang: eave overhang distance, along the slope - gableOverhang: reach past the gable-end walls in plan (gable, gambrel, shed); absent = the eaves' reach - shingleThickness: outer shingle layer thickness - - fascia: plumb fascia and rake boards on the eaves and rakes (gable, hip, shed, flat) (off when absent) + - buildUp: layers outside in (roofing, underlayment, sheathing, structure, insulation, finish); sets deckThickness and shingleThickness + - fascia: fascia and rake boards on the eaves and rakes (gable, hip, shed, flat) (off when absent) + - eaveCut: how the rafter tails are cut at the eaves — plumb, square (to the slope) or plumb-level (a boxed eave with a level soffit); plumb when absent - fasciaHighEdge: shed only — a board on the high edge (off when it meets a wall; on when absent) - - fasciaHeight/fasciaDepth: the boards' size (a 1x8 when absent); with a height, a flat roof's boards reach its top + - fasciaHeight/fasciaDepth: the boards' size (a 1x as deep as the tails need when absent); with a height, a flat roof's boards reach its top - fasciaMaterial/fasciaMaterialPreset: the boards' and rakes' finish (the wall role's when absent) + - heelMaterial/heelMaterialPreset: the wall band under the eaves (the roof's, then the walls' below, when absent) + - gableLeftMaterial/gableRightMaterial (+Preset): one gable end's finish (the edge role's when absent) - gambrelLowerWidthRatio / gambrelLowerHeightRatio: kink position on gambrel roofs - mansardSteepWidthRatio / mansardSteepHeightRatio: waist position on mansard roofs - dutchHipWidthRatio / dutchHipHeightRatio: hip-to-gable split on dutch roofs @@ -912,6 +932,51 @@ export function getEffectiveSegmentSurfaceMaterial( return parentFallback ?? { material: undefined, materialPreset: undefined } } +/** A segment's wall-band surfaces painted apart from the edge role: the heel band and each gable. */ +export type RoofWallBand = 'heel' | 'gable-left' | 'gable-right' + +export const ROOF_WALL_BANDS: readonly RoofWallBand[] = ['heel', 'gable-left', 'gable-right'] + +const WALL_BAND_FIELDS = { + heel: ['heelMaterial', 'heelMaterialPreset'], + 'gable-left': ['gableLeftMaterial', 'gableLeftMaterialPreset'], + 'gable-right': ['gableRightMaterial', 'gableRightMaterialPreset'], +} as const + +/** The node fields one wall band's finish is stored in. */ +export function roofWallBandFields(band: RoofWallBand) { + const [material, materialPreset] = WALL_BAND_FIELDS[band] + return { material, materialPreset } +} + +/** + * A wall band's own finish on a segment (or, for the heel, a roof), or null when it has none and + * the band follows its fallback: the heel the roof's, then the walls' below; a gable the edge role. + */ +export function getRoofWallBandMaterial( + node: Partial< + Pick< + RoofSegmentNode, + | 'heelMaterial' + | 'heelMaterialPreset' + | 'gableLeftMaterial' + | 'gableLeftMaterialPreset' + | 'gableRightMaterial' + | 'gableRightMaterialPreset' + > + >, + band: RoofWallBand, +): RoofSegmentSurfaceMaterialSpec | null { + const fields = roofWallBandFields(band) + const material = node[fields.material] + const materialPreset = node[fields.materialPreset] + if (material === undefined && typeof materialPreset !== 'string') return null + return { + material, + materialPreset: typeof materialPreset === 'string' ? materialPreset : undefined, + } +} + /** The fascia and rake boards' own finish, or null when they take the wall role's. */ export function getSegmentFasciaMaterial( node: RoofSegmentNode, @@ -943,6 +1008,7 @@ export function hasSegmentMaterialOverride(node: RoofSegmentNode): boolean { node.wallMaterial !== undefined || typeof node.wallMaterialPreset === 'string' || node.fasciaMaterial !== undefined || - typeof node.fasciaMaterialPreset === 'string' + typeof node.fasciaMaterialPreset === 'string' || + ROOF_WALL_BANDS.some((band) => getRoofWallBandMaterial(node, band) !== null) ) } diff --git a/packages/core/src/schema/nodes/roof-types.ts b/packages/core/src/schema/nodes/roof-types.ts index c24e25b2d3..29e0c327f1 100644 --- a/packages/core/src/schema/nodes/roof-types.ts +++ b/packages/core/src/schema/nodes/roof-types.ts @@ -15,3 +15,12 @@ export const RoofType = z.enum([ ]) export type RoofType = z.infer + +/** + * How a roof plane's rafter tails are cut at its eaves, and so the fascia over them: `plumb` + * (vertical, the fascia plumb), `square` (square to the slope, the fascia with it) or `plumb-level` + * (plumb, with a level cut under it for a soffit nailed up flat: a boxed eave). + */ +export const RoofEaveCut = z.enum(['plumb', 'square', 'plumb-level']) + +export type RoofEaveCut = z.infer diff --git a/packages/core/src/schema/nodes/roof.ts b/packages/core/src/schema/nodes/roof.ts index e33ab76779..8edaa847c0 100644 --- a/packages/core/src/schema/nodes/roof.ts +++ b/packages/core/src/schema/nodes/roof.ts @@ -38,6 +38,10 @@ export const RoofNode = BaseNode.extend({ edgeMaterialPreset: z.string().optional(), wallMaterial: MaterialSchema.optional(), wallMaterialPreset: z.string().optional(), + // The wall band between the top plate and the eaves (a raised heel): its own finish, under every + // segment that has none; absent, the walls' below it. + heelMaterial: MaterialSchema.optional(), + heelMaterialPreset: z.string().optional(), position: z.tuple([z.number(), z.number(), z.number()]).default([0, 0, 0]), // Rotation around Y axis in radians rotation: z.number().default(0), diff --git a/packages/core/src/schema/nodes/site.ts b/packages/core/src/schema/nodes/site.ts index 49658da981..90a0f7cdfa 100644 --- a/packages/core/src/schema/nodes/site.ts +++ b/packages/core/src/schema/nodes/site.ts @@ -5,6 +5,7 @@ import { z } from 'zod' import { BaseNode, nodeType, objectId } from '../base' import { SitePresentation } from '../site-presentation' import { TerrainData } from '../terrain' +import { WallTypeDefinition } from '../wall-type' import { SiteAddress, SiteParcel, SiteSetbacks } from './site-facts' // 2D Polygon @@ -143,6 +144,11 @@ export const SiteNode = BaseNode.extend({ ), }) .optional(), + /** + * The project's own wall types (`WallTypeDefinition`), listed beside the presets where walls + * are drafted. Absent = none, the state every scene that predates them loads in. + */ + wallTypes: z.array(WallTypeDefinition).max(64).optional(), children: z.array(z.string()).default([]), }).describe( dedent` @@ -155,6 +161,7 @@ export const SiteNode = BaseNode.extend({ - setbacks: required yards in metres; setbacksSource / zone cite them - frontEdge: index of the street-facing polygon edge - northRotation: true north offset from plan up, radians + - wallTypes: the project's own wall types: { id: 'custom-…', label, assembly } with the layers listed from the exterior face around one core - children: array of child node ids (buildings, items) `, ) diff --git a/packages/core/src/schema/nodes/stair-structure.ts b/packages/core/src/schema/nodes/stair-structure.ts new file mode 100644 index 0000000000..0efe1c84b0 --- /dev/null +++ b/packages/core/src/schema/nodes/stair-structure.ts @@ -0,0 +1,50 @@ +import { z } from 'zod' + +/** + * How a stair is actually built, apart from the body it is drawn with (`construction`): + * 'wood-stringers' — sawn 2x stringers carrying wood treads (the house and deck standard); + * 'concrete' — a solid poured flight on a footing (a porch stoop); 'steel-stringers' — steel + * channel stringers with treads between them. A stair without one keeps its original body. + */ +export const StairStructureType = z.enum(['wood-stringers', 'concrete', 'steel-stringers']) +export type StairStructureType = z.infer + +/** Stringer stock: a 2x12 (the standard, DCA 6) or a 2x10 for a short flight. */ +export const StairStringerStock = z.enum(['2x12', '2x10']) +export type StairStringerStock = z.infer + +/** + * 'cut' — sawtooth carriages notched for every tread and riser; 'housed' — solid outer + * stringers with the treads and risers housed (dadoed) into their faces, cut carriages between. + */ +export const StairStringerType = z.enum(['cut', 'housed']) +export type StairStringerType = z.infer + +/** + * Tread stock: two 2x6s (the deck standard), two 5/4x6 deck boards, one 2x12, or a 3/4 in + * plywood subtread under a 3/4 in finish tread (carpet or hardwood inside the house). + */ +export const StairTreadStock = z.enum(['2x6-pair', '5/4x6-pair', '2x12', 'plywood-finish']) +export type StairTreadStock = z.infer + +/** The maximum stringer spacings offered, in inches on centre. */ +export const STAIR_STRINGER_SPACINGS_IN = [12, 16, 18, 24] as const + +export const StairStructure = z.object({ + type: StairStructureType.default('wood-stringers'), + stringerStock: StairStringerStock.default('2x12'), + stringerType: StairStringerType.default('cut'), + /** The most the stringers may stand apart on centre (m) — 16 in; drives the automatic count. */ + stringerSpacing: z.number().positive().default(0.4064), + /** A stringer count chosen by hand; absent = as many as keep every bay within `stringerSpacing`. */ + stringerCount: z.number().int().min(2).max(12).optional(), + /** Absent = two 2x6s on an exterior stair, one 2x12 inside the house. */ + treadStock: StairTreadStock.optional(), + /** Riser boards; absent = closed once the stair rises more than 30 in (IRC R311.7.5.1). */ + closedRisers: z.boolean().optional(), + /** Pressure-treated lumber; absent = treated on an exterior stair. */ + treated: z.boolean().optional(), + /** Nosing projection (m); absent = 1 in on wood and steel treads, none on concrete. */ + nosing: z.number().nonnegative().optional(), +}) +export type StairStructure = z.infer diff --git a/packages/core/src/schema/nodes/stair.ts b/packages/core/src/schema/nodes/stair.ts index c8021c8a85..a2e80cc2db 100644 --- a/packages/core/src/schema/nodes/stair.ts +++ b/packages/core/src/schema/nodes/stair.ts @@ -11,6 +11,7 @@ export { StairRailingMode, StairRailingStyle } from './stair-types' import { StairConstruction } from './stair-construction' import { StairSegmentNode } from './stair-segment' +import { StairStructure } from './stair-structure' export const StairType = z.enum(['straight', 'curved', 'spiral']) export const StairTopLandingMode = z.enum(['none', 'integrated']) @@ -70,6 +71,7 @@ export const StairNode = BaseNode.extend({ thickness: z.number().default(0.25), fillToFloor: z.boolean().default(true), construction: StairConstruction.optional(), + structure: StairStructure.optional(), innerRadius: z.number().default(0.9), sweepAngle: z.number().default(Math.PI / 2), topLandingMode: StairTopLandingMode.default('none'), @@ -115,6 +117,7 @@ export const StairNode = BaseNode.extend({ - totalRise: total stair height - stepCount: number of visible steps - construction: optional explicit construction and finish details, inherited by child segments; absence preserves legacy bodies + - structure: how the stair is built — wood-stringers (2x12 or 2x10 stringers, cut or housed, the count automatic from a maximum spacing of 16 in o.c. unless set; 2x6-pair, 5/4x6-pair, 2x12 or plywood-finish treads; closed risers once it rises over 30 in), concrete (a solid poured flight on a footing) or steel-stringers (steel channels); it draws the body when no explicit construction is set. Absent keeps the original body - autoSurfaceSnap: magnetically connect straight flights to nearby registered top surfaces - thickness: stair slab / tread thickness - fillToFloor: whether the stair mass fills down to the floor or uses tread thickness only diff --git a/packages/core/src/schema/nodes/wall.ts b/packages/core/src/schema/nodes/wall.ts index 1f15d6596f..07196875c4 100644 --- a/packages/core/src/schema/nodes/wall.ts +++ b/packages/core/src/schema/nodes/wall.ts @@ -8,6 +8,7 @@ import { CurtainWallConfig } from './curtain-wall' import { DoorNode } from './door' import { ItemNode } from './item' import { LeanToExtensionNode } from './lean-to-extension' +import { RailingWallConfig } from './railing-wall' import { WindowNode } from './window' // Geometric faces: `a` is left of start → end, `b` is right (wall-frame convention). @@ -83,9 +84,27 @@ export const WALL_SKIRTING_SLOT_DEFAULT = 'library:preset-softwhite' export const WALL_CROWN_SLOT_DEFAULT = 'library:preset-white' export const WALL_CHAIR_RAIL_SLOT_DEFAULT = 'library:preset-cream' +/** + * The paint an interior wall face shows until someone paints it: Seattle grey, + * a cool light grey flat colour from the catalog. Both faces of a partition and + * the inside face of an exterior wall wear it (`getWallFaceDefault`); an + * exterior face shows its assembly's cladding, or its bare block or concrete, + * else `DEFAULT_EXTERIOR_WALL_FINISH`. Raw drywall (`library:concrete-drywall`) + * stays in the catalog for a face meant to be bare. + */ +export const DEFAULT_INTERIOR_WALL_PAINT = 'library:preset-seattlegrey' + +/** + * What an unpainted exterior wall face with no cladding shows: raw drywall, the + * default every face drew before the interior paint, kept outside so an old + * save's exterior walls look as they did and meet the roof's gable and heel + * bands (drywall too) without a seam at the plate. + */ +export const DEFAULT_EXTERIOR_WALL_FINISH = 'library:concrete-drywall' + export const WALL_SURFACE_SLOT_DEFAULTS = { - a: 'library:concrete-drywall', - b: 'library:concrete-drywall', + a: DEFAULT_INTERIOR_WALL_PAINT, + b: DEFAULT_INTERIOR_WALL_PAINT, aSkirting: WALL_SKIRTING_SLOT_DEFAULT, bSkirting: WALL_SKIRTING_SLOT_DEFAULT, aCrown: WALL_CROWN_SLOT_DEFAULT, @@ -214,6 +233,8 @@ export const WallAssembly = z framing: z.object({ kind: WallAssemblyFramingKind, depth: z.number().nonnegative(), + /** Studs on centre, metres; absent = the framer's own. */ + spacing: z.number().positive().optional(), }), interior: z .object({ @@ -244,8 +265,10 @@ export type WallAssembly = z.infer export const WallNode = BaseNode.extend({ id: objectId('wall'), type: nodeType('wall'), - wallType: z.enum(['standard', 'curtain']).optional(), + wallType: z.enum(['standard', 'curtain', 'railing']).optional(), curtainWall: CurtainWallConfig.optional(), + // How a railing wall's guard is built — see RailingWallConfig. + railing: RailingWallConfig.optional(), children: z .array( z.union([ @@ -332,6 +355,7 @@ export const WallNode = BaseNode.extend({ }).describe( dedent` Wall node - used to represent a wall in the building + - wallType: standard (framed), curtain (glazed, curtainWall) or railing (an open guard, railing: { style, postSpacing, postSize, infillSize, infillGap, bottomClearance, cap }; it closes rooms like any wall, its doors are gaps in the guard, its height is its own and its thickness its posts') - thickness: TOTAL thickness in meters (all assembly layers together) - assembly: optional layered construction stack; when present it is the single source of truth and thickness is re-derived from it on every edit @@ -353,16 +377,34 @@ export type WallNode = z.infer /** Legacy semantic side, read only by load migrations. */ export type WallSurfaceSide = 'interior' | 'exterior' -// Declared default appearance for an unpainted wall face in colored mode — -// visual parity with the retired DEFAULT_WALL_MATERIAL. Lives in core so the +// Declared default appearance for an unpainted wall face in colored mode — the +// interior paint (`DEFAULT_INTERIOR_WALL_PAINT`). Lives in core so the // slot declaration (nodes) and the material resolver (viewer) share one value. // May be a `#rrggbb` colour or a `library:` ref. Textures-off still -// collapses to the themed wall role (the escape hatch). +// collapses to the themed wall role (the escape hatch). A face on the wall's +// exterior side defaults to `DEFAULT_EXTERIOR_WALL_FINISH` instead +// (`getWallFaceDefault`). export const WALL_SLOT_DEFAULT: Record = { a: WALL_SURFACE_SLOT_DEFAULTS.a, b: WALL_SURFACE_SLOT_DEFAULTS.b, } +/** + * The default an unpainted face of `wall` shows (`a` is the +normal face, the + * `frontSide`): `DEFAULT_EXTERIOR_WALL_FINISH` where that side faces outdoors, + * the interior paint everywhere else — both faces of a partition or of a wall + * whose rooms are not yet detected, and the inside face of an exterior wall. + * An assembly's cladding or bare structure on the exterior face is drawn ahead + * of it by the renderer. + */ +export function getWallFaceDefault( + wall: Partial>, + face: WallFace, +): string { + const side = face === 'a' ? wall.frontSide : wall.backSide + return side === 'exterior' ? DEFAULT_EXTERIOR_WALL_FINISH : WALL_SLOT_DEFAULT[face] +} + export type WallTrimKind = 'skirting' | 'crown' | 'chairRail' export type WallTrimSlotId = `${WallFace}${'Skirting' | 'Crown' | 'ChairRail'}` diff --git a/packages/core/src/schema/nodes/window.ts b/packages/core/src/schema/nodes/window.ts index 1b7b29f331..8d56f0e6b9 100644 --- a/packages/core/src/schema/nodes/window.ts +++ b/packages/core/src/schema/nodes/window.ts @@ -3,7 +3,7 @@ import { z } from 'zod' import { BaseNode, nodeType, objectId } from '../base' import { GeometryScriptSource } from '../geometry-source' import { MaterialSchema } from '../material' -import { WindowType } from './opening-types' +import { DEFAULT_OPENING_CASING_WIDTH, WindowType } from './opening-types' export { WindowType } from './opening-types' @@ -92,7 +92,7 @@ export const WindowNode = BaseNode.extend({ .number() .optional() .describe( - "Frame depth through the wall; left out, the frame follows its wall: the wall's thickness plus a 1 cm lip on each face.", + "Frame depth through the wall; left out, the frame is exactly the host wall's thickness.", ), // Divisions — ratios allow non-uniform panes @@ -118,14 +118,25 @@ export const WindowNode = BaseNode.extend({ sill: z.boolean().default(true), sillDepth: z.number().default(0.08), sillThickness: z.number().default(0.03), + + // Casing: flat boards on the finished faces of the host wall around the + // opening, never inside it, so the wall cutout stays width × height. The + // faces are the host's `a` / `b` (WallFace), not the unit's own front and + // back, so flipping the window leaves its casing where it is. Absent casing fields keep + // saved openings uncased. + casingFaceA: z.boolean().default(false), + casingFaceB: z.boolean().default(false), + casingWidth: z.number().positive().default(DEFAULT_OPENING_CASING_WIDTH), }).describe(dedent`Window node - a parametric window placed on a wall - position: center of the window in wall-local coordinate system - - width/height: overall outer dimensions + - width/height: overall outer dimensions, which are also the wall cutout - windowType: explicit window family, defaulting old windows to fixed - - frameThickness: width of the frame members + - frameThickness: width of the frame members (new windows use 0.020 m; absent in saved windows keeps 0.05 m) - frameDepth: how deep the frame sits within the wall - columnRatios/rowRatios: pane division ratios - sill: whether to show a window sill + - casingFaceA/casingFaceB: picture-frame casing on the host wall's face a / b, around the cutout (absent means off; new openings enable both) + - casingWidth: face width of the casing boards (2 in by default) - corner: joined to a window on the other wall at this wall's start or end (a corner window) `) diff --git a/packages/core/src/schema/nodes/zone.ts b/packages/core/src/schema/nodes/zone.ts index 2bc81bd511..ab2232aea3 100644 --- a/packages/core/src/schema/nodes/zone.ts +++ b/packages/core/src/schema/nodes/zone.ts @@ -37,6 +37,34 @@ export const ZoneNode = BaseNode.extend({ finish: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(), regions: z.array(SurfacePaintRegion).optional(), script: ZoneFloorScript.optional(), + // How far the floor steps down from the floor it would otherwise share, metres (a porch + // 1.5 in under the house), so it follows the house's floor. An `elevation` wins over it. + drop: z.number().min(0).optional(), + }) + .optional(), + // The outdoor room types: a porch (a covered floor a step down from the house), a + // deck (a framed floor) or a patio (an uncovered slab). Such a room is outdoors whatever covers + // it (`lib/outdoor-room`). Absent, an ordinary room. + roomType: z.enum(['porch', 'deck', 'patio']).optional(), + // A porch's posts and the beam on them (`lib/porch-framing`): placed by the structure kernel + // while `auto` holds (absent = on; a deck's or patio's only once `auto` is true), at these sizes + // and at most `postSpacing` metres apart. + porchFraming: z + .object({ + auto: z.boolean().optional(), + postSize: z.string().optional(), + postSpacing: z.number().positive().optional(), + beamSize: z.string().optional(), + }) + .optional(), + // A deck's boards (`lib/deck-boards`): their stock, the gap between them in metres and the way + // they run against the house, the joists under them following. Absent, 5/4x6 boards 1/4 in apart + // running along the house. + decking: z + .object({ + boardSize: z.enum(['5/4x6', '2x6', '2x4', 'composite']).optional(), + gap: z.number().positive().optional(), + direction: z.enum(['parallel', 'diagonal', 'perpendicular']).optional(), }) .optional(), // Painted parts of the room's ceiling. The automatic ceilings are rebuilt @@ -99,6 +127,10 @@ export const ZoneNode = BaseNode.extend({ - roomNumber/finishes/ceilingHeight/occupancy: construction-document room metadata - floor.regions / ceiling.regions: painted parts of the room's floor and ceiling ([x, z] polygons, later wins) - floor.script: a three.js module that builds the room's floor finish (boards, tiles) for its floor polygon, drawn over the floor; it owns its colours + - floor.drop: metres the floor steps down from the floor it would share (a porch under the house's floor); an explicit floor.elevation wins + - roomType: "porch", "deck" or "patio" for a room outside the house (outdoors even when covered); absent, an ordinary room + - porchFraming: a porch's posts and beam (auto placement on unless false; a deck's or patio's only when auto is true; post size, max post spacing in metres, beam size) + - decking: a deck's boards (boardSize "5/4x6" | "2x6" | "2x4" | "composite", gap in metres, direction "parallel" | "diagonal" | "perpendicular" to the house); absent, 5/4x6 at 1/4 in along the house - floorStepFinish: finish of the room's steps; floorStepOverrides: per-doorway step finishes keyed by door id (or the lower room id), optional step index - enclosureStatus: auto-detected, explicitly enclosed, or open - clearDimensionPolicy: optional room clear-dimension datum preference diff --git a/packages/core/src/schema/types.ts b/packages/core/src/schema/types.ts index c57ae599f0..c12af374d6 100644 --- a/packages/core/src/schema/types.ts +++ b/packages/core/src/schema/types.ts @@ -1,5 +1,6 @@ import z from 'zod' import { ProceduralItemNode } from '../procedural-items/node' +import { BeamNode } from './nodes/beam' import { BlockNode } from './nodes/block' import { BoxVentNode } from './nodes/box-vent' import { BuildingNode } from './nodes/building' @@ -95,6 +96,7 @@ export const AnyNode = nodeUnion([ LevelNode, LeanToExtensionNode, ColumnNode, + BeamNode, ConstructionDimensionNode, BlockNode, StructuralGridNode, diff --git a/packages/core/src/schema/wall-type.ts b/packages/core/src/schema/wall-type.ts new file mode 100644 index 0000000000..4f493c1680 --- /dev/null +++ b/packages/core/src/schema/wall-type.ts @@ -0,0 +1,37 @@ +import { z } from 'zod' +import { Assembly } from './assembly' +import { generateId } from './base' + +/** Every project wall type's id starts with this, so a pick can never collide with a preset id. */ +export const CUSTOM_WALL_TYPE_PREFIX = 'custom-' + +export const WallTypeDefinitionId = z.string().regex(/^custom-[A-Za-z0-9_-]{1,40}$/) + +/** A fresh project wall type id: `custom-` and 16 random characters. */ +export function newWallTypeId(): string { + return generateId('custom').replace('_', '-') +} + +/** + * A wall type of the project's own: a name and the + * layers it builds from the exterior face inward around one framing core (an `Assembly` with + * `face: 'exterior'`). Saved on the site (`SiteNode.wallTypes`), so it travels with the project + * when it is reloaded or shared. A wall drawn with one copies its stack (`wallAssemblyPatch`): the + * definition is the library entry, not a live link, so editing it changes the walls drawn next. + */ +export const WallTypeDefinition = z + .object({ + id: WallTypeDefinitionId, + label: z.string().trim().min(1).max(60), + assembly: Assembly, + }) + .superRefine((type, ctx) => { + if (!type.assembly.layers.some((layer) => layer.core)) { + ctx.addIssue({ + code: 'custom', + message: 'A wall type is built around one core layer', + path: ['assembly', 'layers'], + }) + } + }) +export type WallTypeDefinition = z.infer diff --git a/packages/core/src/services/roof-bearing.test.ts b/packages/core/src/services/roof-bearing.test.ts new file mode 100644 index 0000000000..ea48ba4da3 --- /dev/null +++ b/packages/core/src/services/roof-bearing.test.ts @@ -0,0 +1,40 @@ +import { expect, test } from 'bun:test' +import { type AnyNode, LevelNode, WallNode } from '../schema' +import { shapeOfRect, wallsUnder } from './roof-bearing' + +const RAIL = 3.5 * 0.0254 +const corners: Array<[number, number]> = [ + [0, 0], + [4, 0], + [4, 3], + [0, 3], +] + +// A 4 x 3 m deck with a 36 in guard round it, the south side a wall in `walled`. +function deck(walled = false) { + const level = LevelNode.parse({ id: 'level_deck', level: 0, height: 3 }) + const sides = corners.map((start, i) => + WallNode.parse({ + id: `wall_side${i}`, + parentId: level.id, + start, + end: corners[(i + 1) % 4], + ...(walled && i === 0 + ? { thickness: 0.2, height: 2.5 } + : { wallType: 'railing', thickness: RAIL, height: 36 * 0.0254 }), + }), + ) + level.children = sides.map((wall) => wall.id) + const nodes: Record = Object.fromEntries( + [level, ...sides].map((node) => [node.id, node]), + ) + return { level, nodes } +} + +test('a roof over a deck bears on none of its railings, on a wall along its edge it does', () => { + const shape = shapeOfRect([0, 0, 4, 3], 'x', 'gable', 30) + expect(wallsUnder(deck().nodes, 'level_deck', shape)).toEqual([]) + expect(wallsUnder(deck(true).nodes, 'level_deck', shape).map((wall) => wall.id)).toEqual([ + 'wall_side0', + ]) +}) diff --git a/packages/core/src/services/roof-bearing.ts b/packages/core/src/services/roof-bearing.ts index e60ac94614..3f3966885c 100644 --- a/packages/core/src/services/roof-bearing.ts +++ b/packages/core/src/services/roof-bearing.ts @@ -6,6 +6,7 @@ import { getConicalRoofCoverage, getRoofSegmentDeckReach, getSegmentSlopeFrame, + isRailingWall, type LevelNode, type SlabNode, type WallNode, @@ -167,7 +168,10 @@ type LevelPlan = { walls: WallNode[]; rooms: ZoneNode[]; spans: Map>() -/** A level's visible walls, its rooms and where its walls stand. */ +/** + * A level's visible walls, its rooms and where its walls stand. A railing is a guard round a deck + * or a porch, not a wall: no roof sits on it. + */ function planOf(nodes: Nodes, levelId: string): LevelPlan { let memo = planMemo.get(nodes) if (!memo) { @@ -180,7 +184,7 @@ function planOf(nodes: Nodes, levelId: string): LevelPlan { const rooms: ZoneNode[] = [] for (const node of Object.values(nodes)) { if (node.parentId !== levelId) continue - if (node.type === 'wall' && node.visible !== false) walls.push(node) + if (node.type === 'wall' && node.visible !== false && !isRailingWall(node)) walls.push(node) else if (node.type === 'zone' && node.polygon.length >= 3) rooms.push(node) } const plan = { walls, rooms, spans: wallSpans(nodes, levelId) } diff --git a/packages/core/src/store/actions/node-actions.ts b/packages/core/src/store/actions/node-actions.ts index b33e82f1f2..5968e3fe1c 100644 --- a/packages/core/src/store/actions/node-actions.ts +++ b/packages/core/src/store/actions/node-actions.ts @@ -1480,6 +1480,9 @@ const applyNodeChangesActionImpl = ( removeFromCollections(nextCollections, id) delete nextNodes[id] + // A mark left on a deleted node would sit in the dirty set for good, + // as `deleteNodes` notes: a preview may have marked it before the drop. + nodesToClearDirty.add(id) } refreshDefaultGuttersForRoofIds(nextNodes, roofsToRefresh, nodesToMarkDirty, nodesToClearDirty) @@ -1494,14 +1497,16 @@ const applyNodeChangesActionImpl = ( return { nodes: nextNodes, rootNodeIds: resolvedRootIds, collections: nextCollections } }) + // A store subscriber may already have deleted a node this write touched (the + // structure sync merging a room away): nothing is left to rebuild there. for (const id of nodesToMarkDirty) { - get().markDirty(id) + if (get().nodes[id]) get().markDirty(id) } for (const id of nodesToClearDirty) { get().clearDirty(id) } for (const id of parentsToMarkDirty) { - get().markDirty(id) + if (get().nodes[id]) get().markDirty(id) const parent = get().nodes[id] if (parent && 'children' in parent && Array.isArray(parent.children)) { for (const childId of parent.children) { @@ -1657,7 +1662,9 @@ const updateNodesActionImpl = ( // A disposed scene's frame reaches nothing. if (environment.disposed) return pendingUpdates.forEach((id) => { - get().markDirty(id) + // A node deleted since its update (a room merged away by the same drop) + // has nothing left to rebuild; marking it would leave it in the set. + if (get().nodes[id]) get().markDirty(id) }) pendingUpdates.clear() } diff --git a/packages/core/src/store/derived-node-guard.ts b/packages/core/src/store/derived-node-guard.ts index cc4bcd3f21..2fc1e9f872 100644 --- a/packages/core/src/store/derived-node-guard.ts +++ b/packages/core/src/store/derived-node-guard.ts @@ -6,6 +6,7 @@ import { import { expandFloorIntentChanges, floorIntentConflicts } from '../lib/floor-intent-changes' import { ownFloorIntentChanges } from '../lib/own-floor-intent' import { type Ring, union } from '../lib/polygon-boolean' +import { surfaceIntentZoneIds } from '../lib/surface-intent' import type { AnyNode, AnyNodeId, CeilingNode, SlabNode, ZoneNode } from '../schema' import { FloorOpeningNode, generateId } from '../schema' import { DEFAULT_SLAB_ELEVATION } from '../schema/nodes/slab' @@ -708,8 +709,9 @@ function linkedZoneIds(node: DerivedSurfaceNode): string[] { * Explicit deletion of derived construction is an intent edit, not a refusal: * removing a room's auto ceiling means "this room has no ceiling" * (`hasCeiling: false`), removing its plate means "no floor" (`hasFloor: - * false`). Returns the zone updates that record it, so the reconciler does not - * simply rebuild what the user deleted. + * false`) for the rooms it is the floor of (`surfaceIntentZoneIds`). Returns + * the zone updates that record it, so the reconciler does not simply rebuild + * what the user deleted. * * Cascaded descendants (deleting the level that owns the plate) carry no * intent — the zone is going away with them. @@ -720,11 +722,15 @@ export function derivedDeletionIntent( ): { id: AnyNodeId; data: Partial }[] { const deleted = new Set(ids) const intent = new Map>() + // The plates still standing after the delete: a room on one of its own keeps its floor. + const plates = Object.values(nodes).filter( + (node) => node.type === 'slab' && !deleted.has(node.id as AnyNodeId), + ) for (const id of ids) { const node = nodes[id] if (!isDerivedNode(node)) continue const field = node.type === 'ceiling' ? 'hasCeiling' : 'hasFloor' - for (const zoneId of linkedZoneIds(node)) { + for (const zoneId of surfaceIntentZoneIds(node, plates)) { const zone = nodes[zoneId] if (zone?.type !== 'zone' || deleted.has(zone.id)) continue if (zone[field] === false) continue diff --git a/packages/core/src/store/derived-writer-allowlist.test.ts b/packages/core/src/store/derived-writer-allowlist.test.ts index 21cfaef026..e1940ae2fa 100644 --- a/packages/core/src/store/derived-writer-allowlist.test.ts +++ b/packages/core/src/store/derived-writer-allowlist.test.ts @@ -2,7 +2,7 @@ import { expect, test } from 'bun:test' // Review guardrail for the writers contract (DECISIONS.md E-012, wiki/architecture/space-detection.md): // derived construction — a slab or ceiling marked `boundary: 'auto'` or the -// legacy `autoFromWalls: true` — is written by the structure kernel and the +// legacy `autoFromWalls: true`, plus generated porch framing — is written by the structure kernel and the // load migrations, and by nobody else. A new writer anywhere under a package's // `src` fails here instead of quietly becoming a second construction generator. // @@ -10,7 +10,7 @@ import { expect, test } from 'bun:test' // `node.autoFromWalls`) are not writes and never match. Comments are stripped // first, but a string literal that spells a marker out verbatim still trips the // guard — prose about the contract belongs in a comment or the wiki. -const ALLOWLIST = new Set([ +const PLATE_WRITERS = new Set([ // The kernel and its plate builder ARE the generator. 'packages/core/src/lib/structure-kernel.ts', 'packages/core/src/lib/floor-plates.ts', @@ -22,7 +22,17 @@ const ALLOWLIST = new Set([ 'packages/ifc-converter/src/room-first.ts', ]) -const MARKERS = [/\bboundary:\s*'auto'/, /\bautoFromWalls:\s*true/] +const PORCH_WRITERS = new Set([ + 'packages/core/src/lib/structure-kernel.ts', + 'packages/core/src/lib/porch-framing-sync.ts', +]) + +const MARKERS = [ + { pattern: /\bboundary:\s*'auto'/, writers: PLATE_WRITERS }, + { pattern: /\bautoFromWalls:\s*true/, writers: PLATE_WRITERS }, + { pattern: /\bporch(?:Of|Part|Seed):/, writers: PORCH_WRITERS }, +] +const ALLOWLIST = new Set([...PLATE_WRITERS, ...PORCH_WRITERS]) /** Comments describe the markers; only code that writes them counts. */ function withoutComments(source: string) { @@ -51,9 +61,10 @@ test('only the structure kernel and the load migrations author derived construct const offenders: string[] = [] for await (const relative of new Bun.Glob(PACKAGE_SOURCES).scan({ cwd: root, onlyFiles: true })) { const path = relative.replaceAll('\\', '/') - if (isFixtureOrTest(path) || ALLOWLIST.has(path)) continue + if (isFixtureOrTest(path)) continue const source = withoutComments(await Bun.file(root + relative).text()) - if (MARKERS.some((marker) => marker.test(source))) offenders.push(path) + if (MARKERS.some(({ pattern, writers }) => !writers.has(path) && pattern.test(source))) + offenders.push(path) } expect(offenders).toEqual([]) }) @@ -62,6 +73,9 @@ test('every allowlisted file still authors derived construction', async () => { const root = repoRoot() for (const path of ALLOWLIST) { const source = withoutComments(await Bun.file(root + path).text()) - expect([path, MARKERS.some((marker) => marker.test(source))]).toEqual([path, true]) + expect([ + path, + MARKERS.some(({ pattern, writers }) => writers.has(path) && pattern.test(source)), + ]).toEqual([path, true]) } }) diff --git a/packages/core/src/store/floor-opening-live.test.ts b/packages/core/src/store/floor-opening-live.test.ts index 5cad6a0524..19eacf7234 100644 --- a/packages/core/src/store/floor-opening-live.test.ts +++ b/packages/core/src/store/floor-opening-live.test.ts @@ -2,15 +2,31 @@ import { expect, test } from 'bun:test' import { createMezzanine } from '../commands/structure/create-mezzanine' import { createZone } from '../commands/structure/create-zone' import { cutFloorOpening, removeFloorOpening } from '../commands/structure/floor-opening' +import { setFloorFoundation } from '../commands/structure/set-floor-foundation' import { structureChangeBatch } from '../commands/structure/shared' +import { initSpatialGridSync } from '../hooks/spatial-grid/spatial-grid-sync' import { area, difference, union } from '../lib/polygon-boolean' import { initSpaceDetectionSync, pauseSpaceDetection, resumeSpaceDetection, } from '../lib/space-detection' -import { BuildingNode, generateId, LevelNode, StairNode, StairSegmentNode } from '../schema' +import { + BuildingNode, + type CeilingNode, + generateId, + LevelNode, + type SlabNode, + StairNode, + StairSegmentNode, +} from '../schema' +import { getStoredLevelHeight } from '../services/storey' +import { authorStairOpeningPatches } from '../systems/owned-floor-openings' import { initializeStairOpeningSync } from '../systems/stair/stair-opening-system' +import { resolveStairTotalRise } from '../systems/stair/stair-rise' +import { reconcileStructureOnLoad } from '../utils/reconcile-structure-on-load' +import useLiveNodeOverrides from './use-live-node-overrides' +import useLiveTransforms from './use-live-transforms' import useScene, { clearSceneHistory } from './use-scene' const rect = (x0: number, z0: number, x1: number, z1: number): [number, number][] => [ @@ -287,3 +303,331 @@ test('stair edits own the live floor and ceiling cuts in one undo step', async ( globalThis.cancelAnimationFrame = previousCancel } }) + +// The move tool drags a stair on live previews, then commits its pose and drops the previews in +// one handler; the old cut stayed drawn on the floor above until a reload. +test('a stair dragged and dropped leaves only its new cut on the floor and ceiling', async () => { + const building = BuildingNode.parse({ + id: 'building_dragged_stair', + children: ['level_dragged_stair_0', 'level_dragged_stair_1'], + }) + const ground = LevelNode.parse({ id: 'level_dragged_stair_0', parentId: building.id, level: 0 }) + const upper = LevelNode.parse({ id: 'level_dragged_stair_1', parentId: building.id, level: 1 }) + useScene.setState({ + nodes: { [building.id]: building, [ground.id]: ground, [upper.id]: upper }, + rootNodeIds: [building.id], + dirtyNodes: new Set(), + materials: {}, + collections: {}, + readOnly: false, + }) + clearSceneHistory() + const stopStructure = initSpaceDetectionSync(useScene, { + getState: () => ({ spaces: {}, setSpaces: () => {} }), + }) + const stopStair = initializeStairOpeningSync() + const settle = async () => { + for (let index = 0; index < 4; index++) await Promise.resolve() + } + const surfaces = () => + Object.values(useScene.getState().nodes).filter( + (node): node is SlabNode | CeilingNode => + (node.type === 'slab' && node.parentId === upper.id) || + (node.type === 'ceiling' && node.parentId === ground.id), + ) + try { + for (const levelId of [ground.id, upper.id]) { + const plan = createZone(useScene.getState().nodes, { + levelId, + polygon: rect(0, 0, 8, 5), + enclose: true, + mintId: generateId, + }) + useScene.getState().applyNodeChanges(structureChangeBatch(plan.changes)) + } + await settle() + const stair = StairNode.parse({ + id: 'stair_dragged', + parentId: ground.id, + fromLevelId: ground.id, + toLevelId: upper.id, + slabOpeningMode: 'destination', + position: [2, 0, 1], + children: ['sseg_dragged'], + }) + const segment = StairSegmentNode.parse({ + id: 'sseg_dragged', + parentId: stair.id, + length: 3, + height: 3, + width: 1, + }) + useScene.getState().applyNodeChanges( + structureChangeBatch([ + { op: 'create', node: stair }, + { op: 'create', node: segment }, + ]), + ) + await settle() + const dropped: [number, number, number] = [6, 0, 1] + useLiveNodeOverrides.getState().set(stair.id, { position: dropped, rotation: 0 }) + useLiveTransforms.getState().set(stair.id, { position: dropped, rotation: 0 }) + await settle() + // The drop, as the move tool makes it. + useScene.getState().updateNode(stair.id, { position: dropped }) + useLiveNodeOverrides.getState().clear(stair.id) + useLiveTransforms.getState().clear(stair.id) + await settle() + expect(surfaces()).toHaveLength(2) + for (const surface of surfaces()) { + expect(useLiveNodeOverrides.getState().get(surface.id)).toBeUndefined() + expect(surface.holes).toHaveLength(1) + expect(Math.min(...surface.holes[0]!.map(([x]) => x))).toBeGreaterThan(5) + } + } finally { + stopStair() + stopStructure() + clearSceneHistory() + } +}) + +test('a stair opening reshaped in plan cuts the floor and ceiling to that shape and keeps it', async () => { + const previousFrame = globalThis.requestAnimationFrame + const previousCancel = globalThis.cancelAnimationFrame + globalThis.requestAnimationFrame = ((callback: FrameRequestCallback) => { + callback(0) + return 1 + }) as typeof requestAnimationFrame + globalThis.cancelAnimationFrame = () => {} + const building = BuildingNode.parse({ + id: 'building_shaped_stair', + children: ['level_shaped_stair_0', 'level_shaped_stair_1'], + }) + const ground = LevelNode.parse({ id: 'level_shaped_stair_0', parentId: building.id, level: 0 }) + const upper = LevelNode.parse({ id: 'level_shaped_stair_1', parentId: building.id, level: 1 }) + useScene.setState({ + nodes: { [building.id]: building, [ground.id]: ground, [upper.id]: upper }, + rootNodeIds: [building.id], + dirtyNodes: new Set(), + materials: {}, + collections: {}, + readOnly: false, + }) + clearSceneHistory() + const stopStructure = initSpaceDetectionSync(useScene, { + getState: () => ({ spaces: {}, setSpaces: () => {} }), + }) + const stopStair = initializeStairOpeningSync() + const settle = async () => { + for (let index = 0; index < 4; index++) await Promise.resolve() + } + const nodes = () => useScene.getState().nodes + const owned = () => + Object.values(nodes()).filter( + (node) => node.type === 'floor-opening' && node.ownerId === 'stair_shaped', + ) + const holes = (levelId: string, type: 'slab' | 'ceiling') => + Object.values(nodes()).flatMap((node) => + node.parentId === levelId && node.type === type + ? node.holes.map((outer) => ({ outer, holes: [] })) + : [], + ) + try { + for (const levelId of [ground.id, upper.id]) { + const plan = createZone(nodes(), { + levelId, + polygon: rect(0, 0, 8, 5), + enclose: true, + mintId: generateId, + }) + useScene.getState().applyNodeChanges(structureChangeBatch(plan.changes)) + } + await settle() + const stair = StairNode.parse({ + id: 'stair_shaped', + parentId: ground.id, + fromLevelId: ground.id, + toLevelId: upper.id, + slabOpeningMode: 'destination', + position: [3, 0, 1], + children: ['sseg_shaped'], + }) + const segment = StairSegmentNode.parse({ + id: 'sseg_shaped', + parentId: stair.id, + length: 3, + height: 3, + width: 1, + }) + useScene.getState().applyNodeChanges( + structureChangeBatch([ + { op: 'create', node: stair }, + { op: 'create', node: segment }, + ]), + ) + await settle() + const floorOpening = owned().find( + (node) => node.type === 'floor-opening' && node.drawnOn === 'floor', + )! + // Widen the opening by half a metre on the +X side, as the plan's edge handle does. + const widened = rect(2.5, 1, 4, 4) + const patches = authorStairOpeningPatches(nodes(), floorOpening.id, widened) + expect(patches).toHaveLength(2) + useScene.getState().updateNodes(patches) + await settle() + const inside = [3.75, 2.5] as [number, number] + expect(area(difference(holes(upper.id, 'slab'), [{ outer: widened, holes: [] }]))).toBeLessThan( + 1e-6, + ) + expect(area(holes(upper.id, 'slab'))).toBeCloseTo(area([{ outer: widened, holes: [] }]), 3) + expect( + area( + union([ + ...holes(ground.id, 'ceiling'), + { + outer: [inside, [inside[0] + 0.01, inside[1]], [inside[0], inside[1] + 0.01]], + holes: [], + }, + ]), + ), + ).toBeCloseTo(area(holes(ground.id, 'ceiling')), 4) + // Touching the stair (a reselect re-syncs it) keeps the drawn shape. + useScene.getState().updateNode(stair.id, { name: 'Main stair' }) + await settle() + expect(area(holes(upper.id, 'slab'))).toBeCloseTo(1.5 * 3, 3) + // Moving the stair carries the drawn shape along. + useScene.getState().updateNode(stair.id, { position: [4, 0, 1] }) + await settle() + const moved = owned().find((node) => node.type === 'floor-opening' && node.drawnOn === 'floor') + expect( + moved?.type === 'floor-opening' && Math.max(...moved.polygon.map(([x]) => x)), + ).toBeCloseTo(5) + expect(area(holes(upper.id, 'slab'))).toBeCloseTo(1.5 * 3, 3) + // A reload keeps it. + const reloaded = reconcileStructureOnLoad(nodes()).nodes + const plateHoles = Object.values(reloaded).flatMap((node) => + node.parentId === upper.id && node.type === 'slab' + ? node.holes.map((outer) => ({ outer, holes: [] })) + : [], + ) + expect(area(plateHoles)).toBeCloseTo(1.5 * 3, 3) + } finally { + stopStair() + stopStructure() + clearSceneHistory() + globalThis.requestAnimationFrame = previousFrame + globalThis.cancelAnimationFrame = previousCancel + } +}) + +test('a stair that follows its levels re-rises live when the floor above thickens or a storey grows', async () => { + const previousFrame = globalThis.requestAnimationFrame + const previousCancel = globalThis.cancelAnimationFrame + globalThis.requestAnimationFrame = ((callback: FrameRequestCallback) => { + callback(0) + return 1 + }) as typeof requestAnimationFrame + globalThis.cancelAnimationFrame = () => {} + const building = BuildingNode.parse({ + id: 'building_rise_stair', + children: ['level_rise_stair_0', 'level_rise_stair_1'], + }) + const ground = LevelNode.parse({ id: 'level_rise_stair_0', parentId: building.id, level: 0 }) + const upper = LevelNode.parse({ id: 'level_rise_stair_1', parentId: building.id, level: 1 }) + useScene.setState({ + nodes: { [building.id]: building, [ground.id]: ground, [upper.id]: upper }, + rootNodeIds: [building.id], + dirtyNodes: new Set(), + materials: {}, + collections: {}, + readOnly: false, + }) + clearSceneHistory() + const stopGrid = initSpatialGridSync() + const stopStructure = initSpaceDetectionSync(useScene, { + getState: () => ({ spaces: {}, setSpaces: () => {} }), + }) + const stopStair = initializeStairOpeningSync() + const settle = async () => { + for (let index = 0; index < 8; index++) await Promise.resolve() + } + const nodes = () => useScene.getState().nodes + const stairNode = () => nodes()['stair_rise' as never] as StairNode + const flight = () => (nodes()['sseg_rise' as never] as StairSegmentNode).height + const rise = () => resolveStairTotalRise(stairNode(), nodes()) + try { + for (const levelId of [ground.id, upper.id]) { + const plan = createZone(nodes(), { + levelId, + polygon: rect(0, 0, 8, 5), + enclose: true, + mintId: generateId, + }) + useScene.getState().applyNodeChanges(structureChangeBatch(plan.changes)) + } + await settle() + const stair = StairNode.parse({ + id: 'stair_rise', + parentId: ground.id, + fromLevelId: ground.id, + toLevelId: upper.id, + slabOpeningMode: 'destination', + uniformRisers: true, + position: [3, 0, 1], + children: ['sseg_rise'], + }) + const segment = StairSegmentNode.parse({ + id: 'sseg_rise', + parentId: stair.id, + length: 3, + height: 2.5, + width: 1, + stepCount: 15, + }) + useScene.getState().applyNodeChanges( + structureChangeBatch([ + { op: 'create', node: stair }, + { op: 'create', node: segment }, + ]), + ) + await settle() + const start = rise() + expect(flight()).toBeCloseTo(start, 4) + // A thicker floor above: the stair still lands on its top, no reload. + const plate = Object.values(nodes()).find( + (node): node is SlabNode => + node.type === 'slab' && node.parentId === upper.id && node.plateRole === 'base', + )! + const thicker = 0.45 - plate.thickness + useScene + .getState() + .applyNodeChanges( + structureChangeBatch( + setFloorFoundation(nodes(), { slabId: plate.id, patch: { thickness: 0.45 } }).changes, + ), + ) + await settle() + expect(rise()).toBeCloseTo(start + thicker, 4) + expect(flight()).toBeCloseTo(start + thicker, 4) + // A custom rise holds; back to Follows level it re-reaches the floor. + useScene.getState().updateNode(stair.id, { totalRise: 2.5 }) + await settle() + expect(flight()).toBeCloseTo(2.5, 4) + useScene.getState().updateNode(stair.id, { totalRise: undefined }) + await settle() + expect(flight()).toBeCloseTo(start + thicker, 4) + // A taller storey below: the risers recompute live. + const storey = getStoredLevelHeight(nodes()[ground.id] as LevelNode) + useScene.getState().updateNode(ground.id, { height: storey + 0.3 }) + await settle() + expect(rise()).toBeCloseTo(start + thicker + 0.3, 4) + expect(flight()).toBeCloseTo(start + thicker + 0.3, 4) + } finally { + stopStair() + stopStructure() + stopGrid() + clearSceneHistory() + globalThis.requestAnimationFrame = previousFrame + globalThis.cancelAnimationFrame = previousCancel + } +}) diff --git a/packages/core/src/store/use-scene-window-migration.test.ts b/packages/core/src/store/use-scene-window-migration.test.ts index 4a6feb333d..7d957c7250 100644 --- a/packages/core/src/store/use-scene-window-migration.test.ts +++ b/packages/core/src/store/use-scene-window-migration.test.ts @@ -83,6 +83,8 @@ describe('scene window migrations', () => { expect(window.columnRatios).toEqual([1]) expect(window.rowRatios).toEqual([1]) expect(window.frameThickness).toBe(0.05) + expect(window.casingFaceA).toBe(false) + expect(window.casingFaceB).toBe(false) expect(window.sill).toBe(true) // …and authored fields survive. expect(window.width).toBe(1.2) diff --git a/packages/core/src/systems/owned-floor-openings.ts b/packages/core/src/systems/owned-floor-openings.ts index f97756949a..c2be3bd3bd 100644 --- a/packages/core/src/systems/owned-floor-openings.ts +++ b/packages/core/src/systems/owned-floor-openings.ts @@ -127,6 +127,69 @@ function cutsFromSurfaces(surfaces: Record, owners: Record, +) { + return opening.metadata.ownerOpeningTarget === 'source' || opening.drawnOn === 'ceiling' + ? owner.fromLevelId + : owner.toLevelId +} + +/** + * A stair opening reshaped by hand: the floor cut and the ceiling cut below it (the stair's openings + * on its own two levels) take `polygon` and become openings the stair owns as drawn, so the plate + * and ceiling are cut by that shape (not the derived rectangle) and keep it when the stair is + * reselected or re-synced. The stair's current pose is recorded so they still follow it when it + * moves or resizes. Returns the patches; empty when `openingId` is not a stair opening that can be + * authored this way (an opening on a level between two the stair joins keeps following it). + */ +export function authorStairOpeningPatches( + nodes: Record, + openingId: string, + polygon: [number, number][], +): Array<{ id: AnyNodeId; data: Partial }> { + const opening = nodes[openingId] + if (opening?.type !== 'floor-opening' || opening.source !== 'stair' || !opening.ownerId) return [] + const owner = nodes[opening.ownerId] + if (owner?.type !== 'stair' || authoredOpeningTarget(opening, owner) !== opening.parentId) + return [] + const segment = owner.children + .map((id) => nodes[id]) + .find((node) => node?.type === 'stair-segment') + const footprint = stairFootprintAABB({ ...owner, position: [0, 0, 0], rotation: 0 }, nodes) + const pose: OwnerPose = { + position: owner.position, + rotation: owner.rotation, + width: owner.width, + runLength: segment?.type === 'stair-segment' ? segment.length : 1, + ...(isBox(footprint) ? { footprint } : {}), + } + const ring = canonicalOpeningRing(polygon) + return Object.values(nodes).flatMap((node) => + node.type === 'floor-opening' && + node.source === 'stair' && + node.ownerId === owner.id && + authoredOpeningTarget(node, owner) === node.parentId + ? [ + { + id: node.id as AnyNodeId, + data: { + polygon: ring, + surfaceId: undefined, + legacyPlateCuts: undefined, + legacyCeilingCuts: undefined, + cutsPrimary: true, + cutsAdjacent: false, + metadata: { ...node.metadata, ownerPose: pose }, + }, + }, + ] + : [], + ) +} + export function planOwnedFloorOpenings( nodes: Record, options: { diff --git a/packages/core/src/systems/roof/roof-elevation.test.ts b/packages/core/src/systems/roof/roof-elevation.test.ts index b314b757e6..12d873c633 100644 --- a/packages/core/src/systems/roof/roof-elevation.test.ts +++ b/packages/core/src/systems/roof/roof-elevation.test.ts @@ -131,6 +131,17 @@ describe('resolveRoofElevation', () => { expect(resolveRoofElevation(roof, nodes)).toBe(-0.5) }) + // A deck's 36 in guard pulled the roof over it down onto the railing tops. + test("a railing's top never seats a roof: the walls' do, else it keeps its height", () => { + const { walls, roof, nodes } = scene([2.5]) + const railing = (wall: WallNode) => + ({ ...wall, wallType: 'railing', height: 36 * 0.0254, thickness: 0.0889 }) as WallNode + const deck = { ...nodes, ...Object.fromEntries(walls.map((wall) => [wall.id, railing(wall)])) } + expect(resolveRoofElevation(roof, deck)).toBe(0) + const leaning = { ...deck, [walls[0]!.id]: walls[0]! } + expect(resolveRoofElevation(roof, leaning)).toBe(-0.5) + }) + test('freezes without an enclosure, retaining follow intent', () => { const { walls, roof, nodes } = scene([4]) const remaining = { ...nodes } diff --git a/packages/core/src/systems/roof/roof-elevation.ts b/packages/core/src/systems/roof/roof-elevation.ts index a3da613fde..b2ea856f1f 100644 --- a/packages/core/src/systems/roof/roof-elevation.ts +++ b/packages/core/src/systems/roof/roof-elevation.ts @@ -9,6 +9,7 @@ import type { RoofSegmentNode, WallNode, } from '../../schema' +import { isRailingWall } from '../../schema/nodes/railing-wall' import { coveredStoreyId, servesAsRoofLevel } from '../../services/roof-level' import { findLevelAboveId, @@ -94,7 +95,10 @@ function wallsUnderRoof( }) } -/** The tallest of these walls' tops, from `targetLevelId`'s floor; undefined for none. */ +/** + * The tallest of these walls' tops, from `targetLevelId`'s floor; undefined for none. A railing is a + * guard round a deck or a porch, not a wall: no roof stands on its top. + */ function highestWallTop( targetLevelId: string, wallIds: readonly string[], @@ -104,7 +108,7 @@ function highestWallTop( let highest: number | undefined for (const id of wallIds) { const wall = nodes[id] - if (wall?.type !== 'wall') continue + if (wall?.type !== 'wall' || isRailingWall(wall)) continue const top = resolveRoofWallTopElevation( targetLevelId as LevelNode['id'], wall, diff --git a/packages/core/src/systems/roof/roof-footprint.test.ts b/packages/core/src/systems/roof/roof-footprint.test.ts new file mode 100644 index 0000000000..ca8bb421e1 --- /dev/null +++ b/packages/core/src/systems/roof/roof-footprint.test.ts @@ -0,0 +1,230 @@ +import { describe, expect, test } from 'bun:test' +import { type AnyNode, LevelNode, SeparatorNode, WallNode, ZoneNode } from '../../schema' +import { + outdoorRoomRoofOutline, + resolveRoomRoofFootprint, + resolveRoomRoofFootprintOnLevel, +} from './roof-footprint' + +const RAIL = 3.5 * 0.0254 +type P = [number, number] + +const near = (value: readonly (readonly number[])[], expected: P[]) => { + expect(value).toHaveLength(expected.length) + value.forEach((point, i) => { + expect(point[0]).toBeCloseTo(expected[i]![0], 6) + expect(point[1]).toBeCloseTo(expected[i]![1], 6) + }) +} + +// A 10 x 8 m house of 0.2 m walls, a porch 6 m along its south wall (z 0), 2.5 m deep. +function porch(open: 'separators' | 'railings' = 'separators') { + const level = LevelNode.parse({ id: 'level_ground', level: 0, height: 3 }) + const corners: P[] = [ + [0, 0], + [10, 0], + [10, 8], + [0, 8], + ] + const house = corners.map((start, i) => + WallNode.parse({ + id: `wall_house${i}`, + parentId: level.id, + start, + end: corners[(i + 1) % 4], + thickness: 0.2, + }), + ) + const sides: Array<[P, P]> = [ + [ + [2, 0], + [2, -2.5], + ], + [ + [2, -2.5], + [8, -2.5], + ], + [ + [8, -2.5], + [8, 0], + ], + ] + const edges = sides.map(([start, end], i) => + open === 'separators' + ? SeparatorNode.parse({ id: `separator_p${i}`, parentId: level.id, start, end }) + : WallNode.parse({ + id: `wall_rail${i}`, + parentId: level.id, + start, + end, + wallType: 'railing', + thickness: RAIL, + height: 36 * 0.0254, + }), + ) + const zone = ZoneNode.parse({ + parentId: level.id, + name: open === 'separators' ? 'Porch' : 'Deck', + roomType: open === 'separators' ? 'porch' : 'deck', + polygon: [ + [2, 0], + [2, -2.5], + [8, -2.5], + [8, 0], + ], + }) + level.children = [...house, ...edges, zone].map((node) => node.id) as LevelNode['children'] + const nodes: Record = Object.fromEntries( + [level, ...house, ...edges, zone].map((node) => [node.id, node]), + ) + return { level, house, edges, zone, nodes } +} + +describe('a porch, deck or patio roof outline', () => { + test('a porch keeps its invisible walls as its edge, the house wall on its centre line', () => { + const { house, edges, zone } = porch() + const outline = outdoorRoomRoofOutline(zone, house, edges as SeparatorNode[]) + near(outline.polygon, zone.polygon) + expect(outline.edges.map((edge) => edge?.kind)).toEqual([ + 'separator', + 'separator', + 'separator', + 'wall', + ]) + expect(outline.edges[3]?.id).toBe('wall_house0') + }) + + test("a deck's railings move out to their outside faces, meeting at the posts' corners", () => { + const { house, edges, zone } = porch('railings') + const outline = outdoorRoomRoofOutline(zone, [...house, ...(edges as WallNode[])], []) + const h = RAIL / 2 + near(outline.polygon, [ + [2 - h, 0], + [2 - h, -2.5 - h], + [8 + h, -2.5 - h], + [8 + h, 0], + ]) + expect(outline.edges.map((edge) => edge?.kind)).toEqual([ + 'railing', + 'railing', + 'railing', + 'wall', + ]) + }) + + test('a railing running on into an invisible wall along one line steps out at the join', () => { + const { house, zone } = porch() + const level = zone.parentId! + const rail = WallNode.parse({ + parentId: level, + start: [5, -2.5], + end: [2, -2.5], + wallType: 'railing', + thickness: RAIL, + }) + const separators = [ + SeparatorNode.parse({ parentId: level, start: [2, 0], end: [2, -2.5] }), + SeparatorNode.parse({ parentId: level, start: [8, -2.5], end: [5, -2.5] }), + SeparatorNode.parse({ parentId: level, start: [8, 0], end: [8, -2.5] }), + ] + const room = { + polygon: [ + [2, 0], + [8, 0], + [8, -2.5], + [5, -2.5], + [2, -2.5], + ] as P[], + } + const outline = outdoorRoomRoofOutline(room, [...house, rail], separators) + const h = RAIL / 2 + near(outline.polygon, [ + [2, 0], + [8, 0], + [8, -2.5], + [5, -2.5], + [5, -2.5 - h], + [2, -2.5 - h], + ]) + expect(outline.edges.map((edge) => edge?.kind ?? null)).toEqual([ + 'wall', + 'separator', + 'separator', + null, + 'railing', + 'separator', + ]) + }) +}) + +describe('the Room pick over a porch, deck or patio', () => { + test('roofs a porch to its invisible walls, standing on the house wall it leans on', () => { + const { level, nodes } = porch() + const target = resolveRoomRoofFootprint(level.id, nodes, [5, -1])! + expect(target).toMatchObject({ rectangular: true, levelId: level.id }) + expect(target.width * target.depth).toBeCloseTo(6 * 2.5, 6) + expect(Math.max(target.width, target.depth)).toBeCloseTo(6, 6) + near([target.center], [[5, -1.25]]) + expect(target.wallIds).toEqual(['wall_house0']) + expect([...(target.edgeIds ?? [])].sort()).toEqual([ + 'separator_p0', + 'separator_p1', + 'separator_p2', + ]) + }) + + test("roofs a deck to its railings' outside faces, its railings no walls it stands on", () => { + const { level, nodes } = porch('railings') + const target = resolveRoomRoofFootprint(level.id, nodes, [5, -1])! + const h = RAIL / 2 + expect(Math.max(target.width, target.depth)).toBeCloseTo(6 + 2 * h, 6) + expect(Math.min(target.width, target.depth)).toBeCloseTo(2.5 + h, 6) + near([target.center], [[5, -(2.5 + h) / 2]]) + expect(target.wallIds).toEqual(['wall_house0']) + expect([...(target.edgeIds ?? [])].sort()).toEqual(['wall_rail0', 'wall_rail1', 'wall_rail2']) + }) + + test('finds the porch on the storey below from the roof level', () => { + const { level, nodes } = porch() + const roofLevel = LevelNode.parse({ id: 'level_roof', level: 1, height: 3 }) + const target = resolveRoomRoofFootprint( + roofLevel.id, + { ...nodes, [roofLevel.id]: roofLevel }, + [5, -1], + ) + expect(target?.levelId).toBe(level.id) + expect(target?.wallIds).toEqual(['wall_house0']) + }) + + test("an invisible wall inside the house never shrinks the house's roof to one side of it", () => { + const { level, nodes } = porch() + const divider = SeparatorNode.parse({ parentId: level.id, start: [5, 0], end: [5, 8] }) + const kitchen = ZoneNode.parse({ + parentId: level.id, + name: 'Kitchen', + polygon: [ + [0, 0], + [5, 0], + [5, 8], + [0, 8], + ], + }) + const scene = { + ...nodes, + [divider.id]: divider, + [kitchen.id]: kitchen, + [level.id]: { ...level, children: [...level.children, divider.id, kitchen.id] }, + } as Record + const target = resolveRoomRoofFootprint(level.id, scene, [2, 4])! + expect(target.width * target.depth).toBeCloseTo(10 * 8, 6) + expect(target.wallIds).toHaveLength(4) + expect(target.edgeIds).toBeUndefined() + }) + + test("the storey's own room test still reads walls alone, so a porch on posts stays put", () => { + const { level, nodes } = porch() + // `standsOverStorey` asks this: a porch closed by invisible walls is no room of the walls. + expect(resolveRoomRoofFootprintOnLevel(level.id, nodes, [5, -1])).toBeNull() + expect(resolveRoomRoofFootprintOnLevel(level.id, nodes, [5, 4])?.wallIds).toHaveLength(4) + }) +}) diff --git a/packages/core/src/systems/roof/roof-footprint.ts b/packages/core/src/systems/roof/roof-footprint.ts index 5fa4b8adf1..364f2f310d 100644 --- a/packages/core/src/systems/roof/roof-footprint.ts +++ b/packages/core/src/systems/roof/roof-footprint.ts @@ -1,12 +1,25 @@ +import { isOutdoorRoomType } from '../../lib/outdoor-room' import { pointInPolygon as pointInPolygon2D } from '../../lib/polygon-relations' import { detectSpacesForLevel } from '../../lib/space-detection' -import type { AnyNode, LevelNode, WallNode } from '../../schema' +import type { AnyNode, LevelNode, SeparatorNode, WallNode, ZoneNode } from '../../schema' +import { isRailingWall } from '../../schema/nodes/railing-wall' import { getLevelBelow } from '../../services/storey' +import { isCurvedWall } from '../wall/wall-curve' +import { getWallThickness } from '../wall/wall-footprint' +import { getWallBodyLine } from '../wall/wall-frame' export type RoofFootprintTarget = { id: string polygon: Array<[number, number]> + /** The walls it stands on: a room's walls; a porch's, deck's or patio's house walls. */ wallIds: WallNode['id'][] + /** + * A porch's, deck's or patio's invisible walls and railings along its outside edge: the edge the + * roof's outer face stands on, not walls it stands on (`outdoorRoomRoofOutline`). + */ + edgeIds?: string[] + /** The level the room is on. */ + levelId?: LevelNode['id'] center: [number, number] width: number depth: number @@ -14,6 +27,130 @@ export type RoofFootprintTarget = { rectangular: boolean } +type P = [number, number] + +/** What runs along an edge of a room's roof outline: a wall, a railing or an invisible wall. */ +export type RoofOutlineEdge = { kind: 'wall' | 'railing' | 'separator'; id: string } | null + +/** A room's outline edge this near a boundary's line, and parallel to it, runs along it (m). */ +const ON_BOUNDARY = 0.01 + +/** What runs along the room edge `a` → `b`: the nearest straight wall or invisible wall on it. */ +function boundaryAlong( + a: P, + b: P, + walls: readonly WallNode[], + separators: readonly SeparatorNode[], +): (RoofOutlineEdge & { thickness: number }) | null { + const length = Math.hypot(b[0] - a[0], b[1] - a[1]) + if (length < 1e-9) return null + const dir: P = [(b[0] - a[0]) / length, (b[1] - a[1]) / length] + const mid: P = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2] + const lines = [ + // A wall drawn by a face runs its rooms along its body's centre, half its thickness off it. + ...walls.flatMap((wall) => { + if (isCurvedWall(wall)) return [] + const body = getWallBodyLine(wall) + return [ + { + kind: isRailingWall(wall) ? ('railing' as const) : ('wall' as const), + id: wall.id, + start: [body.start.x, body.start.y] as P, + end: [body.end.x, body.end.y] as P, + thickness: getWallThickness(wall), + }, + ] + }), + ...separators.map((separator) => ({ + kind: 'separator' as const, + id: separator.id, + start: separator.start, + end: separator.end, + thickness: 0, + })), + ] + let found: (RoofOutlineEdge & { thickness: number }) | null = null + let nearest = ON_BOUNDARY + for (const line of lines) { + const run: P = [line.end[0] - line.start[0], line.end[1] - line.start[1]] + const span = Math.hypot(run[0], run[1]) + if (span < 1e-6) continue + const u: P = [run[0] / span, run[1] / span] + if (Math.abs(u[0] * dir[1] - u[1] * dir[0]) > 1e-3) continue + const rel: P = [mid[0] - line.start[0], mid[1] - line.start[1]] + const across = Math.abs(rel[0] * u[1] - rel[1] * u[0]) + const along = rel[0] * u[0] + rel[1] * u[1] + if (across > nearest || along < -ON_BOUNDARY || along > span + ON_BOUNDARY) continue + found = { kind: line.kind, id: line.id, thickness: line.thickness } + nearest = across + } + return found +} + +/** + * The outside edge of a porch, deck or patio (`lib/outdoor-room`) a roof over it lines up with, + * in its level's plan: the room's outline with each edge on a railing moved out to the railing's + * outside face (to its posts' outer corners where two railings meet). An edge on an invisible wall + * stays on its line, which is the room's edge, and one on the house wall the room leans on stays + * on the wall's centre line, as a room's walls do in the house's own roof footprint. `edges[i]` + * runs from `polygon[i]` to `polygon[i + 1]`: what runs along it, null on the short jog where a + * railing runs on into an invisible wall along one line. + */ +export function outdoorRoomRoofOutline( + zone: Pick, + walls: readonly WallNode[], + separators: readonly SeparatorNode[], +): { polygon: P[]; edges: RoofOutlineEdge[] } { + const points = zone.polygon.filter((point, index, all) => { + const next = all[(index + 1) % all.length]! + return Math.hypot(next[0] - point[0], next[1] - point[1]) > 1e-9 + }) as P[] + const n = points.length + if (n < 3) return { polygon: points, edges: points.map(() => null) } + let area = 0 + for (let i = 0; i < n; i++) { + const a = points[i]! + const b = points[(i + 1) % n]! + area += a[0] * b[1] - b[0] * a[1] + } + const turn = area > 0 ? 1 : -1 + const sides = points.map((a, i) => { + const b = points[(i + 1) % n]! + const length = Math.hypot(b[0] - a[0], b[1] - a[1]) + const dir: P = [(b[0] - a[0]) / length, (b[1] - a[1]) / length] + const boundary = boundaryAlong(a, b, walls, separators) + const edge: RoofOutlineEdge = boundary && { kind: boundary.kind, id: boundary.id } + return { + dir, + out: [dir[1] * turn, -dir[0] * turn] as P, + offset: boundary?.kind === 'railing' ? boundary.thickness / 2 : 0, + edge, + } + }) + const polygon: P[] = [] + const edges: RoofOutlineEdge[] = [] + sides.forEach((side, i) => { + const prev = sides[(i - 1 + n) % n]! + const vertex = points[i]! + const from: P = [vertex[0] + prev.out[0] * prev.offset, vertex[1] + prev.out[1] * prev.offset] + const to: P = [vertex[0] + side.out[0] * side.offset, vertex[1] + side.out[1] * side.offset] + const denom = prev.dir[0] * side.dir[1] - prev.dir[1] * side.dir[0] + if (Math.abs(denom) > 1e-9) { + // Where the two edges' moved lines meet. + const t = ((to[0] - from[0]) * side.dir[1] - (to[1] - from[1]) * side.dir[0]) / denom + polygon.push([from[0] + prev.dir[0] * t, from[1] + prev.dir[1] * t]) + } else { + polygon.push(from) + if (Math.hypot(to[0] - from[0], to[1] - from[1]) > 1e-9) { + edges.push(null) + polygon.push(to) + } + } + edges.push(side.edge) + }) + return { polygon, edges } +} + function polygonArea(polygon: ReadonlyArray): number { return Math.abs( polygon.reduce((area, point, index) => { @@ -82,24 +219,68 @@ export function fitRoofFootprint( } } +/** + * The Room pick's footprint at `point`, on the level or else the level below: the porch, deck or + * patio there, to its outside edge (`resolveOutdoorRoomRoofFootprintOnLevel`), else the smallest + * room the level's walls enclose (`resolveRoomRoofFootprintOnLevel`). + */ export function resolveRoomRoofFootprint( levelId: LevelNode['id'], nodes: Readonly>, point: [number, number], options: { rectangularOnly?: boolean } = {}, ): RoofFootprintTarget | null { - const activeTarget = resolveRoomRoofFootprintOnLevel(levelId, nodes, point) + const onLevel = (id: LevelNode['id']): RoofFootprintTarget | null => { + const target = + resolveOutdoorRoomRoofFootprintOnLevel(id, nodes, point) ?? + resolveRoomRoofFootprintOnLevel(id, nodes, point) + return target && { ...target, levelId: id } + } + const activeTarget = onLevel(levelId) if (activeTarget && (!options.rectangularOnly || activeTarget.rectangular)) return activeTarget if (activeTarget) return null const levelBelow = getLevelBelow(levelId, nodes as Record) - const levelBelowTarget = levelBelow - ? resolveRoomRoofFootprintOnLevel(levelBelow.id, nodes, point) - : null + const levelBelowTarget = levelBelow ? onLevel(levelBelow.id) : null return levelBelowTarget && (!options.rectangularOnly || levelBelowTarget.rectangular) ? levelBelowTarget : null } +/** + * The porch, deck or patio at `point` on `levelId` (the smallest), as a roof over it stands: its + * outside edge (`outdoorRoomRoofOutline`), standing on the house walls it leans on, its invisible + * walls and railings the edge its outer face lines up with. Null where no such room is. Indoors the + * Room pick reads the walls alone, so an invisible wall splitting a room off inside the house + * never shrinks the house's roof to it. + */ +export function resolveOutdoorRoomRoofFootprintOnLevel( + levelId: LevelNode['id'], + nodes: Readonly>, + point: [number, number], +): RoofFootprintTarget | null { + const level = nodes[levelId] + if (level?.type !== 'level') return null + const children = level.children.map((id) => nodes[id]) + const zone = children + .filter( + (node): node is ZoneNode => + node?.type === 'zone' && + isOutdoorRoomType(node.roomType) && + node.polygon.length >= 3 && + pointInPolygon2D(point, node.polygon), + ) + .sort((left, right) => polygonArea(left.polygon) - polygonArea(right.polygon))[0] + if (!zone) return null + const walls = children.filter((node): node is WallNode => node?.type === 'wall') + const separators = children.filter((node): node is SeparatorNode => node?.type === 'separator') + const { polygon, edges } = outdoorRoomRoofOutline(zone, walls, separators) + const ids = (kinds: ReadonlyArray['kind']>) => [ + ...new Set(edges.flatMap((edge) => (edge && kinds.includes(edge.kind) ? [edge.id] : []))), + ] + const target = fitRoofFootprint(zone.id, polygon, ids(['wall']) as WallNode['id'][]) + return target && { ...target, edgeIds: ids(['railing', 'separator']) } +} + export function resolveRoomRoofFootprintOnLevel( levelId: LevelNode['id'], nodes: Readonly>, diff --git a/packages/core/src/systems/stair/stair-clearance.test.ts b/packages/core/src/systems/stair/stair-clearance.test.ts index 6774ac5a38..d644b84559 100644 --- a/packages/core/src/systems/stair/stair-clearance.test.ts +++ b/packages/core/src/systems/stair/stair-clearance.test.ts @@ -2,16 +2,23 @@ import { expect, test } from 'bun:test' import { type AnyNode, BuildingNode, + CeilingNode, + clearSceneHistory, containsPoint, + initSpaceDetectionSync, LevelNode, measureStairHeadroom, resolveStairWalkingSurfaces, + runAsSingleSceneHistoryStep, SlabNode, StairNode, StairSegmentNode, stairClearanceOpening, syncAutoStairOpenings, + useScene, } from '../../index' +import { reconcileDocument, runSettlingDocument } from '../../runtime' +import { initializeStairOpeningSync } from './stair-opening-system' test('headroom cuts follow tread heights and slab undersides while preserving authored holes', () => { const building = BuildingNode.parse({}) @@ -172,3 +179,166 @@ test('intermediate slab cuts stop above the floating body and hidden flights ret expect(surfaces[0]?.walkingLine[0][2]).toBeCloseTo(5) expect(surfaces[0]?.top).toBeCloseTo(3.2) }) + +test('a widened straight-flight opening stays a square-cornered rectangle', () => { + const building = BuildingNode.parse({}) + const ground = LevelNode.parse({ parentId: building.id, level: 0, height: 3 }) + const upper = LevelNode.parse({ parentId: building.id, level: 1 }) + const flight = StairSegmentNode.parse({ height: 3, length: 4, stepCount: 15, width: 1 }) + const stair = StairNode.parse({ + parentId: ground.id, + fromLevelId: ground.id, + toLevelId: upper.id, + children: [flight.id], + totalRise: 3, + slabOpeningMode: 'destination', + openingOffset: 0.2, + }) + const nodes: Record = Object.fromEntries( + [building, ground, upper, stair, { ...flight, parentId: stair.id }].map((node) => [ + node.id, + node, + ]), + ) + const [ring, ...rest] = stairClearanceOpening(stair, nodes, 2.8, 0.2, 3)! + expect(rest).toEqual([]) + expect(ring).toHaveLength(4) + const xs = ring!.map(([x]) => x) + expect(Math.min(...xs)).toBeCloseTo(-0.7) + expect(Math.max(...xs)).toBeCloseTo(0.7) + for (const [i, a] of ring!.entries()) { + const b = ring![(i + 1) % 4]! + const c = ring![(i + 2) % 4]! + expect((b[0] - a[0]) * (c[0] - b[0]) + (b[1] - a[1]) * (c[1] - b[1])).toBeCloseTo(0) + } +}) + +test.each(['updateNode', 'applyNodeChanges', 'reconcileDocument'] as const)( + '%s moves a stair between surfaces without leaving its old automatic cutouts, in one undo step', + async (path) => { + const previousScene = useScene.getState() + const previousCancel = globalThis.cancelAnimationFrame + globalThis.cancelAnimationFrame = () => {} + const previousFrame = globalThis.requestAnimationFrame + globalThis.requestAnimationFrame = ((callback: FrameRequestCallback) => { + callback(0) + return 1 + }) as typeof requestAnimationFrame + const building = BuildingNode.parse({ children: ['level_move_ground', 'level_move_upper'] }) + const ground = LevelNode.parse({ + id: 'level_move_ground', + parentId: building.id, + level: 0, + height: 3, + }) + const upper = LevelNode.parse({ id: 'level_move_upper', parentId: building.id, level: 1 }) + useScene.setState({ + nodes: { [building.id]: building, [ground.id]: ground, [upper.id]: upper }, + rootNodeIds: [building.id], + dirtyNodes: new Set(), + materials: {}, + collections: {}, + readOnly: false, + }) + const stopStructure = initSpaceDetectionSync(useScene, { + getState: () => ({ spaces: {}, setSpaces: () => {} }), + }) + const stopStair = initializeStairOpeningSync() + const settle = async () => { + for (let i = 0; i < 4; i++) await Promise.resolve() + } + try { + for (const [left, right] of [ + [0, 4], + [4, 10], + ] as const) { + const polygon: [number, number][] = [ + [left, 0], + [right, 0], + [right, 8], + [left, 8], + ] + useScene.getState().createNodes([ + { + node: SlabNode.parse({ parentId: upper.id, polygon, elevation: 0, thickness: 0.2 }), + parentId: upper.id, + }, + { + node: CeilingNode.parse({ parentId: ground.id, polygon, height: 3 }), + parentId: ground.id, + }, + ]) + } + const segment = StairSegmentNode.parse({ length: 5, height: 3, width: 1, stepCount: 15 }) + const stair = StairNode.parse({ + parentId: ground.id, + fromLevelId: ground.id, + toLevelId: upper.id, + position: [2, 0, 1], + totalRise: 3, + slabOpeningMode: 'destination', + children: [segment.id], + }) + useScene.getState().createNodes([ + { node: stair, parentId: ground.id }, + { node: { ...segment, parentId: stair.id }, parentId: stair.id }, + ]) + await settle() + clearSceneHistory() + const surfaces = () => + Object.values(useScene.getState().nodes).filter( + (node): node is SlabNode | CeilingNode => + (node.type === 'slab' && node.parentId === upper.id) || + (node.type === 'ceiling' && node.parentId === ground.id), + ) + const before = surfaces().map((node) => ({ + id: node.id, + polygon: node.polygon, + holes: node.holes, + })) + expect(before).toHaveLength(4) + expect(before.filter((node) => node.holes.length === 1)).toHaveLength(2) + const data = { position: [6, 0, 1] as [number, number, number] } + if (path === 'updateNode') useScene.getState().updateNode(stair.id, data) + else if (path === 'applyNodeChanges') + useScene.getState().applyNodeChanges({ update: [{ id: stair.id, data }] }) + else + runAsSingleSceneHistoryStep(useScene, () => + runSettlingDocument(useScene, () => { + const beforeMove = useScene.getState().nodes + useScene.getState().applyNodeChanges({ update: [{ id: stair.id, data }] }) + reconcileDocument(useScene, beforeMove) + }), + ) + await settle() + for (const surface of surfaces()) { + const openings = Object.values(useScene.getState().nodes).filter( + (node) => + node.type === 'floor-opening' && + node.ownerId === stair.id && + node.parentId === surface.parentId, + ) + expect(openings).toHaveLength(1) + const atNewPosition = containsPoint([{ outer: surface.polygon, holes: [] }], [6, 4]) + expect(surface.holes).toHaveLength(atNewPosition ? 1 : 0) + const shape = [{ outer: surface.polygon, holes: surface.holes }] + if (atNewPosition) expect(containsPoint(shape, [6, 4])).toBe(false) + else expect(containsPoint(shape, [2, 4])).toBe(true) + expect(surface.polygon).toEqual(before.find((node) => node.id === surface.id)!.polygon) + } + expect(useScene.temporal.getState().pastStates).toHaveLength(1) + useScene.temporal.getState().undo() + await settle() + expect( + surfaces().map((node) => ({ id: node.id, polygon: node.polygon, holes: node.holes })), + ).toEqual(before) + } finally { + stopStair() + stopStructure() + useScene.setState(previousScene) + clearSceneHistory() + globalThis.requestAnimationFrame = previousFrame + globalThis.cancelAnimationFrame = previousCancel + } + }, +) diff --git a/packages/core/src/systems/stair/stair-clearance.ts b/packages/core/src/systems/stair/stair-clearance.ts index c42fb5d38a..6fc54e4763 100644 --- a/packages/core/src/systems/stair/stair-clearance.ts +++ b/packages/core/src/systems/stair/stair-clearance.ts @@ -573,17 +573,35 @@ function expand(region: Polygon, offset: number): Polygon[] { ], holes: [], }) - pieces.push({ - outer: Array.from({ length: 12 }, (_, j) => [ - p[0] + Math.cos((j * TAU) / 12) * offset, - p[1] + Math.sin((j * TAU) / 12) * offset, - ]), - holes: [], - }) + pieces.push(...squareCorner(ring[(i + ring.length - 1) % ring.length]!, p, q, offset)) } return union(pieces) } +/** + * The corner pieces at `p` (between edges `prev → p` and `p → next`) on both sides of the ring: + * a mitred, square-cornered join, so a rectangular flight's opening widens to a rectangle, not a + * rounded box. A corner sharper than ~60° is bevelled instead of mitred to a spike. + */ +function squareCorner(prev: Ring[number], p: Ring[number], next: Ring[number], offset: number) { + const unitNormal = (a: Ring[number], b: Ring[number]): [number, number] | null => { + const length = Math.hypot(b[0] - a[0], b[1] - a[1]) + return length ? [-(b[1] - a[1]) / length, (b[0] - a[0]) / length] : null + } + const n1 = unitNormal(prev, p) + const n2 = unitNormal(p, next) + if (!(n1 && n2)) return [] + const dot = n1[0] * n2[0] + n1[1] * n2[1] + return [1, -1].map((side): Polygon => { + const a: [number, number] = [p[0] + side * n1[0] * offset, p[1] + side * n1[1] * offset] + const b: [number, number] = [p[0] + side * n2[0] * offset, p[1] + side * n2[1] * offset] + if (1 + dot < 0.5) return { outer: [p, a, b], holes: [] } + const scale = (side * offset) / (1 + dot) + const miter: [number, number] = [p[0] + (n1[0] + n2[0]) * scale, p[1] + (n1[1] + n2[1]) * scale] + return { outer: [p, a, miter, b], holes: [] } + }) +} + /** Surface-hole rings cannot contain islands; split annular cuts while preserving their centre. */ function openingRings(regions: Polygon[]): Ring[] { return regions.flatMap((region) => { diff --git a/packages/core/src/systems/stair/stair-construction.ts b/packages/core/src/systems/stair/stair-construction.ts index 51f6f03258..73f7c53bdd 100644 --- a/packages/core/src/systems/stair/stair-construction.ts +++ b/packages/core/src/systems/stair/stair-construction.ts @@ -1,10 +1,19 @@ -import type { StairConstruction, StairNode, StairSegmentNode } from '../../schema' +import type { StairNode, StairSegmentNode } from '../../schema' import { measureStairDetail, STAIR_DETAIL_SURFACE_BUDGET, stairSegmentDetailError, } from './stair-detail-budget' import { resolveStairArcDimensions } from './stair-layout' +import { + type ResolvedStairConstruction, + resolveStairStringerLayout, + type StairStructureHost, + stairLandingFrame, + stairStringerFlight, + stairStringerSlices, + stairStructureConstructionOf, +} from './stair-structure' import { resolveStairWinder } from './stair-winder' export type StairConstructionPiece = { @@ -22,11 +31,19 @@ export type StairConstructionPiece = { top: number } +/** + * The body a segment is drawn with: its own construction, its stair's, or the one the stair's + * structure draws (`stairStructureConstructionOf`) — null keeps the original body. + */ export function resolveStairConstruction( node: Pick, - parent?: Pick, -): StairConstruction | null { - return node.construction ?? parent?.construction ?? null + parent?: Pick & StairStructureHost, +): ResolvedStairConstruction | null { + return ( + node.construction ?? + parent?.construction ?? + (parent ? stairStructureConstructionOf(parent) : null) + ) } export function stairConstructionError( @@ -98,6 +115,14 @@ export function stairSegmentConstructionError( (construction.mode === 'center-stringer' && construction.stringerWidth > segment.width) ) return 'Stringers must fit within the flight width.' + const structure = construction.structure + if ( + structure && + structure.type !== 'concrete' && + !winder && + resolveStairStringerLayout(segment.width, structure).count < 2 + ) + return 'Stringers must fit within the flight width.' if ( winder && construction.mode === 'center-stringer' && @@ -264,6 +289,33 @@ export function resolveStraightStairConstruction( }) } } + // A structure's stringers, each sliced per step at its place across the flight (cut carriages + // notched under the treads, housed boards over the nosing line); a landing's frame under it. + const structure = construction.structure + if (structure && structure.type !== 'concrete' && !segment.winder) { + if (!landing) { + const flight = stairStringerFlight(segment, construction) + for (const band of resolveStairStringerLayout(segment.width, structure).bands) + for (const slice of stairStringerSlices(band, flight)) { + const runs = slice.profile.map((point) => point[0]) + pieces.push({ + role: 'body', + index: slice.index, + x0: band.x0, + x1: band.x1, + z0: Math.min(...runs), + z1: Math.max(...runs), + underside: slice.underside, + top: slice.top, + profile: slice.profile, + }) + } + } else { + const frame = stairLandingFrame(segment, treadThickness + finishThickness, absoluteHeight) + for (const part of [...frame.rims, ...frame.joists, ...frame.posts]) + box('body', 0, part.x0, part.x1, part.z0, part.z1, part.bottom, part.top) + } + } return pieces } @@ -476,20 +528,38 @@ export function resolveArcStairConstruction( } export function straightStairConstructionDetailCost( - segment: Pick, + segment: Pick & + Partial>, parent?: StairNode, ): number { const construction = resolveStairConstruction(segment, parent) const count = segment.segmentType === 'landing' ? 1 : segment.stepCount if (!construction) return count - if (segment.segmentType === 'landing') return 1 + Number(construction.finishThickness > 0) + // a structure's stringers add one slice per stringer per step, a landing its frame + const structure = construction.structure?.type === 'concrete' ? undefined : construction.structure + const width = segment.width ?? parent?.width ?? 1 + if (segment.segmentType === 'landing') { + const frame = structure + ? stairLandingFrame( + { width, length: segment.length ?? width }, + construction.treadThickness + construction.finishThickness, + Number.POSITIVE_INFINITY, + ) + : null + return ( + 1 + + Number(construction.finishThickness > 0) + + (frame ? frame.rims.length + frame.joists.length + frame.posts.length : 0) + ) + } const closed = construction.mode === 'solid' || construction.mode === 'waist' const parts = 1 + Number(closed && construction.nosing > 0) + Number(construction.finishThickness > 0) + Number(!closed && construction.closedRisers) + - (construction.mode === 'side-stringers' ? 2 : construction.mode === 'center-stringer' ? 1 : 0) + (construction.mode === 'side-stringers' ? 2 : construction.mode === 'center-stringer' ? 1 : 0) + + (structure ? resolveStairStringerLayout(width, structure).count : 0) return count * parts } diff --git a/packages/core/src/systems/stair/stair-opening-system.tsx b/packages/core/src/systems/stair/stair-opening-system.tsx index 727ad07b35..2943abd0aa 100644 --- a/packages/core/src/systems/stair/stair-opening-system.tsx +++ b/packages/core/src/systems/stair/stair-opening-system.tsx @@ -37,14 +37,21 @@ export function initializeStairOpeningSync() { } } - const applyPreviewUpdates = (updates: ReturnType) => { + // The guard only stops the preview's own override writes from re-entering the refresh. Held + // past them (to a microtask), it swallowed the refresh a drop asks for in the same tick, and + // the dragged stair's preview cuts stayed drawn on the floor and ceiling until a reload. + const writePreview = (write: () => void) => { syncingPreviewOpenings = true - previewController.apply(updates) - queueMicrotask(() => { + try { + write() + } finally { syncingPreviewOpenings = false - }) + } } + const applyPreviewUpdates = (updates: ReturnType) => + writePreview(() => previewController.apply(updates)) + const applyOpeningChanges = (skipExistingSurfaces = false, ownerIds?: ReadonlySet) => { const changes = planOwnedFloorOpenings(useScene.getState().nodes, { skipExistingSurfaces, @@ -65,11 +72,7 @@ export function initializeStairOpeningSync() { const clearPreviewUpdates = () => { if (previewController.previewSurfaceIds.size === 0) return - syncingPreviewOpenings = true - previewController.clear() - queueMicrotask(() => { - syncingPreviewOpenings = false - }) + writePreview(() => previewController.clear()) } const refreshLivePreview = () => { diff --git a/packages/core/src/systems/stair/stair-sizing.ts b/packages/core/src/systems/stair/stair-sizing.ts index a08c453508..34203619da 100644 --- a/packages/core/src/systems/stair/stair-sizing.ts +++ b/packages/core/src/systems/stair/stair-sizing.ts @@ -12,6 +12,7 @@ import { import { resolveStairArcDimensions } from './stair-layout' import { resolveStairRailPaths } from './stair-rail-path' import { resolveStairTotalRise } from './stair-rise-query' +import { stairStructureDiagnostics } from './stair-structure' import { resolveStairWinder } from './stair-winder' export const DEFAULT_STAIR_DESIGN_TARGETS = StairDesignTargets.parse({}) @@ -241,6 +242,12 @@ export function measureStair(stair: StairNode, nodes: Record) { ) else if (headroom.obstructions.length) report('headroom-target', stair.id, 'Overhead surfaces leave less than the target headroom.') + // a stair with a structure owes the code's numbers too (IRC R311.7 / R312, DCA 6) + for (const issue of stairStructureDiagnostics(stair, measurements, { + totalRise, + headroom: headroom.status === 'unresolved' ? null : headroom.minimum, + })) + report(issue.code, issue.nodeId, issue.message, issue.severity) return { totalRise, targets, diff --git a/packages/core/src/systems/stair/stair-structure.test.ts b/packages/core/src/systems/stair/stair-structure.test.ts new file mode 100644 index 0000000000..068845a35b --- /dev/null +++ b/packages/core/src/systems/stair/stair-structure.test.ts @@ -0,0 +1,343 @@ +import { describe, expect, it } from 'bun:test' +import { + type AnyNode, + autoStairStringerCount, + inferStairStructure, + measureStair, + resolveStairConstruction, + resolveStairStringerLayout, + resolveStairStructure, + resolveStraightStairConstruction, + STAIR_CODE, + STAIR_STRINGER_STOCK, + StairNode, + StairSegmentNode, + StairStructure, + stairLandingFrame, + stairStringerCut, + stairStringerFlight, + stairStructureConstruction, +} from '../../index' + +const IN = 0.0254 + +/** A straight stair with one flight of `risers` × `riser` in over `going` in treads. */ +function flightStair( + risers: number, + riser: number, + going: number, + stair: Partial = {}, + width = 36 * IN, +) { + const flight = StairSegmentNode.parse({ + width, + height: risers * riser * IN, + length: risers * going * IN, + stepCount: risers, + }) + const node = StairNode.parse({ + width, + totalRise: risers * riser * IN, + stepCount: risers, + railingMode: 'both', + railingHeight: 36 * IN, + children: [flight.id], + ...stair, + }) + flight.parentId = node.id + const nodes: Record = { [node.id]: node, [flight.id]: flight } + return { stair: node, flight, nodes } +} + +describe('stair structure schema', () => { + it('defaults to cut 2x12 wood stringers at 16 in o.c. and leaves stairs without one alone', () => { + expect(StairStructure.parse({})).toEqual({ + type: 'wood-stringers', + stringerStock: '2x12', + stringerType: 'cut', + stringerSpacing: 16 * IN, + }) + const legacy = StairNode.parse({}) + expect(legacy.structure).toBeUndefined() + expect(resolveStairStructure(legacy)).toBeNull() + expect(resolveStairConstruction(StairSegmentNode.parse({}), legacy)).toBeNull() + }) + + it('makes its automatic choices from where the stair stands and how far it rises', () => { + const inside = resolveStairStructure(StairNode.parse({ structure: {} }))! + expect(inside).toMatchObject({ + treadStock: '2x12', + closedRisers: true, + treated: false, + nosing: 1 * IN, + exterior: false, + }) + // a short porch flight: open risers are fine up to a 30 in rise (R311.7.5.1) + const porch = resolveStairStructure( + StairNode.parse({ structure: {}, deckSlabId: 'slab_porch', totalRise: 21 * IN }), + )! + expect(porch).toMatchObject({ + treadStock: '2x6-pair', + closedRisers: false, + treated: true, + exterior: true, + }) + const deck = resolveStairStructure( + StairNode.parse({ structure: {}, destinationSurfaceId: 'deck', totalRise: 40 * IN }), + )! + expect(deck.closedRisers).toBe(true) + expect( + resolveStairStructure(StairNode.parse({ structure: { type: 'concrete' } }))!.nosing, + ).toBe(0) + // the hand-set choices win + expect( + resolveStairStructure( + StairNode.parse({ + structure: { treadStock: '5/4x6-pair', closedRisers: false, treated: true, nosing: 0.03 }, + }), + ), + ).toMatchObject({ treadStock: '5/4x6-pair', closedRisers: false, treated: true, nosing: 0.03 }) + }) + + it('infers a legacy stair as concrete when it is painted concrete, wood stringers otherwise', () => { + expect( + inferStairStructure(StairNode.parse({ materialPreset: 'library:concrete-raw' })).type, + ).toBe('concrete') + expect(inferStairStructure(StairNode.parse({ material: { preset: 'concrete' } })).type).toBe( + 'concrete', + ) + expect( + inferStairStructure(StairNode.parse({ materialPreset: 'library:wood-floorplank1' })).type, + ).toBe('wood-stringers') + expect( + inferStairStructure(StairNode.parse({ structure: { type: 'steel-stringers' } })).type, + ).toBe('steel-stringers') + }) +}) + +describe('stringer count and spacing', () => { + it('counts ceil(width / spacing) + 1 stringers, at least two and three from 36 in wide', () => { + expect(autoStairStringerCount(36 * IN, 16 * IN)).toBe(4) + expect(autoStairStringerCount(36 * IN, 18 * IN)).toBe(3) + expect(autoStairStringerCount(36 * IN, 24 * IN)).toBe(3) + expect(autoStairStringerCount(36 * IN, 12 * IN)).toBe(4) + expect(autoStairStringerCount(48 * IN, 16 * IN)).toBe(4) + expect(autoStairStringerCount(24 * IN, 24 * IN)).toBe(2) + expect(autoStairStringerCount(30 * IN, 24 * IN)).toBe(3) + expect(autoStairStringerCount(1, 16 * IN)).toBe(4) + }) + + it('lays the outer stringers flush with the sides and the rest evenly between, never past the spacing', () => { + const width = 1.0 + for (const spacing of [12, 16, 18, 24]) { + const structure = resolveStairStructure( + StairNode.parse({ structure: { stringerSpacing: spacing * IN } }), + )! + const layout = resolveStairStringerLayout(width, structure) + expect(layout.auto).toBe(true) + expect(layout.count).toBe(autoStairStringerCount(width, spacing * IN)) + expect(layout.spacing).toBeLessThanOrEqual(spacing * IN + 1e-9) + expect(layout.bands[0]!.x0).toBeCloseTo(-width / 2, 9) + expect(layout.bands.at(-1)!.x1).toBeCloseTo(width / 2, 9) + for (let i = 1; i < layout.bands.length; i++) + expect(layout.bands[i]!.x - layout.bands[i - 1]!.x).toBeCloseTo(layout.spacing, 9) + expect(layout.bands.every((band) => band.kind === 'cut' && !band.steel)).toBe(true) + expect(layout.thickness).toBeCloseTo(1.5 * IN, 9) + expect(layout.depth).toBeCloseTo(STAIR_STRINGER_STOCK['2x12'].depth, 9) + } + const set = resolveStairStructure( + StairNode.parse({ + structure: { stringerCount: 5, stringerType: 'housed', stringerStock: '2x10' }, + }), + )! + const housed = resolveStairStringerLayout(36 * IN, set) + expect(housed.auto).toBe(false) + expect(housed.count).toBe(5) + expect(housed.depth).toBeCloseTo(9.25 * IN, 9) + expect(housed.bands.map((band) => band.kind)).toEqual(['housed', 'cut', 'cut', 'cut', 'housed']) + const steel = resolveStairStructure( + StairNode.parse({ structure: { type: 'steel-stringers' } }), + )! + expect(resolveStairStringerLayout(1, steel).count).toBe(2) + expect(resolveStairStringerLayout(1.6, steel).count).toBe(3) + expect(resolveStairStringerLayout(1, steel).bands.map((band) => band.kind)).toEqual([ + 'housed', + 'housed', + ]) + // never more stringers than fit side by side + expect(resolveStairStringerLayout(3 * IN, set).count).toBe(2) + }) +}) + +describe('stringer geometry', () => { + // ten 7 in risers over 11 in treads, 2x12 stringers, two 2x6 treads, open risers + const structure = resolveStairStructure( + StairNode.parse({ structure: { treadStock: '2x6-pair', closedRisers: false } }), + )! + const construction = stairStructureConstruction(structure) + const flight = stairStringerFlight( + { stepCount: 10, height: 70 * IN, length: 110 * IN }, + construction, + ) + + it('notches a cut stringer for every tread: seats under the treads, a throat of D − r·cos θ, a level seat on the base and a plumb cut at the top', () => { + const cut = stairStringerCut({ kind: 'cut', depth: 11.25 * IN }, flight) + expect(cut.slices).toHaveLength(10) + const cos = 11 / Math.hypot(7, 11) + expect(cut.throat).toBeCloseTo((11.25 - 7 * cos) * IN, 9) + expect(cut.throat).toBeGreaterThan(STAIR_CODE.minThroat) + for (const [i, slice] of cut.slices.entries()) { + // each seat is the walking top less the 1-1/2 in tread + expect(slice.top).toBeCloseTo(((i + 1) * 7 - 1.5) * IN, 9) + expect(Math.min(...slice.profile.map((point) => point[1]))).toBeGreaterThanOrEqual(-1e-9) + } + // the first riser cut stands on the base and the board is cut level along it + expect(cut.seat![0]).toBeCloseTo(0, 9) + expect(cut.seat![1]).toBeGreaterThan(11 * IN) + expect(cut.plumb.z).toBeCloseTo(110 * IN, 9) + expect(cut.plumb.top).toBeCloseTo((70 - 1.5) * IN, 9) + // the cut length: the run along the slope plus the seat height over the top + const sin = 7 / Math.hypot(7, 11) + expect(cut.length).toBeCloseTo(110 * IN * cos + (70 - 1.5) * IN * sin, 9) + }) + + it('sets the riser cuts back behind riser boards and keeps the last seat inside the run', () => { + const closed = stairStringerFlight( + { stepCount: 10, height: 70 * IN, length: 110 * IN }, + stairStructureConstruction({ ...structure, closedRisers: true }), + ) + const cut = stairStringerCut({ kind: 'cut', depth: 11.25 * IN }, closed) + expect(Math.min(...cut.slices[0]!.profile.map((point) => point[0]))).toBeCloseTo(0.75 * IN, 9) + expect(Math.max(...cut.slices.at(-1)!.profile.map((point) => point[0]))).toBeCloseTo( + 110 * IN, + 9, + ) + }) + + it('stands a housed stringer over the nosing line, level at the base and the floor it reaches', () => { + const housed = stairStringerCut({ kind: 'housed', depth: 11.25 * IN }, flight) + const points = housed.slices.flatMap((slice) => slice.profile) + expect(housed.slices).toHaveLength(10) + expect(Math.min(...points.map((point) => point[1]))).toBeGreaterThanOrEqual(-1e-9) + expect(Math.max(...points.map((point) => point[1]))).toBeLessThanOrEqual(70 * IN + 1e-9) + // its top edge runs 2 in (square) over the nosing line: through each nosing at (i·11 − 1, (i+1)·7) + const slope = 7 / 11 + const reveal = 2 * Math.hypot(1, slope) + for (let i = 0; i < 8; i++) { + const z1 = (i + 1) * 11 + const nosingLine = slope * (z1 + 1) + 7 + expect(housed.slices[i]!.top).toBeCloseTo((nosingLine + reveal) * IN, 9) + } + // it runs an inch ahead of the bottom nosing before its plumb cut + expect(Math.min(...points.map((point) => point[0]))).toBeCloseTo(-2 * IN, 9) + expect(housed.throat).toBeCloseTo(11.25 * IN, 9) + }) +}) + +describe('the body a structure draws', () => { + it('draws treads, risers and a cut stringer per step at every stringer place for wood stringers', () => { + const { stair, flight } = flightStair(10, 7, 11, { + structure: StairStructure.parse({ closedRisers: true }), + }) + const pieces = resolveStraightStairConstruction(flight, 0, stair)! + const layout = resolveStairStringerLayout(flight.width, resolveStairStructure(stair)!) + expect(layout.count).toBe(4) + for (const band of layout.bands) { + const own = pieces.filter((piece) => piece.x0 === band.x0 && piece.x1 === band.x1) + expect(own).toHaveLength(10) + expect(own.every((piece) => piece.role === 'body')).toBe(true) + } + const treads = pieces.filter((piece) => piece.role === 'tread') + expect(treads).toHaveLength(10) + // the walking tops stay the finished heights; the nosing projects 1 in + expect(Math.max(...treads.map((piece) => piece.top))).toBeCloseTo(70 * IN, 9) + expect(Math.min(...treads.map((piece) => piece.z0))).toBeCloseTo(-1 * IN, 9) + // one riser board per step, in front of the riser cuts + const risers = pieces.filter( + (piece) => + piece.role === 'body' && piece.x0 === -flight.width / 2 && piece.x1 === flight.width / 2, + ) + expect(risers).toHaveLength(10) + }) + + it('pours concrete as one solid mass to the base with no stringers', () => { + const { stair, flight } = flightStair(4, 7, 11, { + structure: StairStructure.parse({ type: 'concrete' }), + }) + const construction = resolveStairConstruction(flight, stair)! + expect(construction.mode).toBe('solid') + expect(construction.nosing).toBe(0) + const pieces = resolveStraightStairConstruction(flight, 0, stair)! + expect(pieces).toHaveLength(4) + expect(pieces.every((piece) => piece.role === 'body')).toBe(true) + expect(pieces.every((piece) => piece.underside[1] === 0)).toBe(true) + }) + + it('keeps an explicit body over the structure and frames a wood landing', () => { + const { stair, flight } = flightStair(10, 7, 11, { + structure: StairStructure.parse({}), + construction: { mode: 'solid' } as StairNode['construction'], + }) + expect(resolveStairConstruction(flight, stair)!.structure).toBeUndefined() + const landing = StairSegmentNode.parse({ + segmentType: 'landing', + width: 1, + length: 1, + height: 0, + }) + const wood = StairNode.parse({ structure: {} }) + const pieces = resolveStraightStairConstruction(landing, 1.2, wood)! + const frame = stairLandingFrame({ width: 1, length: 1 }, 1.5 * IN, 1.2) + expect(frame.rims).toHaveLength(4) + expect(frame.posts).toHaveLength(4) + expect(frame.joists.length).toBeGreaterThan(0) + expect(pieces).toHaveLength(1 + frame.rims.length + frame.joists.length + frame.posts.length) + // a landing barely off the base sits on blocking, not posts + expect(stairLandingFrame({ width: 1, length: 1 }, 1.5 * IN, 0.2).posts).toHaveLength(0) + }) +}) + +describe('code checks', () => { + const codes = (stair: StairNode, nodes: Record) => + measureStair(stair, nodes).diagnostics.map((issue) => issue.code) + + it('passes a code-sized wood stair and reports nothing extra for a stair without a structure', () => { + const good = flightStair(14, 7.25, 10.5, { structure: StairStructure.parse({}) }) + expect(codes(good.stair, good.nodes).filter((code) => /^(code|stringer)-/.test(code))).toEqual( + [], + ) + const legacy = flightStair(4, 8, 9, { railingMode: 'none' }) + expect( + codes(legacy.stair, legacy.nodes).filter((code) => /^(code|stringer)-/.test(code)), + ).toEqual([]) + }) + + it('flags risers, treads, nosings, the handrail, the guard, open risers and DCA 6 stringer limits', () => { + const steep = flightStair(5, 8, 9, { + railingMode: 'none', + structure: StairStructure.parse({ closedRisers: false, nosing: 0, stringerCount: 2 }), + }) + const found = codes(steep.stair, steep.nodes) + for (const code of [ + 'code-riser', + 'code-tread', + 'code-nosing', + 'code-handrail', + 'code-guard', + 'code-open-risers', + 'stringer-spacing', + ]) + expect(found).toContain(code) + // a deck stair: a long cut-stringer span and a thin 2x10 throat + const long = flightStair(10, 7.75, 10, { + deckSlabId: 'slab_deck', + structure: StairStructure.parse({ stringerStock: '2x10' }), + }) + const longCodes = codes(long.stair, long.nodes) + expect(longCodes).toContain('stringer-span') + expect(longCodes).toContain('stringer-throat') + // a narrow stair + const narrow = flightStair(4, 7, 11, { structure: StairStructure.parse({}) }, 30 * IN) + expect(codes(narrow.stair, narrow.nodes)).toContain('code-width') + }) +}) diff --git a/packages/core/src/systems/stair/stair-structure.ts b/packages/core/src/systems/stair/stair-structure.ts new file mode 100644 index 0000000000..86bb30798a --- /dev/null +++ b/packages/core/src/systems/stair/stair-structure.ts @@ -0,0 +1,763 @@ +import type { StairConstruction as StairConstructionType, StairNode } from '../../schema' +import { StairConstruction } from '../../schema/nodes/stair-construction' +import { + type StairStringerStock, + type StairStringerType, + StairStructure, + type StairStructureType, + type StairTreadStock, +} from '../../schema/nodes/stair-structure' + +/** + * A stair's structure — how it is really built, apart from the body it is drawn with — resolved + * to numbers: the stringer layout across each flight, the cut profile of every stringer, the + * treads and risers they carry, the construction the viewer draws for it, and the code checks the + * panel reports. Shared by the viewer (the body), the panel (the counts) and Bones (the members), + * so all three put a stringer in the same place. + */ + +const IN = 0.0254 +const EPS = 1e-9 + +/** + * The stair numbers of the IRC (R311.7 stairways, R312 guards) and AWC DCA 6 (deck stairs) the + * structure is checked against, in metres. + */ +export const STAIR_CODE = { + /** R311.7.5.1: risers 7-3/4 in at most. */ + maxRiser: 7.75 * IN, + /** R311.7.5.2: treads 10 in at least. */ + minTread: 10 * IN, + /** R311.7.5.3: a 3/4 in to 1-1/4 in nosing, required where the tread is under 11 in. */ + minNosing: 0.75 * IN, + maxNosing: 1.25 * IN, + nosingWaivedTread: 11 * IN, + /** R311.7.1: 36 in wide. */ + minWidth: 36 * IN, + /** R311.7.2: 6 ft 8 in of headroom. */ + minHeadroom: 80 * IN, + /** R311.7.3: a flight rises 151 in at most between floors or landings. */ + maxFlightRise: 151 * IN, + /** R311.7.6: landings at least 36 in in the direction of travel. */ + minLandingDepth: 36 * IN, + /** R311.7.8: a flight of four or more risers carries a handrail, 34–38 in over the nosings. */ + handrailRisers: 4, + minHandrailHeight: 34 * IN, + maxHandrailHeight: 38 * IN, + /** R312.1.1: a guard where the open side drops more than 30 in. */ + guardDrop: 30 * IN, + /** R311.7.5.1: open risers must stop a 4 in sphere once the stair rises more than 30 in. */ + openRiserSphere: 4 * IN, + openRiserFreeRise: 30 * IN, + /** DCA 6: cut stringers at most 18 in o.c. and 6 ft between supports, with a 5 in throat. */ + cutStringerMaxSpacing: 18 * IN, + cutStringerMaxSpan: 72 * IN, + minThroat: 5 * IN, +} as const + +/** Wood stringer stock, dressed (m). */ +export const STAIR_STRINGER_STOCK: Record< + StairStringerStock, + { thickness: number; depth: number } +> = { + '2x12': { thickness: 1.5 * IN, depth: 11.25 * IN }, + '2x10': { thickness: 1.5 * IN, depth: 9.25 * IN }, +} + +/** The steel stringer: an MC12x10.6 channel, 12 in deep with a 1-1/2 in flange. */ +export const STAIR_STEEL_STRINGER = { name: 'MC12x10.6', thickness: 1.5 * IN, depth: 12 * IN } + +/** Steel channels stand at the sides; a third goes down the middle past this width. */ +const STEEL_STRINGER_MAX_SPACING = 48 * IN + +/** + * Tread stock: the boards laid front to back across one tread (`boards` of `boardWidth`, `gap` + * apart; a sheet fills the tread), their thickness, and the finish laid over them. + */ +export const STAIR_TREAD_STOCK: Record< + StairTreadStock, + { boards: number; boardWidth: number; thickness: number; gap: number; finish: number } +> = { + '2x6-pair': { boards: 2, boardWidth: 5.5 * IN, thickness: 1.5 * IN, gap: 0.25 * IN, finish: 0 }, + '5/4x6-pair': { boards: 2, boardWidth: 5.5 * IN, thickness: 1 * IN, gap: 0.25 * IN, finish: 0 }, + '2x12': { boards: 1, boardWidth: 11.25 * IN, thickness: 1.5 * IN, gap: 0, finish: 0 }, + 'plywood-finish': { + boards: 1, + boardWidth: Number.POSITIVE_INFINITY, + thickness: 0.75 * IN, + gap: 0, + finish: 0.75 * IN, + }, +} + +/** Riser boards are 1x stock, 3/4 in. */ +export const STAIR_RISER_THICKNESS = 0.75 * IN +/** A wood or steel tread's nosing when none is set: 1 in, inside R311.7.5.3's 3/4–1-1/4 in. */ +export const DEFAULT_STAIR_NOSING = 1 * IN +/** A housed stringer's top edge stands this far over the nosing line, square to it. */ +export const HOUSED_STRINGER_REVEAL = 2 * IN +/** A housed stringer runs this far ahead of the bottom nosing before its plumb cut. */ +const HOUSED_STRINGER_LEAD = 1 * IN +/** The housing (dado) a housed tread or riser sits in. */ +export const STAIR_HOUSING_DEPTH = 0.5 * IN +/** A concrete flight's nosing lip, when it has one. */ +const CONCRETE_NOSING_LIP = 1.5 * IN + +export type ResolvedStairStructure = { + type: StairStructureType + stringerStock: StairStringerStock + stringerType: StairStringerType + /** The most the stringers may stand apart on centre (m). */ + stringerSpacing: number + /** The count set by hand; undefined = automatic. */ + stringerCount: number | undefined + treadStock: StairTreadStock + closedRisers: boolean + treated: boolean + nosing: number + exterior: boolean +} + +/** What a structure is read off: the stair's own fields (any of them may be absent). */ +export type StairStructureHost = Partial< + Pick +> + +/** An exterior stair: one fitted to a deck, porch or patio edge. */ +export function stairIsExterior( + stair: Pick, +): boolean { + return Boolean(stair.deckSlabId || stair.destinationSurfaceId) +} + +/** + * The stair's structure with every automatic choice made: two 2x6 treads and treated stock on an + * exterior stair, a 2x12 tread inside; risers closed once the stair rises more than 30 in; a 1 in + * nosing on wood and steel treads. `context` overrides what the stair alone cannot tell (Bones + * knows a stair that lands on grade is exterior). Null without a structure. + */ +export function resolveStairStructure( + stair: StairStructureHost, + context: { exterior?: boolean; totalRise?: number } = {}, +): ResolvedStairStructure | null { + if (!stair.structure) return null + const parsed = StairStructure.safeParse(stair.structure) + if (!parsed.success) return null + const structure = parsed.data + const exterior = context.exterior ?? stairIsExterior(stair) + // a stair that follows its level climbs a whole storey + const rise = context.totalRise ?? stair.totalRise ?? Number.POSITIVE_INFINITY + return { + type: structure.type, + stringerStock: structure.stringerStock, + stringerType: structure.stringerType, + stringerSpacing: structure.stringerSpacing, + stringerCount: structure.stringerCount, + treadStock: structure.treadStock ?? (exterior ? '2x6-pair' : '2x12'), + closedRisers: structure.closedRisers ?? rise > STAIR_CODE.openRiserFreeRise + EPS, + treated: structure.treated ?? exterior, + nosing: structure.nosing ?? (structure.type === 'concrete' ? 0 : DEFAULT_STAIR_NOSING), + exterior, + } +} + +/** + * The structure a stair is framed with: its own, or for a stair drawn before structures existed + * the one its body reads as — a concrete flight when it is painted concrete, wood stringers + * otherwise. + */ +export function inferStairStructure( + stair: Pick, +): StairStructure { + if (stair.structure) { + const parsed = StairStructure.safeParse(stair.structure) + if (parsed.success) return parsed.data + } + const refs = [stair.materialPreset, stair.material?.preset, ...Object.values(stair.slots ?? {})] + const concrete = refs.some((ref) => typeof ref === 'string' && /concrete/i.test(ref)) + return StairStructure.parse({ type: concrete ? 'concrete' : 'wood-stringers' }) +} + +/** + * The automatic stringer count: enough that no bay between neighbours exceeds `maxSpacing` — + * ceil(width / spacing) + 1 — and never fewer than two, or three on a stair 36 in wide or more. + */ +export function autoStairStringerCount(width: number, maxSpacing: number): number { + const floor = width >= STAIR_CODE.minWidth - EPS ? 3 : 2 + if (!(width > 0 && maxSpacing > 0)) return floor + return Math.max(Math.ceil(width / maxSpacing - EPS) + 1, floor) +} + +export type StairStringerBand = { + index: number + /** Centre across the flight, in the flight's frame (m). */ + x: number + x0: number + x1: number + thickness: number + depth: number + /** 'cut' — notched under the treads; 'housed' — a solid board over the nosing line. */ + kind: 'cut' | 'housed' + steel: boolean +} + +export type StairStringerLayout = { + count: number + /** True when the count follows the width and the spacing. */ + auto: boolean + /** Centre to centre between neighbouring stringers (m). */ + spacing: number + thickness: number + depth: number + steel: boolean + bands: StairStringerBand[] +} + +/** + * The stringers across a flight of `width`: the outer two flush with its sides and the rest evenly + * between them, as many as the structure asks (or as its spacing needs). Housed wood stringers + * and steel channels are the outer two; any between them are cut carriages. + */ +export function resolveStairStringerLayout( + width: number, + structure: Pick< + ResolvedStairStructure, + 'type' | 'stringerStock' | 'stringerType' | 'stringerSpacing' | 'stringerCount' + >, +): StairStringerLayout { + const steel = structure.type === 'steel-stringers' + const stock = steel ? STAIR_STEEL_STRINGER : STAIR_STRINGER_STOCK[structure.stringerStock] + const auto = structure.stringerCount === undefined + const wanted = + structure.stringerCount ?? + (steel + ? Math.max(2, Math.ceil(width / STEEL_STRINGER_MAX_SPACING - EPS) + 1) + : autoStairStringerCount(width, structure.stringerSpacing)) + const count = Math.max(0, Math.min(wanted, Math.floor((width + EPS) / stock.thickness))) + const spacing = count > 1 ? (width - stock.thickness) / (count - 1) : 0 + const housedSides = steel || structure.stringerType === 'housed' + const bands: StairStringerBand[] = [] + for (let index = 0; index < count; index++) { + const x = count > 1 ? -width / 2 + stock.thickness / 2 + index * spacing : 0 + bands.push({ + index, + x, + x0: x - stock.thickness / 2, + x1: x + stock.thickness / 2, + thickness: stock.thickness, + depth: stock.depth, + kind: housedSides && (index === 0 || index === count - 1) ? 'housed' : 'cut', + steel, + }) + } + return { + count, + auto, + spacing, + thickness: stock.thickness, + depth: stock.depth, + steel, + bands, + } +} + +/** A construction a structure draws, carrying the structure so the stringers can be laid out. */ +export type ResolvedStairConstruction = StairConstructionType & { + structure?: ResolvedStairStructure +} + +/** + * The body a structure draws: a solid mass for concrete (its nosing a lip over each riser); open + * treads of the tread stock — closed risers when it has them — over the stringers otherwise. + */ +export function stairStructureConstruction( + structure: ResolvedStairStructure, +): ResolvedStairConstruction { + if (structure.type === 'concrete') + return { + ...StairConstruction.parse({ + mode: 'solid', + nosing: structure.nosing, + treadThickness: CONCRETE_NOSING_LIP, + finishThickness: 0, + }), + structure, + } + const tread = STAIR_TREAD_STOCK[structure.treadStock] + const stringer = + structure.type === 'steel-stringers' + ? STAIR_STEEL_STRINGER + : STAIR_STRINGER_STOCK[structure.stringerStock] + return { + ...StairConstruction.parse({ + mode: 'open', + treadThickness: tread.thickness, + finishThickness: tread.finish, + nosing: structure.nosing, + riserThickness: STAIR_RISER_THICKNESS, + closedRisers: structure.closedRisers, + stringerWidth: stringer.thickness, + stringerDepth: stringer.depth, + }), + structure, + } +} + +const constructionMemo = new WeakMap() + +/** + * The construction a straight stair's structure draws, or null (no structure, or a curved or + * spiral stair, which keeps its own body). Memoised on the structure object. + */ +export function stairStructureConstructionOf( + stair: StairStructureHost, +): ResolvedStairConstruction | null { + if (!stair.structure || (stair.stairType ?? 'straight') !== 'straight') return null + const key = `${stair.totalRise ?? ''}|${stairIsExterior(stair)}` + const cached = constructionMemo.get(stair.structure) + if (cached?.key === key) return cached.value + const structure = resolveStairStructure(stair) + if (!structure) return null + const value = stairStructureConstruction(structure) + constructionMemo.set(stair.structure, { key, value }) + return value +} + +/** A landing's joists and rims: 2x8, 16 in o.c. — a stair landing spans a few feet at most. */ +export const STAIR_LANDING_JOIST = { size: '2x8', thickness: 1.5 * IN, depth: 7.25 * IN } as const +export const STAIR_LANDING_JOIST_SPACING = 16 * IN +/** A landing's corner posts: 4x4. */ +export const STAIR_LANDING_POST = 3.5 * IN +/** A landing closer to the base than this over its frame sits on blocking, not posts. */ +const STAIR_LANDING_MIN_POST = 6 * IN + +/** A box in a segment's frame: across `x0..x1`, along the run `z0..z1`, `bottom..top` high. */ +export type StairFrameBox = { + x0: number + x1: number + z0: number + z1: number + bottom: number + top: number +} + +/** + * A wood landing's frame, in the landing's frame (its top at 0): rims all round under the decking + * (`drop` thick), joists between them along the run at 16 in o.c., and a 4x4 post under each + * corner down to the stair's base `baseDepth` below — none when the frame sits within 6 in of it. + */ +export function stairLandingFrame( + landing: { width: number; length: number }, + drop: number, + baseDepth: number, +): { rims: StairFrameBox[]; joists: StairFrameBox[]; posts: StairFrameBox[] } { + const { width, length } = landing + const t = STAIR_LANDING_JOIST.thickness + const top = -drop + const bottom = top - STAIR_LANDING_JOIST.depth + const x0 = -width / 2 + const x1 = width / 2 + const rims: StairFrameBox[] = [] + const joists: StairFrameBox[] = [] + const posts: StairFrameBox[] = [] + if (!(width > 2 * t && length > 2 * t)) return { rims, joists, posts } + rims.push( + { x0, x1, z0: 0, z1: t, bottom, top }, + { x0, x1, z0: length - t, z1: length, bottom, top }, + { x0, x1: x0 + t, z0: t, z1: length - t, bottom, top }, + { x0: x1 - t, x1, z0: t, z1: length - t, bottom, top }, + ) + const bays = Math.max(1, Math.ceil((width - t) / STAIR_LANDING_JOIST_SPACING - EPS)) + for (let i = 1; i < bays; i++) { + const x = x0 + t / 2 + (i * (width - t)) / bays + joists.push({ x0: x - t / 2, x1: x + t / 2, z0: t, z1: length - t, bottom, top }) + } + if (baseDepth + bottom >= STAIR_LANDING_MIN_POST - EPS) { + const p = STAIR_LANDING_POST + for (const [px, pz] of [ + [x0, 0], + [x1 - p, 0], + [x0, length - p], + [x1 - p, length - p], + ] as const) + posts.push({ x0: px, x1: px + p, z0: pz, z1: pz + p, bottom: -baseDepth, top: bottom }) + } + return { rims, joists, posts } +} + +/** One flight as its stringers see it. */ +export type StairStringerFlight = { + stepCount: number + height: number + length: number + /** The structural tread sits this far under each walking top: the tread and its finish. */ + treadDrop: number + /** Each riser cut sits this far behind its riser face: the riser board, when there is one. */ + riserSetback: number + nosing: number + /** False when the flight starts on another flight, not on a floor, pad or landing. */ + bearsOnBase?: boolean +} + +/** The flight a segment and its construction make for the stringers. */ +export function stairStringerFlight( + segment: { stepCount: number; height: number; length: number }, + construction: Pick< + StairConstructionType, + 'treadThickness' | 'finishThickness' | 'riserThickness' | 'closedRisers' | 'nosing' + >, +): StairStringerFlight { + return { + stepCount: Math.max(1, Math.round(segment.stepCount)), + height: segment.height, + length: segment.length, + treadDrop: construction.treadThickness + construction.finishThickness, + riserSetback: construction.closedRisers ? construction.riserThickness : 0, + nosing: construction.nosing, + } +} + +export type StairStringerSlice = { + index: number + /** Closed (run, height) outline in the flight's frame; always convex. */ + profile: [number, number][] + /** The board's underside: height = slope · run + intercept. */ + underside: [number, number] + top: number +} + +/** Keeps the part of a convex polygon on one side of a level line (Sutherland–Hodgman). */ +function clipLevel( + polygon: [number, number][], + level: number, + keepAbove: boolean, +): [number, number][] { + const inside = (p: [number, number]) => (keepAbove ? p[1] >= level - EPS : p[1] <= level + EPS) + const out: [number, number][] = [] + for (let i = 0; i < polygon.length; i++) { + const a = polygon[i]! + const b = polygon[(i + 1) % polygon.length]! + const aIn = inside(a) + const bIn = inside(b) + if (aIn) out.push(a) + if (aIn !== bIn) { + const t = (level - a[1]) / (b[1] - a[1]) + out.push([a[0] + (b[0] - a[0]) * t, level]) + } + } + const same = (a: [number, number], b: [number, number]) => + Math.hypot(a[0] - b[0], a[1] - b[1]) <= EPS + const kept = out.filter((p, i) => i === 0 || !same(p, out[i - 1]!)) + if (kept.length > 1 && same(kept[0]!, kept.at(-1)!)) kept.pop() + return kept +} + +/** + * The uncut board's edges, as heights over the run (height = slope · run + intercept): a cut + * stringer's top edge runs through the outer corners of its notches, a housed one stands + * `HOUSED_STRINGER_REVEAL` over the nosing line; the bottom edge is the board's depth under it. + */ +export function stairStringerEdges( + band: Pick, + flight: StairStringerFlight, +): { slope: number; top: number; bottom: number } { + const count = Math.max(1, Math.round(flight.stepCount)) + const riser = flight.height / count + const slope = flight.length > 0 ? flight.height / flight.length : 0 + const vertical = band.depth * Math.hypot(1, slope) + const top = + band.kind === 'cut' + ? riser - flight.treadDrop - slope * flight.riserSetback + : slope * flight.nosing + riser + HOUSED_STRINGER_REVEAL * Math.hypot(1, slope) + return { slope, top, bottom: top - vertical } +} + +/** + * One stringer down a flight, sliced per step (each slice convex, so the viewer extrudes it and + * Bones boxes it). A cut stringer is notched for every tread and riser: each slice tops out flat + * at its tread seat — the walking top less the tread — its riser cut set back behind the riser + * board, its underside the board's bottom edge. A housed stringer is the solid board standing + * `HOUSED_STRINGER_REVEAL` over the nosing line. Both are cut level where they bear on the base, + * plumb at the top of the run, and a housed one level at the floor it reaches. + */ +export function stairStringerSlices( + band: Pick, + flight: StairStringerFlight, +): StairStringerSlice[] { + const count = Math.max(1, Math.round(flight.stepCount)) + const { height, length } = flight + if (!(height > 0 && length > 0 && band.depth > 0)) return [] + const going = length / count + const riser = height / count + const { slope, top, bottom } = stairStringerEdges(band, flight) + const slices: StairStringerSlice[] = [] + const finish = (index: number, polygon: [number, number][], underside: [number, number]) => { + let profile = polygon + if (flight.bearsOnBase !== false) profile = clipLevel(profile, 0, true) + if (band.kind === 'housed') profile = clipLevel(profile, height, false) + if (profile.length < 3) return + slices.push({ + index, + profile, + underside, + top: Math.max(...profile.map((point) => point[1])), + }) + } + if (band.kind === 'cut') { + const setback = flight.riserSetback + for (let index = 0; index < count; index++) { + const z0 = setback + index * going + const z1 = Math.min(length, setback + (index + 1) * going) + const seat = (index + 1) * riser - flight.treadDrop + if (!(z1 - z0 > EPS && seat > EPS)) continue + finish( + index, + [ + [z0, seat], + [z1, seat], + [z1, slope * z1 + bottom], + [z0, slope * z0 + bottom], + ], + [slope, bottom], + ) + } + return slices + } + for (let index = 0; index < count; index++) { + const z0 = index === 0 ? -(flight.nosing + HOUSED_STRINGER_LEAD) : index * going + const z1 = index === count - 1 ? length : (index + 1) * going + finish( + index, + [ + [z0, slope * z0 + top], + [z1, slope * z1 + top], + [z1, slope * z1 + bottom], + [z0, slope * z0 + bottom], + ], + [slope, bottom], + ) + } + return slices +} + +export type StairStringerCut = { + slices: StairStringerSlice[] + /** Rise over run of the flight. */ + slope: number + /** The board's cut length: the stringer's extent along the slope. */ + length: number + /** Wood left under the notches, square to the slope (DCA 6 asks 5 in); the board depth when housed. */ + throat: number + /** The run the stringer bears on its base along (its level cut), or null when it bears on none. */ + seat: [number, number] | null + /** The plumb cut at the top of the run: its run and the heights it spans. */ + plumb: { z: number; top: number; bottom: number } + /** The uncut board's top and bottom edges (intercepts: height = slope · run + intercept). */ + edge: { top: number; bottom: number } +} + +/** A stringer's cut: its slices and the numbers the takeoff and the code checks read off them. */ +export function stairStringerCut( + band: Pick, + flight: StairStringerFlight, +): StairStringerCut { + const slices = stairStringerSlices(band, flight) + const { slope, top, bottom } = stairStringerEdges(band, flight) + const norm = Math.hypot(1, slope) + const along = (point: [number, number]) => (point[0] + point[1] * slope) / norm + const points = slices.flatMap((slice) => slice.profile) + const extents = points.map(along) + const riser = flight.height / Math.max(1, Math.round(flight.stepCount)) + const onBase = points.filter((point) => Math.abs(point[1]) < 1e-7).map((point) => point[0]) + const atTop = points + .filter((point) => Math.abs(point[0] - flight.length) < 1e-7) + .map((point) => point[1]) + return { + slices, + slope, + length: extents.length ? Math.max(...extents) - Math.min(...extents) : 0, + throat: band.kind === 'cut' ? band.depth - riser / norm : band.depth, + seat: onBase.length > 1 ? [Math.min(...onBase), Math.max(...onBase)] : null, + plumb: { + z: flight.length, + top: atTop.length ? Math.max(...atTop) : 0, + bottom: atTop.length ? Math.min(...atTop) : 0, + }, + edge: { top, bottom }, + } +} + +/** Inches as a builder reads them, to the nearest eighth: 7.75 in → `7-3/4 in`. */ +export function formatStairInches(metres: number): string { + const eighths = Math.round(metres / IN / 0.125) + const whole = Math.floor(eighths / 8) + let numerator = eighths - whole * 8 + let denominator = 8 + while (numerator > 0 && numerator % 2 === 0) { + numerator /= 2 + denominator /= 2 + } + if (numerator === 0) return `${whole} in` + return whole > 0 ? `${whole}-${numerator}/${denominator} in` : `${numerator}/${denominator} in` +} + +export type StairStructureIssue = { + code: string + severity: 'error' | 'warning' + nodeId: string + message: string +} + +/** + * The IRC R311.7 / R312 and DCA 6 checks a stair with a structure owes: risers, treads, nosings, + * width, flight rise, headroom, the handrail on four or more risers, the guard past a 30 in drop, + * open risers on a tall stair, and for cut wood stringers their spacing, throat and span. Stairs + * without a structure keep the design-target checks alone. + */ +export function stairStructureDiagnostics( + stair: StairNode, + flights: readonly { + nodeId: string + count: number + rise: number + length: number + width: number + riserHeight: number | null + going: number | null + }[], + options: { totalRise: number; headroom: number | null }, +): StairStructureIssue[] { + if ((stair.stairType ?? 'straight') !== 'straight') return [] + const structure = resolveStairStructure(stair) + if (!structure) return [] + const issues: StairStructureIssue[] = [] + const warn = (code: string, nodeId: string, message: string) => + issues.push({ code, severity: 'warning', nodeId, message }) + const construction = stairStructureConstruction(structure) + const railings = (stair.railingMode ?? 'none') !== 'none' + const handrail = stair.handrail && stair.handrail.mode !== 'none' + for (const flight of flights) { + const { riserHeight: riser, going } = flight + if (riser === null || going === null) continue + if (riser > STAIR_CODE.maxRiser + EPS) + warn( + 'code-riser', + flight.nodeId, + `Risers of ${formatStairInches(riser)} exceed the 7-3/4 in maximum (IRC R311.7.5.1).`, + ) + if (going < STAIR_CODE.minTread - EPS) + warn( + 'code-tread', + flight.nodeId, + `Treads of ${formatStairInches(going)} fall short of the 10 in minimum (IRC R311.7.5.2).`, + ) + if (structure.type !== 'concrete' || structure.nosing > 0) { + if ( + going < STAIR_CODE.nosingWaivedTread - EPS && + structure.nosing < STAIR_CODE.minNosing - EPS + ) + warn( + 'code-nosing', + flight.nodeId, + 'Treads under 11 in need a 3/4 in to 1-1/4 in nosing (IRC R311.7.5.3).', + ) + else if (structure.nosing > STAIR_CODE.maxNosing + EPS) + warn( + 'code-nosing', + flight.nodeId, + `A ${formatStairInches(structure.nosing)} nosing projects past the 1-1/4 in IRC R311.7.5.3 allows.`, + ) + } + if (flight.width < STAIR_CODE.minWidth - EPS) + warn( + 'code-width', + flight.nodeId, + `The flight is ${formatStairInches(flight.width)} wide; IRC R311.7.1 asks 36 in.`, + ) + if (flight.rise > STAIR_CODE.maxFlightRise + EPS) + warn( + 'code-flight-rise', + flight.nodeId, + `A flight rises ${formatStairInches(flight.rise)}; IRC R311.7.3 allows 151 in between floors or landings. Add a landing.`, + ) + if (flight.count >= STAIR_CODE.handrailRisers && !railings && !handrail) + warn( + 'code-handrail', + flight.nodeId, + `A flight of ${flight.count} risers needs a handrail 34 in to 38 in over the nosings (IRC R311.7.8).`, + ) + if (structure.type !== 'concrete') { + const layout = resolveStairStringerLayout(flight.width, structure) + const carriages = layout.bands.some((band) => band.kind === 'cut') + if (!layout.steel && carriages) { + if (layout.spacing > STAIR_CODE.cutStringerMaxSpacing + EPS) + warn( + 'stringer-spacing', + flight.nodeId, + `Stringers stand ${formatStairInches(layout.spacing)} on centre; DCA 6 allows cut stringers 18 in at most. Add a stringer.`, + ) + const cut = stairStringerCut( + { kind: 'cut', depth: layout.depth }, + stairStringerFlight( + { stepCount: flight.count, height: flight.rise, length: flight.length }, + construction, + ), + ) + if (cut.throat < STAIR_CODE.minThroat - EPS) + warn( + 'stringer-throat', + flight.nodeId, + `The cut stringers keep ${formatStairInches(cut.throat)} of wood under the notches; DCA 6 asks 5 in. Use 2x12 stock or a shallower riser.`, + ) + // DCA 6's span limit is the deck stair's, open below; inside, the walls alongside carry them + if (structure.exterior && flight.length > STAIR_CODE.cutStringerMaxSpan + EPS) + warn( + 'stringer-span', + flight.nodeId, + `The cut stringers span ${formatStairInches(flight.length)} level; DCA 6 limits them to 6 ft between supports. Support them at mid-span on a beam and posts.`, + ) + } + } + } + if (railings && !handrail && Number.isFinite(stair.railingHeight)) { + const height = stair.railingHeight + if (height < STAIR_CODE.minHandrailHeight - EPS || height > STAIR_CODE.maxHandrailHeight + EPS) + warn( + 'code-handrail-height', + stair.id, + `The railing stands ${formatStairInches(height)} over the nosings; a handrail belongs 34 in to 38 in (IRC R311.7.8.1).`, + ) + } + if (options.totalRise > STAIR_CODE.guardDrop + EPS && !railings) + warn( + 'code-guard', + stair.id, + `The stair rises ${formatStairInches(options.totalRise)}; an open side more than 30 in above the floor needs a guard (IRC R312.1.1) unless a wall encloses it.`, + ) + if ( + structure.type !== 'concrete' && + !structure.closedRisers && + options.totalRise > STAIR_CODE.openRiserFreeRise + EPS + ) { + const opening = Math.max( + 0, + ...flights.map( + (flight) => + (flight.riserHeight ?? 0) - construction.treadThickness - construction.finishThickness, + ), + ) + if (opening >= STAIR_CODE.openRiserSphere - EPS) + warn( + 'code-open-risers', + stair.id, + `Open risers leave ${formatStairInches(opening)} between treads; past a 30 in rise they must stop a 4 in sphere (IRC R311.7.5.1). Close them with riser boards.`, + ) + } + if (options.headroom !== null && options.headroom < STAIR_CODE.minHeadroom - EPS) + warn( + 'code-headroom', + stair.id, + `Headroom of ${formatStairInches(options.headroom)} is under the 6 ft 8 in minimum (IRC R311.7.2).`, + ) + return issues +} diff --git a/packages/core/src/systems/wall/wall-assembly.test.ts b/packages/core/src/systems/wall/wall-assembly.test.ts index ea13f3c97f..47c210ac0b 100644 --- a/packages/core/src/systems/wall/wall-assembly.test.ts +++ b/packages/core/src/systems/wall/wall-assembly.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from 'bun:test' import { FOUNDATION_CONSTRUCTIONS } from '../../lib/foundation-construction' -import type { WallNode } from '../../schema' +import { Assembly, type WallNode } from '../../schema' import type { WallAssembly } from '../../schema/nodes/wall' import { assemblyThickness, @@ -19,6 +19,7 @@ import { wallAssemblyExposedStructure, wallAssemblyFromLegacy, wallAssemblyPatch, + wallAssemblyToLegacy, wallLayerBoundaryOffsets, } from './wall-assembly' import { calculateLevelMiters } from './wall-mitering' @@ -109,6 +110,20 @@ describe('assemblyThickness', () => { expect(patch.thickness).toBeCloseTo(assemblyThickness(stack), 12) expect(patch.assembly).toBe(stack) }) + + test("the core's stud spacing rides the inspector's view both ways and adds no thickness", () => { + const spaced = { ...EXT_2X6, framing: { ...EXT_2X6.framing, spacing: 24 * IN } } + const stack = f2(spaced) + expect(stack.layers.find((layer) => layer.core)?.spacing).toBe(24 * IN) + expect(wallAssemblyToLegacy(stack)?.framing).toEqual(spaced.framing) + expect(assemblyThickness(stack)).toBeCloseTo(assemblyThickness(f2(EXT_2X6)), 12) + expect(Assembly.safeParse(stack).success).toBe(true) + const misplaced = { + ...stack, + layers: stack.layers.map((layer) => (layer.core ? layer : { ...layer, spacing: 16 * IN })), + } + expect(Assembly.safeParse(misplaced).success).toBe(false) + }) }) // --------------------------------------------------------------------------- diff --git a/packages/core/src/systems/wall/wall-assembly.ts b/packages/core/src/systems/wall/wall-assembly.ts index 11a75e7cc1..c3e4698ab9 100644 --- a/packages/core/src/systems/wall/wall-assembly.ts +++ b/packages/core/src/systems/wall/wall-assembly.ts @@ -44,9 +44,15 @@ * faces and no cladding or sheathing is drawn (see `resolveWallAssembly`). */ -import type { WallNode } from '../../schema' +import { + getLibraryMaterialIdFromRef, + getMaterialsForCategory, + type MaterialCatalogItem, +} from '../../material-library' +import type { AnyNode, WallNode } from '../../schema' import type { Assembly, AssemblyLayer } from '../../schema/assembly' -import { WallAssembly } from '../../schema/nodes/wall' +import { WallAssembly, type WallFace } from '../../schema/nodes/wall' +import { WallTypeDefinition } from '../../schema/wall-type' import { DEFAULT_WALL_THICKNESS } from './wall-footprint' import { type Point2D, pointToKey, type WallMiterData } from './wall-mitering' @@ -74,6 +80,19 @@ export const GYPSUM_SHEATHING = inches(0.5) export const STUD_2X4 = inches(3.5) /** 2x6 stud, actual 5-1/2 in. Same source as STUD_2X4. */ export const STUD_2X6 = inches(5.5) +/** 2x8 stud, actual 7-1/4 in: the PS 20 dressed size the IRC lumber tables assume. */ +export const STUD_2X8 = inches(7.25) +/** + * Steel stud webs, 3-1/2, 5-1/2 and 8 in: members 350S162, 550S162 and 800S162, whose designation + * leads with the web depth in hundredths of an inch (AISI S201, the designations 2021 IRC R603 + * uses). + */ +export const LGS_STUD_350 = inches(3.5) +export const LGS_STUD_550 = inches(5.5) +export const LGS_STUD_800 = inches(8) +/** Stud spacings the 2021 IRC stud tables are written for, 16 and 24 in on centre (Table R602.3(5)). */ +export const STUD_SPACING_16 = inches(16) +export const STUD_SPACING_24 = inches(24) /** Vinyl / wood lap siding bounding depth, 3/4 in. 2021 IRC R703.11 / R703.5 + Table R703.3(1). */ export const SIDING_LAP = inches(0.75) /** Fiber cement lap board, 5/16 in board. 2021 IRC R703.10.2 + Table R703.3(1). */ @@ -229,6 +248,7 @@ export function wallAssemblyFromLegacy(legacy: WallAssembly): Assembly { core: true, material: legacy.framing.kind, thickness: legacy.framing.depth, + ...(legacy.framing.spacing !== undefined ? { spacing: legacy.framing.spacing } : {}), }) if (interior) layers.push({ id: 'interior', ...interior }) return { @@ -290,6 +310,7 @@ export function wallAssemblyToLegacy(assembly: Assembly): WallAssembly | null { legacy.framing = { kind: framing.material as WallAssembly['framing']['kind'], depth: framing.thickness, + ...(framing.spacing !== undefined ? { spacing: framing.spacing } : {}), } const lining = take('lining') if (layers.length > 0) return null @@ -316,6 +337,7 @@ export function wallAssemblyToLegacy(assembly: Assembly): WallAssembly | null { restored.role === layer.role && restored.core === layer.core && restored.material === layer.material && + restored.spacing === layer.spacing && Math.abs(restored.thickness - layer.thickness) < 1e-12 ) }) @@ -353,6 +375,10 @@ const INTERIOR_FINISH_LABEL: Record = { plaster: 'plaster', none: 'none', } +const INSULATION_LABEL: Record = { + 'rigid-foam': 'rigid foam insulation', + 'mineral-wool': 'mineral wool board', +} /** An F2 layer as the WS5 drawing role and its inspector / poché label. */ function drawnLayer(layer: AssemblyLayer): { role: WallAssemblyLayerRole; material: string } { @@ -374,9 +400,14 @@ function drawnLayer(layer: AssemblyLayer): { role: WallAssemblyLayerRole; materi case 'substrate': case 'membrane': case 'underlay': + // Continuous insulation is a board on the face of the frame, drawn as one. + case 'insulation': return { role: 'sheathing', - material: (material && SHEATHING_LABEL[material]) ?? material ?? layer.role, + material: + (material && (SHEATHING_LABEL[material] ?? INSULATION_LABEL[material])) ?? + material ?? + layer.role, } default: return { @@ -635,15 +666,234 @@ export function wallAssemblyFraming( return { depth: core.thickness, ...(core.material ? { kind: core.material } : {}) } } -/** `library:` ref for the wall's assembly cladding, or null when it has none. */ +/** + * `library:` ref for the wall's assembly cladding, or null when it has none: the product picked + * for its cladding layer while drafting (`wallAssemblyFinishSlots`), else the kind's own + * (`WALL_FINISH_LIBRARY_REF`). A picked product that no longer dresses the cladding (the layer + * changed from siding to stucco since) gives way to the kind's own. + */ export function wallAssemblyFinishRef( - wall: Pick, + wall: Pick, ): string | null { - const finish = wallAssemblyExteriorFinish(wall) - if (!finish) return null + const layer = layersOutsideIn(wall).layers.find((layer) => layer.role === 'finish') + const finish = layer?.material + if (!(layer && finish)) return null + const picked = wall.slots?.[assemblyLayerSlotKey(layer)] + if (isWallCladdingProduct(finish, picked)) return picked! return WALL_FINISH_LIBRARY_REF[finish] ?? null } +/** + * The finish the wall's assembly gives one geometric face (`a` is the +normal face) where the + * face has no paint of its own: on the exterior face its cladding (`wallAssemblyFinishRef`), on a + * lined face the paint picked for that lining while drafting. Null where the assembly says + * nothing, and the face shows the wall's slot default. + */ +export function wallAssemblyFaceFinish( + wall: Pick, + face: WallFace, +): string | null { + const { layers, exteriorSideResolved } = layersOutsideIn(wall) + const exterior = face === (exteriorSideResolved === 1 ? 'a' : 'b') + if (exterior) { + const cladding = wallAssemblyFinishRef(wall) + if (cladding) return cladding + } + const drawn = layers.filter((layer) => layer.thickness > 0) + const outer = exterior ? drawn[0] : drawn[drawn.length - 1] + if (outer?.role !== 'lining') return null + return wall.slots?.[assemblyLayerSlotKey(outer)] ?? null +} + +// ============================================================================ +// FINISHES PICKED WHILE DRAFTING +// ============================================================================ + +/** The `slots` key a layer's look is kept under: its own `slot`, else `layer:` (`AssemblyLayer.slot`). */ +export function assemblyLayerSlotKey(layer: Pick): string { + return layer.slot ?? `layer:${layer.id}` +} + +/** An outdoor wall finish: a brick or stone made for a wall outside, not a floor tile. */ +const outdoorWall = (item: MaterialCatalogItem) => + !!item.surfaces?.includes('wall') && item.surfaces.includes('outdoor') + +/** Which catalog finishes dress each cladding kind. */ +const CLADDING_PRODUCTS: Record MaterialCatalogItem[]> = { + siding: () => getMaterialsForCategory('siding'), + 'fiber-cement': () => getMaterialsForCategory('siding'), + // The textured coat, then the flat colours of an integrally coloured or painted finish coat. + stucco: () => [ + ...getMaterialsForCategory('concrete').filter((item) => item.id.includes('stucco')), + ...getMaterialsForCategory('colors'), + ], + brick: () => getMaterialsForCategory('brick').filter(outdoorWall), + stone: () => getMaterialsForCategory('stone').filter(outdoorWall), +} + +/** + * The catalog products a cladding kind (`siding`, `stucco`, `brick`, …) can be finished with, + * the kind's own (`WALL_FINISH_LIBRARY_REF`) among them: what the drafting finish picker offers + * for a wall type with that cladding. Empty for a kind with none (`none`, an unknown kind). + */ +export function wallCladdingProducts(kind: string | undefined): MaterialCatalogItem[] { + return (kind && CLADDING_PRODUCTS[kind]?.()) || [] +} + +/** Whether `ref` is a `library:` product `wallCladdingProducts(kind)` lists. */ +export function isWallCladdingProduct(kind: string | undefined, ref: string | undefined): boolean { + const id = getLibraryMaterialIdFromRef(ref) + return !!id && wallCladdingProducts(kind).some((item) => item.id === id) +} + +/** + * Whether a stack builds an exterior wall, read from its own layers: it has a cladding side — a + * finish or sheathing layer, or a lining on one face only (block or framing left bare outside). + * A stack lined on both faces, or bare on both, is a partition. + */ +export function isExteriorWallAssembly(assembly: Assembly): boolean { + const layers = [...assembly.layers, ...(assembly.backing ?? [])].filter( + (layer) => layer.thickness > 0, + ) + if (layers.some((layer) => layer.role === 'finish' || layer.role === 'sheathing')) return true + return (layers[0]?.role === 'lining') !== (layers[layers.length - 1]?.role === 'lining') +} + +// ============================================================================ +// PROJECT WALL TYPES +// ============================================================================ + +export type WallTypeCore = { + id: string + label: string + /** The core layer's construction kind, as the framers read it (`wallAssemblyFraming`). */ + material: 'wood' | 'lgs' | 'cmu' + thickness: number + /** Studs on centre, metres; absent for block. */ + spacing?: number +} + +/** + * The framing cores a project wall type is built around: wood studs (2x4, 2x6, 2x8) and steel + * studs (the 3-1/2, 5-1/2 and 8 in webs the framers size steel walls by) at 16 or 24 in on + * centre, or an 8 in block. The core's depth and spacing are what a framer studs the wall at. + */ +export const WALL_TYPE_CORES: readonly WallTypeCore[] = [ + ...( + [ + ['2x4', STUD_2X4], + ['2x6', STUD_2X6], + ['2x8', STUD_2X8], + ] as const + ).flatMap(([size, thickness]) => + ([16, 24] as const).map((oc) => ({ + id: `wood-${size}-${oc}`, + label: `${size} wood studs @ ${oc}" o.c.`, + material: 'wood' as const, + thickness, + spacing: oc === 16 ? STUD_SPACING_16 : STUD_SPACING_24, + })), + ), + ...( + [ + ['3-1/2"', '350', LGS_STUD_350], + ['5-1/2"', '550', LGS_STUD_550], + ['8"', '800', LGS_STUD_800], + ] as const + ).flatMap(([depth, web, thickness]) => + ([16, 24] as const).map((oc) => ({ + id: `lgs-${web}-${oc}`, + label: `${depth} steel studs @ ${oc}" o.c.`, + material: 'lgs' as const, + thickness, + spacing: oc === 16 ? STUD_SPACING_16 : STUD_SPACING_24, + })), + ), + { id: 'cmu-8', label: 'CMU 8" block', material: 'cmu', thickness: CMU_8_ACTUAL }, +] + +const near = (a: number, b: number) => Math.abs(a - b) < 1e-6 + +/** + * The listed core a stack is built around, or undefined for one off the list. A core with no + * spacing of its own (every preset's: the framer's default) reads as the 16 in one. + */ +export function wallTypeCoreOf(assembly: Assembly): WallTypeCore | undefined { + const core = assembly.layers.find((layer) => layer.core) + if (!core) return undefined + const spacing = core.spacing ?? STUD_SPACING_16 + return WALL_TYPE_CORES.find( + (option) => + option.material === core.material && + near(option.thickness, core.thickness) && + (option.spacing === undefined || near(option.spacing, spacing)), + ) +} + +/** The id each layer role takes in a project wall type, as the presets name them. */ +const WALL_TYPE_LAYER_ID: Partial> = { + finish: 'exterior', + air: 'air-space', + sheathing: 'sheathing', + structure: 'framing', +} + +/** + * A project wall type's stack from its layers listed outside-in, with ids as the presets give + * them (`exterior`, `sheathing`, `framing`, `interior`, a lining outside the core + * `interior-back`, a repeat numbered `-2`, `-3`…), so a stack the inspector's cladding / + * sheathing / framing / interior rows can express stays editable there. + */ +export function wallTypeAssembly( + id: string, + layers: readonly Omit[], +): Assembly { + const coreIndex = layers.findIndex((layer) => layer.core) + const used = new Set() + return { + layers: layers.map((layer, index) => { + const base = + layer.role === 'lining' + ? index < coreIndex + ? 'interior-back' + : 'interior' + : (WALL_TYPE_LAYER_ID[layer.role] ?? layer.role) + let layerId = base + for (let n = 2; used.has(layerId); n += 1) layerId = `${base}-${n}` + used.add(layerId) + return { id: layerId, ...layer } + }), + face: 'exterior', + presetId: id, + } +} + +/** + * The project's own wall types: those saved on its site (`SiteNode.wallTypes`), in their saved + * order. A scene is loaded without parsing, so an entry that does not parse, or repeats an id, is + * skipped rather than trusted. + */ +export function projectWallTypes( + nodes: Readonly>, + rootNodeIds: readonly string[], +): WallTypeDefinition[] { + const site = rootNodeIds.map((id) => nodes[id]).find((node) => node?.type === 'site') + return parseWallTypes(site?.type === 'site' ? site.wallTypes : undefined) +} + +/** A saved `SiteNode.wallTypes` list as `projectWallTypes` reads it: parsed, first id wins. */ +export function parseWallTypes(saved: unknown): WallTypeDefinition[] { + const seen = new Set() + const types: WallTypeDefinition[] = [] + for (const entry of Array.isArray(saved) ? saved : []) { + const parsed = WallTypeDefinition.safeParse(entry) + if (!parsed.success || seen.has(parsed.data.id)) continue + seen.add(parsed.data.id) + types.push(parsed.data) + } + return types +} + /** The structural cores that are left bare where nothing covers them: block and cast concrete. */ export type ExposedStructure = 'cmu' | 'concrete' diff --git a/packages/core/src/systems/wall/wall-finish.test.ts b/packages/core/src/systems/wall/wall-finish.test.ts index b0e6bc021d..0f2a5987a7 100644 --- a/packages/core/src/systems/wall/wall-finish.test.ts +++ b/packages/core/src/systems/wall/wall-finish.test.ts @@ -1,7 +1,14 @@ import { describe, expect, test } from 'bun:test' import { extractRooms } from '../../lib/room-graph' +import { getMaterialPresetByRef, MATERIAL_CATALOG } from '../../material-library' +import { wallSlots } from '../../node-slots/wall' import { type AnyNode, LevelNode } from '../../schema' -import { WallNode } from '../../schema/nodes/wall' +import { + DEFAULT_EXTERIOR_WALL_FINISH, + DEFAULT_INTERIOR_WALL_PAINT, + getWallFaceDefault, + WallNode, +} from '../../schema/nodes/wall' import { ZoneNode } from '../../schema/nodes/zone' import { buildWallFinishLayout, @@ -156,7 +163,7 @@ describe('wall finish resolution order', () => { expect(resolveWallFaceChain(host, 'a')).toEqual({ kind: 'ref', ref: 'library:slot-a' }) expect(resolveWallFaceChain(host, 'b')).toEqual({ kind: 'default', - ref: 'library:concrete-drywall', + ref: 'library:preset-seattlegrey', }) }) @@ -181,8 +188,59 @@ describe('wall finish resolution order', () => { expect(resolveWallFaceChain(withSlot, 'a')).toEqual({ kind: 'ref', ref: 'library:slot' }) expect(resolveWallFaceChain(host, 'a')).toEqual({ kind: 'default', + ref: 'library:preset-seattlegrey', + }) + }) + + test('an unpainted face wears Seattle grey; a painted face keeps its paint, raw drywall included', () => { + const plain = WallNode.parse({ start: [0, 0], end: [4, 0] }) + expect(DEFAULT_INTERIOR_WALL_PAINT).toBe('library:preset-seattlegrey') + expect(getMaterialPresetByRef(DEFAULT_INTERIOR_WALL_PAINT)?.mapProperties.color).toBe('#d8d6d1') + expect(MATERIAL_CATALOG.find((m) => m.id === 'preset-seattlegrey')?.label).toBe('Seattle grey') + for (const face of ['a', 'b'] as const) + expect(resolveWallFaceChain(plain, face)).toEqual({ + kind: 'default', + ref: DEFAULT_INTERIOR_WALL_PAINT, + }) + // Raw drywall is still a finish to pick on purpose. + const painted = { ...plain, slots: { a: 'library:concrete-drywall', b: 'library:preset-sage' } } + expect(getMaterialPresetByRef('library:concrete-drywall')).not.toBeNull() + expect(resolveWallFaceChain(painted, 'a')).toEqual({ + kind: 'ref', ref: 'library:concrete-drywall', }) + expect(resolveWallFaceChain(painted, 'b')).toEqual({ kind: 'ref', ref: 'library:preset-sage' }) + }) + + test("Seattle grey stays inside: an exterior face keeps raw drywall, a partition's faces go grey", () => { + const at = (frontSide: string, backSide: string) => { + const wall = WallNode.parse({ start: [0, 0], end: [4, 0], frontSide, backSide }) + return (['a', 'b'] as const).map((face) => { + const chain = resolveWallFaceChain(wall, face) + return chain.kind === 'default' ? chain.ref : chain.kind + }) + } + expect(DEFAULT_EXTERIOR_WALL_FINISH).toBe('library:concrete-drywall') + const grey = DEFAULT_INTERIOR_WALL_PAINT + const drywall = DEFAULT_EXTERIOR_WALL_FINISH + // An exterior wall: drywall outside (the default before the interior paint), grey inside. + expect(at('exterior', 'interior')).toEqual([drywall, grey]) + expect(at('interior', 'exterior')).toEqual([grey, drywall]) + expect(at('exterior', 'unknown')).toEqual([drywall, grey]) + // A partition, or a wall whose rooms are not detected yet: grey both faces. + expect(at('interior', 'interior')).toEqual([grey, grey]) + expect(at('unknown', 'unknown')).toEqual([grey, grey]) + // Outdoors on both sides: no inside face. + expect(at('exterior', 'exterior')).toEqual([drywall, drywall]) + // The face's slot declaration says the same, and paint on an exterior face still wins. + const outside = WallNode.parse({ start: [0, 0], end: [4, 0], frontSide: 'exterior' }) + expect(getWallFaceDefault(outside, 'a')).toBe(drywall) + expect(wallSlots(outside).find((slot) => slot.slotId === 'a')?.default).toBe(drywall) + expect(wallSlots(outside).find((slot) => slot.slotId === 'b')?.default).toBe(grey) + expect(resolveWallFaceChain({ ...outside, slots: { a: 'library:preset-sage' } }, 'a')).toEqual({ + kind: 'ref', + ref: 'library:preset-sage', + }) }) test('later regions win and legacy inline finishes sit between slot and default', () => { diff --git a/packages/core/src/systems/wall/wall-finish.ts b/packages/core/src/systems/wall/wall-finish.ts index 544f731fde..9e8ee9725f 100644 --- a/packages/core/src/systems/wall/wall-finish.ts +++ b/packages/core/src/systems/wall/wall-finish.ts @@ -3,8 +3,8 @@ import { sampleWallPointsForRoomDetection, WALL_JUNCTION_TOLERANCE } from '../.. import type { AnyNode, AnyNodeId } from '../../schema' import { getEffectiveWallFaceMaterial, + getWallFaceDefault, WALL_FACE_REGION_LIMIT, - WALL_SLOT_DEFAULT, type WallFace, type WallFaceRegion, type WallNode, @@ -325,7 +325,8 @@ export function wallFinishMaterialIndex( /** * The wall's own chain for one face, in the order the renderer walks it: * `slots[face]` ref → legacy inline finish (per-face, then wall-wide) → the - * declared default. A dangling ref renders the declared default. + * face's default (`getWallFaceDefault`: the interior paint, or raw drywall on + * the exterior side). A dangling ref renders the face's default. */ export type WallFaceChainFinish = | { kind: 'ref'; ref: string } @@ -333,14 +334,15 @@ export type WallFaceChainFinish = | { kind: 'default'; ref: string } export function resolveWallFaceChain( - wall: Pick, + wall: Pick & + Partial>, face: WallFace, ): WallFaceChainFinish { const ref = wall.slots?.[face] if (ref) return { kind: 'ref', ref } const spec = getEffectiveWallFaceMaterial(wall, face) if (spec.materialPreset || spec.material) return { kind: 'legacy', spec } - return { kind: 'default', ref: WALL_SLOT_DEFAULT[face] } + return { kind: 'default', ref: getWallFaceDefault(wall, face) } } // Paint roles a wall resolves to (the paint tool offers `room:`): diff --git a/packages/core/src/systems/wall/wall-footprint.ts b/packages/core/src/systems/wall/wall-footprint.ts index 4a363ca878..393e81b6a9 100644 --- a/packages/core/src/systems/wall/wall-footprint.ts +++ b/packages/core/src/systems/wall/wall-footprint.ts @@ -72,11 +72,11 @@ export function getWallPlanFootprint(wallNode: WallNode, miterData: WallMiterDat const polygon: Point2D[] = [pStartRight, pEndRight] if (endJunction) { - polygon.push(endJunction.closing ?? wallEnd) + polygon.push(...(endJunction.closingPath ?? [endJunction.closing ?? wallEnd])) } polygon.push(pEndLeft, pStartLeft) if (startJunction) { - polygon.push(startJunction.closing ?? wallStart) + polygon.push(...(startJunction.closingPath ?? [startJunction.closing ?? wallStart])) } return polygon diff --git a/packages/core/src/systems/wall/wall-merge.test.ts b/packages/core/src/systems/wall/wall-merge.test.ts index e39218f1e4..9edb65d1da 100644 --- a/packages/core/src/systems/wall/wall-merge.test.ts +++ b/packages/core/src/systems/wall/wall-merge.test.ts @@ -106,11 +106,25 @@ describe('explicit wall merge', () => { ).toThrow('These walls have a different height.') }) - test('refuses anything that would change the layout', () => { + test('merges a straight run across a T: the wall meeting it stays on its body', () => { const a = wall([0, 0], [4, 0]) const b = wall([4, 0], [8, 0]) const tee = wall([4, 0], [4, 3]) - expect(() => planWallMerge(map([a, b, tee]), [a.id, b.id])).toThrow('Another wall') + const { changes, wallId } = planWallMerge(map([a, b, tee]), [a.id, b.id]) + const merged = changes.update.find((op) => op.id === wallId)!.data as Partial + expect([merged.start, merged.end]).toEqual([ + [0, 0], + [8, 0], + ]) + expect(changes.update.some((op) => op.id === tee.id)).toBe(false) + expect(changes.delete).toHaveLength(1) + }) + + test('refuses anything that would change the layout', () => { + const a = wall([0, 0], [4, 0]) + const b = wall([4, 0], [8, 0]) + const along = wall([4, 0], [6, 0]) + expect(() => planWallMerge(map([a, b, along]), [a.id, b.id])).toThrow('Another wall') const corner = wall([4, 0], [4, 4]) expect(() => planWallMerge(map([a, corner]), [a.id, corner.id])).toThrow('straight line') const thick = wall([4, 0], [8, 0], { thickness: 0.3 }) @@ -200,6 +214,8 @@ describe('explicit wall merge through the store', () => { rotation: [0, 0.25, 0], hingesSide: 'left', handleSide: 'right', + casingFaceA: true, + casingFaceB: false, }) kept.children = keptWindows.map((w) => w.id) absorbed.children = [absorbedWindow.id, absorbedDoor.id] @@ -212,6 +228,7 @@ describe('explicit wall merge through the store', () => { const moved = nodes[absorbedWindow.id] as WindowNode expect(moved.position[0]).toBeCloseTo(expectedX) expect(moved.side).toBe('back') + expect([moved.casingFaceA, moved.casingFaceB]).toEqual([false, false]) // A door on the reversed wall turns with its frame — depth and yaw — while // its hinges and handle, hung off that yaw, keep their stored side. const door = nodes[absorbedDoor.id] as DoorNode @@ -219,6 +236,8 @@ describe('explicit wall merge through the store', () => { expect(door.rotation[1]).toBeCloseTo(0.25 - Math.PI) expect(door.hingesSide).toBe('left') expect(door.handleSide).toBe('right') + // Its casing, kept per wall face, stays on the same side of the wall. + expect([door.casingFaceA, door.casingFaceB]).toEqual([false, true]) // The kept wall's own openings keep their side and their world place. const keptFirst = nodes[keptWindows[0]!.id] as WindowNode expect(keptFirst.side).toBeUndefined() diff --git a/packages/core/src/systems/wall/wall-merge.ts b/packages/core/src/systems/wall/wall-merge.ts index f1bfc9991b..5ad8408521 100644 --- a/packages/core/src/systems/wall/wall-merge.ts +++ b/packages/core/src/systems/wall/wall-merge.ts @@ -72,11 +72,13 @@ export function wallStyleMismatch( Math.abs((a.height ?? 0) - (b.height ?? 0)) > 1e-6 ) return 'height' - // Faces are compared as the merged wall will carry them: b read in a's direction. + // Faces are compared as the merged wall will carry them: b read in a's direction. An unpainted + // face's default follows its room side, which room detection reclassifies, so it is set aside. + const painted = (wall: WallNode) => ({ ...wall, frontSide: undefined, backSide: undefined }) for (const face of ['a', 'b'] as const) { if ( - JSON.stringify(resolveWallFaceChain(a, face)) !== - JSON.stringify(resolveWallFaceChain(alignedB, face)) + JSON.stringify(resolveWallFaceChain(painted(a), face)) !== + JSON.stringify(resolveWallFaceChain(painted(alignedB), face)) ) return `side ${face.toUpperCase()} finish` } @@ -327,13 +329,18 @@ export function resolveMergedWallEndpoints( * 0 front / π back). A wall read backwards turns that frame by 180° about Y, * so the face and the yaw swap and the caller mirrors depth. Hinges, handles * and swing hang off the node's own yaw (the plan symbol flips them from it), - * so they stay as stored. + * so they stay as stored. Door and window casing is kept per wall face, so it + * swaps faces too and stays on the same side of the wall. */ function reversedWallChildPatch(child: AnyNode): Partial { const patch: Record = {} if ('side' in child && (child.side === 'front' || child.side === 'back')) { patch.side = child.side === 'front' ? 'back' : 'front' } + if (child.type === 'door' || child.type === 'window') { + const [faceA, faceB] = [child.casingFaceA === true, child.casingFaceB === true] + if (faceA !== faceB) Object.assign(patch, { casingFaceA: faceB, casingFaceB: faceA }) + } if ('rotation' in child && Array.isArray(child.rotation)) { const yaw = child.rotation[1] + Math.PI patch.rotation = [ @@ -451,16 +458,29 @@ export function planWallMerge( } } if (!(next && joint)) throw Error('Merge walls that touch end to end.') + if (!areWallsCollinearAcrossPoint(merged, next, joint)) + throw Error('Merge walls that continue in a straight line.') + // A wall meeting the joint from the side stays T'd into the merged wall's + // body there; one running along the line would be buried in it. + const runX = merged.end[0] - merged.start[0] + const runZ = merged.end[1] - merged.start[1] + const alongRun = (wall: WallNode) => { + const free = getWallFreeEndpoint(wall, joint) + const x = free[0] - joint[0] + const z = free[1] - joint[1] + const length = Math.hypot(x, z) * Math.hypot(runX, runZ) + return length < 1e-12 || Math.abs(x * runZ - z * runX) / length < 1e-4 + } const atJoint = Object.values(virtual).filter( - (node) => + (node): node is WallNode => node?.type === 'wall' && + node.id !== merged.id && + node.id !== next.id && (node.parentId ?? null) === levelId && getWallEndpointAtPoint(node, joint) !== null, ) - if (atJoint.length !== 2) + if (atJoint.some(alongRun)) throw Error('Another wall meets this joint, so merging would disconnect it.') - if (!areWallsCollinearAcrossPoint(merged, next, joint)) - throw Error('Merge walls that continue in a straight line.') const mismatch = wallStyleMismatch(merged, next, { sides: false, heightOf: (wall) => getWallEffectiveHeightForNodes(wall, virtual), diff --git a/packages/core/src/systems/wall/wall-mitering.test.ts b/packages/core/src/systems/wall/wall-mitering.test.ts index cbe1b331d3..9be398d9e3 100644 --- a/packages/core/src/systems/wall/wall-mitering.test.ts +++ b/packages/core/src/systems/wall/wall-mitering.test.ts @@ -1,5 +1,6 @@ import { describe, expect, test } from 'bun:test' import type { WallNode } from '../../schema' +import { getWallPlanFootprint } from './wall-footprint' import { calculateLevelMiters, getWallMiterBoundaryPoints, pointToKey } from './wall-mitering' function wall(id: string, start: [number, number], end: [number, number]): WallNode { @@ -129,3 +130,97 @@ describe('junction grid prefilter', () => { expect(junction?.connectedWalls.map((cw) => cw.wall.id)).toEqual(['spur', 'long']) }) }) + +describe('outside corner with a partition in line', () => { + // Two outside walls 0.18 thick turn a corner at the origin: one runs off to + // -x, the other to +z, outdoors between them. A 0.11 partition carries the + // first one's line on to +x. + const outsideLeft = { + ...wall('wall_left', [-3, 0], [0, 0]), + thickness: 0.18, + frontSide: 'exterior', + backSide: 'interior', + } as WallNode + const outsideDown = { + ...wall('wall_down', [0, 0], [0, 3]), + thickness: 0.18, + frontSide: 'exterior', + backSide: 'interior', + } as WallNode + const partition = { + ...wall('wall_part', [0, 0], [3, 0]), + thickness: 0.11, + frontSide: 'interior', + backSide: 'interior', + } as WallNode + const walls = [outsideLeft, outsideDown, partition] + const near = (p: { x: number; y: number } | undefined, x: number, y: number) => + !!p && Math.abs(p.x - x) < 1e-9 && Math.abs(p.y - y) < 1e-9 + const inside = (polygon: { x: number; y: number }[], x: number, y: number) => { + let hit = false + for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) { + const a = polygon[i]! + const b = polygon[j]! + if (a.y > y !== b.y > y && x < ((b.x - a.x) * (y - a.y)) / (b.y - a.y) + a.x) hit = !hit + } + return hit + } + const corner = () => calculateLevelMiters(walls).junctionData.get(pointToKey({ x: 0, y: 0 }))! + + test('the outside faces miter to the corner', () => { + for (const id of ['wall_left', 'wall_down']) { + const ends = corner().get(id)! + expect(near(ends.left, -0.09, 0.09) || near(ends.right, -0.09, 0.09)).toBe(true) + } + }) + + test('the partition stops square at the inside face of the corner', () => { + const miter = calculateLevelMiters(walls) + const ends = miter.junctionData.get(pointToKey({ x: 0, y: 0 }))!.get('wall_part')! + expect(near(ends.left, 0.09, 0.055)).toBe(true) + expect(near(ends.right, 0.09, -0.055)).toBe(true) + const footprint = getWallPlanFootprint(partition, miter) + expect(Math.min(...footprint.map((p) => p.x))).toBeCloseTo(0.09, 9) + }) + + test("each room's own walls cover its side of the corner", () => { + const miter = calculateLevelMiters(walls) + const left = getWallPlanFootprint(outsideLeft, miter) + const down = getWallPlanFootprint(outsideDown, miter) + // The room beyond the line (z < 0) is walled by the left wall and the + // partition: the corner's half on its side is the left wall's. + for (const [x, y] of [ + [0.05, -0.05], + [0.08, -0.01], + [-0.05, -0.08], + ] as const) { + expect(inside(left, x, y)).toBe(true) + expect(inside(down, x, y)).toBe(false) + } + // The room between the partition and the down wall (x, z > 0) is theirs. + expect(inside(down, 0.05, 0.05)).toBe(true) + expect(inside(left, 0.05, 0.05)).toBe(false) + }) + + test('a corner of walls that are not outside walls keeps the shared miter', () => { + const indoors = walls.map( + (w) => ({ ...w, frontSide: 'interior', backSide: 'interior' }) as WallNode, + ) + const ends = calculateLevelMiters(indoors) + .junctionData.get(pointToKey({ x: 0, y: 0 }))! + .get('wall_part') + expect(ends?.closing).toBeUndefined() + }) +}) + +describe('a wall T-joined into a wall body', () => { + test('ends square on the host face, not in a wedge to its middle', () => { + const host = wall('wall_host', [-3, 0], [3, 0]) + const stem = { ...wall('wall_stem', [0, 0], [0, 2]), thickness: 0.1 } as WallNode + const miter = calculateLevelMiters([host, stem]) + const ends = miter.junctionData.get(pointToKey({ x: 0, y: 0 }))!.get('wall_stem')! + expect(ends.closing?.y).toBeCloseTo(0.05, 9) + const footprint = getWallPlanFootprint(stem, miter) + expect(Math.min(...footprint.map((p) => p.y))).toBeCloseTo(0.05, 9) + }) +}) diff --git a/packages/core/src/systems/wall/wall-mitering.ts b/packages/core/src/systems/wall/wall-mitering.ts index 65a6cfbf09..0ada55a42c 100644 --- a/packages/core/src/systems/wall/wall-mitering.ts +++ b/packages/core/src/systems/wall/wall-mitering.ts @@ -25,7 +25,12 @@ interface LineEquation { } // Map of wallId -> { left?: Point2D, right?: Point2D } for each junction -type WallIntersections = Map +// `closingPath` (left to right) closes an end through several points where one +// `closing` point can't. +type WallIntersections = Map< + string, + { left?: Point2D; right?: Point2D; closing?: Point2D; closingPath?: Point2D[] } +> // Map of junctionKey -> WallIntersections type JunctionData = Map @@ -293,6 +298,162 @@ interface ProcessedWall { halfThickness: number // Used to bound the miter joint against runaway spikes isPassthrough: boolean // True if wall passes through junction (T-junction) wallId: string + /** An outside wall: one face is outdoors (`frontSide` / `backSide`). */ + outside: boolean + /** Unit direction out of the junction, and its left normal. */ + dir: Point2D + normal: Point2D + /** The body across `normal` from the meeting point: edge B at `lo`, edge A at `hi`. */ + lo: number + hi: number +} + +function isOutsideWall(wall: WallNode) { + return wall.frontSide === 'exterior' || wall.backSide === 'exterior' +} + +/** Each wall's joint with its neighbours round the junction (sorted by angle). */ +function miterAdjacentWalls( + processedWalls: ProcessedWall[], + meetingPoint: Point2D, +): WallIntersections { + const wallIntersections: WallIntersections = new Map() + const n = processedWalls.length + + // Calculate intersections between adjacent walls (exactly like demo) + for (let i = 0; i < n; i++) { + const wall1 = processedWalls[i]! + const wall2 = processedWalls[(i + 1) % n]! + + // Intersect left edge of wall1 with right edge of wall2 + const det = wall1.edgeA.a * wall2.edgeB.b - wall2.edgeB.a * wall1.edgeA.b + + // If lines are parallel (det ≈ 0), skip this intersection - walls will use defaults + if (Math.abs(det) < 1e-9) { + continue + } + + const p = { + x: (wall1.edgeA.b * wall2.edgeB.c - wall2.edgeB.b * wall1.edgeA.c) / det, + y: (wall2.edgeB.a * wall1.edgeA.c - wall1.edgeA.a * wall2.edgeB.c) / det, + } + + // Miter limit: `det` only catches walls that are *exactly* parallel. Two + // walls meeting at a shallow angle have a small-but-nonzero `det`, so `p` + // lands far from the junction (∝ 1/sin θ) and the wall renders as an + // infinite spike. Reject any joint farther than MITER_LIMIT half-thicknesses + // from the meeting point — those walls fall back to a square joint. + const maxMiter = MITER_LIMIT * Math.max(wall1.halfThickness, wall2.halfThickness) + const dx = p.x - meetingPoint.x + const dy = p.y - meetingPoint.y + if ( + !(Number.isFinite(p.x) && Number.isFinite(p.y)) || + dx * dx + dy * dy > maxMiter * maxMiter + ) { + continue + } + + // Only assign intersection to non-passthrough walls + // Passthrough walls don't receive junction data (their geometry doesn't change) + if (!wall1.isPassthrough) { + if (!wallIntersections.has(wall1.wallId)) { + wallIntersections.set(wall1.wallId, {}) + } + wallIntersections.get(wall1.wallId)!.left = p + } + + if (!wall2.isPassthrough) { + if (!wallIntersections.has(wall2.wallId)) { + wallIntersections.set(wall2.wallId, {}) + } + wallIntersections.get(wall2.wallId)!.right = p + } + } + + return wallIntersections +} + +// Walls within about 15° of each other don't make an outside corner. +const CORNER_MIN_SINE = Math.sin(Math.PI / 12) +// Walls within about 1° of each other run in line. +const IN_LINE_SINE = Math.sin(Math.PI / 180) + +const dot2 = (a: Point2D, b: Point2D) => a.x * b.x + a.y * b.y +const cross2 = (a: Point2D, b: Point2D) => a.x * b.y - a.y * b.x + +/** + * An outside corner keeps its own miter when a partition carries one of its + * walls on past the corner (two outside walls at an angle, one inside wall in + * line with one of them): the outside faces miter to the corner, the partition + * stops square at the other outside wall's inside face, and the in-line outside + * wall fills the corner on the partition's room side. So each room's own walls + * cover its side of the corner, and its floor and ceiling stop at them, where a + * three-way miter would notch the corner. Null for any other junction. + */ +function outsideCornerIntersections( + processedWalls: ProcessedWall[], + meetingPoint: Point2D, +): WallIntersections | null { + if (processedWalls.length !== 3 || processedWalls.some((wall) => wall.isPassthrough)) return null + const outside = processedWalls.filter((wall) => wall.outside) + const inside = processedWalls.find((wall) => !wall.outside) + if (outside.length !== 2 || !inside) return null + const inLine = outside.find( + (wall) => + Math.abs(cross2(wall.dir, inside.dir)) < IN_LINE_SINE && dot2(wall.dir, inside.dir) < 0, + ) + const across = outside.find((wall) => wall !== inLine) + if (!(inLine && across) || Math.abs(cross2(inLine.dir, across.dir)) < CORNER_MIN_SINE) { + return null + } + + const corner = miterAdjacentWalls(outside, meetingPoint) + const inLineEnds = corner.get(inLine.wallId) + const acrossEnds = corner.get(across.wallId) + if (!(inLineEnds?.left && inLineEnds.right && acrossEnds?.left && acrossEnds.right)) return null + + // Of the L's two joints, the one toward the partition is its inside corner. + const toward = (point: Point2D) => + dot2({ x: point.x - meetingPoint.x, y: point.y - meetingPoint.y }, inside.dir) + // Where a line parallel to the partition, `offset` across it, meets the + // across wall's face toward the partition. + const face = dot2(inside.dir, across.normal) > 0 ? across.hi : across.lo + const rate = dot2(inside.dir, across.normal) + const onFace = (offset: number): Point2D => { + const origin = { + x: meetingPoint.x + inside.normal.x * offset, + y: meetingPoint.y + inside.normal.y * offset, + } + const along = (face - offset * dot2(inside.normal, across.normal)) / rate + return { x: origin.x + inside.dir.x * along, y: origin.y + inside.dir.y * along } + } + // The shared line's point on that face: the in-line wall fills the corner up to it. + const heel = onFace(0) + + corner.set(inLine.wallId, { + left: inLineEnds.left, + right: inLineEnds.right, + closingPath: + toward(inLineEnds.left) > toward(inLineEnds.right) + ? [heel, meetingPoint] + : [meetingPoint, heel], + }) + corner.set( + across.wallId, + toward(acrossEnds.left) > toward(acrossEnds.right) + ? { left: heel, right: acrossEnds.right } + : { left: acrossEnds.left, right: heel }, + ) + const left = onFace(inside.hi) + const right = onFace(inside.lo) + corner.set(inside.wallId, { + left, + right, + // Square across the partition: closing through the junction would reach + // back into the corner. + closing: { x: (left.x + right.x) / 2, y: (left.y + right.y) / 2 }, + }) + return corner } function calculateJunctionIntersections( @@ -335,6 +496,11 @@ function calculateJunctionIntersections( edgeB, isPassthrough: true, halfThickness: halfT, + outside: isOutsideWall(wall), + dir: { x: v.x / L, y: v.y / L }, + normal: nUnit, + lo: b, + hi: a, }) } } else { @@ -361,6 +527,11 @@ function calculateJunctionIntersections( edgeB, isPassthrough: false, halfThickness: halfT, + outside: isOutsideWall(wall), + dir: { x: v.x / L, y: v.y / L }, + normal: nUnit, + lo: b, + hi: a, }) } } @@ -373,75 +544,38 @@ function calculateJunctionIntersections( return a.wallId < b.wallId ? -1 : a.wallId > b.wallId ? 1 : 0 }) - const wallIntersections: WallIntersections = new Map() - const n = processedWalls.length - - if (n < 2) return wallIntersections - - // Calculate intersections between adjacent walls (exactly like demo) - for (let i = 0; i < n; i++) { - const wall1 = processedWalls[i]! - const wall2 = processedWalls[(i + 1) % n]! - - // Intersect left edge of wall1 with right edge of wall2 - const det = wall1.edgeA.a * wall2.edgeB.b - wall2.edgeB.a * wall1.edgeA.b + if (processedWalls.length < 2) return new Map() - // If lines are parallel (det ≈ 0), skip this intersection - walls will use defaults - if (Math.abs(det) < 1e-9) { - continue - } - - const p = { - x: (wall1.edgeA.b * wall2.edgeB.c - wall2.edgeB.b * wall1.edgeA.c) / det, - y: (wall2.edgeB.a * wall1.edgeA.c - wall1.edgeA.a * wall2.edgeB.c) / det, - } - - // Miter limit: `det` only catches walls that are *exactly* parallel. Two - // walls meeting at a shallow angle have a small-but-nonzero `det`, so `p` - // lands far from the junction (∝ 1/sin θ) and the wall renders as an - // infinite spike. Reject any joint farther than MITER_LIMIT half-thicknesses - // from the meeting point — those walls fall back to a square joint. - const maxMiter = MITER_LIMIT * Math.max(wall1.halfThickness, wall2.halfThickness) - const dx = p.x - meetingPoint.x - const dy = p.y - meetingPoint.y - if ( - !(Number.isFinite(p.x) && Number.isFinite(p.y)) || - dx * dx + dy * dy > maxMiter * maxMiter - ) { - continue - } + if (!connectedWalls.some(({ wall }) => wall.justification !== undefined)) { + const corner = outsideCornerIntersections(processedWalls, meetingPoint) + if (corner) return corner + } - // Only assign intersection to non-passthrough walls - // Passthrough walls don't receive junction data (their geometry doesn't change) - if (!wall1.isPassthrough) { - if (!wallIntersections.has(wall1.wallId)) { - wallIntersections.set(wall1.wallId, {}) - } - wallIntersections.get(wall1.wallId)!.left = p - } + const wallIntersections = miterAdjacentWalls(processedWalls, meetingPoint) - if (!wall2.isPassthrough) { - if (!wallIntersections.has(wall2.wallId)) { - wallIntersections.set(wall2.wallId, {}) + const host = connectedWalls.find(({ endType }) => endType === 'passthrough') + if (host) { + // A wall T'd into another's body ends square on its face: both edges + // already meet the host's near face, and closing through the reference + // vertex would add a triangular sliver inside the host. + for (const entry of connectedWalls) { + if (entry.endType === 'passthrough') continue + const edges = wallIntersections.get(entry.wall.id) + if (edges?.left && edges.right) { + edges.closing = { + x: (edges.left.x + edges.right.x) / 2, + y: (edges.left.y + edges.right.y) / 2, + } } - wallIntersections.get(wall2.wallId)!.right = p } } if (connectedWalls.some(({ wall }) => wall.justification !== undefined)) { - const host = connectedWalls.find(({ endType }) => endType === 'passthrough') for (const entry of connectedWalls) { if (entry.endType === 'passthrough') continue const edges = wallIntersections.get(entry.wall.id) - if (!edges) continue - if (host && edges.left && edges.right) { - // Both edges already meet the host's near face. Closing through the - // reference vertex would add a triangular sliver inside the host. - edges.closing = { - x: (edges.left.x + edges.right.x) / 2, - y: (edges.left.y + edges.right.y) / 2, - } - } else if (connectedWalls.length === 2) { + if (!edges || (host && edges.left && edges.right)) continue + if (connectedWalls.length === 2) { const other = connectedWalls.find((candidate) => candidate !== entry)! if (other.endType === 'passthrough') continue const bodyLine = (candidate: typeof entry) => { diff --git a/packages/core/src/systems/wall/wall-move.ts b/packages/core/src/systems/wall/wall-move.ts index 0197de2e93..03c375cace 100644 --- a/packages/core/src/systems/wall/wall-move.ts +++ b/packages/core/src/systems/wall/wall-move.ts @@ -6,20 +6,22 @@ export type WallPlanPoint = [number, number] // Unit direction vector (x,z) to constrain move deltas along. export type WallMoveAxis = [number, number] export type WallMoveEndpoint = 'start' | 'end' +/** A wall's line as the move planners read it: invisible walls move by the same rules. */ +export type WallMoveLine = Pick & { id: string } -export type WallMoveBridgePlan> = { +export type WallMoveBridgePlan = { wall: TWall originalPoint: WallPlanPoint movedEndpoint: WallMoveEndpoint } -export type WallMoveLinkedWallTargetPlan> = { +export type WallMoveLinkedWallTargetPlan = { wall: TWall originalPoint: WallPlanPoint targetPoint: WallPlanPoint } -export type WallMoveJunctionPlan> = { +export type WallMoveJunctionPlan = { linkedWallsToMove: TWall[] linkedWallTargetPlans: Array> bridgePlans: Array> @@ -66,7 +68,7 @@ function otherWallEndpoint(wall: Pick, point: WallPla } type MoveWallRelation = 'same-direction' | 'opposite-direction' | 'off-axis' | 'stationary' -type RelatedWallEntry> = { +type RelatedWallEntry = { wall: TWall relation: MoveWallRelation } @@ -111,7 +113,7 @@ function getMoveWallRelation( * matchPoint/targetPoint pair encodes the pivot, not the original ↔ next * endpoint mapping. */ -export function getLinkedWallUpdates>( +export function getLinkedWallUpdates( linkedWalls: Array<{ wall: TWall matchPoint?: WallPlanPoint @@ -150,7 +152,7 @@ export function getLinkedWallUpdates>( +export function getPlannedLinkedWallUpdates( plan: WallMoveJunctionPlan, originalStart: WallPlanPoint, originalEnd: WallPlanPoint, @@ -183,7 +185,7 @@ export function getPlannedLinkedWallUpdates>( +export function planWallMoveJunctions( linkedWalls: TWall[], originalStart: WallPlanPoint, originalEnd: WallPlanPoint, @@ -321,3 +323,72 @@ export function planWallMoveJunctions>( + walls: readonly TWall[], + originalStart: WallPlanPoint, + originalEnd: WallPlanPoint, + nextStart: WallPlanPoint, + nextEnd: WallPlanPoint, +): Array<{ id: TWall['id']; start: WallPlanPoint; end: WallPlanPoint }> { + const dx = originalEnd[0] - originalStart[0] + const dz = originalEnd[1] - originalStart[1] + const length = Math.hypot(dx, dz) + const mx = nextEnd[0] - nextStart[0] + const mz = nextEnd[1] - nextStart[1] + const movedLength = Math.hypot(mx, mz) + if (length < AXIS_EPSILON || movedLength < AXIS_EPSILON) return [] + const ux = dx / length + const uz = dz / length + + const updates: Array<{ id: TWall['id']; start: WallPlanPoint; end: WallPlanPoint }> = [] + for (const wall of walls) { + if ((wall.curveOffset ?? 0) !== 0) continue + if (wallTouchesPoint(wall, originalStart) || wallTouchesPoint(wall, originalEnd)) continue + const next = { start: wall.start, end: wall.end } + let moved = false + for (const end of ['start', 'end'] as const) { + const point = wall[end] + const along = (point[0] - originalStart[0]) * ux + (point[1] - originalStart[1]) * uz + const across = (point[1] - originalStart[1]) * ux - (point[0] - originalStart[0]) * uz + if ( + Math.abs(across) > ATTACH_TOLERANCE || + along <= ATTACH_TOLERANCE || + along >= length - ATTACH_TOLERANCE + ) { + continue + } + const other = end === 'start' ? wall.end : wall.start + const wx = point[0] - other[0] + const wz = point[1] - other[1] + const denominator = wx * mz - wz * mx + if (Math.abs(denominator) <= ATTACH_MIN_SINE * Math.hypot(wx, wz) * movedLength) continue + // other + w·s meets nextStart + m·t. + const ox = nextStart[0] - other[0] + const oz = nextStart[1] - other[1] + const s = (ox * mz - oz * mx) / denominator + const t = (ox * wz - oz * wx) / denominator + if (t < -AXIS_EPSILON || t > 1 + AXIS_EPSILON) continue + const target: WallPlanPoint = [other[0] + wx * s, other[1] + wz * s] + if (Math.hypot(target[0] - other[0], target[1] - other[1]) < ATTACHED_MIN_LENGTH) continue + next[end] = target + moved = true + } + if (moved) updates.push({ id: wall.id, start: next.start, end: next.end }) + } + return updates +} diff --git a/packages/core/src/systems/wall/wall-top.test.ts b/packages/core/src/systems/wall/wall-top.test.ts index c568f9c950..4df19975e8 100644 --- a/packages/core/src/systems/wall/wall-top.test.ts +++ b/packages/core/src/systems/wall/wall-top.test.ts @@ -36,6 +36,11 @@ describe('resolveWallTop', () => { expect(resolveWallTop({}, 3, -0.4)).toBe(3) }) + test('a railing never follows its storey: its own height, else a 36 in guard, over its base', () => { + expect(resolveWallTop({ wallType: 'railing', height: 1.0668 }, 1.0668, 0.2)).toBeCloseTo(1.2668) + expect(resolveWallTop({ wallType: 'railing' }, 3, 0.2)).toBeCloseTo(0.2 + 0.9144) + }) + test('an authored storey-height wall ends at the covering underside, not its support plus height', () => { expect(resolveWallTop({ height: 3.6 }, 3.6, 0.05)).toBeCloseTo(3.6) expect(resolveWallEffectiveHeight({ height: 3.6 }, 3.6, 0.05)).toBeCloseTo(3.55) diff --git a/packages/core/src/systems/wall/wall-top.ts b/packages/core/src/systems/wall/wall-top.ts index 793875fbd5..59f90c8531 100644 --- a/packages/core/src/systems/wall/wall-top.ts +++ b/packages/core/src/systems/wall/wall-top.ts @@ -1,3 +1,4 @@ +import { RAILING_GUARD_HEIGHT } from '../../schema/nodes/railing-wall' import type { WallNode } from '../../schema/nodes/wall' /** @@ -10,9 +11,11 @@ import type { WallNode } from '../../schema/nodes/wall' export const MIN_WALL_HEIGHT = 0.5 export function wallFollowsStorey( - wall: Pick, + wall: Pick, authoredStoreyHeight: number | null, ): boolean { + // A railing is a guard as tall as itself, never the storey (36 in when it says nothing). + if (wall.wallType === 'railing') return false return ( wall.height == null || (authoredStoreyHeight !== null && @@ -34,13 +37,14 @@ export function wallFollowsStorey( * Returns the top in level-local Y (same frame as `electedBase`). */ export function resolveWallTop( - wall: Pick, + wall: Pick, storeyHeight: number, electedBase: number, authoredStoreyHeight: number | null = storeyHeight, ): number { if (wallFollowsStorey(wall, authoredStoreyHeight)) return storeyHeight - return electedBase + wall.height! + // Only a railing reaches here with no height of its own. + return electedBase + (wall.height ?? RAILING_GUARD_HEIGHT) } /** diff --git a/packages/core/src/systems/wall/wall-topology.test.ts b/packages/core/src/systems/wall/wall-topology.test.ts index 3e16a8b6f6..4842f47afa 100644 --- a/packages/core/src/systems/wall/wall-topology.test.ts +++ b/packages/core/src/systems/wall/wall-topology.test.ts @@ -1031,3 +1031,49 @@ describe('planJoinOpenWallEnd', () => { ).toEqual([]) }) }) + +describe('a wall started in a corner block', () => { + // Two 0.18 walls turn a corner at the origin. + const across = WallNode.parse({ + id: 'wall_across', + parentId: LEVEL_ID, + start: [-3, 0], + end: [0, 0], + thickness: 0.18, + }) + const down = WallNode.parse({ + id: 'wall_down', + parentId: LEVEL_ID, + start: [0, 0], + end: [0, 3], + thickness: 0.18, + }) + + test('joins the corner instead of splitting a stub off the wall', () => { + // 8 cm short of the corner, inside the other wall's body. + const result = planWallInsertion(nodeMap([across, down]), { + levelId: LEVEL_ID, + start: [-0.08, 0], + end: [3, 0], + joinRadius: 0.05, + }) + expect(result.ok).toBe(true) + if (!result.ok) return + expect(result.plan.resolvedStart).toEqual([0, 0]) + expect(result.plan.changes.delete).toEqual([]) + expect(result.plan.insertedWalls).toHaveLength(1) + }) + + test('past the corner block it still T-joins the wall', () => { + const result = planWallInsertion(nodeMap([across, down]), { + levelId: LEVEL_ID, + start: [-0.5, 0], + end: [-0.5, -2], + joinRadius: 0.05, + }) + expect(result.ok).toBe(true) + if (!result.ok) return + expect(result.plan.resolvedStart).toEqual([-0.5, 0]) + expect(result.plan.changes.delete).toEqual(['wall_across']) + }) +}) diff --git a/packages/core/src/systems/wall/wall-topology.ts b/packages/core/src/systems/wall/wall-topology.ts index cf550e1d29..90189e49ec 100644 --- a/packages/core/src/systems/wall/wall-topology.ts +++ b/packages/core/src/systems/wall/wall-topology.ts @@ -8,11 +8,13 @@ import { type DoorNode, getScaledDimensions, type ItemNode, + SeparatorNode, type WallNode, WallNode as WallSchema, type WindowNode, } from '../../schema' import { getWallArcData, getWallCurveFrameAt, getWallCurveLength, isCurvedWall } from './wall-curve' +import { getWallFaceOffsets } from './wall-frame' import type { WallPlanPoint } from './wall-move' export const WALL_MIN_LENGTH = 0.01 @@ -185,6 +187,30 @@ function projectPointOntoWallCenterline( } } +/** + * How near `end` of `host` a join on `host` counts as that end: the split + * epsilon, or as far as the bodies of the other walls meeting there reach, so a + * join inside a corner block takes the corner rather than splitting off a stub + * of `host` buried in it. + */ +function cornerBlockReach( + end: WallPlanPoint, + host: WallNode, + walls: WallNode[], + ignoreWallIds: ReadonlySet, +) { + let reach = WALL_SPLIT_ENDPOINT_EPSILON + for (const other of walls) { + if (other.id === host.id || ignoreWallIds.has(other.id)) continue + if (distanceSquared(other.start, end) > 1e-12 && distanceSquared(other.end, end) > 1e-12) { + continue + } + const { a, b } = getWallFaceOffsets(other) + reach = Math.max(reach, a, -b) + } + return reach +} + function nearestWallProjection( point: WallPlanPoint, walls: WallNode[], @@ -199,11 +225,10 @@ function nearestWallProjection( if (!projection) continue const candidateDistance = distanceSquared(point, projection.point) if (candidateDistance > radius * radius || candidateDistance >= bestDistance) continue - const corner = ([wall.start, wall.end] as WallPlanPoint[]).find( - (candidate) => - distanceSquared(projection.point, candidate) <= - WALL_SPLIT_ENDPOINT_EPSILON * WALL_SPLIT_ENDPOINT_EPSILON, - ) + const corner = ([wall.start, wall.end] as WallPlanPoint[]).find((candidate) => { + const reach = cornerBlockReach(candidate, wall, walls, ignoreWallIds) + return distanceSquared(projection.point, candidate) <= reach * reach + }) best = corner ? { wall: null, point: [corner[0], corner[1]], wallT: projection.wallT } : { wall, ...projection } @@ -363,7 +388,10 @@ function segmentCurveOffset(wall: WallNode, startT: number, endT: number) { return arc.direction * arc.radius * (1 - Math.cos(angle / 2)) } -function attachmentSpan(node: AnyNode): { min: number; max: number; center: number } | null { +/** Where a door, window or wall item sits along its wall: metres from the wall start. */ +export function wallAttachmentSpan( + node: AnyNode, +): { min: number; max: number; center: number } | null { if (node.type === 'door') { const door = node as DoorNode return { @@ -470,7 +498,7 @@ export function splitWall( const segmentChildren = segments.map(() => [] as AnyNodeId[]) const updates: WallTopologyChanges['update'] = [] for (const attachment of wallAttachments(wall, nodes)) { - const span = attachmentSpan(attachment) + const span = wallAttachmentSpan(attachment) if (!span) return null const segmentIndex = parameters.slice(0, -1).findIndex((startT, index) => { const endT = parameters[index + 1]! @@ -505,6 +533,16 @@ export function planWallInsertion( joinRadius: number wallDefaults?: Partial mintId?: () => string + /** + * Draw along walls that already cover the span instead of refusing: the + * caller has the new wall take that stretch over (`finishWallEdit`). + */ + replaceCovered?: boolean + /** + * Leave the walls the new one meets whole: an end on a wall's body joins + * it there as a T (rooms and miters read the junction off the body), and a + * wall it crosses stays one wall, the new one split either side of it. + */ }, ): WallInsertionResult { const walls = Object.values(nodes).filter( @@ -514,7 +552,7 @@ export function planWallInsertion( const startProjection = nearestWallProjection(args.start, walls, args.joinRadius) const resolvedStart = startProjection?.point ?? args.start const resolvedEnd = endProjection?.point ?? args.end - if (wallSegmentsCoverSegment(resolvedStart, resolvedEnd, walls)) { + if (!args.replaceCovered && wallSegmentsCoverSegment(resolvedStart, resolvedEnd, walls)) { return { ok: false, reason: 'covered-existing-wall' } } const crossings = walls @@ -632,6 +670,119 @@ export function planWallInsertion( return { ok: true, plan } } +/** + * The stretches of `start` → `end` no line already closes rooms along: an invisible wall on it or + * a straight wall's reference line. Two lines on top of each other close no room; they leave a + * sliver between them. + */ +function uncoveredStretches( + start: WallPlanPoint, + end: WallPlanPoint, + lines: readonly { start: WallPlanPoint; end: WallPlanPoint }[], +): [WallPlanPoint, WallPlanPoint][] { + const length = Math.hypot(end[0] - start[0], end[1] - start[1]) + const dir = [(end[0] - start[0]) / length, (end[1] - start[1]) / length] as const + const along = (point: WallPlanPoint) => + (point[0] - start[0]) * dir[0] + (point[1] - start[1]) * dir[1] + const at = (t: number): WallPlanPoint => + t <= 0 ? start : t >= length ? end : [start[0] + dir[0] * t, start[1] + dir[1] * t] + const covered = lines + .flatMap((line) => { + if ( + distanceToLine(line.start, start, end) > 1e-3 || + distanceToLine(line.end, start, end) > 1e-3 + ) + return [] + const a = along(line.start) + const b = along(line.end) + const lo = Math.max(0, Math.min(a, b)) + const hi = Math.min(length, Math.max(a, b)) + return hi - lo > 1e-6 ? [[lo, hi] as const] : [] + }) + .sort((a, b) => a[0] - b[0]) + const stretches: [WallPlanPoint, WallPlanPoint][] = [] + let reach = 0 + for (const [lo, hi] of covered) { + if (lo > reach + 1e-6) stretches.push([at(reach), at(lo)]) + reach = Math.max(reach, hi) + } + if (reach < length - 1e-6) stretches.push([at(reach), at(length)]) + return stretches +} + +/** + * An invisible wall drawn `start` → `end` (a room divider): a room separator, so + * rooms close on it as on a wall, but it is no wall and cuts none. An end landing on a wall joins + * it on its reference line, where the room graph meets it (a join inside a corner block takes the + * corner), and the line breaks either side of a wall it crosses so each piece tees into it. A + * stretch drawn over an invisible wall or along a wall's reference line adds nothing. Null when + * nothing is left to add, or it would be too short. + */ +export function planSeparatorInsertion( + nodes: Record, + args: { + levelId: AnyNodeId + start: WallPlanPoint + end: WallPlanPoint + joinRadius: number + mintId?: () => string + }, +): { + changes: WallTopologyChanges + separators: SeparatorNode[] + resolvedStart: WallPlanPoint + resolvedEnd: WallPlanPoint +} | null { + const walls = Object.values(nodes).filter( + (node): node is WallNode => node.type === 'wall' && node.parentId === args.levelId, + ) + const resolvedStart = + nearestWallProjection(args.start, walls, args.joinRadius)?.point ?? args.start + const resolvedEnd = nearestWallProjection(args.end, walls, args.joinRadius)?.point ?? args.end + if (!isSegmentLongEnough(resolvedStart, resolvedEnd)) return null + const crossings = walls + .flatMap((wall) => + isCurvedWall(wall) + ? curvedSegmentIntersections(resolvedStart, resolvedEnd, wall) + : [straightSegmentIntersection(resolvedStart, resolvedEnd, wall)].filter( + (crossing): crossing is WallSegmentIntersection => crossing !== null, + ), + ) + .map((crossing) => joinCrossingAtNearbyWallEndpoint(crossing, walls)) + .filter( + ({ draftT }) => draftT > WALL_INTERSECTION_EPSILON && draftT < 1 - WALL_INTERSECTION_EPSILON, + ) + .sort((left, right) => left.draftT - right.draftT) + const vertices = [resolvedStart] + for (const { point } of crossings) + if (!vertices.some((vertex) => distanceSquared(vertex, point) <= 1e-12)) vertices.push(point) + vertices.push(resolvedEnd) + const lines = [ + ...Object.values(nodes).filter( + (node): node is SeparatorNode => node.type === 'separator' && node.parentId === args.levelId, + ), + ...walls.filter((wall) => !isCurvedWall(wall)), + ] + const separators = vertices + .slice(0, -1) + .flatMap((start, index) => uncoveredStretches(start, vertices[index + 1]!, lines)) + .filter(([from, to]) => isSegmentLongEnough(from, to)) + .map(([start, end]) => + SeparatorNode.parse({ id: args.mintId?.(), parentId: args.levelId, start, end }), + ) + if (!separators.length) return null + return { + changes: { + create: separators.map((node) => ({ node, parentId: args.levelId })), + update: [], + delete: [], + }, + separators, + resolvedStart, + resolvedEnd, + } +} + function distanceToLine(point: WallPlanPoint, a: WallPlanPoint, b: WallPlanPoint) { const length = Math.hypot(b[0] - a[0], b[1] - a[1]) return Math.abs((point[0] - a[0]) * (b[1] - a[1]) - (point[1] - a[1]) * (b[0] - a[0])) / length @@ -739,7 +890,7 @@ function planWallEndJoin( const dz = (after.end[1] - after.start[1]) / length const oldLength = wallLength(before) for (const attachment of wallAttachments(before, adjusted)) { - const span = attachmentSpan(attachment) + const span = wallAttachmentSpan(attachment) if (!span) return false const oldPoint = getWallCurveFrameAt(before, span.center / oldLength).point const projection = isCurvedWall(after) diff --git a/packages/core/src/systems/wall/wall-types.test.ts b/packages/core/src/systems/wall/wall-types.test.ts new file mode 100644 index 0000000000..2add9a0000 --- /dev/null +++ b/packages/core/src/systems/wall/wall-types.test.ts @@ -0,0 +1,213 @@ +import { describe, expect, test } from 'bun:test' +import type { AnyNode, WallNode } from '../../schema' +import { SiteNode } from '../../schema/nodes/site' +import { newWallTypeId, WallTypeDefinition } from '../../schema/wall-type' +import { + assemblyThickness, + GYPSUM_HALF, + getWallAssemblyPreset, + isExteriorWallAssembly, + projectWallTypes, + STUCCO_3_COAT, + STUD_2X6, + STUD_SPACING_24, + WALL_ASSEMBLY_PRESETS, + WALL_FINISH_LIBRARY_REF, + WALL_TYPE_CORES, + WSP_SHEATHING, + wallAssemblyFaceFinish, + wallAssemblyFinishRef, + wallAssemblyFraming, + wallAssemblyPatch, + wallAssemblyToLegacy, + wallCladdingProducts, + wallTypeAssembly, + wallTypeCoreOf, +} from './wall-assembly' + +const IN = 0.0254 +const core = (id: string) => WALL_TYPE_CORES.find((entry) => entry.id === id)! + +/** A 2x6 at 24 in stucco wall with an inch of foam outside the sheathing. */ +const STUCCO_FOAM = wallTypeAssembly('custom-stucco-foam', [ + { role: 'finish', material: 'stucco', thickness: STUCCO_3_COAT }, + { role: 'insulation', material: 'rigid-foam', thickness: 1 * IN }, + { role: 'sheathing', material: 'osb', thickness: WSP_SHEATHING }, + { + role: 'structure', + core: true, + material: 'wood', + thickness: core('wood-2x6-24').thickness, + spacing: core('wood-2x6-24').spacing, + }, + { role: 'lining', material: 'drywall', thickness: GYPSUM_HALF }, +]) + +function wall(assembly = getWallAssemblyPreset('exterior-2x6-siding')!.assembly, extra = {}) { + return { + id: 'wall_a', + type: 'wall', + children: [], + start: [0, 0], + end: [4, 0], + frontSide: 'exterior', + backSide: 'interior', + ...wallAssemblyPatch(assembly), + ...extra, + } as unknown as WallNode +} + +describe('wall type placement, read from the stack', () => { + test('each preset lists under exterior when it has a cladding side, interior when both faces are lined', () => { + const exterior = WALL_ASSEMBLY_PRESETS.filter((preset) => + isExteriorWallAssembly(preset.assembly), + ).map((preset) => preset.id) + expect(exterior).toEqual([ + 'exterior-2x4-siding', + 'exterior-2x6-siding', + 'exterior-2x6-stucco', + 'exterior-2x6-brick', + 'exterior-cmu-stucco', + ]) + const interior = WALL_ASSEMBLY_PRESETS.filter( + (preset) => !isExteriorWallAssembly(preset.assembly), + ).map((preset) => preset.id) + // The furred block wall is drywall on both faces: a partition by its own layers. + expect(interior).toEqual([ + 'interior-2x4-drywall', + 'interior-2x6-plumbing', + 'cmu-8-furred-drywall', + ]) + }) + + test('a stack lined on one face only has an exterior side; bare on both is a partition', () => { + const block = { role: 'structure', core: true, material: 'cmu', thickness: 0.19 } as const + const lining = { role: 'lining', material: 'drywall', thickness: GYPSUM_HALF } as const + expect(isExteriorWallAssembly(wallTypeAssembly('custom-a', [block, lining]))).toBe(true) + expect(isExteriorWallAssembly(wallTypeAssembly('custom-b', [lining, block, lining]))).toBe( + false, + ) + expect(isExteriorWallAssembly(wallTypeAssembly('custom-c', [block]))).toBe(false) + expect(isExteriorWallAssembly(STUCCO_FOAM)).toBe(true) + }) +}) + +describe('project wall types', () => { + test('the layers set the thickness, and the core frames at its size and spacing', () => { + const patch = wallAssemblyPatch(STUCCO_FOAM) + const expected = STUCCO_3_COAT + 1 * IN + WSP_SHEATHING + STUD_2X6 + GYPSUM_HALF + expect(patch.thickness).toBeCloseTo(expected, 12) + expect(assemblyThickness(STUCCO_FOAM)).toBeCloseTo(expected, 12) + expect(wallAssemblyFraming({ assembly: STUCCO_FOAM })).toEqual({ + depth: STUD_2X6, + kind: 'wood', + }) + const framing = STUCCO_FOAM.layers.find((layer) => layer.core)! + expect(framing.spacing).toBeCloseTo(STUD_SPACING_24, 12) + expect(wallTypeCoreOf(STUCCO_FOAM)?.id).toBe('wood-2x6-24') + }) + + test('layers take the ids the presets use, so a stack WS5 can express stays editable', () => { + expect(STUCCO_FOAM.layers.map((layer) => layer.id)).toEqual([ + 'exterior', + 'insulation', + 'sheathing', + 'framing', + 'interior', + ]) + const plain = wallTypeAssembly('custom-plain', [ + { role: 'finish', material: 'siding', thickness: 0.75 * IN }, + { role: 'sheathing', material: 'osb', thickness: WSP_SHEATHING }, + { role: 'structure', core: true, material: 'wood', thickness: STUD_2X6 }, + { role: 'lining', material: 'drywall', thickness: GYPSUM_HALF }, + ]) + expect(wallAssemblyToLegacy(plain)?.framing.depth).toBe(STUD_2X6) + // A preset's own core (no spacing: the framer's default) reads as the 16 in one. + expect(wallTypeCoreOf(getWallAssemblyPreset('exterior-2x6-siding')!.assembly)?.id).toBe( + 'wood-2x6-16', + ) + expect(wallTypeCoreOf(getWallAssemblyPreset('exterior-cmu-stucco')!.assembly)?.id).toBe('cmu-8') + }) + + test('a project type round-trips through the site schema and a save, and legacy sites are unchanged', () => { + const id = newWallTypeId() + expect(id).toMatch(/^custom-[a-z0-9]{16}$/) + const type = WallTypeDefinition.parse({ + id, + label: '2x6 stucco + foam', + assembly: { ...STUCCO_FOAM, presetId: id }, + }) + const legacy = SiteNode.parse({ id: 'site_lot', children: ['building_house'] }) + expect(legacy.wallTypes).toBeUndefined() + const saved = JSON.parse(JSON.stringify({ ...legacy, wallTypes: [type] })) + const restored = SiteNode.parse(saved) + expect(restored.wallTypes).toEqual([type]) + const nodes = { [restored.id]: restored } as unknown as Record + expect(projectWallTypes(nodes, [restored.id])).toEqual([type]) + }) + + test('a type without a core, or with a preset-style id, does not parse; a bad saved entry is skipped', () => { + const coreless = { ...STUCCO_FOAM, layers: STUCCO_FOAM.layers.filter((layer) => !layer.core) } + expect( + WallTypeDefinition.safeParse({ id: 'custom-x', label: 'X', assembly: coreless }).success, + ).toBe(false) + expect( + WallTypeDefinition.safeParse({ id: 'exterior-2x6-siding', label: 'X', assembly: STUCCO_FOAM }) + .success, + ).toBe(false) + const good = { id: 'custom-good', label: 'Good', assembly: STUCCO_FOAM } + const site = { + ...SiteNode.parse({ id: 'site_lot' }), + wallTypes: [{ id: 'custom-bad', label: '' }, good, { ...good, label: 'Repeat' }], + } + const nodes = { [site.id]: site } as unknown as Record + expect(projectWallTypes(nodes, [site.id]).map((type) => type.label)).toEqual(['Good']) + }) +}) + +describe('finishes picked while drafting', () => { + const sage = 'library:siding-lap-sage' + const blush = 'library:preset-blush' + + test('each kind offers its own products, its default among them', () => { + for (const kind of ['siding', 'fiber-cement', 'stucco', 'brick']) { + const ids = wallCladdingProducts(kind).map((item) => `library:${item.id}`) + expect(ids).toContain(WALL_FINISH_LIBRARY_REF[kind]!) + } + expect(wallCladdingProducts('siding').every((item) => item.category === 'siding')).toBe(true) + expect(wallCladdingProducts('brick').every((item) => item.category === 'brick')).toBe(true) + expect(wallCladdingProducts('none')).toEqual([]) + }) + + test('the faces follow the exterior side: cladding outside, paint inside, either way round', () => { + const slots = { 'layer:exterior': sage, 'layer:interior': blush } + const front = wall(undefined, { slots }) + expect(wallAssemblyFinishRef(front)).toBe(sage) + expect(wallAssemblyFaceFinish(front, 'a')).toBe(sage) + expect(wallAssemblyFaceFinish(front, 'b')).toBe(blush) + const back = wall(undefined, { slots, frontSide: 'interior', backSide: 'exterior' }) + expect(wallAssemblyFaceFinish(back, 'a')).toBe(blush) + expect(wallAssemblyFaceFinish(back, 'b')).toBe(sage) + // No picks: the kind's own cladding outside, nothing inside (the slot default shows). + const plain = wall() + expect(wallAssemblyFaceFinish(plain, 'a')).toBe(WALL_FINISH_LIBRARY_REF.siding!) + expect(wallAssemblyFaceFinish(plain, 'b')).toBeNull() + }) + + test('a partition shows its paint on both faces', () => { + const partition = wall(getWallAssemblyPreset('interior-2x4-drywall')!.assembly, { + frontSide: 'interior', + backSide: 'interior', + slots: { 'layer:interior-back': blush, 'layer:interior': blush }, + }) + expect(wallAssemblyFaceFinish(partition, 'a')).toBe(blush) + expect(wallAssemblyFaceFinish(partition, 'b')).toBe(blush) + }) + + test('a product picked for siding gives way once the cladding is changed to stucco', () => { + const changed = wall(getWallAssemblyPreset('exterior-2x6-stucco')!.assembly, { + slots: { 'layer:exterior': sage }, + }) + expect(wallAssemblyFinishRef(changed)).toBe(WALL_FINISH_LIBRARY_REF.stucco!) + }) +}) diff --git a/packages/core/src/utils/structure-id.ts b/packages/core/src/utils/structure-id.ts index 0d86d0bec2..e944db61ea 100644 --- a/packages/core/src/utils/structure-id.ts +++ b/packages/core/src/utils/structure-id.ts @@ -1,4 +1,5 @@ import { comparePlateComponents, floorPlateId } from '../lib/floor-plate-id' +import { remapPorchOwner } from '../lib/porch-framing-sync' import type { SceneNodes } from '../lib/structure-kernel' import { reconcileSceneStructure, @@ -51,6 +52,8 @@ function remapReferences(value: T, ids: Map): // Only newly minted rooms are remapped; pick their colour from the final id before persistence. if (fields.type === 'zone' && typeof fields.id === 'string' && ids.has(fields.id)) changes.color = zoneColorForSeed(ids.get(fields.id)!) + const metadata = remapPorchOwner(fields.metadata as Record | undefined, ids) + if (metadata) changes.metadata = metadata for (const key of ['children', 'zoneIds', 'members']) { const references = fields[key] if (Array.isArray(references) && references.some((id) => ids.has(id))) { diff --git a/packages/core/src/utils/wall-face-migration.test.ts b/packages/core/src/utils/wall-face-migration.test.ts index 64e7853f8b..ea2feaee25 100644 --- a/packages/core/src/utils/wall-face-migration.test.ts +++ b/packages/core/src/utils/wall-face-migration.test.ts @@ -38,13 +38,18 @@ function oldSide(node: Raw, face: Face): Side { : 'exterior' } -function oldChain(node: Raw, side: Side): string { +function oldChain(node: Raw, face: Face, side: Side): string { const ref = node.slots?.[side] if (ref) return `ref:${ref}` const spec = getEffectiveWallSurfaceMaterial(node, side) if (spec.materialPreset) return `preset:${spec.materialPreset}` if (spec.material) return `inline:${JSON.stringify(spec.material)}` - return 'default:library:concrete-drywall' + // The default the migration leaves alone: raw drywall then; now the interior paint, with raw + // drywall kept on a face whose stored side is exterior. + const stored = face === 'a' ? node.frontSide : node.backSide + return stored === 'exterior' + ? 'default:library:concrete-drywall' + : 'default:library:preset-seattlegrey' } function oldBands(node: Raw) { @@ -73,7 +78,7 @@ function oldBands(node: Raw) { function oldFaceFinish(node: Raw, face: Face, y: number): string { const side = oldSide(node, face) const bands = oldBands(node) - if (!bands.enabled) return oldChain(node, side) + if (!bands.enabled) return oldChain(node, face, side) const band = y < bands.lowerTop ? 'lower' @@ -85,7 +90,7 @@ function oldFaceFinish(node: Raw, face: Face, y: number): string { ? 'top' : 'upper' const ref = node.slots?.[`${band}${SUFFIX[side]}`] - return ref ? `ref:${ref}` : oldChain(node, side) + return ref ? `ref:${ref}` : oldChain(node, face, side) } function oldTrimFace(node: Raw, side: Side): Face { diff --git a/packages/editor/src/components/editor-2d/floorplan-adjacent-walls-layer.test.ts b/packages/editor/src/components/editor-2d/floorplan-adjacent-walls-layer.test.ts new file mode 100644 index 0000000000..a173a8a47e --- /dev/null +++ b/packages/editor/src/components/editor-2d/floorplan-adjacent-walls-layer.test.ts @@ -0,0 +1,76 @@ +import { expect, test } from 'bun:test' +import { type AnyNode, BuildingNode, LevelNode, WallNode } from '@pascal-app/core' +import { normalizePersistedEditorLayoutState } from '../../store/use-editor' +import { adjacentWallLevels, adjacentWallOutlines } from './floorplan-adjacent-walls-layer' + +function house() { + const building = BuildingNode.parse({ id: 'building_adj' }) + const levels = ['ground', 'upper', 'roof'].map((name, level) => + LevelNode.parse({ + id: `level_adj_${name}`, + parentId: building.id, + level, + height: 3, + ...(name === 'roof' ? { metadata: { role: 'roof' } } : {}), + }), + ) + building.children = levels.map((level) => level.id) + const walls = [ + WallNode.parse({ + id: 'wall_adj_a', + parentId: levels[1]!.id, + start: [0, 0], + end: [6, 0], + thickness: 0.2, + }), + WallNode.parse({ + id: 'wall_adj_b', + parentId: levels[1]!.id, + start: [6, 0], + end: [6, 4], + thickness: 0.2, + }), + WallNode.parse({ id: 'wall_adj_c', parentId: levels[0]!.id, start: [0, 0], end: [6, 0] }), + ] + return Object.fromEntries( + [building, ...levels, ...walls].map((node) => [node.id, node]), + ) as Record +} + +test('the roof plan traces the top storey’s walls below, both faces, joined at the corner', () => { + const nodes = house() + expect(adjacentWallLevels(nodes, 'level_adj_roof', { below: true, above: true })).toEqual({ + below: 'level_adj_upper', + above: null, + }) + expect(adjacentWallLevels(nodes, 'level_adj_upper', { below: true, above: false })).toEqual({ + below: 'level_adj_ground', + above: null, + }) + const outlines = adjacentWallOutlines(nodes, 'level_adj_upper') + expect(outlines.map((outline) => outline.id).sort()).toEqual(['wall_adj_a', 'wall_adj_b']) + const points = outlines + .find((outline) => outline.id === 'wall_adj_a')! + .points.split(' ') + .map((pair) => pair.split(',').map(Number) as [number, number]) + const zs = points.map(([, z]) => z) + // Both faces of the 0.2 m wall, and mitred into the corner at x = 6 (past the centreline). + expect(Math.max(...zs) - Math.min(...zs)).toBeCloseTo(0.2) + expect(Math.max(...points.map(([x]) => x))).toBeCloseTo(6.1) +}) + +test('walls below start on for the roof plan and off for the floor plans, each kept as set', () => { + const fresh = normalizePersistedEditorLayoutState(undefined) + expect(fresh.showRoofWallsBelow).toBe(true) + expect(fresh.showWallsBelow).toBe(false) + // Saved before the roof plan had its own setting: the roof plan still starts on. + expect(normalizePersistedEditorLayoutState({ showWallsBelow: false }).showRoofWallsBelow).toBe( + true, + ) + const turnedOff = normalizePersistedEditorLayoutState({ + showRoofWallsBelow: false, + showWallsBelow: true, + }) + expect(turnedOff.showRoofWallsBelow).toBe(false) + expect(turnedOff.showWallsBelow).toBe(true) +}) diff --git a/packages/editor/src/components/editor-2d/floorplan-adjacent-walls-layer.tsx b/packages/editor/src/components/editor-2d/floorplan-adjacent-walls-layer.tsx new file mode 100644 index 0000000000..9c6dcc0908 --- /dev/null +++ b/packages/editor/src/components/editor-2d/floorplan-adjacent-walls-layer.tsx @@ -0,0 +1,186 @@ +'use client' + +import { + type AnyNode, + type AnyNodeId, + calculateLevelMiters, + getLevelAbove, + getLevelBelow, + getWallPlanFootprint, + type LevelNode, + type Point2D, + servesAsRoofLevel, + useScene, + type WallNode, +} from '@pascal-app/core' +import { memo, useMemo } from 'react' +import { useShallow } from 'zustand/react/shallow' +import useEditor from '../../store/use-editor' +import { useLevelWallCopyOffer } from '../ui/level-wall-copy-prompt' + +/** Walls below read blue, walls above magenta: told apart at a glance and from the active walls. */ +export const ADJACENT_WALL_COLORS = { below: '#2563eb', above: '#c026d3' } as const + +export type AdjacentWallOutline = { id: string; points: string } + +/** + * Each visible wall of `levelId` as the outline of its full thickness (both faces, joined at the + * corners as the level draws them), in plan metres. + */ +export function adjacentWallOutlines( + nodes: Record, + levelId: string | null | undefined, +): AdjacentWallOutline[] { + if (!levelId) return [] + const walls = Object.values(nodes).filter( + (node): node is WallNode => + node.type === 'wall' && node.parentId === levelId && node.visible !== false, + ) + if (!walls.length) return [] + const miters = calculateLevelMiters(walls) + return walls.flatMap((wall) => { + const polygon: Point2D[] = getWallPlanFootprint(wall, miters) + return polygon.length >= 3 + ? [{ id: wall.id, points: polygon.map((point) => `${point.x},${point.y}`).join(' ') }] + : [] + }) +} + +/** + * The levels directly below and above `levelId` in its building's stack (by ordinal, as the + * storey stack orders them): on a roof level, "below" is the top storey, the walls the roof bears + * on. Reads only the building's levels, so a plan selector can call it on every scene change. + */ +export function adjacentLevelIds( + nodes: Record, + levelId: string | null | undefined, +): { below: string | null; above: string | null } { + const level = levelId ? nodes[levelId] : undefined + if (level?.type !== 'level') return { below: null, above: null } + const building = level.parentId ? nodes[level.parentId] : undefined + if (building?.type !== 'building') { + const graph = nodes as Record + return { + below: getLevelBelow(level.id, graph)?.id ?? null, + above: getLevelAbove(level.id, graph)?.id ?? null, + } + } + let below: LevelNode | null = null + let above: LevelNode | null = null + for (const id of building.children) { + const other = nodes[id] + if (other?.type !== 'level' || other.id === level.id) continue + if (other.level < level.level && (!below || other.level > below.level)) below = other + if (other.level > level.level && (!above || other.level < above.level)) above = other + } + return { below: below?.id ?? null, above: above?.id ?? null } +} + +/** The adjacent levels whose walls the plan traces: each only while it is shown. */ +export function adjacentWallLevels( + nodes: Record, + levelId: string | null | undefined, + show: { below: boolean; above: boolean }, +): { below: string | null; above: string | null } { + const levels = adjacentLevelIds(nodes, levelId) + return { below: show.below ? levels.below : null, above: show.above ? levels.above : null } +} + +/** + * The "Walls below" setting that applies on `levelId`: the roof plan's, on until turned off, on a + * roof level; the floor plans', off until turned on, on a storey. + */ +export function useWallsBelowSetting(levelId: string | null | undefined): { + onRoofLevel: boolean + shown: boolean + setShown: (show: boolean) => void +} { + const onRoofLevel = useScene((state) => { + const level = levelId ? state.nodes[levelId as AnyNodeId] : undefined + return level?.type === 'level' && servesAsRoofLevel(state.nodes, level) + }) + const shown = useEditor((state) => + onRoofLevel ? state.showRoofWallsBelow : state.showWallsBelow, + ) + const setRoof = useEditor((state) => state.setShowRoofWallsBelow) + const setFloor = useEditor((state) => state.setShowWallsBelow) + return { onRoofLevel, shown, setShown: onRoofLevel ? setRoof : setFloor } +} + +/** The level's own walls, read through its children rather than the whole scene. */ +function useLevelWalls(levelId: string | null) { + return useScene( + useShallow((state) => { + const level = levelId ? state.nodes[levelId as AnyNodeId] : undefined + if (level?.type !== 'level') return [] as WallNode[] + return level.children.flatMap((id) => { + const node = state.nodes[id as AnyNodeId] + return node?.type === 'wall' ? [node] : [] + }) + }), + ) +} + +function Outlines({ color, outlines }: { color: string; outlines: AdjacentWallOutline[] }) { + return ( + <> + {outlines.map((outline) => ( + + ))} + + ) +} + +/** + * "Walls below / above": dashed outlines of the walls on the neighbouring levels, drawn over the + * active level's plan so second-storey walls line up with the ones under them and a roof outline + * can be checked against the walls it covers — while its toggle is on, or while a new level's + * "Copy exterior walls?" offer is open. Display only: never hit-tested, never snapped to. + */ +export const FloorplanAdjacentWallsLayer = memo(function FloorplanAdjacentWallsLayer({ + levelId, +}: { + levelId: string | null | undefined +}) { + const offer = useLevelWallCopyOffer((state) => + state.offer && state.offer.levelId === levelId ? state.offer.direction : null, + ) + const showBelow = useWallsBelowSetting(levelId).shown || offer === 'below' + const showAbove = useEditor((state) => state.showWallsAbove) || offer === 'above' + const levels = useScene( + useShallow((state) => + adjacentWallLevels(state.nodes as Record, levelId, { + below: showBelow, + above: showAbove, + }), + ), + ) + const belowWalls = useLevelWalls(levels.below) + const aboveWalls = useLevelWalls(levels.above) + const below = useMemo( + () => adjacentWallOutlines(Object.fromEntries(belowWalls.map((w) => [w.id, w])), levels.below), + [belowWalls, levels.below], + ) + const above = useMemo( + () => adjacentWallOutlines(Object.fromEntries(aboveWalls.map((w) => [w.id, w])), levels.above), + [aboveWalls, levels.above], + ) + if (!(below.length || above.length)) return null + return ( + + + + + ) +}) diff --git a/packages/editor/src/components/editor-2d/floorplan-alignment-guide-layer.tsx b/packages/editor/src/components/editor-2d/floorplan-alignment-guide-layer.tsx index 8478747b71..1cda92192b 100644 --- a/packages/editor/src/components/editor-2d/floorplan-alignment-guide-layer.tsx +++ b/packages/editor/src/components/editor-2d/floorplan-alignment-guide-layer.tsx @@ -2,7 +2,7 @@ import { useViewer } from '@pascal-app/viewer' import { memo } from 'react' -import useAlignmentGuides from '../../store/use-alignment-guides' +import useAlignmentGuides, { type DraftGuideLine } from '../../store/use-alignment-guides' import { formatMeasurement } from '../editor/measurement-pill' import { useFloorplanRender } from './floorplan-render-context' @@ -24,16 +24,29 @@ import { useFloorplanRender } from './floorplan-render-context' * * Stroke widths and handle radii are scaled by `unitsPerPixel` so they * stay a constant size on screen no matter the zoom. + * + * A wall pulled from a wall end (and the run it continues) publishes its + * projection guides beside them (`useAlignmentGuides.draft`): dashed lines — + * the extension of the wall it comes from in amber, lines through other walls' + * ends in indigo, lines through the run's start in emerald — and a ringed ✕ + * where two of them cross, matching the 3D layer. */ -export const FloorplanAlignmentGuideLayer = memo(function FloorplanAlignmentGuideLayer() { +export const FloorplanAlignmentGuideLayer = memo(function FloorplanAlignmentGuideLayer({ + unitsPerPixel, +}: { + /** The plan's live scale, which keeps a wall draft's guides screen-sized. */ + unitsPerPixel?: number +}) { const guides = useAlignmentGuides((s) => s.guides) + const draft = useAlignmentGuides((s) => s.draft) const unit = useViewer((s) => s.unit) const metricNotation = useViewer((s) => s.metricNotation) const ctx = useFloorplanRender() - if (guides.length === 0) return null + if (guides.length === 0 && !draft) return null const upp = ctx?.unitsPerPixel ?? 0.01 + const draftUpp = unitsPerPixel ?? upp const sceneRot = ctx?.sceneRotationDeg ?? 0 // Pixel-budgeted sizes converted to world meters so visuals stay @@ -50,6 +63,47 @@ export const FloorplanAlignmentGuideLayer = memo(function FloorplanAlignmentGuid return ( + {draft?.lines.map((line, i) => ( + + ))} + {draft?.intersections.map((point, i) => ( + + + + + + ))} {guides.map((guide, i) => { const { from, to, axis } = guide const midX = (from.x + to.x) / 2 @@ -107,6 +161,12 @@ export const FloorplanAlignmentGuideLayer = memo(function FloorplanAlignmentGuid ) }) +const DRAFT_GUIDE_COLORS: Record = { + extension: '#f59e0b', // amber-500 + alignment: '#6366f1', // indigo-500 — the snap marker's colour + 'run-start': '#10b981', // emerald-500 — the pull grip's colour +} + function XCap({ color, size, diff --git a/packages/editor/src/components/editor-2d/floorplan-group-move.tsx b/packages/editor/src/components/editor-2d/floorplan-group-move.tsx index 28c7d11d90..a40975e112 100644 --- a/packages/editor/src/components/editor-2d/floorplan-group-move.tsx +++ b/packages/editor/src/components/editor-2d/floorplan-group-move.tsx @@ -24,6 +24,8 @@ import { applyFloorplanAlignment } from '../../lib/floorplan/apply-alignment' import { clientToPlan } from '../../lib/floorplan/plan-coords' import { isHistoryShortcut } from '../../lib/history' import { formatLinearMeasurement } from '../../lib/measurements' +import type { WallGroupPush } from '../../lib/room-handle-drag' +import { useRoomHandleDrag } from '../../lib/room-handle-drag' import { sfxEmitter } from '../../lib/sfx-bus' import { isTypingTarget } from '../../lib/typing-target' import useAlignmentGuides from '../../store/use-alignment-guides' @@ -36,6 +38,7 @@ import useEditor, { import useFloorplanMode from '../../store/use-floorplan-mode' import useInteractionScope, { useMovingNode } from '../../store/use-interaction-scope' import { + beginGroupWallPush, classifyParticipant, collectParticipants, computeGroupPlanBox, @@ -120,6 +123,8 @@ export function startFloorplanGroupMove( rotation: number restCenter: Vec2 lastDelta: Vec2 | null + /** Walls alone: each moves as its push arrow does instead of the rigid slide. */ + push: WallGroupPush | null } let session: Session | null = null @@ -185,6 +190,7 @@ export function startFloorplanGroupMove( rotation: 0, restCenter, lastDelta: null, + push: beginGroupWallPush(starts, levelId), } } @@ -201,8 +207,14 @@ export function startFloorplanGroupMove( let dz = snap ? Math.round((plan[1] - startPlan[1]) / step) * step : plan[1] - startPlan[1] // Figma-style alignment layered on top: guides display in every mode - // except Off; the magnetic pull applies only in 'lines' mode. - if (isAlignmentGuideActive() && s.candidates.length > 0 && s.restAnchors.length > 0) { + // except Off; the magnetic pull applies only in 'lines' mode. Pushed walls + // don't move as one footprint, so they have no box to align. + if ( + !s.push && + isAlignmentGuideActive() && + s.candidates.length > 0 && + s.restAnchors.length > 0 + ) { const proposed: [number, number] = [startPlan[0] + dx, startPlan[1] + dz] const aligned = applyFloorplanAlignment( proposed, @@ -225,6 +237,10 @@ export function startFloorplanGroupMove( sfxEmitter.emit('sfx:grid-snap') s.lastDelta = [dx, dz] } + if (s.push) { + s.push.preview([dx, dz]) + return + } const entries = translateGroupPatches(s.starts, s.links, dx, dz) const patchById = new Map(entries) @@ -252,6 +268,8 @@ export function startFloorplanGroupMove( // current delta — the carried group turns exactly like the idle keyboard // rotate, and the commit stays a single updateNodes. const rotateSession = (s: Session, direction: 1 | -1) => { + // Pushed walls keep their bearing: there is nothing to turn. + if (s.push) return const pivot = { x: s.restCenter[0], z: s.restCenter[1] } const delta = -direction * (Math.PI / 4) const rotated = rotateGroupSnapshots(s.starts, s.links, pivot, delta) @@ -271,6 +289,7 @@ export function startFloorplanGroupMove( } const clearLivePreviews = (s: Session) => { + s.push?.cancel() const overrides = useLiveNodeOverrides.getState() const liveTransforms = useLiveTransforms.getState() for (const id of s.affectedIds) { @@ -330,6 +349,13 @@ export function startFloorplanGroupMove( // doesn't clear the multi-selection the drag is preserving. swallowNextClick() sfxEmitter.emit('sfx:item-place') + if (session.push) { + resumeSceneHistory(useScene) + session.push.commit() + session = null + teardown() + return + } const overrides = useLiveNodeOverrides.getState() const updates: { id: AnyNodeId; data: Partial }[] = [] for (const id of session.affectedIds) { @@ -632,6 +658,8 @@ export const FloorplanGroupSelectionBox = memo(function FloorplanGroupSelectionB const delta = useFloorplanGroupDrag((s) => s.delta) const liveRotation = useFloorplanGroupDrag((s) => s.rotation) const movingNode = useMovingNode() + // Pushed walls don't move as one box: the room widths they show take its place. + const wallPush = useRoomHandleDrag((s) => s.drag?.kind === 'wall-group-push') const mode = useEditor((s) => s.mode) const floorplanMode = useFloorplanMode((s) => s.mode) const sceneRotationDeg = useFloorplanSceneRotation() @@ -673,7 +701,7 @@ export const FloorplanGroupSelectionBox = memo(function FloorplanGroupSelectionB } }, [selectedIds, levelId, nodes, meshEpoch]) - if (!box || movingNode || mode === 'delete') return null + if (!box || movingNode || wallPush || mode === 'delete') return null const pad = 6 * unitsPerPixel const stroke = palette?.selectedStroke ?? '#3b82f6' diff --git a/packages/editor/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx b/packages/editor/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx index 4a6fb14f7b..079529b3ce 100644 --- a/packages/editor/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx +++ b/packages/editor/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx @@ -1,6 +1,6 @@ 'use client' -import type { OpenWallEnd } from '@pascal-app/core' +import type { AnyNodeId, OpenWallEnd } from '@pascal-app/core' import { useViewer } from '@pascal-app/viewer' import { memo, useEffect, useState } from 'react' import { createPortal } from 'react-dom' @@ -31,7 +31,8 @@ function sceneScreenPoint(point: [number, number]): { left: number; top: number * Shows where walls look joined but are not, so a room can't close: a red dot * on each open end, a dashed line to the wall it nearly meets with what is * wrong ("4 cm gap"), and — while drawing — the walls that bound no room dimmed. Hover or click a - * dot for "Join walls", which applies core's join planner as one undo step. + * dot for "Join walls", which applies core's join planner as one undo step; a + * click on a dot also selects its wall. * * On while walls or rooms are being drawn (the wall tool's variants, Divide); * otherwise only when a wall that bounds no room has a near miss. @@ -76,7 +77,14 @@ const ActiveOpenWallEndsLayer = memo(function ActiveOpenWallEndsLayer() { label={openWallEndLabel(end, unit)} onHoverEnd={focus.releaseHover} onHoverStart={() => focus.keepHover(key)} - onPin={() => focus.togglePin(key)} + onPin={() => { + focus.togglePin(key) + // The dot can cover all of a wall a few centimetres long: its + // click selects that wall too, so it can be fixed or deleted. + if (!drawing && useEditor.getState().mode === 'select') { + useViewer.getState().setSelection({ selectedIds: [end.wallId as AnyNodeId] }) + } + }} sceneRotationDeg={sceneRotationDeg} unitsPerPixel={unitsPerPixel} /> diff --git a/packages/editor/src/components/editor-2d/floorplan-registry-move-overlay.tsx b/packages/editor/src/components/editor-2d/floorplan-registry-move-overlay.tsx index ef1de406d7..123c3e18c6 100644 --- a/packages/editor/src/components/editor-2d/floorplan-registry-move-overlay.tsx +++ b/packages/editor/src/components/editor-2d/floorplan-registry-move-overlay.tsx @@ -388,7 +388,13 @@ export function FloorplanRegistryMoveOverlay() { endTransientMarkers() }) sfxEmitter.emit('sfx:item-place') - useViewer.getState().setSelection({ selectedIds: initialAffectedIds }) + // The moved node stays selected, as after a 3D move: the joined walls and + // rooms a wall move reshapes are part of its write, not a pick. + useViewer.getState().setSelection({ + selectedIds: useScene.getState().nodes[movingNode.id] + ? [movingNode.id] + : initialAffectedIds, + }) return } diff --git a/packages/editor/src/components/editor-2d/floorplan-snap-beacon-layer.tsx b/packages/editor/src/components/editor-2d/floorplan-snap-beacon-layer.tsx index 0a943e2f18..b8b0d3c26e 100644 --- a/packages/editor/src/components/editor-2d/floorplan-snap-beacon-layer.tsx +++ b/packages/editor/src/components/editor-2d/floorplan-snap-beacon-layer.tsx @@ -13,33 +13,92 @@ import { useFloorplanRender } from './floorplan-render-context' * * endpoint (corner) → square midpoint → triangle * intersection → ✕ cross wall body (edge) → circle + * perpendicular → ⊥ corner projection guide → diamond + * grid length → small + * * Indigo to match the 3D beacon, except the corner (endpoint) square which is - * green to match the alignment guides. Sizes are pixel-budgeted via - * `unitsPerPixel` so the marker stays a + * green to match the alignment guides. A point that carries a `label` (a wall + * pulled from a wall end) also names what it caught in a pill beside the + * glyph. Sizes are pixel-budgeted via `unitsPerPixel` so the marker stays a * constant size on screen at any zoom. Mounted inside the `data-floorplan-scene` * group so coordinates are world meters (XZ) 1:1, like the alignment guides. */ const COLOR = '#6366f1' // indigo-500 — matches the 3D beacon const ENDPOINT_COLOR = '#22c55e' // green-500 — corner (endpoint) snap accent -export const FloorplanSnapBeaconLayer = memo(function FloorplanSnapBeaconLayer() { +export const FloorplanSnapBeaconLayer = memo(function FloorplanSnapBeaconLayer({ + unitsPerPixel, +}: { + /** The plan's live scale, which keeps a labelled marker screen-sized. */ + unitsPerPixel?: number +}) { const point = useWallSnapIndicator((s) => s.point) const ctx = useFloorplanRender() if (!point) return null - const upp = ctx?.unitsPerPixel ?? 0.01 + // A labelled point (a wall pulled from a wall end) is sized on screen. + const upp = (point.label ? unitsPerPixel : undefined) ?? ctx?.unitsPerPixel ?? 0.01 const m = 6 * upp // base half-size of the glyph in world meters const stroke = 1.5 * upp return ( + {point.label ? ( + + ) : null} ) }) +/** What the snap caught, in a pill down and to the right of the glyph, kept upright. */ +function SnapLabel({ + color, + sceneRotationDeg, + text, + upp, + x, + z, +}: { + color: string + sceneRotationDeg: number + text: string + upp: number + x: number + z: number +}) { + const fontSize = 10.5 * upp + const padX = 5 * upp + const width = text.length * fontSize * 0.56 + padX * 2 + const height = fontSize + 6 * upp + return ( + + + + {text} + + + ) +} + function SnapMarker({ color, kind, @@ -72,6 +131,39 @@ function SnapMarker({ ) } + if (kind === 'perpendicular') { + // ⊥ — a base line with an upright from its middle, and the square corner. + const c = m * 1.3 + return ( + + + + + + ) + } + if (kind === 'alignment') { + const c = m * 1.2 + return ( + + ) + } + if (kind === 'grid') { + const c = m * 0.9 + return ( + + + + + ) + } // 'wall' (edge / along-wall) → circle return } diff --git a/packages/editor/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx b/packages/editor/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx index 640164afe1..71ae0bb0e4 100644 --- a/packages/editor/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx +++ b/packages/editor/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx @@ -11,6 +11,7 @@ import { resolveDimensionDrive, } from '../../../lib/floorplan/dimension-drive' import { formatScheduleLength } from '../../../lib/floorplan/schedules' +import { commitRoomPush } from '../../../lib/room-handle-drag' import useEditor from '../../../store/use-editor' /** @@ -20,7 +21,8 @@ import useEditor from '../../../store/use-editor' * plate, pre-filled with the current text. Enter commits, Esc cancels. * Committing DRIVES geometry: the anchor the dimension runs toward moves * along the dimension direction by the delta, and connected wall junctions - * follow (`planDimensionDrive`). When nothing bindable is under the far + * follow (`planDimensionDrive`); a dimension across a wall slides the whole + * wall, as its push arrow does (`commitRoomPush`). When nothing bindable is under the far * anchor the value is written as `textOverride` on a construction-dimension * node instead, and the label renders an "override" badge. * @@ -60,6 +62,32 @@ export function useDimensionEditAllowed(): boolean { return useEditor((state) => isDimensionEditAllowed(state, { readOnly })) } +/** + * The typeable dimension value under a press, with the node typing it drives: + * the pressed element's or, when the plan's dashed group box lies over it, the + * one beneath (a multi-selection's walls keep their dimensions inside it). + */ +export function typeableDimensionAt( + target: EventTarget | null, + clientX: number, + clientY: number, +): { label: Element; ownerNodeId: AnyNodeId } | null { + const resolve = (element: Element | null | undefined) => { + const hit = element?.closest?.('[data-floorplan-dimension-hit]') + const label = hit?.closest('[data-floorplan-annotation-label]') + const ownerNodeId = hit?.closest('[data-node-id]')?.getAttribute('data-node-id') + return label && ownerNodeId ? { label, ownerNodeId: ownerNodeId as AnyNodeId } : null + } + const element = target as Element | null + const direct = resolve(element) + if (direct || !element?.closest?.('[data-group-selection-box]')) return direct + for (const below of document.elementsFromPoint(clientX, clientY)) { + const found = resolve(below) + if (found) return found + } + return null +} + type EditTarget = { ownerNodeId: AnyNodeId text: string @@ -93,13 +121,9 @@ export function FloorplanDimensionEditOverlay(): React.ReactElement | null { return } if (!isDimensionEditAllowed(useEditor.getState(), useScene.getState())) return - const origin = event.target as Element | null - const hit = origin?.closest?.('[data-floorplan-dimension-hit]') - if (!hit) return - const label = hit.closest('[data-floorplan-annotation-label]') - const owner = hit.closest('[data-node-id]') - const ownerNodeId = owner?.getAttribute('data-node-id') - if (!label || !ownerNodeId) return + const found = typeableDimensionAt(event.target, event.clientX, event.clientY) + if (!found) return + const { label, ownerNodeId } = found const value = number(label.getAttribute('data-floorplan-dimension-value')) const witnessStart = point( @@ -117,7 +141,7 @@ export function FloorplanDimensionEditOverlay(): React.ReactElement | null { const box = label.getBoundingClientRect() const text = label.getAttribute('data-floorplan-dimension-text') ?? '' setTarget({ - ownerNodeId: ownerNodeId as AnyNodeId, + ownerNodeId, text, value, witnessStart, @@ -247,6 +271,21 @@ export function commitDimensionValue(args: { return { ok: true } } + if (resolution.target.kind === 'wall-offset') { + // The wall's own push: the whole wall slides along its normal, connected + // walls follow through the junction planner, rooms and floors re-form — + // one undo step, exactly as dragging its side arrow that far. + const delta = args.nextLength - args.target.value + if (Math.abs(delta) < 1e-9) return { ok: true } + return commitRoomPush( + { wallId: resolution.target.wallId, t0: 0, t1: 1 }, + resolution.target.direction, + delta, + ) + ? { ok: true } + : { ok: false, reason: "Can't move this wall there" } + } + const plan = planDimensionDrive({ nodes, target: resolution.target, diff --git a/packages/editor/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts b/packages/editor/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts index 58cccf2cae..3eb19b4966 100644 --- a/packages/editor/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +++ b/packages/editor/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts @@ -24,6 +24,7 @@ import { collectFloorplanLinkedLevelNodes, computeAffectedSiblingIds, floorplanAffordanceReshapeScope, + floorplanEntryStripsHandles, floorplanEntryYieldsToTool, floorplanHandleDoubleClickAffordance, InteractiveGeometry, @@ -162,7 +163,6 @@ describe('site-scoped floorplan discovery', () => { siblingEpoch: 0, unit: 'metric' as const, metricNotation: 'meters' as const, - wallDimensionReference: 'finished-faces' as const, visibilityRootId: site.id, } const committedSnapshot = structuredClone(overlay) @@ -793,6 +793,17 @@ describe('floorplan entry routing while a tool is active', () => { expect(floorplanEntryYieldsToTool({ mode: 'select', openingPlacement: false })).toBe(false) expect(floorplanEntryYieldsToTool({ mode: 'delete', openingPlacement: false })).toBe(false) }) + + // A roof plane selected before arming the roof tool kept its live corner and edge handles: a + // click near its eave resized it instead of drawing. + test('a selected node shows no edit handles while a build tool is armed', () => { + const entry = { multiSelected: false, ceilingWithoutSession: false } + expect(floorplanEntryStripsHandles({ ...entry, mode: 'select' })).toBe(false) + expect(floorplanEntryStripsHandles({ ...entry, mode: 'build' })).toBe(true) + expect(floorplanEntryStripsHandles({ ...entry, mode: 'select', multiSelected: true })).toBe( + true, + ) + }) }) describe('isFloorplanHierarchyVisible', () => { diff --git a/packages/editor/src/components/editor-2d/renderers/floorplan-registry-layer.tsx b/packages/editor/src/components/editor-2d/renderers/floorplan-registry-layer.tsx index f23e2a8c79..4023abb0a5 100644 --- a/packages/editor/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +++ b/packages/editor/src/components/editor-2d/renderers/floorplan-registry-layer.tsx @@ -78,7 +78,7 @@ import { resolveNodeForDrawingType } from '../../../lib/floorplan/drawing-coordi import { createFloorplanContextExtensions, type FloorplanAnnotationRole, - type FloorplanWallDimensionReference, + type FloorplanWallDimensionFaces, getFloorplanNodeExtension, readFloorplanGeometryMetadata, withFloorplanGeometryMetadata, @@ -86,7 +86,6 @@ import { import { type FloorplanMode, resolveFloorplanAnnotationVisibility, - resolveFloorplanWallDimensionReference, } from '../../../lib/floorplan/floorplan-mode' import { buildFloorplanContext, @@ -115,6 +114,11 @@ import { createSessionWrites, type SessionWrites } from '../../../lib/session-wr import { sfxEmitter } from '../../../lib/sfx-bus' import { clearSurfacePlanSnapFeedback } from '../../../lib/surface-plan-snap' import { paintZoneMembership } from '../../../lib/units' +import { + startWallPull, + WALL_PULL_AFFORDANCE, + type WallPullGripPayload, +} from '../../../lib/wall-pull' import useDirectManipulationFeedback from '../../../store/use-direct-manipulation-feedback' import useDrawingView from '../../../store/use-drawing-view' import useEditor, { isAngleSnapActive, type Mode } from '../../../store/use-editor' @@ -130,7 +134,12 @@ import { isViewVisible, VIEW_2D } from '../../../store/view-layout' import { FloorRegionControls2D } from '../../editor/floor-region-controls' import { startGroupPickUp } from '../../editor/group-actions' import { classifyParticipant } from '../../editor/group-transform-shared' -import { RoomHandleDragPreview2D, RoomHandles2D } from '../../editor/room-handles-2d' +import { + RoomHandleDragPreview2D, + RoomHandles2D, + SelectedWallDimensions2D, + useSelectionDimensionNodes, +} from '../../editor/room-handles-2d' import { RoomHighlight2D } from '../../editor/room-highlight' import { RoomLabels2D } from '../../editor/room-labels' import { suppressBoxSelectForPointer } from '../../tools/select/box-select-state' @@ -150,7 +159,10 @@ import { resolveSvgAnnotationCollisions, svgAnnotationLabelId, } from './floorplan-annotation-layout' -import { FloorplanDimensionEditOverlay } from './floorplan-dimension-edit-overlay' +import { + FloorplanDimensionEditOverlay, + typeableDimensionAt, +} from './floorplan-dimension-edit-overlay' import { FloorplanDimensionRenderer } from './floorplan-dimension-renderer' import { FloorplanGeometryRenderer } from './floorplan-geometry-renderer' import { @@ -199,6 +211,15 @@ const DIRECT_DRAG_THRESHOLD_PX = 4 const DIRECT_ROTATE_EPSILON = 1e-6 const DIRECT_ROTATE_RADIANS_PER_PIXEL = Math.PI / 180 const MAX_HANDLE_UNITS_PER_PIXEL = 0.015 +// A wall end's pull grip, in screen pixels out from the end along the wall: +// clear of the end's move grip (its hit ring reaches ~17 px), a short dashed +// leader, then a round button with an outward arrow. +const PULL_GRIP_LEADER_START_PX = 9 +const PULL_GRIP_CENTER_PX = 30 +const PULL_GRIP_RADIUS_PX = 10 +const PULL_GRIP_HIT_RADIUS_PX = 13 +const PULL_GRIP_FILL = '#10b981' // emerald-500 +const PULL_GRIP_HOVER_FILL = '#059669' // emerald-600 export function resolveFloorplanHandleUnitsPerPixel(unitsPerPixel: number): number { return Math.min(unitsPerPixel, MAX_HANDLE_UNITS_PER_PIXEL) @@ -387,7 +408,7 @@ type NodeDeps = { live: LiveTransform | undefined unit: 'metric' | 'imperial' metricNotation: 'meters' | 'millimeters' - wallDimensionReference: FloorplanWallDimensionReference + wallDimensionFaces?: FloorplanWallDimensionFaces selected: boolean highlighted: boolean hovered: boolean @@ -497,6 +518,20 @@ export function floorplanEntryYieldsToTool(state: { return state.mode === 'build' || state.openingPlacement } +/** + * Whether an entry draws its node without edit handles or dimension chrome: a member of a + * multi-selection, a ceiling outside its edit session, or anything while a build tool is armed (a + * selected roof keeps its selection for a new plane to join it, but a press near its eave must + * draw, not resize it). + */ +export function floorplanEntryStripsHandles(state: { + mode: Mode + multiSelected: boolean + ceilingWithoutSession: boolean +}): boolean { + return state.multiSelected || state.ceilingWithoutSession || state.mode === 'build' +} + function floorplanEntryYieldsToToolNow(): boolean { const { mode, tool } = useEditor.getState() const movingNode = getMovingNode() @@ -596,6 +631,11 @@ export const FloorplanRegistryLayer = memo(function FloorplanRegistryLayer() { // `handleClickStop` / `handleSelect`, so the tool never sees it. Pass // clicks through in that case (`floorplanEntryYieldsToToolNow`). const editorMode = useEditor((s) => s.mode) + const selectionDimensionNodes = useSelectionDimensionNodes() + const selectionDimensionIds = useMemo( + () => new Set(selectionDimensionNodes.map((node) => node.id)), + [selectionDimensionNodes], + ) const floorplanSelectionTool = useEditor((s) => s.floorplanSelectionTool) const endpointReshape = useEndpointReshape() const isMarqueeSelectionActive = @@ -609,12 +649,9 @@ export const FloorplanRegistryLayer = memo(function FloorplanRegistryLayer() { const floorplanVisible = useEditor((s) => isViewVisible(s, VIEW_2D)) const drawingType = useDrawingView((s) => s.drawingType) const annotationVisibility = useFloorplanAnnotationVisibility((s) => s.visibility) - const wallDimensionReference = useFloorplanAnnotationVisibility((s) => s.wallDimensionReference) + const showDimensions = useFloorplanAnnotationVisibility((s) => s.showDimensions) + const wallDimensionFaces = useFloorplanAnnotationVisibility((s) => s.wallDimensionFaces) const floorplanMode = useFloorplanMode((s) => s.mode) - const effectiveWallDimensionReference = resolveFloorplanWallDimensionReference( - floorplanMode, - wallDimensionReference, - ) // Elevator builders read runtime state imperatively, so entries include this // rare-changing ref in their cache deps. const interactiveElevators = useInteractive((s) => s.elevators) @@ -981,6 +1018,12 @@ export const FloorplanRegistryLayer = memo(function FloorplanRegistryLayer() { if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return false if (movingNode) return false if (useEditor.getState().mode === 'delete') return false + // A press on a member's dimension value is the type-a-value box's: its click opens it. + if (!immediate && typeableDimensionAt(event.target, event.clientX, event.clientY)) { + event.stopPropagation() + suppressBoxSelectForPointer(event) + return true + } const started = startFloorplanGroupMove(id, event, { immediate, onClickFallthrough: immediate ? undefined : () => startGroupPickUp(), @@ -1299,6 +1342,16 @@ export const FloorplanRegistryLayer = memo(function FloorplanRegistryLayer() { runFloorplanWallPush(payload, event.clientX, event.clientY) return } + // A wall end's pull grip opens the Walls run at that end; the plan's + // wall draft then follows the pointer and the release places the wall. + if (affordance === WALL_PULL_AFFORDANCE) { + event.preventDefault() + event.stopPropagation() + suppressBoxSelectForPointer(event) + const grip = payload as WallPullGripPayload + startWallPull({ wallId: grip.wallId, endpoint: grip.endpoint, origin: '2d' }) + return + } const sceneNodes = useScene.getState().nodes const node = sceneNodes[nodeId] @@ -1590,6 +1643,7 @@ export const FloorplanRegistryLayer = memo(function FloorplanRegistryLayer() { {renderEntries('handles')} + {/* Click-to-type dimension labels. Portals its HTML input to document.body, so mounting it inside the SVG tree is safe. */} @@ -1707,9 +1763,8 @@ function FloorplanAnnotationLayoutResolver({ active }: { active: boolean }) { const drawingType = useDrawingView((state) => state.drawingType) const annotationLayoutOverrides = useDrawingView((state) => state.annotationLayoutOverrides) const annotationVisibility = useFloorplanAnnotationVisibility((state) => state.visibility) - const wallDimensionReference = useFloorplanAnnotationVisibility( - (state) => state.wallDimensionReference, - ) + const showDimensions = useFloorplanAnnotationVisibility((state) => state.showDimensions) + const wallDimensionFaces = useFloorplanAnnotationVisibility((state) => state.wallDimensionFaces) const floorplanMode = useFloorplanMode((state) => state.mode) const layoutInputs = useMemo( () => ({ @@ -1718,7 +1773,8 @@ function FloorplanAnnotationLayoutResolver({ active }: { active: boolean }) { drawingType, interactionIdle, settledLayoutEpoch, - wallDimensionReference, + showDimensions, + wallDimensionFaces, floorplanMode, }), [ @@ -1727,7 +1783,8 @@ function FloorplanAnnotationLayoutResolver({ active }: { active: boolean }) { drawingType, interactionIdle, settledLayoutEpoch, - wallDimensionReference, + showDimensions, + wallDimensionFaces, floorplanMode, ], ) @@ -1955,6 +2012,7 @@ function readFloorplanAnnotationLayoutOffset(label: SVGGElement) { type FloorplanRegistryEntryProps = { activeDragId: string | null annotationVisibility: FloorplanAnnotationVisibility + showDimensions: boolean floorplanMode: FloorplanMode ctxOverrides: FloorplanContextOverrides | undefined floorplanVisible: boolean @@ -1963,6 +2021,8 @@ type FloorplanRegistryEntryProps = { hoveredHandleId: string | null interactiveElevators: unknown isMarqueeSelectionActive: boolean + /** A wall in a multi-selection still shows its own length (`useSelectionDimensionNodes`). */ + keepsSelectionDimensions: boolean levelDataCacheRef: { current: Map } levelNodeIdsByType: ReadonlyMap moving: boolean @@ -1996,13 +2056,14 @@ type FloorplanRegistryEntryProps = { siblingEpoch: number unit: 'metric' | 'imperial' metricNotation: 'meters' | 'millimeters' - wallDimensionReference: FloorplanWallDimensionReference + wallDimensionFaces: FloorplanWallDimensionFaces visibilityRootId: AnyNodeId | undefined } const FloorplanRegistryEntry = memo(function FloorplanRegistryEntry({ activeDragId, annotationVisibility, + showDimensions, floorplanMode, ctxOverrides, floorplanVisible, @@ -2011,6 +2072,7 @@ const FloorplanRegistryEntry = memo(function FloorplanRegistryEntry({ hoveredHandleId, interactiveElevators, isMarqueeSelectionActive, + keepsSelectionDimensions, levelDataCacheRef, levelNodeIdsByType, moving, @@ -2032,7 +2094,7 @@ const FloorplanRegistryEntry = memo(function FloorplanRegistryEntry({ siblingEpoch, unit, metricNotation, - wallDimensionReference, + wallDimensionFaces, visibilityRootId, }: FloorplanRegistryEntryProps): React.ReactElement | null { // A node an agent just built is drawn on its construction-reveal turn, as in 3D. @@ -2049,7 +2111,12 @@ const FloorplanRegistryEntry = memo(function FloorplanRegistryEntry({ const ceilingWithoutSession = useCeilingEditSession( (state) => node.type === 'ceiling' && state.session?.ceilingId !== nodeId, ) - const suppressHandles = multiSelected || ceilingWithoutSession + const mode = useEditor((state) => state.mode) + const suppressHandles = floorplanEntryStripsHandles({ + mode, + multiSelected, + ceilingWithoutSession, + }) const selectedLevelId = useViewer((state) => state.selection.levelId) const selectionProxyId = resolveSelectionProxyId( node, @@ -2089,6 +2156,7 @@ const FloorplanRegistryEntry = memo(function FloorplanRegistryEntry({ referencedAnnotationRole, selected, target: 'editor', + dimensions: showDimensions, }, ) @@ -2220,7 +2288,7 @@ const FloorplanRegistryEntry = memo(function FloorplanRegistryEntry({ siblingEpoch, unit, metricNotation, - wallDimensionReference, + wallDimensionFaces, visibilityRootId, }) const rawGeometry = cacheEntry ? cacheEntry[pass] : null @@ -2229,10 +2297,10 @@ const FloorplanRegistryEntry = memo(function FloorplanRegistryEntry({ : null // Multi-selection shows highlight only: strip this member's edit handles / // dimension chrome (all of which live in the overlay pass) while keeping - // its highlighted body geometry. + // its highlighted body geometry and, for a wall, its own length. const geometry = visibleGeometry && suppressHandles && pass !== 'base' - ? stripHandleChrome(visibleGeometry) + ? stripHandleChrome(visibleGeometry, keepsSelectionDimensions) : visibleGeometry useFloorplanReveal(nodeId, entryRef, cacheEntry, revealWaiting, revealActive) if (revealWaiting || !geometry) return null @@ -2293,7 +2361,7 @@ type BuildFloorplanEntryGeometryArgs = { siblingEpoch: number unit: 'metric' | 'imperial' metricNotation: 'meters' | 'millimeters' - wallDimensionReference: FloorplanWallDimensionReference + wallDimensionFaces?: FloorplanWallDimensionFaces visibilityRootId: AnyNodeId | undefined } @@ -2353,7 +2421,7 @@ export function buildFloorplanEntryGeometry({ siblingEpoch, unit, metricNotation, - wallDimensionReference, + wallDimensionFaces, visibilityRootId, }: BuildFloorplanEntryGeometryArgs): CacheEntry | null { const def = nodeRegistry.get(node.type) @@ -2381,7 +2449,7 @@ export function buildFloorplanEntryGeometry({ live, unit, metricNotation, - wallDimensionReference, + wallDimensionFaces, selected, highlighted, hovered, @@ -2468,7 +2536,7 @@ export function buildFloorplanEntryGeometry({ unit, metricNotation, roomLabelOverlay: true, - wallDimensionReference, + wallDimensionFaces, highlighted, hovered, moving, @@ -2494,7 +2562,7 @@ export function buildFloorplanEntryGeometry({ metricNotation, purpose: 'edit', roomLabelOverlay: true, - wallDimensionReference, + wallDimensionFaces, }), viewState: palette ? { @@ -2642,6 +2710,87 @@ export const InteractiveGeometry = memo(function InteractiveGeometry({ return renderInteractive(geometry, 0) + /** + * A wall end's "pull to continue" grip: screen-sized, just past the end + * along the wall, emerald so it reads apart from the end's move grip. + */ + function renderPullGrip( + g: Extract, + keyHint: number, + ): React.ReactElement { + const handleId = `${makeHandleId(nodeId, g.payload)}:pull` + const isHovered = hoveredHandleId === handleId + const k = handleUnitsPerPixel + const c = PULL_GRIP_CENTER_PX * k + const r = PULL_GRIP_RADIUS_PX * (isHovered ? 1.12 : 1) * k + // Outward arrow inside the button: shaft then head, tip along +x. + const arrowD = [ + `M ${c - 5.5 * k},${-1.4 * k}`, + `L ${c + 0.5 * k},${-1.4 * k}`, + `L ${c + 0.5 * k},${-4.6 * k}`, + `L ${c + 6 * k},0`, + `L ${c + 0.5 * k},${4.6 * k}`, + `L ${c + 0.5 * k},${1.4 * k}`, + `L ${c - 5.5 * k},${1.4 * k}`, + 'Z', + ].join(' ') + const affordance = g.affordance + const payload = g.payload + return ( + e.stopPropagation()} + transform={`translate(${g.point[0]} ${g.point[1]}) rotate(${(g.angle * 180) / Math.PI})`} + > + + + + { + if (affordance) { + onHandlePointerDown(affordance, payload, e as ReactPointerEvent) + } + }} + onPointerEnter={() => onHandleHoverChange(handleId)} + onPointerLeave={() => onHandleHoverChange(null)} + // Fill only: the default stroke is a plan metre wide, and would take + // the press meant for the end's move grip. + pointerEvents="fill" + r={PULL_GRIP_HIT_RADIUS_PX * k} + style={{ cursor: 'grab' }} + > + {g.title ? {g.title} : null} + + + ) + } + function renderInteractive(g: FloorplanGeometry, keyHint: number): React.ReactElement { switch (g.kind) { case 'group': { @@ -2914,7 +3063,8 @@ export const InteractiveGeometry = memo(function InteractiveGeometry({ const head1 = `M ${t1x} ${t1y} L ${b1ax} ${b1ay} L ${b1bx} ${b1by} Z` const head2 = `M ${t2x} ${t2y} L ${b2ax} ${b2ay} L ${b2bx} ${b2by} Z` const fill = isHovered ? '#a5b4fc' : '#8381ed' - const strokeWidthPx = isHovered ? 2.4 : 1.8 + const scale = g.scale ?? 1 + const strokeWidthPx = (isHovered ? 2.4 : 1.8) * Math.sqrt(scale) const angleDeg = (g.angle * 180) / Math.PI const affordance = g.affordance const payload = g.payload @@ -2923,7 +3073,7 @@ export const InteractiveGeometry = memo(function InteractiveGeometry({ e.stopPropagation()} - transform={`translate(${g.point[0]} ${g.point[1]}) rotate(${angleDeg})`} + transform={`translate(${g.point[0]} ${g.point[1]}) rotate(${angleDeg}) scale(${scale})`} > + if (g.variant === 'pull') return renderPullGrip(g, keyHint) // Affordance-routed arrows (door width-resize) get a per-payload // handle id so each side can hover independently; default // (move-flow) arrows share the node's :move id like the dot. @@ -2987,13 +3138,14 @@ export const InteractiveGeometry = memo(function InteractiveGeometry({ // so it shrinks on zoom-out and grows on zoom-in, matching the // wall it accompanies. Composed of a rectangular shaft + triangular // head, drawn as a single path for a clean fill + stroke outline. - const sl = 0.1 // shaft length (shortened body) - const hl = 0.12 // head length - const sh = 0.04 // shaft half-height - const hh = 0.1 // head half-height + const k = g.scale ?? 1 + const sl = 0.1 * k // shaft length (shortened body) + const hl = 0.12 * k // head length + const sh = 0.04 * k // shaft half-height + const hh = 0.1 * k // head half-height // Inset the shaft start so the arrow sits a little off the wall // body (matches the 3D `HANDLE_OFFSET`). - const bi = 0.03 // base inset + const bi = 0.03 * k // base inset const arrowD = `M ${bi},${-sh} L ${bi + sl},${-sh} L ${bi + sl},${-hh} L ${bi + sl + hl},0 L ${bi + sl},${hh} L ${bi + sl},${sh} L ${bi},${sh} Z` // Indigo palette to match the 3D wall push arrows // (`ARROW_COLOR` / `ARROW_HOVER_COLOR`) and the corner-sphere @@ -3642,11 +3794,19 @@ const HANDLE_CHROME_KINDS = new Set([ 'equal-spacing-badge', ]) -function stripHandleChrome(g: FloorplanGeometry): FloorplanGeometry | null { +function stripHandleChrome( + g: FloorplanGeometry, + keepContextualDimensions = false, +): FloorplanGeometry | null { + if ( + keepContextualDimensions && + readFloorplanGeometryMetadata(g).annotationRole === 'contextual-dimension' + ) + return g if (HANDLE_CHROME_KINDS.has(g.kind)) return null if (g.kind === 'group') { const children = g.children - .map(stripHandleChrome) + .map((child) => stripHandleChrome(child, keepContextualDimensions)) .filter((c): c is FloorplanGeometry => c !== null) if (children.length === 0) return null return { kind: 'group', children, transform: g.transform } @@ -3763,7 +3923,7 @@ function nodeDepsEqual(a: NodeDeps, b: NodeDeps): boolean { 'live', 'unit', 'metricNotation', - 'wallDimensionReference', + 'wallDimensionFaces', 'selected', 'highlighted', 'hovered', diff --git a/packages/editor/src/components/editor/alignment-3d-guide-layer.tsx b/packages/editor/src/components/editor/alignment-3d-guide-layer.tsx index 1349720c4f..4914d84f88 100644 --- a/packages/editor/src/components/editor/alignment-3d-guide-layer.tsx +++ b/packages/editor/src/components/editor/alignment-3d-guide-layer.tsx @@ -4,10 +4,13 @@ import { type AlignmentGuide, sceneRegistry } from '@pascal-app/core' import { useViewer } from '@pascal-app/viewer' import { useFrame } from '@react-three/fiber' import { memo, useMemo, useRef } from 'react' -import { BoxGeometry, CircleGeometry, type Group, Vector3 } from 'three' +import { BoxGeometry, CircleGeometry, type Group, RingGeometry, Vector3 } from 'three' import { MeshBasicNodeMaterial } from 'three/webgpu' import { EDITOR_LAYER } from '../../lib/constants' -import useAlignmentGuides from '../../store/use-alignment-guides' +import useAlignmentGuides, { + type DraftGuideLine, + type DraftGuides, +} from '../../store/use-alignment-guides' import { Html } from './localized-html' import { formatMeasurement } from './measurement-pill' @@ -22,13 +25,18 @@ import { formatMeasurement } from './measurement-pill' * the design reference — so they're real 3D geometry, not screen billboards. * Only the distance pill is screen-space (``). * - * Guide coordinates are XZ meters in the WORLD frame — alignment now resolves - * on the world axes (via `resolveAlignmentForActiveBuilding`) so the guides - * stay parallel to the visible world grid even when the active building is - * rotated. This layer is mounted OUTSIDE the building-local ToolManager group - * for the same reason. The whole ribbon is lifted to the active level's WORLD - * Y each frame so it lies on the floor being edited — not the building base — - * when floors are stacked. + * Guide coordinates are XZ meters in the active building's LOCAL frame — + * alignment resolves on the building's own axes, the axes its 3D grid is laid + * on — and the layer is mounted inside the building-local ToolManager group. + * The whole ribbon is lifted to the active level's WORLD Y each frame so it + * lies on the floor being edited — not the building base — when floors are + * stacked. + * + * A wall pulled from a wall end (and the run it continues) publishes its + * projection guides beside them (`useAlignmentGuides.draft`): the extension of + * the wall it comes from in amber, lines through other walls' ends in indigo, + * lines through the run's start in emerald, all dashed, with a ringed marker + * where two of them cross. */ const LINE_COLOR = 0x81_8c_f8 // indigo-400 — matches the editor's selection accent (box-select / wall highlights) @@ -59,11 +67,33 @@ const dotMaterial = new MeshBasicNodeMaterial({ }) const DASH_GEOMETRY = new BoxGeometry(1, 1, 1) const DOT_GEOMETRY = new CircleGeometry(1, 24) +const RING_GEOMETRY = new RingGeometry(0.7, 1, 28) + +// Draft projection guides: one material per kind, shared like the above. +const draftGuideMaterial = (color: number) => + new MeshBasicNodeMaterial({ + color, + depthTest: false, + depthWrite: false, + toneMapped: false, + transparent: true, + opacity: 0.9, + }) +const DRAFT_GUIDE_MATERIALS: Record = { + extension: draftGuideMaterial(0xf5_9e_0b), // amber-500 + alignment: guideMaterial, + 'run-start': draftGuideMaterial(0x10_b9_81), // emerald-500 — the pull grip's colour +} +const DRAFT_DASH_LEN = 0.14 +const DRAFT_DASH_GAP = 0.12 +const DRAFT_LINE_WIDTH = 0.035 +const INTERSECTION_RADIUS = 0.13 type Vec3 = [number, number, number] export const Alignment3DGuideLayer = memo(function Alignment3DGuideLayer() { const guides = useAlignmentGuides((s) => s.guides) + const draft = useAlignmentGuides((s) => s.draft) const levelId = useViewer((s) => s.selection.levelId) const unit = useViewer((s) => s.unit) const metricNotation = useViewer((s) => s.metricNotation) @@ -82,16 +112,77 @@ export const Alignment3DGuideLayer = memo(function Alignment3DGuideLayer() { group.position.y = levelMesh ? levelMesh.getWorldPosition(worldYWork).y : 0 }) - if (guides.length === 0) return null + if (guides.length === 0 && !draft) return null return ( {guides.map((guide, i) => ( ))} + {draft ? : null} ) }) +/** A wall draft's dashed projection guides and the markers where they cross. */ +function DraftGuidesLayer({ draft }: { draft: DraftGuides }) { + return ( + <> + {draft.lines.map((line, i) => ( + + ))} + {draft.intersections.map((point, i) => ( + + ))} + + ) +} + +function DraftLine({ line }: { line: DraftGuideLine }) { + const [fx, fz] = line.from + const [tx, tz] = line.to + const { dashes, angleY } = useMemo(() => { + const dx = tx - fx + const dz = tz - fz + const length = Math.hypot(dx, dz) + const angle = -Math.atan2(dz, dx) + if (length < 1e-4) return { dashes: [] as Vec3[], angleY: angle } + const ux = dx / length + const uz = dz / length + const period = Math.max(DRAFT_DASH_LEN + DRAFT_DASH_GAP, length / MAX_DASHES) + const centres: Vec3[] = [] + for (let d = period / 2; d - DRAFT_DASH_LEN / 2 <= length; d += period) { + centres.push([fx + ux * d, GUIDE_Y, fz + uz * d]) + } + return { dashes: centres, angleY: angle } + }, [fx, fz, tx, tz]) + const material = DRAFT_GUIDE_MATERIALS[line.kind] + return ( + <> + {dashes.map((centre, i) => ( + + ))} + + ) +} + function GuideLine({ guide, metricNotation, diff --git a/packages/editor/src/components/editor/bake-thumbnail.tsx b/packages/editor/src/components/editor/bake-thumbnail.tsx index bfc9d578e5..c6f1a8e1f6 100644 --- a/packages/editor/src/components/editor/bake-thumbnail.tsx +++ b/packages/editor/src/components/editor/bake-thumbnail.tsx @@ -47,8 +47,9 @@ const THUMBNAIL_BACKDROP = { inner: '#FAFAFA', outer: '#E4E4E4' } const THUMBNAIL_SHADOW_CATCHER_OPACITY = 0.7 /** Soft shade hugging the ground-floor walls so the building never floats. */ const THUMBNAIL_WALL_CONTACT = { opacity: 0.5, spreadM: 0.9 } -/** Unpainted walls render as smooth plaster rather than the screw-dotted - * prepared-drywall default, which reads as unfinished at card size. */ +/** A roof's unpainted trim and gable bands render as smooth plaster rather + * than the screw-dotted prepared-drywall default, which reads as unfinished + * at card size. Unpainted walls already wear the interior paint. */ const THUMBNAIL_SLOT_DEFAULT_OVERRIDES = { 'library:concrete-drywall': 'library:concrete-plaster', } as const diff --git a/packages/editor/src/components/editor/custom-camera-controls.tsx b/packages/editor/src/components/editor/custom-camera-controls.tsx index 85263d8208..4e663ab72b 100644 --- a/packages/editor/src/components/editor/custom-camera-controls.tsx +++ b/packages/editor/src/components/editor/custom-camera-controls.tsx @@ -62,6 +62,7 @@ import { orbitFloorMinY, overviewEyeY, } from '../../lib/orbit-floor-clearance' +import { orbitNearPlane } from '../../lib/orbit-near-plane' import { editorOwnsOneFingerDrag } from '../../lib/touch-gesture-priority' import { frameViewerCamera } from '../../lib/viewer-selection' import { publishCameraPose } from '../../store/camera-pose-store' @@ -766,8 +767,16 @@ export const CustomCameraControls = ({ paused = false }: { paused?: boolean }) = }, [camera, isFirstPersonMode, viewportSize]) const handleCameraUpdate = useCallback(() => { + const control = controls.current + if (control && isPerspectiveCamera(camera)) { + const near = orbitNearPlane(control.distance) + if (Math.abs(camera.near - near) > 1e-4) { + camera.near = near + camera.updateProjectionMatrix() + } + } publishCurrentPose() - }, [publishCurrentPose]) + }, [camera, publishCurrentPose]) useEffect(() => { publishInitialCameraPose(publishCurrentPose) @@ -1054,7 +1063,10 @@ export const CustomCameraControls = ({ paused = false }: { paused?: boolean }) = updateNavigationCursor() } - const onWheel = () => { + const onWheel = (event: WheelEvent) => { + // Zooming in carries on past the closest orbit, the target with it; zooming out stops at + // the farthest, or the eye would drift off the site. Seen before the controls' own listener. + if (controls.current) controls.current.infinityDolly = event.deltaY < 0 beginLocalCameraInteraction() cameraDraggingLifecycle.scheduleEnd() } @@ -1452,13 +1464,12 @@ export const CustomCameraControls = ({ paused = false }: { paused?: boolean }) = } }, [cameraDraggingLifecycle]) - // Preset capture mode frames a single subtree (often a 0.3–2m preset), - // so the default 2m minDistance prevents the user from getting close - // enough to compose a good thumbnail. Relax the clamp to 0.5m while - // capturing presets; reset on exit so general editing keeps the looser - // navigation guardrails. + // The wheel dollies toward the cursor and, at the closest orbit, carries the + // target on (infinity dolly), so the eye goes right up to a window's trim + // or through a doorway rather than stopping short of the orbit's pivot. + // Preset capture frames a single small subtree and orbits it closer still. const isPresetCapture = captureMode.mode === 'preset' - const minDistance = isPresetCapture ? 0.5 : 2 + const minDistance = isPresetCapture ? 0.25 : 0.5 // Over modeled or mapped surroundings (a neighbourhood instead of the // horizon disc) the camera may pull back far enough to take it all in. const groundReplaced = useSceneGroundReplacement() @@ -1471,6 +1482,7 @@ export const CustomCameraControls = ({ paused = false }: { paused?: boolean }) = return ( state.metricNotation) + // The thickness the wall commits at, as the 3D draft shows it. + const wallDraftThickness = useWallDraftThickness(DEFAULT_WALL_THICKNESS) const wallDraftEnd = useFloorplanDraftPreview((s) => s.wallDraftEnd) const fenceDraftEnd = useFloorplanDraftPreview((s) => s.fenceDraftEnd) const roofDraftEnd = useFloorplanDraftPreview((s) => s.roofDraftEnd) @@ -4489,10 +4525,12 @@ function FloorplanLinearDraftLayer({ ) { return null } - const draftWall = getSharedFloorplanWall(buildDraftWall(levelId, wallDraftStart, wallDraftEnd)) + const draftWall = getSharedFloorplanWall( + buildDraftWall(levelId, wallDraftStart, wallDraftEnd, wallDraftThickness), + ) // Keep the live draft preview cheap; full level-wide mitering here runs on every mouse move. return getWallPlanFootprint(draftWall, EMPTY_WALL_MITER_DATA) - }, [levelId, wallDraftStart, wallDraftEnd]) + }, [levelId, wallDraftStart, wallDraftEnd, wallDraftThickness]) // Rectangle mode drafts four walls at once; they read exactly like a line // draft — same mitered footprints, measurement plates and axis guides. @@ -5067,6 +5105,9 @@ export function FloorplanPanel({ // Walls committed by the current 2D-only chain — exclusion set for the // T-junction chain-termination test (mirrors the 3D tool's `chainWallIds`). const wallChainWallIdsRef = useRef([]) + // Direction of the run's last wall (a pulled run's source first): the next + // holds square to it. Null before the run has a wall. + const wallRunReferenceRef = useRef(null) const setDraftEnd = useCallback( (next: WallPlanPoint | null | ((prev: WallPlanPoint | null) => WallPlanPoint | null)) => { const store = useFloorplanDraftPreview.getState() @@ -5082,14 +5123,10 @@ export function FloorplanPanel({ }, [], ) - const [roofDraftStart, setRoofDraftStart] = useState(null) - const setRoofDraftEnd = useCallback( - (next: WallPlanPoint | null | ((prev: WallPlanPoint | null) => WallPlanPoint | null)) => { - const store = useFloorplanDraftPreview.getState() - store.setRoofDraftEnd(typeof next === 'function' ? next(store.roofDraftEnd) : next) - }, - [], - ) + // The roof tool that owns the input (the 3D tool, or the plan's own in 2D-only view) writes the + // roof draft from the corners it snaps and commits; the plan only draws it, so its rectangle is + // the roof the next click makes. + const roofDraftStart = useFloorplanDraftPreview((s) => s.roofDraftStart) const [ceilingDraftPoints, setCeilingDraftPoints] = useState([]) const [slabDraftPoints, setSlabDraftPoints] = useState([]) const slabPlacementBaseRef = useRef(null) @@ -5102,9 +5139,6 @@ export function FloorplanPanel({ useEffect(() => { useFloorplanDraftPreview.getState().setFenceDraftStart(fenceDraftStart) }, [fenceDraftStart]) - useEffect(() => { - useFloorplanDraftPreview.getState().setRoofDraftStart(roofDraftStart) - }, [roofDraftStart]) const [zoneDraftPoints, setZoneDraftPoints] = useState([]) const [siteBoundaryDraft, setSiteBoundaryDraft] = useState(null) const [siteVertexDragState, setSiteVertexDragState] = useState(null) @@ -7890,20 +7924,29 @@ export function FloorplanPanel({ setWallChainFirstVertex(null) wallConstructionOptionsRef.current = undefined wallChainWallIdsRef.current = [] + wallRunReferenceRef.current = null setDraftEnd(null) useSegmentDraftChain.getState().clear('wall') + // A run pulled from a wall end ends with the plan's draft: back to Select. + endWallPullRun() }, [setDraftEnd]) const clearFencePlacementDraft = useCallback(() => { setFenceDraftStart(null) setFenceDraftEnd(null) }, [setFenceDraftEnd]) const clearRoofPlacementDraft = useCallback(() => { - setRoofDraftStart(null) - setRoofDraftEnd(null) - }, [setRoofDraftEnd]) + const draft = useFloorplanDraftPreview.getState() + draft.setRoofDraftStart(null) + draft.setRoofDraftEnd(null) + }, []) const clearCeilingPlacementDraft = useCallback(() => { setCeilingDraftPoints([]) }, []) + // Beside the 3D view its ceiling tool commits; in 2D-only view the plan does. Each keeps its own + // corners, so a polygon begun under one owner must not be closed against the other's. + useEffect(() => { + if (shownScene) clearCeilingPlacementDraft() + }, [clearCeilingPlacementDraft, shownScene]) const clearSlabPlacementDraft = useCallback(() => { setSlabDraftPoints([]) slabPlacementBaseRef.current = null @@ -7999,6 +8042,30 @@ export function FloorplanPanel({ } }, [clearDraft]) + // A wall end's pull grip pressed in the plan opens the Walls run at that + // end: start the plan's draft there, as if the end had been clicked. A pull + // from the 3D view drafts there (the plan beside it follows its moves). + const wallPullRun = useWallPullRun((state) => state.run) + const seededWallPullSeqRef = useRef(null) + useEffect(() => { + if (!(wallPullRun && wallPullRun.origin === '2d' && isWallBuildActive && levelId)) return + if (seededWallPullSeqRef.current === wallPullRun.seq) return + seededWallPullSeqRef.current = wallPullRun.seq + const start = wallPullRun.start + wallConstructionOptionsRef.current = resolveTerrainWallConstructionOptions( + useScene.getState().nodes, + levelId, + start, + useEditor.getState().toolDefaults.wall, + ) + wallChainWallIdsRef.current = [] + wallRunReferenceRef.current = wallPullRun.reference + setDraftStart(start) + setWallChainFirstVertex(start) + setDraftEnd(start) + setCursorPoint(start) + }, [isWallBuildActive, levelId, setCursorPoint, setDraftEnd, wallPullRun]) + const createZoneOnCurrentLevel = useCallback( (points: WallPlanPoint[]) => { if (!levelId) { @@ -9313,14 +9380,6 @@ export function FloorplanPanel({ setCursorPoint((previousPoint) => previousPoint && pointsEqual(previousPoint, snappedPoint) ? previousPoint : snappedPoint, ) - - if (roofDraftStart) { - setRoofDraftEnd((previousPoint) => - previousPoint && pointsEqual(previousPoint, snappedPoint) - ? previousPoint - : snappedPoint, - ) - } return } @@ -9535,35 +9594,61 @@ export function FloorplanPanel({ return } - // Wall draft: grid + magnetic snap, then Figma-style alignment. - // While a draft is open the segment locks to 15° rays from its start. - // Snapping is governed by the snapping mode (`'off'` is the bypass); - // there is no Shift hold-to-bypass. - const wallAngleSnap = draftStart !== null && isAngleSnapActive() - const wallSnap = snapWallDraftPointDetailed({ - point: planPoint, - walls: [...walls, ...wallPolygonDraftWalls()], - start: draftStart ?? undefined, - angleSnap: wallAngleSnap, - magnetic: isMagneticSnapActive(), - }) - const wallSnapped = wallSnap.point - // Locked onto existing geometry (corner / midpoint / crossing / edge) → - // that snap wins, so skip Figma alignment and stand the beacon there. - const lockedToWall = wallSnap.snap !== null - let snappedPoint = wallSnapped - if (lockedToWall) { - useAlignmentGuides.getState().clear() + // Wall draft: grid + magnetic snap, then Figma-style alignment. A Walls + // segment locks to 15° rays from its start; a run's segment (a Polygon + // side, a pulled run) holds square to the last wall and the house's axes, + // with projection guides and a labelled snap marker + // (`snapWallRunDraftPoint`). Snapping is governed by the snapping mode + // (`'off'` is the bypass); Alt frees a run's segment. An invisible wall + // draft catches the invisible walls already drawn as well. + let snappedPoint: WallPlanPoint + const draftSnapWalls = [ + ...walls, + ...wallPolygonDraftWalls(), + ...invisibleWallDraftSnapLines(), + ] + if (draftStart && wallDraftIsRun()) { + const runSnap = snapWallRunDraftPoint({ + point: planPoint, + start: draftStart, + runStart: wallChainFirstVertex ?? draftStart, + reference: wallRunReferenceRef.current, + walls: draftSnapWalls, + free: isWallRunFree(event), + }) + snappedPoint = runSnap.point + publishWallRunFeedback(runSnap) } else { - // Alignment lines show in every mode; the pull applies only when - // magnetic ('lines') and the segment isn't angle-locked. - snappedPoint = alignFloorplanDraftPoint(wallSnapped, { - applySnap: isMagneticSnapActive() && !wallAngleSnap, + const wallAngleSnap = draftStart !== null && isAngleSnapActive() + const wallSnap = snapWallDraftPointDetailed({ + point: planPoint, + walls: draftSnapWalls, + start: draftStart ?? undefined, + angleSnap: wallAngleSnap, + magnetic: isMagneticSnapActive(), + // Same as the click: an end aimed into a wall's body joins it. + captureWallBodies: true, }) + const wallSnapped = wallSnap.point + // Locked onto existing geometry (corner / midpoint / crossing / edge) → + // that snap wins, so skip Figma alignment and stand the beacon there. + const lockedToWall = wallSnap.snap !== null + snappedPoint = wallSnapped + if (lockedToWall) { + useAlignmentGuides.getState().clear() + } else { + // Alignment lines show in every mode; the pull applies only when + // magnetic ('lines') and the segment isn't angle-locked. + snappedPoint = alignFloorplanDraftPoint(wallSnapped, { + applySnap: isMagneticSnapActive() && !wallAngleSnap, + }) + } + useWallSnapIndicator + .getState() + .set( + wallSnap.snap ? { x: snappedPoint[0], z: snappedPoint[1], kind: wallSnap.snap } : null, + ) } - useWallSnapIndicator - .getState() - .set(wallSnap.snap ? { x: snappedPoint[0], z: snappedPoint[1], kind: wallSnap.snap } : null) // Emit `grid:move` so the registry-driven wall tool's 3D preview // tracks the cursor. The local draftEnd update below is what @@ -9621,15 +9706,14 @@ export function FloorplanPanel({ levelId, publishFloorplanNavigationPose, referenceScaleDraft, - roofDraftStart, siteVertexDragState, surfaceSize.height, surfaceSize.width, svgAspectRatio, walls, + wallChainFirstVertex, setCursorPoint, setDraftEnd, - setRoofDraftEnd, setFenceDraftEnd, ], ) @@ -9823,6 +9907,7 @@ export function FloorplanPanel({ ) { startWallPolygonDraft(levelId as AnyNodeId, point, wallConstructionOptionsRef.current) } + wallRunReferenceRef.current = null setDraftStart(point) setWallChainFirstVertex(point) setDraftEnd(point) @@ -9833,6 +9918,8 @@ export function FloorplanPanel({ if (!isSegmentLongEnough(draftStart, point)) { return } + // The run's next segment holds square to this one. + const placedDirection = wallRunDirection(draftStart, point) // The 3D wall tool's `grid:click` listener // (`packages/nodes/src/wall/tool.tsx`) owns the wall-create @@ -9849,7 +9936,7 @@ export function FloorplanPanel({ // ceiling 2D-only committers: create locally here, gated on the // view, so split / 3D keep their single-owner tool commit. const viewIs2DOnly = visibleScene(useEditor.getState()) === '2d' - let createdWall: WallNode | null = null + let createdWall: WallNode | SeparatorNode | null = null // 2D-only Polygon room: the corner joins the draft; nothing is written // until it closes, seals or tees (then every wall at once). if (viewIs2DOnly && getWallDrawVariant() === 'polygon') { @@ -9859,17 +9946,18 @@ export function FloorplanPanel({ setCursorPoint(null) return } + wallRunReferenceRef.current = placedDirection setDraftStart(point) setDraftEnd(point) setCursorPoint(point) return } if (viewIs2DOnly) { - createdWall = createWallOnCurrentLevel( - draftStart, - point, - wallConstructionOptionsRef.current, - ) + // The Walls variant's Invisible draws room separators, not walls. + createdWall = + getWallLineKind() === 'invisible' + ? createInvisibleWallOnCurrentLevel(draftStart, point) + : createWallOnCurrentLevel(draftStart, point, wallConstructionOptionsRef.current) } if (createdWall) { wallChainWallIdsRef.current.push(createdWall.id) @@ -9885,7 +9973,7 @@ export function FloorplanPanel({ : (publishedNextStart ?? point) if ( - useEditor.getState().getContinuation('wall') === 'single' || + !wallDraftIsRun() || (wallChainFirstVertex && isWithinWallJoinSnapRadius(nextStart, wallChainFirstVertex)) ) { clearWallPlacementDraft() @@ -9907,7 +9995,7 @@ export function FloorplanPanel({ levelWalls, wallChainWallIdsRef.current, ) || - wallClosesRoom(levelWalls, createdWall) + (createdWall.type === 'wall' && wallClosesRoom(levelWalls, createdWall)) ) { clearWallPlacementDraft() setCursorPoint(null) @@ -9923,6 +10011,7 @@ export function FloorplanPanel({ return } + wallRunReferenceRef.current = placedDirection setDraftStart(nextStart) setDraftEnd(nextStart) setCursorPoint(nextStart) @@ -9953,6 +10042,11 @@ export function FloorplanPanel({ }) => snapWallDraftPoint({ ...args, magnetic: isMagneticSnapActive() }), [], ) + // What the click needs to snap an open run's segment as the move did. + const getWallRunContext = useCallback( + () => ({ runStart: wallChainFirstVertex, reference: wallRunReferenceRef.current }), + [wallChainFirstVertex], + ) const { handleBackgroundPlacementClick } = useFloorplanBackgroundPlacement({ activePolygonDraftPoints, ceilingDraftPoints, @@ -9965,6 +10059,7 @@ export function FloorplanPanel({ findClosestWallPoint, floorplanOpeningLocalY, getSnappedFloorplanPoint, + getWallRunContext, handleCeilingItemPlacementClick, handleCeilingPlacementPoint, handleSlabPlacementPoint, @@ -9988,20 +10083,16 @@ export function FloorplanPanel({ isWallBuildActive, isZoneBuildActive, levelId, - roofDraftStart, setCursorPoint, setFenceDraftEnd, setFenceDraftStart, - setRoofDraftEnd, - setRoofDraftStart, snapPolygonDraftPoint, snapWallDraftPoint: snapWallDraftPointMagnetic, toPoint2D, walls, - // World-axis grid snap so drafts land on the visible grid even - // when the active building is rotated. The helper resolves the - // active building's pose internally; this hook stays oblivious to - // building rotation / position. + // Building-grid snap: the lattice this plan draws inside its rotated + // scene group, so drafts land on the visible grid however the + // building is turned, and where the 3D tool would put them. worldGridSnap: snapBuildingLocalToWorldGrid, }) @@ -10204,6 +10295,16 @@ export function FloorplanPanel({ ) const handleSvgPointerUp = useCallback( (event: ReactPointerEvent) => { + // Letting go of a wall end's pull grip places the pulled wall, as a click + // there would; the click the browser fires next is eaten. + const pull = useWallPullRun.getState().run + if (event.button === 0 && pull?.dragging && pull.origin === '2d') { + releaseWallPullDrag() + if (isWallBuildActive && draftStart) { + swallowNextClick() + handleBackgroundClick(event) + } + } if ( isFenceBuildActive && useEditor.getState().getContinuation('fence') === 'freehand' && @@ -10215,14 +10316,30 @@ export function FloorplanPanel({ endFloorplanNavigation(event) }, [ + draftStart, emitFloorplanGridEvent, endFloorplanNavigation, getPlanPointFromClientPoint, + handleBackgroundClick, isFenceBuildActive, + isWallBuildActive, ], ) const handleBackgroundDoubleClick = useCallback( (event: ReactMouseEvent) => { + // A double-click ends a wall run as the 3D tool's detail-2 click does: + // the walls already drawn stay, an open Polygon room is kept, and the + // draft goes. The click path does this on its second click; this also + // covers one the plan never routed there (the walls the run drew sit + // under the pointer by then). + if (isWallBuildActive) { + if (draftStart) { + commitWallPolygonDraft() + clearWallPlacementDraft() + setCursorPoint(null) + } + return + } if (!(isPolygonDraftBuildActive && !isRoofBuildActive)) { return } @@ -10268,6 +10385,8 @@ export function FloorplanPanel({ }, [ activePolygonDraftPoints, + clearWallPlacementDraft, + draftStart, emitFloorplanGridEvent, handleCeilingPlacementConfirm, getPlanPointFromClientPoint, @@ -10276,8 +10395,10 @@ export function FloorplanPanel({ isCeilingBuildActive, isPolygonDraftBuildActive, isRoofBuildActive, + isWallBuildActive, isZoneBuildActive, levelId, + setCursorPoint, ], ) @@ -11626,6 +11747,11 @@ export function FloorplanPanel({ `floorplan-wall-move-ghost-layer.tsx`. */} + {/* Dashed walls of the level below / above, over the plan but + outside the measured group so they never change the fit. */} + {activeDrawingType !== 'site-plan' && ( + + )} {activeDrawingType !== 'site-plan' && } @@ -11641,7 +11767,7 @@ export function FloorplanPanel({ overlay during a free-translate drag. Sits above the registry layer so the red lines and distance pills paint on top of node geometry. */} - + {/* The property line, its vertex handles and its edge labels are drawn in BUILDING-LOCAL metres (the frame the level's walls @@ -11695,7 +11821,7 @@ export function FloorplanPanel({ {/* "Magnetic" wall-snap beacon — per-kind glyph at the active draft / endpoint-move snap point. Same store + coord space as the alignment guides. */} - + diff --git a/packages/editor/src/components/editor/grid.tsx b/packages/editor/src/components/editor/grid.tsx index bda40eb44e..72f046f5d8 100644 --- a/packages/editor/src/components/editor/grid.tsx +++ b/packages/editor/src/components/editor/grid.tsx @@ -15,7 +15,8 @@ import { MeshBasicNodeMaterial } from 'three/webgpu' import { useCeilingEvents } from '../../hooks/use-ceiling-events' import { useGridEvents } from '../../hooks/use-grid-events' import { getPlacementSurface, usesOrientedPlacementPlane } from '../../lib/active-placement-surface' -import { gridLocalNormal, gridLocalPoint } from '../../lib/grid-frame' +import { gridLocalNormal, gridLocalPoint, layHorizontalGrid } from '../../lib/grid-frame' +import { getActiveGridPose } from '../../lib/world-grid-snap' import useEditor, { getActiveSnapContext, isGridSnapActive } from '../../store/use-editor' import { getMovingNode } from '../../store/use-interaction-scope' @@ -27,10 +28,9 @@ export const EDITOR_GRID_INPUT_NAME = 'pascal-editor-grid-input' const PLACEMENT_REVEAL_RADIUS = 12 const UP = new Vector3(0, 1, 0) -// PlaneGeometry faces +Z; this is the orientation that lays it flat (its normal -// → world +Y), equivalent to the old `rotation-x={-π/2}`. +// PlaneGeometry faces +Z; the oriented (wall-plane) lattice turns this normal +// into the host's. The flat lattice is laid by `layHorizontalGrid`. const PLANE_LOCAL_NORMAL = new Vector3(0, 0, 1) -const HORIZONTAL_QUATERNION = new Quaternion().setFromUnitVectors(PLANE_LOCAL_NORMAL, UP) export const Grid = ({ cellSize = 0.5, @@ -184,10 +184,10 @@ export const Grid = ({ useCeilingEvents() // Track the last world-space cursor hit. The reveal-fade shader reads - // `positionLocal.xy` (vertex position on the un-transformed plane), and the - // laid-flat orientation maps `positionLocal.y` to world `-Z` relative to the - // mesh origin. The cursor is recomputed every frame from the stored world hit - // so the reveal stays put regardless of where the mesh origin sits. + // `positionLocal.xy` (vertex position on the un-transformed plane), so the + // cursor is taken into the plane's frame every frame from the stored world + // hit — the reveal stays put wherever the mesh origin sits and however it + // is turned. const lastWorldCursorRef = useRef(null) useEffect(() => { const onGridMove = (event: GridEvent) => { @@ -279,20 +279,29 @@ export const Grid = ({ setGridY(surfacePoint.y) } } else { - // Horizontal: keep the lattice anchored to world XZ (0,0); only the Y - // origin follows the surface height (floor / shelf top). Snap directly — - // the old lerp made the grid visibly drift up to a new floor height. - // Cursor uniform tracks the world cursor (mirrored on Z for the flat plane). + // Horizontal: lay the lattice on the frame the tools snap in — the + // active building's yaw and offset, so a turned house's walls sit square + // on it, or world XZ (0,0) for site work; only the Y origin follows the + // surface height (floor / shelf top). Snap directly — the old lerp made + // the grid visibly drift up to a new floor height. const targetY = surfacePoint ? surfacePoint.y : levelY // Visual mesh rides 1mm above the surface: at exactly the surface Y the // lattice is coplanar with the slab top and z-fights it. The event plane // (`gridY` → useGridEvents) stays at the true surface height. - gridMesh.position.set(0, targetY + 0.001, 0) - gridMesh.quaternion.copy(HORIZONTAL_QUATERNION) + layHorizontalGrid( + getActiveGridPose(), + targetY + 0.001, + gridMesh.position, + gridMesh.quaternion, + ) + // Cursor uniform → plane-local XY, as for the wall plane above. const world = lastWorldCursorRef.current if (world) { + invQuatRef.current.copy(gridMesh.quaternion).invert() const local = gridLocalPoint(gridMesh.parent, world, localCursorRef.current) - cursorPositionRef.current.set(local.x, -local.z) + .sub(gridMesh.position) + .applyQuaternion(invQuatRef.current) + cursorPositionRef.current.set(local.x, local.y) } if (lastGridYRef.current !== targetY) { lastGridYRef.current = targetY diff --git a/packages/editor/src/components/editor/group-actions.ts b/packages/editor/src/components/editor/group-actions.ts index a14125a858..3f3200f575 100644 --- a/packages/editor/src/components/editor/group-actions.ts +++ b/packages/editor/src/components/editor/group-actions.ts @@ -41,6 +41,7 @@ import useFloorplanMode from '../../store/use-floorplan-mode' import useInteractionScope from '../../store/use-interaction-scope' import { useFloorplanGroupDrag } from '../editor-2d/floorplan-group-move' import { + beginGroupWallPush, classifyParticipant, collectParticipants, computeGroupBox, @@ -185,6 +186,9 @@ export function startGroupPickUp( handle: GROUP_MOVE_DRAG_LABEL, }) document.body.style.cursor = 'grabbing' + // Walls alone move as their push arrows do; copies (paste, duplicate) are + // carried rigidly, joined to nothing yet. + const push = opts.scopeToSelection ? null : beginGroupWallPush(starts, levelId) const applyMove = (e: PointerEvent) => { const plan = resolvePlanPoint(e) @@ -202,7 +206,8 @@ export function startGroupPickUp( let dx = snap ? Math.round(rawDx / step) * step : rawDx let dz = snap ? Math.round(rawDz / step) * step : rawDz - if (isAlignmentGuideActive() && candidates.length > 0 && restAnchors.length > 0) { + // Pushed walls don't move as one footprint, so they have no box to align. + if (!push && isAlignmentGuideActive() && candidates.length > 0 && restAnchors.length > 0) { const result = resolveAlignment({ moving: restAnchors.map((a) => ({ ...a, x: a.x + dx, z: a.z + dz })), candidates, @@ -225,6 +230,10 @@ export function startGroupPickUp( sfxEmitter.emit('sfx:grid-snap') lastDelta = [dx, dz] } + if (push) { + push.preview([dx, dz]) + return + } const entries = translateGroupPatches(starts, links, dx, dz) const patchById = new Map(entries) @@ -252,6 +261,8 @@ export function startGroupPickUp( // the current delta — the carried group turns exactly like the idle // keyboard rotate, and the placement stays a single updateNodes. const rotateCarried = (direction: 1 | -1) => { + // Pushed walls keep their bearing: there is nothing to turn. + if (push) return const pivot = { x: restCenter[0], z: restCenter[1] } const delta = -direction * (Math.PI / 4) const rotated = rotateGroupSnapshots(starts, links, pivot, delta) @@ -271,6 +282,7 @@ export function startGroupPickUp( } const clearLivePreviews = () => { + push?.cancel() const overrides = useLiveNodeOverrides.getState() const liveTransforms = useLiveTransforms.getState() for (const id of affectedIds) { @@ -303,6 +315,12 @@ export function startGroupPickUp( const commit = () => { swallowNextClick() sfxEmitter.emit('sfx:item-place') + if (push) { + resumeSceneHistory(useScene) + push.commit() + teardown() + return + } const overrides = useLiveNodeOverrides.getState() const updates: { id: AnyNodeId; data: Partial }[] = [] for (const id of affectedIds) { diff --git a/packages/editor/src/components/editor/group-move-3d.ts b/packages/editor/src/components/editor/group-move-3d.ts index 74cc625d31..81e5da6002 100644 --- a/packages/editor/src/components/editor/group-move-3d.ts +++ b/packages/editor/src/components/editor/group-move-3d.ts @@ -16,6 +16,7 @@ import { useViewer } from '@pascal-app/viewer' import { type Camera, Plane, type Raycaster, Vector2, Vector3 } from 'three' import { GROUP_MOVE_DRAG_LABEL } from '../../lib/contextual-help' import { isHistoryShortcut } from '../../lib/history' +import type { WallGroupPush } from '../../lib/room-handle-drag' import { sfxEmitter } from '../../lib/sfx-bus' import { isTypingTarget } from '../../lib/typing-target' import useAlignmentGuides from '../../store/use-alignment-guides' @@ -29,6 +30,7 @@ import { useFloorplanGroupDrag } from '../editor-2d/floorplan-group-move' import { suppressBoxSelectForPointer } from '../tools/select/box-select-state' import { startGroupPickUp } from './group-actions' import { + beginGroupWallPush, classifyParticipant, collectParticipants, computeGroupBox, @@ -99,6 +101,8 @@ export function armGroupMove3d(args: { startLocal: Vector3 frameInv: ReturnType['inverse'] lastDelta: Vec2 | null + /** Walls alone: each moves as its push arrow does instead of the rigid slide. */ + push: WallGroupPush | null } let session: Session | null = null @@ -179,6 +183,7 @@ export function armGroupMove3d(args: { startLocal, frameInv, lastDelta: null, + push: beginGroupWallPush(starts, levelId), } } @@ -202,8 +207,14 @@ export function armGroupMove3d(args: { : moveLocal.z - s.startLocal.z // Figma-style alignment layered on top: guides display in every mode - // except Off; the magnetic pull applies only in 'lines' mode. - if (isAlignmentGuideActive() && s.candidates.length > 0 && s.restAnchors.length > 0) { + // except Off; the magnetic pull applies only in 'lines' mode. Pushed walls + // don't move as one footprint, so they have no box to align. + if ( + !s.push && + isAlignmentGuideActive() && + s.candidates.length > 0 && + s.restAnchors.length > 0 + ) { const result = resolveAlignment({ moving: s.restAnchors.map((a) => ({ ...a, x: a.x + dx, z: a.z + dz })), candidates: s.candidates, @@ -227,6 +238,10 @@ export function armGroupMove3d(args: { sfxEmitter.emit('sfx:grid-snap') s.lastDelta = [dx, dz] } + if (s.push) { + s.push.preview([dx, dz]) + return + } const entries = translateGroupPatches(s.starts, s.links, dx, dz) const patchById = new Map(entries) @@ -255,6 +270,8 @@ export function armGroupMove3d(args: { // current delta — the carried group turns exactly like the idle keyboard // rotate, and the commit stays a single updateNodes. const rotateSession = (s: Session, direction: 1 | -1) => { + // Pushed walls keep their bearing: there is nothing to turn. + if (s.push) return const pivot = { x: s.restCenter[0], z: s.restCenter[1] } const delta = -direction * (Math.PI / 4) const rotated = rotateGroupSnapshots(s.starts, s.links, pivot, delta) @@ -276,6 +293,7 @@ export function armGroupMove3d(args: { } const clearLivePreviews = (s: Session) => { + s.push?.cancel() const overrides = useLiveNodeOverrides.getState() const liveTransforms = useLiveTransforms.getState() for (const id of s.affectedIds) { @@ -342,6 +360,13 @@ export function armGroupMove3d(args: { } swallowNextClick() sfxEmitter.emit('sfx:item-place') + if (session.push) { + resumeSceneHistory(useScene) + session.push.commit() + session = null + teardown() + return + } const overrides = useLiveNodeOverrides.getState() const updates: { id: AnyNodeId; data: Partial }[] = [] for (const id of session.affectedIds) { diff --git a/packages/editor/src/components/editor/group-selection-box-3d.tsx b/packages/editor/src/components/editor/group-selection-box-3d.tsx index 6e33fe67ed..c580159e37 100644 --- a/packages/editor/src/components/editor/group-selection-box-3d.tsx +++ b/packages/editor/src/components/editor/group-selection-box-3d.tsx @@ -5,6 +5,7 @@ import { useViewer } from '@pascal-app/viewer' import { type ThreeEvent, useThree } from '@react-three/fiber' import { useEffect, useMemo } from 'react' import * as THREE from 'three' +import { useRoomHandleDrag } from '../../lib/room-handle-drag' import useEditor from '../../store/use-editor' import { useMovingNode } from '../../store/use-interaction-scope' import { useFloorplanGroupDrag } from '../editor-2d/floorplan-group-move' @@ -38,6 +39,8 @@ export function GroupSelectionBox3D() { const mode = useEditor((s) => s.mode) const movingNode = useMovingNode() const delta = useFloorplanGroupDrag((s) => s.delta) + // Pushed walls don't move as one box: the room widths they show take its place. + const wallPush = useRoomHandleDrag((s) => s.drag?.kind === 'wall-group-push') const { camera, raycaster, gl } = useThree() const participantIds = useMemo( @@ -118,7 +121,7 @@ export function GroupSelectionBox3D() { return new THREE.Vector3(delta[0], 0, delta[1]).applyMatrix4(matrix).sub(origin) }, [delta, levelId]) - if (!box || !edges || movingNode || mode !== 'select') return null + if (!box || !edges || movingNode || wallPush || mode !== 'select') return null const handlePointerDown = (event: ThreeEvent) => { const native = event.nativeEvent diff --git a/packages/editor/src/components/editor/group-transform-shared.ts b/packages/editor/src/components/editor/group-transform-shared.ts index 954f3dbaf0..68ab00bf00 100644 --- a/packages/editor/src/components/editor/group-transform-shared.ts +++ b/packages/editor/src/components/editor/group-transform-shared.ts @@ -10,6 +10,7 @@ import { type WallNode, } from '@pascal-app/core' import { Box3, type BufferGeometry, Matrix4, type Object3D, Vector3 } from 'three' +import { beginWallGroupPush, type WallGroupPush } from '../../lib/room-handle-drag' // Shared plumbing for the group transform gizmos (rotate + move). Both operate // on the same multi-selection: classify each participant by how its placement @@ -486,6 +487,25 @@ export function rotatePlanBounds( return { minX, minZ, maxX, maxZ } } +/** + * A group move of walls alone moves each wall as its push arrow does + * (`planWallGroupPush`) rather than sliding the selection rigidly: null for + * any other selection, which keeps the rigid slide. Doors and windows are not + * participants (they ride their wall), so they never make a selection mixed. + */ +export function beginGroupWallPush( + starts: readonly ParticipantStart[], + levelId: string | null, +): WallGroupPush | null { + const nodes = useScene.getState().nodes + if (!levelId || starts.length === 0) return null + if (!starts.every((s) => s.kind === 'endpoint' && nodes[s.id]?.type === 'wall')) return null + return beginWallGroupPush( + starts.map((s) => s.id), + levelId, + ) +} + // Rigid group slide: shift every participant (and each linked neighbour's // shared endpoint) by the same level-frame XZ delta. Y is untouched; the // snapshot's rotation rides along because a mid-gesture R/T turns the diff --git a/packages/editor/src/components/editor/index.tsx b/packages/editor/src/components/editor/index.tsx index 56e50c9fca..49257989c4 100644 --- a/packages/editor/src/components/editor/index.tsx +++ b/packages/editor/src/components/editor/index.tsx @@ -6,6 +6,7 @@ import { createI18n, getCatalogMaterialById, getLibraryMaterialIdFromRef, + getMaterialSwatch, getSceneMaterialIdFromRef, initSpaceDetectionSync, initSpatialGridSync, @@ -77,7 +78,7 @@ import useSessionGroups from '../../store/use-session-groups' import { paneOfView, VIEW_2D, VIEW_3D, type ViewPaneIndex } from '../../store/view-layout' import { PointAskLayer } from '../point-ask/point-ask-layer' import { CeilingSelectionAffordanceSystem } from '../systems/ceiling/ceiling-selection-affordance-system' -import { CeilingSystem } from '../systems/ceiling/ceiling-system' +import { CeilingSystem, CeilingTopsSync } from '../systems/ceiling/ceiling-system' import { RoofEditSystem } from '../systems/roof/roof-edit-system' import { SelectionAffordanceManager } from '../systems/selection-affordance-manager' import { StairEditSystem } from '../systems/stair/stair-edit-system' @@ -773,7 +774,17 @@ function getActivePaintMaterialSwatchImageUrl( const catalogId = getLibraryMaterialIdFromRef(material?.materialPreset) ?? material?.material?.id ?? undefined const catalogMaterial = getCatalogMaterialById(catalogId) - return catalogMaterial?.previewThumbnailUrl ?? catalogMaterial?.preset.maps.albedoMap + return catalogMaterial ? (getMaterialSwatch(catalogMaterial).imageUrl ?? undefined) : undefined +} + +/** Whether the badge's image is a white albedo its colour tints (a siding's profile). */ +function isActivePaintMaterialSwatchTinted(material: ActivePaintMaterial | null) { + if (material?.material?.texture?.url || getSceneMaterialIdFromRef(material?.materialPreset)) + return false + const catalogId = + getLibraryMaterialIdFromRef(material?.materialPreset) ?? material?.material?.id ?? undefined + const catalogMaterial = getCatalogMaterialById(catalogId) + return catalogMaterial ? getMaterialSwatch(catalogMaterial).tinted : false } function PaintCursorBadge({ @@ -781,6 +792,7 @@ function PaintCursorBadge({ state, swatchColor, swatchImageUrl, + swatchTinted = false, isEraser, isPicker = false, }: { @@ -788,6 +800,8 @@ function PaintCursorBadge({ state: PaintCursorBadgeState swatchColor: string swatchImageUrl?: string + /** Multiply the image by the colour (a tinted albedo). */ + swatchTinted?: boolean isEraser: boolean /** The eyedropper: the swatch is what a click would take. */ isPicker?: boolean @@ -861,6 +875,7 @@ function PaintCursorBadge({ backgroundImage: swatchImageUrl ? `url(${JSON.stringify(swatchImageUrl)})` : undefined, + backgroundBlendMode: swatchImageUrl && swatchTinted ? 'multiply' : undefined, opacity: state === 'aim' ? 0.55 : 1, }} /> @@ -1124,6 +1139,7 @@ function PaintCursorLayer({ const swatchMaterial = picking ? picked : activePaintMaterial const swatchColor = getActivePaintMaterialSwatchColor(swatchMaterial, sceneMaterials) const swatchImageUrl = getActivePaintMaterialSwatchImageUrl(swatchMaterial, sceneMaterials) + const swatchTinted = isActivePaintMaterialSwatchTinted(swatchMaterial) if (!active || !position) return null @@ -1139,6 +1155,7 @@ function PaintCursorLayer({ state={badgeState} swatchColor={swatchColor} swatchImageUrl={swatchImageUrl} + swatchTinted={swatchTinted} /> ) @@ -1367,6 +1384,7 @@ const ViewerCanvas = memo(function ViewerCanvas({ const viewId = layout.panes[pane] return (
view.id === viewId)} /> + {/* A restored pane's plugin is known only once the project has loaded: until + then it would read "This view isn't available". */} + {isSceneDataLoading && loadingOverlay}
) })} @@ -1866,6 +1887,7 @@ function EditorContent({ return ( <> + {!isLoading && isPreviewMode ? ( + {!isLoading && isPreviewMode ? ( (state.expanded ? state.activeExtensionId : null)) + if (isMobile) return null + return extensions + .filter((extension) => extension !== primaryExtension) + .map((extension) => ( + { + event.stopPropagation() + useInspectorExpanded.getState().applyMode(openExtension(extension.id)) + }} + pressed={active === extension.id} + > + {renderExtensionIcon(extension.icon)} + + )) +} diff --git a/packages/editor/src/components/editor/registry-action-contributions.tsx b/packages/editor/src/components/editor/registry-action-contributions.tsx index 6009261ba2..bb0dfa8c0f 100644 --- a/packages/editor/src/components/editor/registry-action-contributions.tsx +++ b/packages/editor/src/components/editor/registry-action-contributions.tsx @@ -17,6 +17,7 @@ import { type ComponentType, lazy, Suspense } from 'react' import { useShallow } from 'zustand/react/shallow' import { getFloorplanNodeExtension } from '../../lib/floorplan/floorplan-extension' import { ActionMenuButton } from './action-menu-button' +import { InspectorExtensionActions } from './inspector-extension-actions' type Loader = () => Promise<{ default: ComponentType }> const lazyCache = new WeakMap() @@ -106,7 +107,8 @@ function MechanismAction() { /** * The buttons kinds add to the action menu for selections holding them * (`extensions['pascal:editor/floorplan'].actionMenu.actions`), in 2D and 3D - * alike. Each contribution reads the selection and decides its own visibility. + * alike, then one per plugin inspector extension of the selected node. Each + * contribution reads the selection and decides its own visibility. */ export function RegistryActionContributions() { const selectedIds = useViewer((s) => s.selection.selectedIds) @@ -133,6 +135,7 @@ export function RegistryActionContributions() { ) : null })} + ) } diff --git a/packages/editor/src/components/editor/room-handles-2d.tsx b/packages/editor/src/components/editor/room-handles-2d.tsx index 02e594c7a6..df3f9d64e5 100644 --- a/packages/editor/src/components/editor/room-handles-2d.tsx +++ b/packages/editor/src/components/editor/room-handles-2d.tsx @@ -1,10 +1,20 @@ 'use client' -import { type FloorplanGeometry, type Point, roomDrawnFloor, useScene } from '@pascal-app/core' +import { + type AnyNode, + type AnyNodeId, + type FloorplanGeometry, + nodeRegistry, + type Point, + roomDrawnFloor, + useScene, +} from '@pascal-app/core' import { useViewer } from '@pascal-app/viewer' import { Minus, Plus } from 'lucide-react' import { type PointerEvent as ReactPointerEvent, useMemo, useState } from 'react' -import { useSelectedRoom } from '../../hooks/use-selected-room' +import { useShallow } from 'zustand/react/shallow' +import { useRoomRecords, useSelectedRoom } from '../../hooks/use-selected-room' +import { getFloorplanNodeExtension } from '../../lib/floorplan/floorplan-extension' import { formatLinearMeasurement, MEASUREMENT_FLOORPLAN_COLOR } from '../../lib/measurements' import { commitRoomFloorElevation, @@ -21,8 +31,13 @@ import { useRoomHandleDrag, type WallPushHandle, } from '../../lib/room-handle-drag' -import type { RoomDimension } from '../../lib/room-push-dimensions' +import { + mergeSelectionDimensions, + type OwnedSelectionDimension, + type RoomDimension, +} from '../../lib/room-push-dimensions' import useEditor from '../../store/use-editor' +import useFloorplanAnnotationVisibility from '../../store/use-floorplan-annotation-visibility' import useInteractionScope from '../../store/use-interaction-scope' import { useFloorplanRender } from '../editor-2d/floorplan-render-context' import { FloorplanGeometryRenderer } from '../editor-2d/renderers/floorplan-geometry-renderer' @@ -158,9 +173,10 @@ function startArrow(event: ReactPointerEvent, run: () => unknown /** * The selected room's arrows on the plan: one push/pull chevron per boundary - * span (on the far face, along the normal the handle supplies) and, for a - * mezzanine, one per plate edge. Mounted after every node's handles so a - * wall outline never takes the press. The drags are the 3D arrows' own. + * wall span (on the far face, along the normal the handle supplies), one per + * straight edge of invisible walls and, for a mezzanine, one per plate edge. + * Mounted after every node's handles so a wall outline never takes the press. + * The drags are the 3D arrows' own. */ export function RoomHandles2D({ levelId }: { levelId: string | null }) { const room = useRoomControls() @@ -327,6 +343,13 @@ export function RoomHandleDragPreview2D({ levelId }: { levelId: string | null }) const unit = useViewer((s) => s.unit) const metricNotation = useViewer((s) => s.metricNotation) if (!drag || drag.levelId !== levelId || drag.kind === 'elevation') return null + if (drag.kind === 'wall-group-push') + return ( + + + {drag.message && } + + ) const plan = drag as PlanDrag const at: Point = [ plan.anchor[0] + plan.outward[0] * plan.distance, @@ -352,3 +375,130 @@ export function RoomHandleDragPreview2D({ levelId }: { levelId: string | null }) ) } + +function selectionDimensionsOf(node: AnyNode | undefined) { + return node + ? getFloorplanNodeExtension(nodeRegistry.get(node.type))?.selectionDimensions + : undefined +} + +const NO_NODES: readonly AnyNode[] = [] + +/** + * The selected nodes that show their temporary dimensions now: Select mode, + * nothing in progress, Display → Dimensions on, kinds with `selectionDimensions` + * only (a wall among other selected things still shows its own), on the first + * one's level. A new array only when one of them changes. + */ +export function useSelectionDimensionNodes(): readonly AnyNode[] { + const selectedIds = useViewer((s) => s.selection.selectedIds) + const enabled = useEditor((s) => s.mode === 'select') + const idle = useInteractionScope((s) => s.scope.kind === 'idle') + const dragging = useRoomHandleDrag((s) => s.drag !== null) + const shown = useFloorplanAnnotationVisibility((s) => s.showDimensions) + const active = enabled && idle && !dragging && shown + return useScene( + useShallow((s) => { + if (!active) return NO_NODES + const found: AnyNode[] = [] + for (const id of selectedIds) { + const node = s.nodes[id as AnyNodeId] + if (!node || !selectionDimensionsOf(node)) continue + if (found.length && node.parentId !== found[0]!.parentId) continue + found.push(node) + } + return found + }), + ) +} + +/** + * The selected nodes' temporary dimensions (`useSelectionDimensionNodes`), + * from each kind's `selectionDimensions` (a wall: the room widths its push + * shows and, for an exterior wall, the outside size, as Display → Measure + * walls asks). Several selected walls show each one's, a room two of them + * bound measured once. Shared by the plan and the 3D view; typing into one + * drives the node it runs from. Recomputed only when a measured node or its + * level's rooms change (the room index keeps its records while unrelated + * nodes edit). + */ +export function useSelectedWallDimensions(): { + levelId: string + dimensions: readonly OwnedSelectionDimension[] +} | null { + const measured = useSelectionDimensionNodes() + const faces = useFloorplanAnnotationVisibility((s) => s.wallDimensionFaces) + const levelId = measured[0]?.parentId ?? null + const rooms = useRoomRecords(levelId) + return useMemo(() => { + // `rooms` is the invalidation key: it changes when the level's room + // topology, slabs, ceilings or zones do. + if (!levelId || !rooms) return null + const nodes = useScene.getState().nodes + const dimensions = mergeSelectionDimensions( + measured.map((node) => ({ + ownerId: node.id, + dimensions: selectionDimensionsOf(node)?.({ node, nodes, faces }) ?? [], + })), + ) + return dimensions.length ? { levelId, dimensions } : null + }, [faces, levelId, measured, rooms]) +} + +/** + * The selected walls' temporary dimensions on the plan, drawn as the push + * drag draws its room widths (indigo line, end dots). Each is a `dimension` + * owned by the wall it runs from, so a click on its value opens the plan's + * type-a-value box (`FloorplanDimensionEditOverlay`) and the typed size slides + * that wall. + */ +export function SelectedWallDimensions2D({ levelId }: { levelId: string | null }) { + const selection = useSelectedWallDimensions() + const context = useFloorplanRender() + const unit = useViewer((s) => s.unit) + const metricNotation = useViewer((s) => s.metricNotation) + const owners = useMemo(() => { + const byOwner = new Map() + for (const { from, to, distance, ownerId } of selection?.dimensions ?? []) { + const length = Math.hypot(to[0] - from[0], to[1] - from[1]) || 1 + const geometry: FloorplanGeometry = { + kind: 'dimension', + start: from, + end: to, + offsetNormal: [-(to[1] - from[1]) / length, (to[0] - from[0]) / length], + offsetDistance: 0, + extensionOvershoot: 0, + extensionStartGap: 0, + terminator: 'dot', + text: formatLinearMeasurement(distance, unit, metricNotation), + stroke: MEASUREMENT_FLOORPLAN_COLOR, + } + const list = byOwner.get(ownerId) + if (list) list.push(geometry) + else byOwner.set(ownerId, [geometry]) + } + return [...byOwner].map(([ownerId, children]) => ({ + ownerId, + geometry: { kind: 'group', children } satisfies FloorplanGeometry, + })) + }, [metricNotation, selection, unit]) + if (!selection || selection.levelId !== levelId) return null + return ( + event.stopPropagation()} + > + {owners.map(({ ownerId, geometry }) => ( + + + + ))} + + ) +} diff --git a/packages/editor/src/components/editor/room-handles.tsx b/packages/editor/src/components/editor/room-handles.tsx index 86e7fe5de1..34f91c0717 100644 --- a/packages/editor/src/components/editor/room-handles.tsx +++ b/packages/editor/src/components/editor/room-handles.tsx @@ -1,10 +1,12 @@ 'use client' import { + type AnyNodeId, clampRoomFloorHandle, type Point, roomDrawnFloor, sceneRegistry, + usePascalI18n, useScene, } from '@pascal-app/core' import { useViewer } from '@pascal-app/viewer' @@ -32,6 +34,7 @@ import { publishStructuralElevationGuide, resolveStructuralElevationSnap, } from '../../lib/elevation-guides' +import { parseDimensionInput } from '../../lib/floorplan/dimension-drive' import { formatLinearMeasurement, MEASUREMENT_ACTIVE_COLOR } from '../../lib/measurements' import { commitRoomFloorElevation, roomFloorBase } from '../../lib/room-construction-commands' import { @@ -50,11 +53,16 @@ import { import type { RoomDimension } from '../../lib/room-push-dimensions' import type { RoomSelectionRecord } from '../../lib/room-selection' import useEditor, { isGridSnapActive, isMagneticSnapActive } from '../../store/use-editor' +import { + commitDimensionValue, + useDimensionEditAllowed, +} from '../editor-2d/renderers/floorplan-dimension-edit-overlay' import { suppressBoxSelectForPointer } from '../tools/select/box-select-state' import { ARROW_COLOR, ARROW_SCALE, HandleArrow } from './handles/handle-arrow' import { resolveResizeSnapValue } from './handles/resize-snap' import { Html } from './localized-html' import { formatMeasurement } from './measurement-pill' +import { useSelectedWallDimensions } from './room-handles-2d' import { WallPushArrow } from './wall-push-arrow' const PILL = @@ -295,8 +303,9 @@ export function ElevationArrows({ /** * A selected room's 3D handles: the floor elevation tracker at its centroid - * and one push/pull arrow outside every boundary wall. Rendered in the level - * frame by `RoomControls3D`, only while nothing else is in progress. + * and one push/pull arrow outside every boundary wall and every straight edge + * of invisible walls. Rendered in the level frame by `RoomControls3D`, only + * while nothing else is in progress. */ export function RoomHandles3D({ room }: { room: RoomSelectionRecord }) { const nodes = useScene((s) => s.nodes) @@ -307,7 +316,11 @@ export function RoomHandles3D({ room }: { room: RoomSelectionRecord }) { () => outlineCentroid([room.polygon as Point[], ...(room.holes as Point[][])]), [room.polygon, room.holes], ) - const handles = useMemo(() => roomPushHandles(nodes, room.spans), [nodes, room.spans]) + // Its invisible walls' arrows lie on its floor, where their dashed lines are drawn. + const handles = useMemo( + () => roomPushHandles(nodes, room.spans, elevation), + [nodes, room.spans, elevation], + ) // A mezzanine has no walls: its plate edges carry the push arrows instead. const edges = useMemo( () => (room.mezzanine ? mezzanineEdgeHandles(nodes, room.zoneId) : []), @@ -414,9 +427,20 @@ const DIMENSION_LABEL_OUTLINE = [ * above its room's floor and drawn over the walls, closed by cross ticks, with * the measurement's outlined label — apart from the moved-distance pill. */ -function RoomDimensionLines3D({ dimensions }: { dimensions: RoomDimension[] }) { +function RoomDimensionLines3D({ + dimensions, + hidden = false, +}: { + /** With an `ownerId` (a selected wall's), a value can be typed to move that wall. */ + dimensions: readonly (RoomDimension & { ownerId?: string })[] + /** Hides the labels while keeping their drei `Html` roots mounted. */ + hidden?: boolean +}) { + const i18n = usePascalI18n() const unit = useViewer((s) => s.unit) const metricNotation = useViewer((s) => s.metricNotation) + const editAllowed = useDimensionEditAllowed() + const [editing, setEditing] = useState(null) const geometry = useMemo(() => { if (!dimensions.length) return null const positions: number[] = [] @@ -441,27 +465,175 @@ function RoomDimensionLines3D({ dimensions }: { dimensions: RoomDimension[] }) { raycast={noRaycast} renderOrder={1001} /> - {dimensions.map((dimension) => ( - -
{ + const editable = editAllowed && !!wallId + return ( + - {formatMeasurement(dimension.distance, unit, metricNotation)} -
- - ))} + {editable && wallId && !hidden && editing === dimension.key ? ( + setEditing(null)} + unit={unit} + wallId={wallId} + /> + ) : ( +
setEditing(dimension.key) : undefined} + onKeyDown={ + editable + ? (event) => { + if (event.key === 'Enter') setEditing(dimension.key) + } + : undefined + } + onPointerDown={editable ? (event) => event.stopPropagation() : undefined} + role={editable ? 'button' : undefined} + style={{ textShadow: DIMENSION_LABEL_OUTLINE }} + tabIndex={editable ? 0 : undefined} + title={ + editable + ? i18n._({ + id: 'editor.roomHandles.typeASizeToMoveThe', + message: 'Type a size to move the wall', + }) + : undefined + } + > + {formatMeasurement(dimension.distance, unit, metricNotation)} +
+ )} + + ) + })} + + ) +} + +/** + * A temporary dimension's value, typed: Enter moves the selected wall so the + * dimension reads it (`commitDimensionValue`, one undo step), Esc or a click + * away leaves it. Feet-inches, metric and bare numbers parse as in the plan. + */ +function DimensionValueInput({ + dimension, + initial, + onClose, + unit, + wallId, +}: { + dimension: RoomDimension + initial: string + onClose: () => void + unit: 'metric' | 'imperial' + wallId: string +}) { + const i18n = usePascalI18n() + const [draft, setDraft] = useState(initial) + const [error, setError] = useState(null) + const commit = () => { + const nextLength = parseDimensionInput(draft, unit) + if (nextLength === null) { + setError( + i18n._({ + id: 'editor.roomHandles.cannotReadInput', + message: 'Cannot read "{input}"', + values: { input: draft.trim() }, + }), + ) + return + } + const outcome = commitDimensionValue({ + target: { + ownerNodeId: wallId as AnyNodeId, + witnessStart: dimension.from, + witnessEnd: dimension.to, + value: dimension.distance, + }, + nextLength, + unit, + }) + if (outcome.ok) onClose() + else setError(outcome.reason) + } + return ( +
event.stopPropagation()} + > + { + setDraft(event.target.value) + setError(null) + }} + onFocus={(event) => event.target.select()} + onKeyDown={(event) => { + event.stopPropagation() + if (event.key === 'Enter') { + event.preventDefault() + commit() + } else if (event.key === 'Escape') { + event.preventDefault() + onClose() + } + }} + spellCheck={false} + value={draft} + /> + {error ? ( +
+ {error} +
+ ) : null} +
+ ) +} + +/** + * The selected walls' temporary dimensions in 3D, the plan's twin + * (`SelectedWallDimensions2D`): the room widths their pushes show and the + * outside sizes, drawn as the push draws them, in the walls' level frame. + */ +export function SelectedWallDimensions3D() { + const selection = useSelectedWallDimensions() + const isFloorplanHovered = useEditor((s) => s.isFloorplanHovered) + const levelId = selection?.levelId ?? null + const root = useRef(null) + useFrame(() => { + const level = levelId ? sceneRegistry.nodes.get(levelId) : null + if (!root.current) return + root.current.visible = !!level && !isFloorplanHovered + if (level) { + level.updateWorldMatrix(true, false) + root.current.matrix.copy(level.matrixWorld) + } + }) + // The labels are DOM (drei `Html`); with no document (a headless + // renderer) there is nothing to draw them into. + if (!selection || typeof document === 'undefined') return null + // Hovering the plan hides the dimensions rather than unmounting them: drei + // `Html` unmounts its DOM root synchronously, which React reports as an error + // when it happens inside a render. + return ( + + ) } @@ -524,6 +696,7 @@ function MezzanineEdgeArrow({ } export function RoomHandleDragPreview3D() { + const i18n = usePascalI18n() const drag = useRoomHandleDrag((s) => s.drag) const unit = useViewer((s) => s.unit) const metricNotation = useViewer((s) => s.metricNotation) @@ -614,7 +787,9 @@ export function RoomHandleDragPreview3D() { />
- Floor + + {i18n._({ id: 'editor.roomHandles.floor', message: 'Floor' })} + {formatMeasurement( drag.value - roomFloorBase(useScene.getState().nodes, drag.zoneId), @@ -627,6 +802,45 @@ export function RoomHandleDragPreview3D() { ) } + const ghosts = drag.ghosts.map((ghost, index) => { + const length = Math.hypot(ghost.end[0] - ghost.start[0], ghost.end[1] - ghost.start[1]) + if (length < 1e-3) return null + return ( + + + + ) + }) + if (drag.kind === 'wall-group-push') + return ( + + + {ghosts} + {drag.message && ( + +
+ {drag.message} +
+ + )} +
+ ) const at: Point = [ drag.anchor[0] + drag.outward[0] * drag.distance, drag.anchor[1] + drag.outward[1] * drag.distance, @@ -636,31 +850,7 @@ export function RoomHandleDragPreview3D() { return ( - {drag.ghosts.map((ghost, index) => { - const length = Math.hypot(ghost.end[0] - ghost.start[0], ghost.end[1] - ghost.start[1]) - if (length < 1e-3) return null - return ( - - - - ) - })} + {ghosts}
{drag.message ? ( diff --git a/packages/editor/src/components/editor/room-highlight.tsx b/packages/editor/src/components/editor/room-highlight.tsx index eb50d1f747..c1e6f54718 100644 --- a/packages/editor/src/components/editor/room-highlight.tsx +++ b/packages/editor/src/components/editor/room-highlight.tsx @@ -25,6 +25,7 @@ import { describeZoneOutline, type RoomSelectionRecord } from '../../lib/room-se import useEditor from '../../store/use-editor' import useInteractionScope from '../../store/use-interaction-scope' import { RoomControls2D, RoomControls3D } from './room-controls' +import { SelectedWallDimensions3D } from './room-handles' /** * A zone reached as a zone (hovered or selected through its area or pill, not @@ -188,6 +189,7 @@ export function RoomHighlight3D() { return ( <> + {room ? : null} ) diff --git a/packages/editor/src/components/editor/selection-manager.tsx b/packages/editor/src/components/editor/selection-manager.tsx index 1d099638e2..76f94bc186 100644 --- a/packages/editor/src/components/editor/selection-manager.tsx +++ b/packages/editor/src/components/editor/selection-manager.tsx @@ -15,7 +15,6 @@ import { type NodeEvent, nodeRegistry, type RoofEvent, - type RoofNode, type RoofSegmentEvent, type RoofSegmentNode, resolveLevelId, @@ -29,7 +28,11 @@ import { useScene, wallFaceScriptPaintRefusal, } from '@pascal-app/core' -import { getRoofMaterialArray, registerMaterialCacheCleanup, useViewer } from '@pascal-app/viewer' +import { + ROOF_HEEL_MATERIAL_INDEX, + registerMaterialCacheCleanup, + useViewer, +} from '@pascal-app/viewer' import { useThree } from '@react-three/fiber' import { useCallback, useEffect, useRef } from 'react' import { type BufferGeometry, Color, type Material, type Mesh, type Object3D, Vector3 } from 'three' @@ -57,7 +60,6 @@ import { import { selectionEnabled } from '../../lib/interaction/scope' import { type ActivePaintMaterial, - buildRoofSurfaceMaterialPatch, hasActivePaintMaterial, resolveActivePaintMaterialFromSelection, } from '../../lib/material-paint' @@ -90,7 +92,6 @@ import { paintScopeRole, paintSurfaceLabel, resolvePaintScopeTargets, - slotDisplayLabel, type WallPaintHit, } from '../../lib/paint-scope' import { @@ -248,9 +249,10 @@ function resolveStairMaterialTarget( function resolveRoofMaterialTarget( event: RoofEvent | RoofSegmentEvent, -): 'top' | 'edge' | 'wall' | null { +): 'top' | 'edge' | 'wall' | 'heel' | null { const materialIndex = getIntersectionMaterialIndex(getEventObject(event), event.faceIndex) if (materialIndex === 3) return 'top' + if (materialIndex === ROOF_HEEL_MATERIAL_INDEX) return 'heel' if (materialIndex === 0) return 'edge' if (materialIndex === 1 || materialIndex === 2) return 'wall' @@ -451,14 +453,6 @@ function resolveSelectModeNodeTarget(event: NodeEvent, drill = false): AnyNode { return event.node } -function previewMeshMaterial(mesh: Mesh, material: Material | Material[]): PaintPreviewCleanup { - const previousMaterial = mesh.material - mesh.material = material - return () => { - mesh.material = previousMaterial - } -} - function previewCursor(cursor: string): PaintPreviewCleanup { const previousCursor = document.body.style.cursor document.body.style.cursor = cursor @@ -467,33 +461,6 @@ function previewCursor(cursor: string): PaintPreviewCleanup { } } -function applyRoofPaintPreview( - node: RoofNode, - role: 'top' | 'edge' | 'wall', - material: ActivePaintMaterial, -): PaintPreviewCleanup | null { - const root = getRegisteredNodeObject(node.id) - const mesh = root?.getObjectByName('merged-roof') as Mesh | undefined - if (!mesh) return null - - const previewNode = { - ...node, - ...buildRoofSurfaceMaterialPatch(node, role, material.material, material.materialPreset), - } - const previewMaterial = getRoofMaterialArray( - previewNode, - useViewer.getState().shading, - useViewer.getState().textures, - useViewer.getState().colorPreset, - useViewer.getState().sceneTheme, - null, - useScene.getState().materials, - ) - if (!previewMaterial) return null - - return previewMeshMaterial(mesh, previewMaterial) -} - // Chimney + dormer paint dispatch lives on their NodeDefinition's // `capabilities.paint` (see packages/nodes/src/{chimney,dormer}/ // paint.ts). The generic registry-driven arm in this file consults @@ -892,9 +859,7 @@ export const SelectionManager = () => { // Registry-driven paint dispatch — kinds that declare // `capabilities.paint` route hover / click / preview through - // their definition. Wall, chimney, and dormer use this; legacy - // roof / stair / single-surface arms below stay until they - // migrate too. + // their definition (wall, chimney, dormer, roof, …). const paintCap = nodeRegistry.get(node.type)?.capabilities?.paint if (paintCap) { const materialIndex = getIntersectionMaterialIndex(getEventObject(event), event.faceIndex) @@ -1063,51 +1028,7 @@ export const SelectionManager = () => { } } - // A segment paints through its definition's `capabilities.paint`; the merged shell's hit is - // the roof's, and fans to it. - if (node.type === 'roof') { - const role = resolveRoofMaterialTarget(event as RoofEvent) - if (isPaintPicking()) return pickInteraction(node, role, event, null) - const compatible = role !== null && paintEnabled - return { - key: `roof:${node.id}:${role ?? 'unsupported'}:${eraser ? 'erase' : 'paint'}`, - hoveredId: node.id as AnyNodeId, - hoverMode: compatible ? (eraser ? 'erase-ready' : 'paint-ready') : 'paint-disabled', - // Roof isn't on the slot model (role-specific fields, custom commit), - // so it offers only the single surface — but still labels it. - paintHover: - compatible && role - ? { - scopes: ['single'], - slotLabel: slotDisplayLabel(node, role), - nodeNoun: 'roof', - } - : null, - apply: - compatible && role - ? () => { - useScene - .getState() - .updateNode( - node.id as AnyNodeId, - buildRoofSurfaceMaterialPatch( - node, - role, - paintSpec.material, - paintSpec.materialPreset, - ), - ) - } - : null, - preview: - compatible && role - ? () => applyRoofPaintPreview(node, role, paintSpec) - : () => previewCursor('not-allowed'), - } - } - - // Only `roof` reaches a legacy paint arm (above) — every - // other paintable kind declares `capabilities.paint` and returns from the + // Every paintable kind declares `capabilities.paint` and returns from the // registry-driven dispatch at the top of this function. const disabledNodeTypes = ['zone'] diff --git a/packages/editor/src/components/editor/separator-end-grip.tsx b/packages/editor/src/components/editor/separator-end-grip.tsx new file mode 100644 index 0000000000..2c78638ead --- /dev/null +++ b/packages/editor/src/components/editor/separator-end-grip.tsx @@ -0,0 +1,74 @@ +'use client' + +import { type SeparatorNode, sceneRegistry } from '@pascal-app/core' +import { type ThreeEvent, useThree } from '@react-three/fiber' +import { useState } from 'react' +import { OrthographicCamera, Plane, Vector2, Vector3 } from 'three' +import { runSeparatorEndDrag } from '../../lib/separator-edit' +import { suppressBoxSelectForPointer } from '../tools/select/box-select-state' +import { HandleArrow } from './handles/handle-arrow' + +/** + * An invisible wall's 3D end grip, the twin of its end handle on the plan: a + * cube at the end, on the floor at `height`. Dragging it moves the end across + * that floor (`runSeparatorEndDrag`), the invisible walls joined there + * following. Rendered in the level frame. + */ +export function SeparatorEndGrip({ + separator, + endpoint, + height, + levelId, +}: { + separator: SeparatorNode + endpoint: 'start' | 'end' + height: number + levelId: string +}) { + const [hover, setHover] = useState(false) + const { camera, raycaster, gl } = useThree() + const zoom = camera instanceof OrthographicCamera ? 1 / camera.zoom : 1 + const [x, z] = separator[endpoint] + const onPointerDown = (event: ThreeEvent) => { + if (event.button !== 0) return + event.stopPropagation() + suppressBoxSelectForPointer(event) + const level = sceneRegistry.nodes.get(levelId) + if (!level) return + level.updateWorldMatrix(true, false) + const toLocal = level.matrixWorld.clone().invert() + const floor = new Plane().setFromNormalAndCoplanarPoint( + new Vector3(0, 1, 0).transformDirection(level.matrixWorld), + new Vector3(x, height, z).applyMatrix4(level.matrixWorld), + ) + runSeparatorEndDrag({ + separatorId: separator.id, + endpoint, + levelId, + toPlan: (clientX, clientY) => { + const rect = gl.domElement.getBoundingClientRect() + raycaster.setFromCamera( + new Vector2( + ((clientX - rect.left) / rect.width) * 2 - 1, + -((clientY - rect.top) / rect.height) * 2 + 1, + ), + camera, + ) + const hit = raycaster.ray.intersectPlane(floor, new Vector3()) + if (!hit) return null + const local = hit.applyMatrix4(toLocal) + return [local.x, local.z] + }, + }) + } + return ( + + ) +} diff --git a/packages/editor/src/components/editor/use-floorplan-background-placement.ts b/packages/editor/src/components/editor/use-floorplan-background-placement.ts index c62d584a28..2ca3096445 100644 --- a/packages/editor/src/components/editor/use-floorplan-background-placement.ts +++ b/packages/editor/src/components/editor/use-floorplan-background-placement.ts @@ -19,6 +19,8 @@ import { resolveGenericFloorplanGridEventPoint } from '../../lib/floorplan-grid- import { snapRegisteredDraftPoint } from '../../lib/registered-draft-snap' import { resolveSlabPlanPointSnap } from '../../lib/slab-plan-snap' import { commitWallPolygonDraft, wallPolygonDraftWalls } from '../../lib/wall-polygon-draft' +import { wallDraftIsRun } from '../../lib/wall-pull' +import { isWallRunFree, snapWallRunDraftPoint } from '../../lib/wall-run-snap' import useAlignmentGuides from '../../store/use-alignment-guides' import useEditor, { isAngleSnapActive, isMagneticSnapActive } from '../../store/use-editor' import usePlacementPreview from '../../store/use-placement-preview' @@ -52,6 +54,8 @@ type UseFloorplanBackgroundPlacementArgs = { wall: WallNode } | null floorplanOpeningLocalY: number + /** An open wall run's start and the direction of its last wall (null before one). */ + getWallRunContext: () => { runStart: WallPlanPoint | null; reference: WallPlanPoint | null } getSnappedFloorplanPoint: (point: WallPlanPoint) => WallPlanPoint handleCeilingItemPlacementClick: ( planPoint: WallPlanPoint, @@ -72,12 +76,9 @@ type UseFloorplanBackgroundPlacementArgs = { isZoneBuildActive: boolean levelId: string | null registryToolOwnsSnapping: boolean - roofDraftStart: WallPlanPoint | null setCursorPoint: React.Dispatch> setFenceDraftEnd: React.Dispatch> setFenceDraftStart: React.Dispatch> - setRoofDraftEnd: React.Dispatch> - setRoofDraftStart: React.Dispatch> snapWallDraftPoint: (args: { point: WallPlanPoint walls: WallNode[] @@ -86,6 +87,7 @@ type UseFloorplanBackgroundPlacementArgs = { bypassSnap?: boolean step?: number gridSnap?: (point: WallPlanPoint) => WallPlanPoint + captureWallBodies?: boolean }) => WallPlanPoint snapPolygonDraftPoint: (args: { point: WallPlanPoint @@ -95,10 +97,9 @@ type UseFloorplanBackgroundPlacementArgs = { toPoint2D: (point: WallPlanPoint) => { x: number; y: number } walls: WallNode[] /** - * Snap a building-local plan point to the world XZ grid at `step`. - * Injected so the hook doesn't have to know the building's rotation - * or position — used by wall / fence branches that snap at variable - * step. + * Snap a building-local plan point onto the building's grid lattice at + * `step` (the lattice the plan draws, which turns with the building). + * Injected — used by wall / fence branches that snap at variable step. */ worldGridSnap: (point: WallPlanPoint, step: number) => WallPlanPoint } @@ -115,6 +116,7 @@ export function useFloorplanBackgroundPlacement({ findClosestWallPoint, floorplanOpeningLocalY, getSnappedFloorplanPoint, + getWallRunContext, handleCeilingItemPlacementClick, handleCeilingPlacementPoint, handleSlabPlacementPoint, @@ -131,12 +133,9 @@ export function useFloorplanBackgroundPlacement({ isZoneBuildActive, levelId, registryToolOwnsSnapping, - roofDraftStart, setCursorPoint, setFenceDraftEnd, setFenceDraftStart, - setRoofDraftEnd, - setRoofDraftStart, snapWallDraftPoint, snapPolygonDraftPoint, toPoint2D, @@ -219,24 +218,14 @@ export function useFloorplanBackgroundPlacement({ if (isRoofBuildActive) { // Footprint placement (polygon context: grid / lines / off, no angle), // mode-driven to match the chip. Alt is force/free at commit time; - // alignment display/pull follows the active magnetic mode. + // alignment display/pull follows the active magnetic mode. The roof + // tool snaps the corner it commits and writes the draft rectangle from + // it, so the plan shows exactly the roof the click makes. const snappedPoint = alignFloorplanDraftPoint(getSnappedFloorplanPoint(planPoint), { applySnap: isMagneticSnapActive(), }) emitFloorplanGridEvent('click', snappedPoint, event) setCursorPoint(snappedPoint) - - if (roofFootprintSource !== 'draw') { - clearRoofPlacementDraft() - return true - } - - if (roofDraftStart) { - clearRoofPlacementDraft() - } else { - setRoofDraftStart(snappedPoint) - setRoofDraftEnd(snappedPoint) - } return true } @@ -254,8 +243,8 @@ export function useFloorplanBackgroundPlacement({ if (isFenceBuildActive) { // Fence draft: mode-driven (matches the chip), same as the move - // preview. `grid` snaps to the world XZ grid (rotation-safe via the - // `gridSnap` callback), `angles` locks 15° rays from the start, `lines` + // preview. `grid` snaps to the building's grid lattice (the `gridSnap` + // callback), `angles` locks 15° rays from the start, `lines` // pulls onto walls / fences / alignment, `off` is free. const fenceStep = getSegmentGridStep() const fenceAngleSnap = fenceDraftStart !== null && isAngleSnapActive() @@ -363,30 +352,48 @@ export function useFloorplanBackgroundPlacement({ // / draftEnd state in the floor plan would never update, leaving // the dashed-line draft preview invisible. if (isWallBuildActive) { - // Wall draft: mode-driven (matches the chip + the move-preview branch). - // `grid` snaps to the world XZ grid (rotation-safe via `gridSnap`), - // `angles` locks 15° rays from the start, `lines` pulls the endpoint - // onto existing wall corners / edges + alignment, `off` is free. - const wallStep = getSegmentGridStep() - const wallAngleSnap = draftStart !== null && isAngleSnapActive() - const wallSnapped = snapWallDraftPoint({ - point: planPoint, - walls: [...walls, ...wallPolygonDraftWalls()], - start: draftStart ?? undefined, - angleSnap: wallAngleSnap, - gridSnap: (p) => worldGridSnap(p, wallStep), - }) - const wallGridBase = worldGridSnap(planPoint, wallStep) - const wallLocked = wallSnapped[0] !== wallGridBase[0] || wallSnapped[1] !== wallGridBase[1] - let snappedPoint = wallSnapped - if (wallLocked) { - useAlignmentGuides.getState().clear() + // Wall draft, matching the move-preview branch: mode-driven (matches + // the chip). `grid` snaps to the building's grid lattice (`gridSnap`), + // `angles` locks a Walls segment to 15° rays from its start, `lines` + // pulls the point onto existing wall corners / edges + alignment, `off` + // is free, and in every mode but `lines` an end aimed into a wall's body + // joins that wall. A run's segment (a Polygon side, a pulled run) lands + // where the move showed it (`snapWallRunDraftPoint`). + let snappedPoint: WallPlanPoint + if (draftStart && wallDraftIsRun()) { + const run = getWallRunContext() + snappedPoint = snapWallRunDraftPoint({ + point: planPoint, + start: draftStart, + runStart: run.runStart ?? draftStart, + reference: run.reference, + walls: [...walls, ...wallPolygonDraftWalls()], + free: isWallRunFree(event), + }).point } else { - // Alignment lines are shown in every mode; the pull applies only when - // magnetic ('lines') and the segment isn't angle-locked. - snappedPoint = alignFloorplanDraftPoint(wallSnapped, { - applySnap: isMagneticSnapActive() && !wallAngleSnap, + const wallStep = getSegmentGridStep() + const wallAngleSnap = draftStart !== null && isAngleSnapActive() + const wallSnapped = snapWallDraftPoint({ + point: planPoint, + walls: [...walls, ...wallPolygonDraftWalls()], + start: draftStart ?? undefined, + angleSnap: wallAngleSnap, + gridSnap: (p) => worldGridSnap(p, wallStep), + captureWallBodies: true, }) + const wallGridBase = worldGridSnap(planPoint, wallStep) + const wallLocked = + wallSnapped[0] !== wallGridBase[0] || wallSnapped[1] !== wallGridBase[1] + snappedPoint = wallSnapped + if (wallLocked) { + useAlignmentGuides.getState().clear() + } else { + // Alignment lines are shown in every mode; the pull applies only when + // magnetic ('lines') and the segment isn't angle-locked. + snappedPoint = alignFloorplanDraftPoint(wallSnapped, { + applySnap: isMagneticSnapActive() && !wallAngleSnap, + }) + } } emitFloorplanGridEvent('click', snappedPoint, event) @@ -437,12 +444,12 @@ export function useFloorplanBackgroundPlacement({ activePolygonDraftPoints, ceilingDraftPoints, clearFencePlacementDraft, - clearRoofPlacementDraft, clearWallPlacementDraft, emitFloorplanGridEvent, fenceDraftStart, fences, findClosestWallPoint, + getWallRunContext, floorplanOpeningLocalY, getSnappedFloorplanPoint, handleCeilingItemPlacementClick, @@ -459,14 +466,10 @@ export function useFloorplanBackgroundPlacement({ isWallBuildActive, isZoneBuildActive, levelId, - roofDraftStart, registryToolOwnsSnapping, - roofFootprintSource, setCursorPoint, setFenceDraftEnd, setFenceDraftStart, - setRoofDraftEnd, - setRoofDraftStart, snapWallDraftPoint, snapPolygonDraftPoint, toPoint2D, diff --git a/packages/editor/src/components/editor/wall-move-side-handles.tsx b/packages/editor/src/components/editor/wall-move-side-handles.tsx index 34c7f8d9a0..e1ed7a6f39 100644 --- a/packages/editor/src/components/editor/wall-move-side-handles.tsx +++ b/packages/editor/src/components/editor/wall-move-side-handles.tsx @@ -70,6 +70,7 @@ import { NO_RAYCAST, useInvisibleHitAreaMaterial, } from './node-arrow-handles' +import { WallPullGrip } from './wall-pull-grip' import { WallPushArrow } from './wall-push-arrow' const HANDLE_OFFSET = 0.27 @@ -251,6 +252,9 @@ function WallMoveSideHandlesForWall({ wall }: { wall: WallNode }) { /> + {/* Past each end, the grip that pulls the next wall out of it. */} + + createPullArrowGeometry(), []) + const hitGeometry = useMemo(() => createEndpointHitAreaGeometry(PULL_HIT_RADIUS), []) + const hitMaterial = useInvisibleHitAreaMaterial() + const material = useMemo( + () => + new MeshBasicNodeMaterial({ + color: new Color(PULL_FILL), + side: DoubleSide, + transparent: true, + opacity: 0.95, + depthTest: false, + depthWrite: false, + toneMapped: false, + }), + [], + ) + useEffect(() => { + material.color.set(hover ? PULL_HOVER_FILL : PULL_FILL) + }, [hover, material]) + useEffect(() => () => geometry.dispose(), [geometry]) + useEffect(() => () => hitGeometry.dispose(), [hitGeometry]) + useEffect(() => () => material.dispose(), [material]) + // Warm the wall tool's module so the press starts drawing at once. + useEffect(() => { + void nodeRegistry + .get('wall') + ?.tool?.() + .catch(() => {}) + }, []) + useEffect( + () => () => { + hideGripTooltip() + if (document.body.style.cursor === 'grab') document.body.style.cursor = '' + }, + [], + ) + + if (!seed) return null + const [dx, dz] = seed.reference + const offset = PULL_ARROW_OFFSET * zoom + const position: [number, number, number] = [ + seed.start[0] + dx * offset, + PULL_FLOOR_LIFT, + seed.start[1] + dz * offset, + ] + const rotationY = Math.atan2(-dz, dx) + + const onPointerDown = (event: ThreeEvent) => { + if (event.button !== 0) return + event.stopPropagation() + suppressBoxSelectForPointer(event) + sfxEmitter.emit('sfx:item-pick') + setHover(false) + hideGripTooltip() + if (document.body.style.cursor === 'grab') document.body.style.cursor = '' + startWallPull({ wallId: wall.id, endpoint, origin: '3d' }) + } + + return ( + + + { + event.stopPropagation() + setHover(true) + showGripTooltip(event.nativeEvent.clientX, event.nativeEvent.clientY) + document.body.style.cursor = 'grab' + }} + onPointerLeave={(event) => { + event.stopPropagation() + setHover(false) + hideGripTooltip() + if (document.body.style.cursor === 'grab') document.body.style.cursor = '' + }} + scale={1} + /> + + + + ) +} diff --git a/packages/editor/src/components/editor/wall-snap-beacon-layer.tsx b/packages/editor/src/components/editor/wall-snap-beacon-layer.tsx index 1c9a8c55de..25ee75f111 100644 --- a/packages/editor/src/components/editor/wall-snap-beacon-layer.tsx +++ b/packages/editor/src/components/editor/wall-snap-beacon-layer.tsx @@ -16,6 +16,7 @@ import { } from '@pascal-app/core' import { useWallSnapIndicator, type WallSnapKind } from '@pascal-app/editor' import { useViewer } from '@pascal-app/viewer' +import { Html } from '@react-three/drei' import { useFrame } from '@react-three/fiber' import { memo, useMemo, useRef } from 'react' import { BoxGeometry, CircleGeometry, CylinderGeometry, type Group } from 'three' @@ -31,10 +32,14 @@ import { EDITOR_LAYER } from '../../lib/constants' * * endpoint (corner) → square midpoint → triangle * intersection → ✕ cross wall body (edge) → circle + * perpendicular → ⊥ corner projection guide → diamond + * grid length → small + * * Subscribes to the shared `useWallSnapIndicator` store (published by the wall * draft + endpoint-move tools). The vertical mouse pillar and the corner - * (endpoint) square are green; the other floor glyphs are indigo. + * (endpoint) square are green; the other floor glyphs are indigo. A point that + * carries a `label` (a wall pulled from a wall end) also names what it caught + * in a pill beside the foot of the pillar. * * The point carries only XZ (building-local plan coords); like the alignment * guides it's lifted to the active level's building-local Y each frame so it @@ -135,6 +140,23 @@ export const WallSnapBeaconLayer = memo(function WallSnapBeaconLayer() { renderOrder={1002} /> + {point.label ? ( + +
+ {point.label} +
+ + ) : null} ) }) @@ -295,6 +317,64 @@ function SnapMarker({ kind, x, z }: { kind: WallSnapKind; x: number; z: number } ) } + if (kind === 'perpendicular') { + // ⊥ — a base bar with an upright from its middle. + return ( + <> + + + + ) + } + if (kind === 'alignment') { + return ( + + ) + } + if (kind === 'grid') { + return ( + <> + + + + ) + } // 'wall' (edge / along-wall) → circle return ( { + const fresh = normalizePersistedEditorLayoutState(undefined) + expect(fresh.showRoofCeilings).toBe(true) + expect(fresh.showCeilings).toBe(false) + const turned = normalizePersistedEditorLayoutState({ + showRoofCeilings: false, + showCeilings: true, + }) + expect(turned.showRoofCeilings).toBe(false) + expect(turned.showCeilings).toBe(true) +}) + +test('the level’s ceilings setting draws the ceiling tops, stepping aside to place on a ceiling', async () => { + const previous = { + scene: useScene.getState(), + viewer: useViewer.getState(), + editor: useEditor.getState(), + scope: useInteractionScope.getState(), + } + const actGlobal = globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean } + const previousAct = actGlobal.IS_REACT_ACT_ENVIRONMENT + actGlobal.IS_REACT_ACT_ENVIRONMENT = true + const makeCanvas = () => + Object.assign(new EventTarget(), { + getBoundingClientRect: () => ({ left: 0, top: 0, width: 100, height: 100 }), + }) as unknown as HTMLCanvasElement + const canvas = makeCanvas() + const previewCanvas = makeCanvas() + const root = createRoot(canvas) + const previewRoot = createRoot(previewCanvas) + const building = BuildingNode.parse({}) + const storey = LevelNode.parse({ parentId: building.id, level: 0, height: 3 }) + const roof = LevelNode.parse({ + parentId: building.id, + level: 1, + height: 3, + metadata: { role: 'roof' }, + }) + building.children = [storey.id, roof.id] + const ceiling = CeilingNode.parse({ + parentId: storey.id, + height: 2.7, + polygon: [ + [0, 0], + [4, 0], + [4, 4], + [0, 4], + ], + }) + const select = (levelId: typeof storey.id) => + act(async () => + useViewer.setState({ + selection: { buildingId: building.id, levelId, zoneId: null, selectedIds: [] }, + }), + ) + const tops = () => useViewer.getState().showCeilingTops + try { + useScene.setState({ + nodes: { + [building.id]: building, + [storey.id]: storey, + [roof.id]: roof, + [ceiling.id]: ceiling, + }, + }) + useEditor.setState({ + ...normalizePersistedEditorLayoutState(undefined), + tool: null, + selectedItem: null, + isPreviewMode: false, + isCaptureMode: false, + }) + useInteractionScope.setState({ scope: { kind: 'idle' } }) + useViewer.setState({ showCeilingTops: false, hoveredId: null }) + await select(roof.id) + const configure = (target: typeof root, domElement: HTMLCanvasElement) => + target.configure({ + gl: { + domElement, + render() {}, + setSize() {}, + setPixelRatio() {}, + } as unknown as WebGLRenderer, + camera: Object.assign(new OrthographicCamera(), { manual: true }), + frameloop: 'never', + dpr: 1, + size: { width: 100, height: 100, top: 0, left: 0 }, + }) + await configure(root, canvas) + await act(async () => + root.render( + createElement(Fragment, null, createElement(CeilingTopsSync), createElement(CeilingSystem)), + ), + ) + expect(tops()).toBe(true) + + // A second viewer's ceiling system (the preview's) going away leaves the tops as set. + await configure(previewRoot, previewCanvas) + await act(async () => previewRoot.render(createElement(CeilingSystem))) + await act(async () => previewRoot.unmount()) + expect(tops()).toBe(true) + + await select(storey.id) + expect(tops()).toBe(false) + await act(async () => useEditor.getState().setShowCeilings(true)) + expect(tops()).toBe(true) + await act(async () => useEditor.setState({ tool: 'ceiling' })) + expect(tops()).toBe(false) + await act(async () => useEditor.setState({ tool: null, isPreviewMode: true })) + expect(tops()).toBe(false) + await act(async () => useEditor.setState({ isPreviewMode: false })) + expect(tops()).toBe(true) + + // The roof level keeps its own setting. + await select(roof.id) + await act(async () => useEditor.getState().setShowRoofCeilings(false)) + expect(tops()).toBe(false) + expect(useEditor.getState().showCeilings).toBe(true) + + await act(async () => useEditor.getState().setShowRoofCeilings(true)) + expect(tops()).toBe(true) + await act(async () => root.unmount()) + expect(tops()).toBe(false) + } finally { + useScene.setState(previous.scene, true) + useViewer.setState(previous.viewer, true) + useEditor.setState(previous.editor, true) + useInteractionScope.setState(previous.scope, true) + actGlobal.IS_REACT_ACT_ENVIRONMENT = previousAct + } +}) diff --git a/packages/editor/src/components/systems/ceiling/ceiling-system.tsx b/packages/editor/src/components/systems/ceiling/ceiling-system.tsx index 22607d1fc3..5e4a832b33 100644 --- a/packages/editor/src/components/systems/ceiling/ceiling-system.tsx +++ b/packages/editor/src/components/systems/ceiling/ceiling-system.tsx @@ -1,4 +1,4 @@ -import { type AnyNodeId, sceneRegistry, useScene } from '@pascal-app/core' +import { type AnyNodeId, sceneRegistry, servesAsRoofLevel, useScene } from '@pascal-app/core' import { isProceduralItem } from '@pascal-app/core/procedural-items' import { useViewer } from '@pascal-app/viewer' import { useEffect } from 'react' @@ -74,10 +74,59 @@ function setCeilingGridHighlighted(ceilingGrid: Mesh, highlighted: boolean) { delete userData[CEILING_GRID_HIGHLIGHT_MATERIAL_KEY] } -export const CeilingSystem = () => { +/** + * The "Ceilings" setting that applies on `levelId`: the roof level's, on until turned off; the + * floor plans', off until turned on. On, ceilings read as solid from above too. + */ +export function useCeilingsSetting(levelId: string | null | undefined): { + onRoofLevel: boolean + shown: boolean + setShown: (show: boolean) => void +} { + const onRoofLevel = useScene((state) => { + const level = levelId ? state.nodes[levelId as AnyNodeId] : undefined + return level?.type === 'level' && servesAsRoofLevel(state.nodes, level) + }) + const shown = useEditor((state) => (onRoofLevel ? state.showRoofCeilings : state.showCeilings)) + const setRoof = useEditor((state) => state.setShowRoofCeilings) + const setFloor = useEditor((state) => state.setShowCeilings) + return { onRoofLevel, shown, setShown: onRoofLevel ? setRoof : setFloor } +} + +function useIsCeilingToolActive(): boolean { const tool = useEditor((state) => state.tool) const selectedItem = useEditor((state) => state.selectedItem) const movingNode = useMovingNode() + return ( + tool === 'ceiling' || + selectedItem?.attachTo === 'ceiling' || + (movingNode?.type === 'item' && movingNode?.asset?.attachTo === 'ceiling') || + (isProceduralItem(movingNode) && movingNode.recipe.mounting?.attachTo === 'ceiling') + ) +} + +/** + * Whether the viewer draws ceiling tops (`showCeilingTops`), from the level's Ceilings setting. + * Mounted once by the editor, outside the canvases: the editor and preview viewers each mount a + * `CeilingSystem`, and two writers each turning the tops off on unmount raced. + */ +export const CeilingTopsSync = () => { + const activeLevelId = useViewer((state) => state.selection.levelId) + const ceilingsShown = useCeilingsSetting(activeLevelId).shown + const isPreviewMode = useEditor((state) => state.isPreviewMode) + const isCaptureMode = useEditor((state) => state.isCaptureMode) + const isCeilingToolActive = useIsCeilingToolActive() + // Placing on a ceiling looks through it from above, so the tops step aside; preview and + // captures keep the open look. + const showTops = ceilingsShown && !isCeilingToolActive && !isPreviewMode && !isCaptureMode + useEffect(() => { + useViewer.getState().setShowCeilingTops(showTops) + return () => useViewer.getState().setShowCeilingTops(false) + }, [showTops]) + return null +} + +export const CeilingSystem = () => { const selectedIds = useViewer((state) => state.selection.selectedIds) const activeLevelId = useViewer((state) => state.selection.levelId) const hoveredId = useViewer((state) => state.hoveredId) @@ -87,6 +136,7 @@ export const CeilingSystem = () => { // reveal is gated here, on the consumer. const inputDragging = useViewer((state) => state.inputDragging) const scopeIdle = useInteractionScope((state) => state.scope.kind === 'idle') + const isCeilingToolActive = useIsCeilingToolActive() useEffect(() => { const nodes = useScene.getState().nodes @@ -96,12 +146,6 @@ export const CeilingSystem = () => { const levelsToShowCeilings = new Set() - const isCeilingToolActive = - tool === 'ceiling' || - selectedItem?.attachTo === 'ceiling' || - (movingNode?.type === 'item' && movingNode?.asset?.attachTo === 'ceiling') || - (isProceduralItem(movingNode) && movingNode.recipe.mounting?.attachTo === 'ceiling') - if (isCeilingToolActive && activeLevelId) { levelsToShowCeilings.add(activeLevelId) } @@ -162,15 +206,6 @@ export const CeilingSystem = () => { } } }) - }, [ - tool, - selectedItem, - movingNode, - selectedIds, - activeLevelId, - hoveredId, - scopeIdle, - inputDragging, - ]) + }, [isCeilingToolActive, selectedIds, activeLevelId, hoveredId, scopeIdle, inputDragging]) return null } diff --git a/packages/editor/src/components/tools/item/placement-strategies.test.ts b/packages/editor/src/components/tools/item/placement-strategies.test.ts index 1adaf7b8ed..b96d7f87ca 100644 --- a/packages/editor/src/components/tools/item/placement-strategies.test.ts +++ b/packages/editor/src/components/tools/item/placement-strategies.test.ts @@ -1,6 +1,7 @@ -import { beforeEach, describe, expect, test } from 'bun:test' +import { afterEach, beforeEach, describe, expect, test } from 'bun:test' import { BlockNode, + BuildingNode, type CeilingEvent, type CeilingNode, type GridEvent, @@ -11,7 +12,11 @@ import { type WallEvent, type WallNode, } from '@pascal-app/core' +import { useViewer } from '@pascal-app/viewer' import { BufferGeometry, Mesh, MeshBasicMaterial, type Object3D, Vector3 } from 'three' +import { GROUP_MOVE_DRAG_LABEL } from '../../../lib/contextual-help' +import useEditor from '../../../store/use-editor' +import useInteractionScope from '../../../store/use-interaction-scope' import { ceilingStrategy, faceHostStrategy, @@ -498,6 +503,64 @@ describe('floorStrategy.move', () => { expect(result.cursorPosition[1]).toBe(0) expect(result.nodeUpdate?.position?.[1]).toBe(0) }) + + describe('in grid mode', () => { + const originalSelection = useViewer.getState().selection + + beforeEach(() => { + // The group-move scope resolves to the item snap context without the + // node registry; grid mode at a 0.5 m step. + useInteractionScope + .getState() + .begin({ kind: 'handle-drag', nodeId: 'item_test', handle: GROUP_MOVE_DRAG_LABEL }) + useEditor.getState().setSnappingMode('item', 'grid') + useEditor.getState().setGridSnapStep(0.5) + }) + + afterEach(() => { + useInteractionScope.getState().end() + useEditor.getState().setSnappingMode('item', 'lines') + useViewer.setState({ selection: originalSelection } as never) + }) + + // A 0.5 m plant centres half a cell off the lattice, its edges on it. + test("inside a turned building it lands on the building's lattice, square to the house", () => { + const yaw = (17 * Math.PI) / 180 + const building = BuildingNode.parse({ position: [12.37, 0, -8.91], rotation: [0, yaw, 0] }) + useScene.setState((state) => ({ + ...state, + nodes: { ...state.nodes, [building.id]: building }, + })) + useViewer.setState({ + selection: { buildingId: building.id, levelId: null, zoneId: null, selectedIds: [] }, + } as never) + const local: [number, number] = [1.37, 2.61] + const cos = Math.cos(yaw) + const sin = Math.sin(yaw) + const event: GridEvent = { + position: [ + 12.37 + local[0] * cos + local[1] * sin, + 0, + -8.91 - local[0] * sin + local[1] * cos, + ], + localPosition: [local[0], 0, local[1]], + nativeEvent: {} as GridEvent['nativeEvent'], + } + + const result = floorStrategy.move(floorItemContext(), event) + expect(result?.nodeUpdate?.position?.[0]).toBeCloseTo(1.25, 9) + expect(result?.nodeUpdate?.position?.[2]).toBeCloseTo(2.75, 9) + }) + + test('outside any building it keeps the world grid', () => { + useViewer.setState({ + selection: { buildingId: null, levelId: null, zoneId: null, selectedIds: [] }, + } as never) + const result = floorStrategy.move(floorItemContext(), makeGridEvent(5.37, 0, -3.12)) + expect(result?.nodeUpdate?.position?.[0]).toBeCloseTo(5.25, 9) + expect(result?.nodeUpdate?.position?.[2]).toBeCloseTo(-3.25, 9) + }) + }) }) describe('ceilingStrategy.move', () => { diff --git a/packages/editor/src/components/tools/item/placement-strategies.ts b/packages/editor/src/components/tools/item/placement-strategies.ts index d4e715a988..053be4c1b5 100644 --- a/packages/editor/src/components/tools/item/placement-strategies.ts +++ b/packages/editor/src/components/tools/item/placement-strategies.ts @@ -27,13 +27,12 @@ import { resolveSurfacePlacement, roofFacePointToSegment, sceneRegistry, - snapLocalXZInWorld, useScene, wouldCreateHostingCycle, } from '@pascal-app/core' import { Euler, Quaternion, Vector3 } from 'three' import { hasRoofFaceChildOverlap, resolveRoofWallHit } from '../../../lib/roof-wall-hit' -import { getActiveBuildingPose } from '../../../lib/world-grid-snap' +import { snapPlanPointToActiveGrid } from '../../../lib/world-grid-snap' import { itemEventToSurfaceHit, surfaceWorldNormalY } from '../shared/surface-hit' import { calculateItemRotation, @@ -73,17 +72,14 @@ export const floorStrategy = { const [dimX, , dimZ] = dims const rotY = ctx.draftItem?.rotation?.[1] ?? 0 const swapDims = Math.abs(Math.sin(rotY)) > 0.9 - // Snap on the world XZ grid (the grid the editor renders) so the - // item edges land on the visible grid even when the active building - // is rotated; then project the world point back into building-local - // for storage. Without this, a rotated building drags placement off - // the world grid. + // Snap on the lattice the grid is drawn on: a turned building's own + // lattice inside it (item edges square to the house), the world grid + // outside any building. // Snapping is governed by the active mode (snapToGrid returns raw in Off / // non-grid modes); Alt is force-place only and never bypasses snapping here. const dimensions = [swapDims ? dimZ : dimX, swapDims ? dimX : dimZ] as const - const [x, z] = snapLocalXZInWorld( + const [x, z] = snapPlanPointToActiveGrid( [event.localPosition[0], event.localPosition[2]], - getActiveBuildingPose(), (value, axis) => snapToGrid(value, dimensions[axis]), ) const y = ctx.gridPosition.y diff --git a/packages/editor/src/components/tools/item/use-placement-coordinator.tsx b/packages/editor/src/components/tools/item/use-placement-coordinator.tsx index b258e3f224..241259a322 100644 --- a/packages/editor/src/components/tools/item/use-placement-coordinator.tsx +++ b/packages/editor/src/components/tools/item/use-placement-coordinator.tsx @@ -1008,9 +1008,9 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea // Floor grab-offset: the item tracks the grabbed point instead of snapping // its origin under the cursor. The offset is computed in building-local space - // (`event.localPosition`), but `floorStrategy.move` snaps on the WORLD grid - // (`event.position`), so the corrected local point is re-projected to a - // corrected world point and both frames carry the offset to stay consistent. + // (`event.localPosition`, which `floorStrategy.move` snaps), and the corrected + // local point is re-projected to a corrected world point so both frames carry + // the offset and stay consistent. const applyFloorGrabOffset = (event: GridEvent): GridEvent => { if (relativeFloorStart === null) return event const rawX = event.localPosition[0] diff --git a/packages/editor/src/components/tools/select/select-candidates.test.ts b/packages/editor/src/components/tools/select/select-candidates.test.ts index 0595e4ee4b..cf7fd3c09b 100644 --- a/packages/editor/src/components/tools/select/select-candidates.test.ts +++ b/packages/editor/src/components/tools/select/select-candidates.test.ts @@ -139,4 +139,49 @@ describe('selectable candidates', () => { }) expect(collectSelectableCandidateIds().sort()).toEqual(['item_pick', 'wall_pick']) }) + + test("a box leaves a room's automatic floor plate and ceiling to the room, keeping what hangs from it", () => { + const restore = nodeRegistry._snapshot() + try { + for (const kind of ['slab', 'ceiling', 'box-select-test-light'] as const) + if (!nodeRegistry.has(kind)) + registerNode({ + kind, + schemaVersion: 1, + schema: z.object({ type: z.literal(kind) }) as never, + category: 'structure', + defaults: () => ({}), + capabilities: { selectable: {} }, + } as AnyNodeDefinition) + useScene.setState({ + nodes: { + level_test: { + id: 'level_test', + type: 'level', + parentId: 'building_test', + children: ['slab_shared', 'slab_drawn', 'ceiling_auto'], + }, + slab_shared: { + id: 'slab_shared', + type: 'slab', + parentId: 'level_test', + boundary: 'auto', + plateRole: 'base', + }, + slab_drawn: { id: 'slab_drawn', type: 'slab', parentId: 'level_test' }, + ceiling_auto: { + id: 'ceiling_auto', + type: 'ceiling', + parentId: 'level_test', + boundary: 'auto', + children: ['light_hung'], + }, + light_hung: { id: 'light_hung', type: 'box-select-test-light', parentId: 'ceiling_auto' }, + } as unknown as Record, + }) + expect(collectSelectableCandidateIds().sort()).toEqual(['light_hung', 'slab_drawn']) + } finally { + restore() + } + }) }) diff --git a/packages/editor/src/components/tools/select/select-candidates.ts b/packages/editor/src/components/tools/select/select-candidates.ts index 40cb618aab..446d00b749 100644 --- a/packages/editor/src/components/tools/select/select-candidates.ts +++ b/packages/editor/src/components/tools/select/select-candidates.ts @@ -1,6 +1,7 @@ import { type AnyNode, type AnyNodeId, + isDerivedNode, isRegistrySelectable, type LevelNode, nodeRegistry, @@ -16,6 +17,14 @@ function isVisibleSelectableNode(node: AnyNode): boolean { return isRegistrySelectable(node.type) } +/** + * Derived construction (a room's automatic floor plate or ceiling) belongs to its rooms, so a box + * never takes it along: a box round a porch would otherwise catch the house's shared floor plate, + * and deleting the selection took the floor out from under every room on it. A click still selects + * one on its own. + */ +const boxSelectable = (node: AnyNode) => !isDerivedNode(node) + export function collectSelectableCandidateIds(): string[] { const { levelId } = useViewer.getState().selection const { nodes } = useScene.getState() @@ -43,7 +52,8 @@ export function collectSelectableCandidateIds(): string[] { ) return - if (isRegistrySelectable(node.type)) { + // A ceiling's hung lights and fans are still the box's; the ceiling is not. + if (isRegistrySelectable(node.type) && boxSelectable(node)) { addNode(node) } @@ -70,7 +80,8 @@ export function collectSelectableCandidateIds(): string[] { const buildingId = resolveBuildingForLevel(levelId as AnyNodeId, nodes) for (const node of Object.values(nodes)) { - if (!node || node.type === 'level' || !isVisibleSelectableNode(node)) continue + if (!node || node.type === 'level' || !isVisibleSelectableNode(node) || !boxSelectable(node)) + continue const def = nodeRegistry.get(node.type) const isBuildingScoped = def?.floorplanScope === 'building' diff --git a/packages/editor/src/components/tools/wall/wall-drafting.test.ts b/packages/editor/src/components/tools/wall/wall-drafting.test.ts index 66cc2d1582..70a5554af4 100644 --- a/packages/editor/src/components/tools/wall/wall-drafting.test.ts +++ b/packages/editor/src/components/tools/wall/wall-drafting.test.ts @@ -9,6 +9,7 @@ import { createTerrainField, DoorNode as DoorSchema, encodeTerrainField, + findOpenWallEnds, flattenPatch, GROUND_SUPPORT_ID, getFloorPlacedElevation, @@ -19,6 +20,7 @@ import { resolveTerrainWallConstructionOptions, runAsSingleSceneHistoryStep, SlabNode, + snapWorldXZToBuildingLocal, spatialGridManager, useScene, type WallNode, @@ -30,11 +32,15 @@ import { migrateRoomZones, } from '@pascal-app/core/scene-migrations' import { useViewer } from '@pascal-app/viewer' -import useEditor from '../../../store/use-editor' +import type { SnappingMode } from '../../../lib/snapping-mode' +import { snapBuildingLocalToWorldGrid } from '../../../lib/world-grid-snap' +import useEditor, { isAngleSnapActive, isMagneticSnapActive } from '../../../store/use-editor' import useInteractionScope from '../../../store/use-interaction-scope' import { createWallOnCurrentLevel, + getSegmentGridStep, resolveEndpointWallSplit, + snapWallDraftPoint, snapWallDraftPointDetailed, } from './wall-drafting' import type { WallPlanPoint } from './wall-snap-geometry' @@ -758,27 +764,64 @@ describe('createWallOnCurrentLevel', () => { expect(levelWalls()).toHaveLength(2) }) - test('genuine mid-wall endpoint still splits the host (T junction)', () => { - const created = createWallOnCurrentLevel([2, 2], [2, 0]) + test.each(['grid', 'lines', 'angles', 'off'] as const)( + '%s drafting splits the host at a mid-wall junction', + (mode) => { + useEditor.getState().setSnappingMode('wall', mode) + const created = createWallOnCurrentLevel([2, 2], [2, 0]) + + expect(created?.end).toEqual([2, 0]) + expect(useScene.getState().nodes['wall_a' as AnyNodeId]).toBeUndefined() + expect( + levelWalls() + .filter((wall) => wall.id !== created?.id) + .map(({ start, end }) => [start, end]), + ).toEqual([ + [ + [0, 0], + [2, 0], + ], + [ + [2, 0], + [4, 0], + ], + ]) + }, + ) - expect(created?.end).toEqual([2, 0]) - expect(useScene.getState().nodes['wall_a' as AnyNodeId]).toBeUndefined() - const walls = levelWalls() - expect(walls).toHaveLength(3) - expect( - walls.some((wall) => wall.start[0] === 0 && wall.end[0] === 2 && wall.end[1] === 0), - ).toBe(true) - expect( - walls.some((wall) => wall.start[0] === 2 && wall.start[1] === 0 && wall.end[0] === 4), - ).toBe(true) + test('a wall drawn exactly over one built another way takes its place', () => { + // The seed wall is plain; the wall tool draws a thicker one. + const previousDefaults = useEditor.getState().toolDefaults + useEditor.setState({ toolDefaults: { ...previousDefaults, wall: { thickness: 0.3 } } } as never) + try { + const drawn = createWallOnCurrentLevel([0, 0], [4, 0]) + expect(drawn).not.toBeNull() + expect(useScene.getState().nodes['wall_a' as AnyNodeId]).toBeUndefined() + expect(levelWalls().map((wall) => wall.id)).toEqual([drawn!.id]) + } finally { + useEditor.setState({ toolDefaults: previousDefaults } as never) + } }) - test('exact duplicate segment is rejected', () => { + test('a wall drawn exactly over one built the same is refused', () => { expect(createWallOnCurrentLevel([0, 0], [4, 0])).toBeNull() expect(levelWalls()).toHaveLength(1) }) - test('grid mode: endpoint resolved onto a wall body still splits the host', () => { + test('a wall drawn on along part of another takes that stretch over', () => { + const drawn = createWallOnCurrentLevel([2, 0], [6, 0]) + expect(drawn).not.toBeNull() + const walls = levelWalls() + // The seed wall keeps [0, 2]; nothing else runs along [2, 4]. + expect(walls).toHaveLength(2) + const seed = walls.find((wall) => wall.id !== drawn!.id)! + expect([seed.start, seed.end]).toEqual([ + [0, 0], + [2, 0], + ]) + }) + + test('grid mode: endpoint resolved onto a wall body splits its host', () => { useEditor.getState().setSnappingMode('wall', 'grid') const created = createWallOnCurrentLevel([2, 2], [2, 0]) @@ -798,7 +841,7 @@ describe('createWallOnCurrentLevel', () => { expect(levelWalls()).toHaveLength(2) }) - test('mid-span split migrates the host attachments to the covering half', () => { + test('a T into a wall rehosts its door at the same position', () => { const door = DoorSchema.parse({ position: [1, 1.05, 0], parentId: 'wall_a', @@ -809,12 +852,12 @@ describe('createWallOnCurrentLevel', () => { const created = createWallOnCurrentLevel([2, 2], [2, 0]) expect(created?.end).toEqual([2, 0]) - const walls = levelWalls() - const firstHalf = walls.find((wall) => wall.start[0] === 0 && wall.end[0] === 2) - expect(firstHalf).toBeDefined() - const migratedDoor = useScene.getState().nodes[door.id as AnyNodeId] - expect(migratedDoor?.parentId).toBe(firstHalf?.id) - expect(firstHalf?.children).toContain(door.id) + const kept = useScene.getState().nodes[door.id as AnyNodeId] as DoorSchema + expect(kept.parentId).not.toBe('wall_a') + expect(kept.position[0]).toBe(1) + expect((useScene.getState().nodes[kept.parentId as AnyNodeId] as WallNode).children).toContain( + door.id, + ) }) test('a splitting commit lands as a single undo step', () => { @@ -826,7 +869,7 @@ describe('createWallOnCurrentLevel', () => { expect(useScene.temporal.getState().pastStates.length - before).toBe(1) }) - test('a crossing splits both the host and the inserted wall in one undo step', () => { + test('a crossing splits both walls in one undo step', () => { const before = useScene.temporal.getState().pastStates.length const created = createWallOnCurrentLevel([2, -2], [2, 2]) @@ -1095,4 +1138,237 @@ describe('snapWallDraftPointDetailed', () => { expect(freed.point).toEqual([2, 0]) expect(freed.snap).toBeNull() }) + + test('an end aimed into an L corner block joins the corner and reads as one', () => { + const south = { ...makeWall([0, 0], [4, 0], 'wall_south'), thickness: 0.2 } + const west = { ...makeWall([0, 4], [0, 0], 'wall_west'), thickness: 0.2 } + const result = snapWallDraftPointDetailed({ + point: [0.08, 0.08], + walls: [south, west], + start: [2, 3], + magnetic: false, + step: 0, + captureWallBodies: true, + }) + expect(result.point).toEqual([0, 0]) + expect(result.snap).toBe('endpoint') + expect(result.targetWallIds).toEqual(['wall_south', 'wall_west']) + }) + + // The 3D tool snaps to the floor below as a reference but can't join it: an + // end by a lower wall's face stays put, while its corner still snaps. + test('walls left out of bodyWalls never capture an end, but still snap corners', () => { + const lower = { ...makeWall([0, 0.4], [4, 0.4], 'wall_lower'), thickness: 0.2 } + const snap = (point: WallPlanPoint, bodyWalls?: WallNode[]) => + snapWallDraftPointDetailed({ + point, + walls: [lower], + start: [1, 3], + magnetic: false, + step: 0, + captureWallBodies: true, + bodyWalls, + }) + + const captured = snap([1, 0.5]) + expect(captured.snap).toBe('wall') + expect(captured.point[1]).toBeCloseTo(0.4, 12) + + const free = snap([1, 0.5], []) + expect(free.point).toEqual([1, 0.5]) + expect(free.snap).toBeNull() + + const corner = snap([0.02, 0.42], []) + expect(corner.point).toEqual([0, 0.4]) + expect(corner.snap).toBe('endpoint') + }) }) + +// The site planner sets a house on its lot turned and offset. Its walls are +// drawn square to the house, in building-local metres. An interior wall drawn +// across it has to meet both exterior walls exactly and stay square to the +// house however the building is turned, in 3D and on the plan alike. +const HOUSE_BUILDING_ID = 'building_lot' +// A 30' × 24' house of 8" walls, 2' × 1' off the building origin, so no wall +// line or face lies on the 0.5 m lattice. +const HOUSE_MIN: WallPlanPoint = [0.6096, 0.3048] +const HOUSE_MAX: WallPlanPoint = [9.7536, 7.62] +const EXTERIOR_THICKNESS = 0.2032 +// Where a builder aims an interior wall's end: just inside the exterior +// wall's interior face (1.18" off it). +const FACE_AIM = EXTERIOR_THICKNESS / 2 + 0.03 + +const BUILDING_POSES: Array<{ + label: string + yaw: number + position: [number, number, number] +}> = [ + { label: 'an unturned building at the origin', yaw: 0, position: [0, 0, 0] }, + { + label: 'a building turned 17° and offset on its lot', + yaw: (17 * Math.PI) / 180, + position: [12.37, 0, -8.91], + }, +] + +function seedHouse({ yaw, position }: { yaw: number; position: [number, number, number] }) { + const [x0, z0] = HOUSE_MIN + const [x1, z1] = HOUSE_MAX + const walls = [ + makeWall([x0, z0], [x1, z0], 'wall_south'), + makeWall([x1, z0], [x1, z1], 'wall_east'), + makeWall([x1, z1], [x0, z1], 'wall_north'), + makeWall([x0, z1], [x0, z0], 'wall_west'), + ].map((wall) => ({ ...wall, thickness: EXTERIOR_THICKNESS })) + const building = BuildingNode.parse({ + id: HOUSE_BUILDING_ID, + position, + rotation: [0, yaw, 0], + children: [LEVEL_ID], + }) + const level = LevelSchema.parse({ id: LEVEL_ID, parentId: building.id, level: 0, height: 2.5 }) + useScene.setState({ + nodes: Object.fromEntries([ + [building.id, building], + [level.id, { ...level, children: walls.map((wall) => wall.id) }], + ...walls.map((wall) => [wall.id, wall] as const), + ]), + rootNodeIds: [building.id], + dirtyNodes: new Set(), + collections: {}, + } as never) + useViewer.setState({ + selection: { + buildingId: HOUSE_BUILDING_ID, + levelId: LEVEL_ID, + zoneId: null, + selectedIds: [], + }, + } as never) +} + +for (const pose of BUILDING_POSES) { + describe(`an interior wall drawn across a house in ${pose.label}`, () => { + const [, z0] = HOUSE_MIN + const [, z1] = HOUSE_MAX + + beforeEach(() => { + useEditor.getState().setGridSnapStep(0.5) + // A reshaping-endpoint scope resolves to the 'wall' snap context + // without the node registry, as in `createWallOnCurrentLevel` above. + useInteractionScope + .getState() + .begin({ kind: 'reshaping', nodeId: 'wall_south', reshape: 'endpoint', driver: 'tool' }) + seedHouse(pose) + useScene.temporal.getState().clear() + useScene.temporal.getState().resume() + }) + + afterEach(() => { + useEditor.getState().setSnappingMode('wall', 'grid') + }) + + const setMode = (mode: SnappingMode) => useEditor.getState().setSnappingMode('wall', mode) + + // The cursor as a grid event hands it over: a hit on the world plane, + // taken into the building's frame. + const cursorAt = (local: WallPlanPoint): WallPlanPoint => { + const cos = Math.cos(pose.yaw) + const sin = Math.sin(pose.yaw) + const worldX = pose.position[0] + local[0] * cos + local[1] * sin + const worldZ = pose.position[2] - local[0] * sin + local[1] * cos + return snapWorldXZToBuildingLocal(worldX, worldZ, pose.position, pose.yaw, 0).local + } + + // The 3D wall tool's snap call. + const snapIn3d = (point: WallPlanPoint, start?: WallPlanPoint, captureWallBodies = true) => + snapWallDraftPointDetailed({ + point, + walls: levelWalls(), + start, + angleSnap: start !== undefined && isAngleSnapActive(), + magnetic: isMagneticSnapActive(), + captureWallBodies, + }) + + // The plan's click: the same cursor through the plan's grid callback. + const snapOnPlan = (point: WallPlanPoint, start?: WallPlanPoint) => + snapWallDraftPoint({ + point, + walls: levelWalls(), + start, + angleSnap: start !== undefined && isAngleSnapActive(), + magnetic: isMagneticSnapActive(), + gridSnap: (p) => snapBuildingLocalToWorldGrid(p, getSegmentGridStep()), + captureWallBodies: true, + }) + + const partitionOpenEnds = (partition: WallNode) => + findOpenWallEnds(useScene.getState().nodes, LEVEL_ID).filter( + (end) => end.wallId === partition.id, + ) + + test('grid: both ends land on the exterior walls, square to the house, with no gap', () => { + setMode('grid') + const startAim = cursorAt([4.2, z0 + FACE_AIM]) + const start = snapIn3d(startAim) + expect(start.snap).toBe('wall') + expect(start.targetWallIds).toEqual(['wall_south']) + expect(start.point[0]).toBeCloseTo(4, 9) + expect(start.point[1]).toBeCloseTo(z0, 9) + + // The cursor drifts a little sideways on its way across the house. + const endAim = cursorAt([4.1, z1 - FACE_AIM]) + const end = snapIn3d(endAim, start.point) + expect(end.snap).toBe('wall') + expect(end.targetWallIds).toEqual(['wall_north']) + expect(end.point[0]).toBeCloseTo(start.point[0], 9) + expect(end.point[1]).toBeCloseTo(z1, 9) + + // The plan snaps the same cursor to the same points. + expect(snapOnPlan(startAim)).toEqual(start.point) + expect(snapOnPlan(endAim, start.point)).toEqual(end.point) + + const partition = createWallOnCurrentLevel(start.point, end.point) + expect(partition).not.toBeNull() + expect(partitionOpenEnds(partition!)).toEqual([]) + }) + + test('ortho holds the wall square to the house and lands it on the far wall', () => { + setMode('angles') + const startAim = cursorAt([4.2, z0 + FACE_AIM]) + const start = snapIn3d(startAim) + expect(start.point[0]).toBeCloseTo(4.2, 9) + expect(start.point[1]).toBeCloseTo(z0, 9) + + // 4° off square: the 15° lock squares it to the house. + const endAim = cursorAt([3.7, z1 - FACE_AIM]) + const end = snapIn3d(endAim, start.point) + expect(end.snap).toBe('wall') + expect(end.point[0]).toBeCloseTo(start.point[0], 9) + expect(end.point[1]).toBeCloseTo(z1, 9) + + const onPlan = snapOnPlan(endAim, start.point) + expect(onPlan[0]).toBeCloseTo(end.point[0], 9) + expect(onPlan[1]).toBeCloseTo(end.point[1], 9) + + const partition = createWallOnCurrentLevel(start.point, end.point) + expect(partition).not.toBeNull() + expect(partitionOpenEnds(partition!)).toEqual([]) + }) + + test('without the body snap the lattice stops the end short of the face: an open gap', () => { + setMode('grid') + const start = snapIn3d(cursorAt([4.2, z0 + FACE_AIM])) + const end = snapIn3d(cursorAt([4.1, z1 - FACE_AIM]), start.point, false) + // The lattice line under the cursor, 0.72" short of the north wall's face. + expect(end.snap).toBeNull() + expect(end.point[1]).toBeCloseTo(7.5, 9) + + const partition = createWallOnCurrentLevel(start.point, end.point) + const [open] = partitionOpenEnds(partition!) + expect(open?.reason).toBe('gap') + expect(open?.gap).toBeCloseTo(z1 - EXTERIOR_THICKNESS / 2 - 7.5, 3) + }) + }) +} diff --git a/packages/editor/src/components/tools/wall/wall-drafting.ts b/packages/editor/src/components/tools/wall/wall-drafting.ts index d38285b04b..6bf31ec0f0 100644 --- a/packages/editor/src/components/tools/wall/wall-drafting.ts +++ b/packages/editor/src/components/tools/wall/wall-drafting.ts @@ -1,21 +1,30 @@ import { type AnyNodeId, DEFAULT_ANGLE_STEP, + finishWallEdit, + generateId, + planSeparatorInsertion, planWallInsertion, planWallSplitAtPoint, + railingWallDefaults, resolveWallConstruction, runAsSingleSceneHistoryStep, + type SeparatorNode, + sameWallConstruction, snapPointAlongAngleRay, useScene, type WallConstructionOptions, type WallNode, + wallsRunAlong, } from '@pascal-app/core' import { useViewer } from '@pascal-app/viewer' import { sfxEmitter } from '../../../lib/sfx-bus' import { resolveSnapFlags } from '../../../lib/snapping-mode' +import { getWallLineKind } from '../../../lib/wall-draw-variant' import useEditor, { getActiveSnappingMode, isMagneticSnapActive } from '../../../store/use-editor' import { distanceSquared, + findWallBodySnapTarget, findWallSnapTarget, findWallSpecialPointSnap, WALL_CONNECT_SNAP_RADIUS, @@ -109,14 +118,30 @@ type SnapWallDraftArgs = { */ magnetic?: boolean /** - * Optional grid-snap override. Lets the caller route grid snapping - * through a world-XZ aligned snap (so a rotated building's draft - * lands on the visible grid). When omitted, falls back to the - * local-axis grid at `step`. + * Optional grid-snap override, in the caller's plan frame. When omitted, + * falls back to the building-local grid at `step` — the lattice the wall + * tools draft on, square to the house however the building is turned. */ gridSnap?: (point: WallPlanPoint) => WallPlanPoint /** Optional magnetic snap radii. Omitted means wall tools keep their defaults. */ snapRadii?: WallSnapRadii + /** + * The point is a wall end (drawn or dragged): in the non-magnetic modes an + * end aimed into another wall's drawn body, or within the connect radius of + * either face, lands on that wall's reference line — where the wall + * topology T-joins it — ahead of the grid / angle placement, keeping the + * segment's direction from `start` (see `findWallBodySnapTarget`). Without + * it the grid quantises an end aimed at a face to the nearest lattice point, + * a fraction short of the face, and the end stays open with a gap. + */ + captureWallBodies?: boolean + /** + * The walls `captureWallBodies` may join an end into; `walls` when omitted. + * A body capture T-joins the wall, so a caller that adds reference walls it + * can't join (the floor below) keeps them out of this list while they still + * serve the corner and edge snaps. + */ + bodyWalls?: WallNode[] } export function snapWallDraftPointDetailed(args: SnapWallDraftArgs): WallDraftSnapResult { @@ -131,6 +156,8 @@ export function snapWallDraftPointDetailed(args: SnapWallDraftArgs): WallDraftSn magnetic = true, gridSnap, snapRadii, + captureWallBodies = false, + bodyWalls = walls, } = args if (bypassSnap) return { point, snap: null, targetWallIds: [] } @@ -144,9 +171,8 @@ export function snapWallDraftPointDetailed(args: SnapWallDraftArgs): WallDraftSn } const step = overrideStep ?? getSegmentGridStep() - // The angle path snaps the distance ALONG the 15° ray — a scalar, the - // same in world and local frames — so the `gridSnap` world-grid override - // only applies when the angle lock is off. + // The angle path snaps the distance ALONG the 15° ray from `start`, so the + // `gridSnap` override only applies when the angle lock is off. const basePoint: WallPlanPoint = start && angleSnap ? [...snapPointAlongAngleRay(start, point, DEFAULT_ANGLE_STEP, step)] @@ -182,6 +208,30 @@ export function snapWallDraftPointDetailed(args: SnapWallDraftArgs): WallDraftSn } const connectSpecial = findWallSpecialPointSnap(basePoint, walls, ignoreWallIds, connectRadii) if (connectSpecial) return connectSpecial + // A wall end aimed into a wall's body joins it, whichever lattice point or + // ray station the mode picked near its face. + const bodySnap = captureWallBodies + ? findWallBodySnapTarget(point, bodyWalls, { + ignoreWallIds, + placed: basePoint, + start, + margin: WALL_CONNECT_SNAP_RADIUS, + }) + : null + if (bodySnap) { + // An end aimed into a corner block joins the corner, and reads as one. + const atCorner = bodyWalls.some( + (wall) => + !ignoreWallIds?.includes(wall.id) && + (distanceSquared(bodySnap, wall.start) <= 1e-12 || + distanceSquared(bodySnap, wall.end) <= 1e-12), + ) + return { + point: bodySnap, + snap: atCorner ? 'endpoint' : 'wall', + targetWallIds: wallIdsAtSnapPoint(bodySnap, walls, ignoreWallIds), + } + } const connectWall = findWallSnapTarget(basePoint, walls, { ignoreWallIds, radius: WALL_CONNECT_SNAP_RADIUS, @@ -205,6 +255,36 @@ export function isSegmentLongEnough(start: WallPlanPoint, end: WallPlanPoint): b return distanceSquared(start, end) >= WALL_MIN_LENGTH * WALL_MIN_LENGTH } +/** + * An invisible wall drawn `start` → `end` on the current level (the Walls variant's Invisible, a room + * divider): room separators, each end joined to a wall it lands on and broken + * either side of a wall it crosses (`planSeparatorInsertion`), as one undo step. Rooms close on + * it; a room it closes off outside the house becomes a porch. The last piece, for the run to go + * on from its end; null when it would be too short. + */ +export function createInvisibleWallOnCurrentLevel( + start: WallPlanPoint, + end: WallPlanPoint, +): SeparatorNode | null { + const currentLevelId = useViewer.getState().selection.levelId + const { nodes, applyNodeChanges } = useScene.getState() + if (!(currentLevelId && isSegmentLongEnough(start, end))) return null + const joinRadius = isMagneticSnapActive() ? WALL_JOIN_SNAP_RADIUS : WALL_CONNECT_SNAP_RADIUS + return runAsSingleSceneHistoryStep(useScene, () => { + const plan = planSeparatorInsertion(nodes, { + levelId: currentLevelId as AnyNodeId, + start, + end, + joinRadius, + mintId: () => generateId('separator'), + }) + if (!plan) return null + applyNodeChanges(plan.changes) + sfxEmitter.emit('sfx:structure-build') + return plan.separators.at(-1) ?? null + }) +} + export function createWallOnCurrentLevel( start: WallPlanPoint, end: WallPlanPoint, @@ -220,13 +300,33 @@ export function createWallOnCurrentLevel( const joinRadius = isMagneticSnapActive() ? WALL_JOIN_SNAP_RADIUS : WALL_CONNECT_SNAP_RADIUS return runAsSingleSceneHistoryStep(useScene, () => { - const result = planWallInsertion(nodes, { + // The Walls variant's Railing draws railings: a guard of their own. + const insertion = { levelId: currentLevelId as AnyNodeId, start, end, joinRadius, - wallDefaults: useEditor.getState().toolDefaults.wall ?? {}, - }) + wallDefaults: + getWallLineKind() === 'railing' + ? railingWallDefaults() + : (useEditor.getState().toolDefaults.wall ?? {}), + } + let result = planWallInsertion(nodes, insertion) + if (!result.ok && result.reason === 'covered-existing-wall') { + // Drawn over walls built another way (an outside wall over an inside + // jog), the new wall takes their stretch over; over walls built the + // same, it would change nothing, so it stays refused. + const replacing = planWallInsertion(nodes, { ...insertion, replaceCovered: true }) + if ( + replacing.ok && + replacing.plan.insertedWalls.some((wall) => + wallsRunAlong(nodes, { ...wall, parentId: currentLevelId } as WallNode).some( + (covered) => !sameWallConstruction(covered, wall), + ), + ) + ) + result = replacing + } if (!result.ok) return null const { plan } = result @@ -237,20 +337,28 @@ export function createWallOnCurrentLevel( const sourceAlreadyUpdated = sourceUpdate ? plan.changes.update.some((operation) => operation.id === sourceUpdate.id) : false - applyNodeChanges({ - ...plan.changes, - update: plan.changes.update - .map((operation) => - sourceUpdate?.id === operation.id - ? { ...operation, data: { ...operation.data, ...sourceUpdate.data } } - : operation, - ) - .concat(sourceUpdate && !sourceAlreadyUpdated ? [sourceUpdate] : []), - create: plan.changes.create.map((operation) => ({ - ...operation, - node: finalizedWallsById.get(operation.node.id as WallNode['id']) ?? operation.node, - })), - }) + // A wall drawn along part of a parallel wall takes that stretch over, so + // drawing on from a wall never doubles the one it runs along. + applyNodeChanges( + finishWallEdit( + nodes, + { + ...plan.changes, + update: plan.changes.update + .map((operation) => + sourceUpdate?.id === operation.id + ? { ...operation, data: { ...operation.data, ...sourceUpdate.data } } + : operation, + ) + .concat(sourceUpdate && !sourceAlreadyUpdated ? [sourceUpdate] : []), + create: plan.changes.create.map((operation) => ({ + ...operation, + node: finalizedWallsById.get(operation.node.id as WallNode['id']) ?? operation.node, + })), + }, + { winnerIds: finalizedWalls.map((wall) => wall.id), mintId: () => generateId('wall') }, + ), + ) sfxEmitter.emit('sfx:structure-build') const terminalWall = finalizedWalls.at(-1)! diff --git a/packages/editor/src/components/tools/wall/wall-pull-snap.test.ts b/packages/editor/src/components/tools/wall/wall-pull-snap.test.ts new file mode 100644 index 0000000000..d7ccf92c6f --- /dev/null +++ b/packages/editor/src/components/tools/wall/wall-pull-snap.test.ts @@ -0,0 +1,274 @@ +import { describe, expect, test } from 'bun:test' +import type { WallNode } from '@pascal-app/core' +import { lockWallPullDirection, snapWallPullPoint, type WallPullSnapInput } from './wall-pull-snap' +import type { WallPlanPoint } from './wall-snap-geometry' + +function makeWall(start: WallPlanPoint, end: WallPlanPoint, id?: string): WallNode { + return { + object: 'node', + id: (id ?? `wall_${start.join('_')}_${end.join('_')}`) as WallNode['id'], + type: 'wall', + name: 'Wall', + parentId: null, + visible: true, + metadata: {}, + children: [], + start, + end, + thickness: 0.1, + frontSide: 'unknown', + backSide: 'unknown', + } as unknown as WallNode +} + +const deg = (degrees: number) => (degrees * Math.PI) / 180 +const polar = (from: WallPlanPoint, degrees: number, length: number): WallPlanPoint => [ + from[0] + Math.cos(deg(degrees)) * length, + from[1] + Math.sin(deg(degrees)) * length, +] + +function expectPoint(actual: WallPlanPoint, expected: WallPlanPoint) { + expect(actual[0]).toBeCloseTo(expected[0], 6) + expect(actual[1]).toBeCloseTo(expected[1], 6) +} + +// A 4 × 3 m room; the pull starts at the south wall's east end. +const ROOM = [ + makeWall([0, 0], [4, 0], 'south'), + makeWall([4, 0], [4, 3], 'east'), + makeWall([4, 3], [0, 3], 'north'), + makeWall([0, 3], [0, 0], 'west'), +] + +function pullFromRoom(point: WallPlanPoint, extra: Partial = {}) { + return snapWallPullPoint({ + point, + start: [4, 0], + runStart: [4, 0], + reference: [1, 0], + walls: ROOM, + gridStep: 0.5, + ...extra, + }) +} + +describe('lockWallPullDirection', () => { + test('holds straight on from the wall it comes from within about 7°', () => { + expect(lockWallPullDirection(polar([0, 0], 6, 3), [1, 0])).toEqual({ + direction: [1, 0], + lock: 'straight', + }) + expect(lockWallPullDirection(polar([0, 0], 8, 3), [1, 0]).lock).toBe('angle') + }) + + test('holds square to the wall it comes from, either side', () => { + const left = lockWallPullDirection(polar([0, 0], 85, 3), [1, 0]) + expect(left.lock).toBe('square') + expectPoint(left.direction, [0, 1]) + const right = lockWallPullDirection(polar([0, 0], -96, 3), [1, 0]) + expect(right.lock).toBe('square') + expectPoint(right.direction, [0, -1]) + }) + + test('holds straight on to a skewed wall, and the house axes beside it', () => { + const skew: WallPlanPoint = [Math.cos(deg(20)), Math.sin(deg(20))] + const straight = lockWallPullDirection(polar([0, 0], 23, 3), skew) + expect(straight.lock).toBe('straight') + expectPoint(straight.direction, skew) + const axis = lockWallPullDirection(polar([0, 0], 4, 3), skew) + expect(axis.lock).toBe('axis') + expectPoint(axis.direction, [1, 0]) + }) + + test('past the lock it steps by 15° on the house axes', () => { + for (const [cursor, expected] of [ + [40, 45], + [28, 30], + [52, 45], + [-118, -120], + ] as const) { + const { direction, lock } = lockWallPullDirection(polar([0, 0], cursor, 3), [1, 0]) + expect(lock).toBe('angle') + expectPoint(direction, polar([0, 0], expected, 1)) + } + }) +}) + +describe('snapWallPullPoint', () => { + test('a straight pull steps its length on the grid', () => { + const result = pullFromRoom([6.6, 0.2]) + expect(result.lock).toBe('straight') + expect(result.snap).toBe('grid') + expect(result.label).toBe('Grid') + expectPoint(result.point, [6.5, 0]) + }) + + test('a square pull holds 90° to the pulled wall', () => { + const result = pullFromRoom([4.25, -2.6]) + expect(result.lock).toBe('square') + expectPoint(result.point, [4, -2.5]) + }) + + test('further round it snaps to 15° steps, with a grid length along them', () => { + const result = pullFromRoom(polar([4, 0], -40, 3)) + expect(result.lock).toBe('angle') + // 3 m at 40° is 2.99 m along 45°: 3 m on the 0.5 m grid. + expectPoint(result.point, polar([4, 0], -45, 3)) + }) + + test('Alt is fully free', () => { + const cursor = polar([4, 0], -40, 3.13) + const result = pullFromRoom(cursor, { free: true }) + expect(result.lock).toBe('free') + expect(result.snap).toBeNull() + expectPoint(result.point, cursor) + }) + + test('the extension of the pulled wall is always drawn', () => { + const result = pullFromRoom([5.3, -1.9]) + const extension = result.guides.find((guide) => guide.kind === 'extension') + expect(extension?.from).toEqual([4, 0]) + expect(extension?.to[1]).toBeCloseTo(0, 9) + expect(extension?.to[0] ?? 0).toBeGreaterThan(5.3) + }) + + test('an existing wall end wins over the held direction', () => { + const result = snapWallPullPoint({ + point: [4.15, 3.2], + start: [7, 3], + runStart: [4, 0], + reference: [0, 1], + walls: [...ROOM, makeWall([4, 0], [7, 0], 'p1'), makeWall([7, 0], [7, 3], 'p2')], + gridStep: 0.5, + }) + expect(result.snap).toBe('endpoint') + expect(result.label).toBe('Endpoint') + expect(result.point).toEqual([4, 3]) + expect(result.targetWallIds.sort()).toEqual(['east', 'north']) + }) + + test('a held direction running into a wall lands on its line, square', () => { + // From the east of the room, back west at the north wall's height: the + // wall runs into the east wall at (4, 1.5), square to it. + const result = snapWallPullPoint({ + point: [4.2, 1.52], + start: [7, 1.5], + runStart: [7, -1], + reference: [0, 1], + walls: ROOM, + gridStep: 0.5, + }) + expect(result.snap).toBe('perpendicular') + expect(result.label).toBe('Perpendicular') + expectPoint(result.point, [4, 1.5]) + expect(result.targetWallIds).toEqual(['east']) + }) + + test('a run lines up with its start, then closes on it', () => { + // Pulled east out of a lone wall's end S = (0, 0): east to (5, 0), north + // to (5, 4), then west — the run's start guide catches x = 0 … + const source = makeWall([-4, 0], [0, 0], 'source') + const walls = [source, makeWall([0, 0], [5, 0], 'r1'), makeWall([5, 0], [5, 4], 'r2')] + const across = snapWallPullPoint({ + point: [0.1, 4.05], + start: [5, 4], + runStart: [0, 0], + reference: [0, 1], + walls, + gridStep: 0, + }) + expect(across.snap).toBe('alignment') + expect(across.label).toBe('In line with start') + expectPoint(across.point, [0, 4]) + const startGuide = across.guides.find((guide) => guide.kind === 'run-start') + expect(startGuide?.from).toEqual([0, 0]) + expect(startGuide?.to[0]).toBeCloseTo(0, 9) + expect(startGuide?.to[1] ?? 0).toBeGreaterThan(4) + // … and the last wall closes square back onto it. + const close = snapWallPullPoint({ + point: [0.12, 0.2], + start: [0, 4], + runStart: [0, 0], + reference: [-1, 0], + walls: [...walls, makeWall([5, 4], [0, 4], 'r3')], + gridStep: 0.5, + }) + expect(close.snap).toBe('endpoint') + expect(close.point).toEqual([0, 0]) + }) + + test('guides cross near the cursor: the crossing is marked and snaps', () => { + // The run's start S = (0, 0) and another wall's end P = (2, 6): S's + // vertical and P's horizontal cross at (0, 6). + const walls = [ + makeWall([-4, 0], [0, 0], 'source'), + makeWall([0, 0], [5, 0], 'r1'), + makeWall([5, 0], [5, 4], 'r2'), + makeWall([2, 6], [2, 9], 'p'), + ] + const near = snapWallPullPoint({ + point: [0.45, 5.6], + start: [5, 4], + runStart: [0, 0], + reference: [0, 1], + walls, + gridStep: 0.5, + }) + expect(near.intersections.some((point) => point[0] === 0 && point[1] === 6)).toBe(true) + expect(near.snap).not.toBe('intersection') + + const on = snapWallPullPoint({ + point: [0.1, 5.9], + start: [5, 4], + runStart: [0, 0], + reference: [0, 1], + walls, + gridStep: 0.5, + }) + expect(on.snap).toBe('intersection') + expect(on.label).toBe('Intersection') + expect(on.point).toEqual([0, 6]) + expect(on.guides.map((guide) => guide.kind).sort()).toEqual([ + 'alignment', + 'extension', + 'run-start', + ]) + const vertical = on.guides.find((guide) => guide.kind === 'run-start') + expect(vertical?.from).toEqual([0, 0]) + const horizontal = on.guides.find((guide) => guide.kind === 'alignment') + expect(horizontal?.from).toEqual([2, 6]) + }) + + test('a wall middle and a wall crossing snap too', () => { + const midpoint = pullFromRoom([2.1, 3.15], { start: [4, -2], reference: [0, -1] }) + expect(midpoint.snap).toBe('midpoint') + expect(midpoint.point).toEqual([2, 3]) + }) + + test("on a turned building the lock follows the house's axes, not the world's", () => { + // The house is turned 30° on its lot. Plan points are in its own frame, + // as both views hand them to the tools; a world cursor along the house's + // east side comes in along the house's X, and the held wall goes back out + // along it. + const yaw = deg(30) + const origin: WallPlanPoint = [12, -7] + const toWorld = ([x, z]: WallPlanPoint): WallPlanPoint => [ + origin[0] + x * Math.cos(yaw) + z * Math.sin(yaw), + origin[1] - x * Math.sin(yaw) + z * Math.cos(yaw), + ] + const toLocal = ([x, z]: WallPlanPoint): WallPlanPoint => { + const dx = x - origin[0] + const dz = z - origin[1] + return [dx * Math.cos(yaw) - dz * Math.sin(yaw), dx * Math.sin(yaw) + dz * Math.cos(yaw)] + } + const worldCursor = toWorld([6.6, 0.25]) + const result = pullFromRoom(toLocal(worldCursor)) + expect(result.lock).toBe('straight') + expectPoint(result.point, [6.5, 0]) + const worldStart = toWorld([4, 0]) + const worldEnd = toWorld(result.point) + const bearing = Math.atan2(worldEnd[1] - worldStart[1], worldEnd[0] - worldStart[0]) + // Along the house's X, which sits 30° off the world's. + expect(bearing).toBeCloseTo(-yaw, 9) + }) +}) diff --git a/packages/editor/src/components/tools/wall/wall-pull-snap.ts b/packages/editor/src/components/tools/wall/wall-pull-snap.ts new file mode 100644 index 0000000000..7174a23d9f --- /dev/null +++ b/packages/editor/src/components/tools/wall/wall-pull-snap.ts @@ -0,0 +1,563 @@ +// Pure snap geometry for a wall pulled from a selected wall's end (the "pull to +// continue" grip) and for the run it continues — no store / viewer / React +// deps, so it's unit-testable in isolation. Coordinates are XZ plan points in +// the building's own frame, the frame both views draft in: the building's axes +// are the plan's X and Z, so a turned house keeps its square. + +import { isCurvedWall, type WallNode } from '@pascal-app/core' +import { + distanceSquared, + findWallBodySnapTarget, + findWallSpecialPointSnap, + WALL_CONNECT_SNAP_RADIUS, + type WallPlanPoint, + wallIdsAtSnapPoint, +} from './wall-snap-geometry' + +/** + * What a pulled wall's end caught, as the snap marker names it: an existing + * wall's end or middle, a crossing (two walls, or two guides), a point on a + * wall (`perpendicular` when the new wall meets it square), a guide it lines up + * with, or a plain grid length. + */ +export type WallPullSnapKind = + | 'endpoint' + | 'midpoint' + | 'intersection' + | 'wall' + | 'perpendicular' + | 'alignment' + | 'grid' + +/** The words the snap marker shows for each kind. */ +export const WALL_PULL_SNAP_LABELS: Record = { + endpoint: 'Endpoint', + midpoint: 'Midpoint', + intersection: 'Intersection', + wall: 'On wall', + perpendicular: 'Perpendicular', + alignment: 'Aligned', + grid: 'Grid', +} + +/** + * How the wall's direction was held: straight on from the wall it comes from, + * square to it, along one of the house's axes, on a 15° step, or not at all. + */ +export type WallPullDirectionLock = 'straight' | 'square' | 'axis' | 'angle' | 'free' + +/** + * A dashed guide: the extension of the wall the new one comes from, a line + * through another wall's end along one of the house's axes, or the same through + * the run's start (so the run can close square back to it). + */ +export type WallPullGuideKind = 'extension' | 'alignment' | 'run-start' + +export type WallPullGuide = { + kind: WallPullGuideKind + from: WallPlanPoint + to: WallPlanPoint +} + +export type WallPullSnapResult = { + point: WallPlanPoint + snap: WallPullSnapKind | null + /** `WALL_PULL_SNAP_LABELS[snap]`, or "In line with start" for the run's start guide. */ + label: string | null + lock: WallPullDirectionLock + /** Walls whose geometry the end landed on, for the marker's wall highlight. */ + targetWallIds: string[] + guides: WallPullGuide[] + /** Where two guides cross near the cursor: markers, and snap targets. */ + intersections: WallPlanPoint[] +} + +/** Snap radii (m) measured from the cursor, or along the held direction for `wall` / `alignment`. */ +export type WallPullSnapRadii = { + endpoint: number + /** A wall's middle, or where two walls cross. */ + special: number + /** Where two guides cross. */ + intersection: number + /** The held direction landing on a wall's line, or the square foot on it. */ + wall: number + /** The held direction landing on a guide. */ + alignment: number + /** How near a guide line passes the cursor to be considered at all. */ + guide: number +} + +export const WALL_PULL_SNAP_RADII: WallPullSnapRadii = { + endpoint: 0.3, + special: 0.2, + intersection: 0.2, + wall: 0.25, + alignment: 0.15, + guide: 0.6, +} + +/** The direction holds straight on / square / on a house axis within this angle. */ +export const WALL_PULL_LOCK_TOLERANCE = (7 * Math.PI) / 180 +/** Past the lock the direction snaps to steps of this angle, on the house's axes. */ +export const WALL_PULL_ANGLE_STEP = Math.PI / 12 + +const PERPENDICULAR_SINE = Math.sin((1 * Math.PI) / 180) +const ON_LINE = 1e-6 +const INTERSECTION_SHOW_RADIUS = 0.75 +const EXTENSION_MIN_LENGTH = 1.5 +const EXTENSION_OVERSHOOT = 1 +const GUIDE_OVERSHOOT = 0.5 + +export type WallPullSnapInput = { + /** The raw cursor. */ + point: WallPlanPoint + /** Where the wall being drawn starts. */ + start: WallPlanPoint + /** Where the run started: the pulled wall end. */ + runStart: WallPlanPoint + /** + * Unit direction of the wall the new one comes from, pointing out of its end + * (the pulled wall's, then each placed wall's). Null draws on the house's + * axes and 15° steps only. + */ + reference: WallPlanPoint | null + /** The level's walls: snap targets and guide anchors. */ + walls: readonly WallNode[] + /** Length step along the held direction; 0 leaves lengths free. */ + gridStep: number + /** Alt, or snapping off: the end follows the cursor. */ + free?: boolean + radii?: Partial +} + +type GuideLine = { + kind: WallPullGuideKind + /** A point on the line: the anchor it is drawn from. */ + anchor: WallPlanPoint + /** Unit direction. */ + direction: WallPlanPoint +} + +function unit(vector: WallPlanPoint): WallPlanPoint | null { + const length = Math.hypot(vector[0], vector[1]) + return length > 1e-9 ? [vector[0] / length, vector[1] / length] : null +} + +function angleBetween(a: WallPlanPoint, b: WallPlanPoint): number { + return Math.abs(Math.atan2(a[0] * b[1] - a[1] * b[0], a[0] * b[0] + a[1] * b[1])) +} + +function samePoint(a: WallPlanPoint, b: WallPlanPoint, tolerance = 1e-6): boolean { + return distanceSquared(a, b) <= tolerance * tolerance +} + +/** + * The direction a pull from `start` toward `vector` holds: straight on from + * `reference` or square to it, or along a house axis, whichever is nearest + * within `WALL_PULL_LOCK_TOLERANCE`; otherwise the nearest 15° step on the + * house's axes. Folding back over the wall it comes from is not offered. + */ +export function lockWallPullDirection( + vector: WallPlanPoint, + reference: WallPlanPoint | null, +): { direction: WallPlanPoint; lock: WallPullDirectionLock } { + const along = unit(vector) + if (!along) return { direction: reference ?? [1, 0], lock: 'free' } + const candidates: Array<{ direction: WallPlanPoint; lock: WallPullDirectionLock }> = [] + const ref = reference ? unit(reference) : null + if (ref) { + candidates.push( + { direction: ref, lock: 'straight' }, + { direction: [-ref[1], ref[0]], lock: 'square' }, + { direction: [ref[1], -ref[0]], lock: 'square' }, + ) + } + for (const axis of [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ] as WallPlanPoint[]) { + candidates.push({ direction: axis, lock: 'axis' }) + } + let best: { direction: WallPlanPoint; lock: WallPullDirectionLock } | null = null + let bestAngle = Number.POSITIVE_INFINITY + for (const candidate of candidates) { + const angle = angleBetween(along, candidate.direction) + if (angle < bestAngle - 1e-9) { + best = candidate + bestAngle = angle + } + } + if (best && bestAngle <= WALL_PULL_LOCK_TOLERANCE) return best + const stepped = + Math.round(Math.atan2(along[1], along[0]) / WALL_PULL_ANGLE_STEP) * WALL_PULL_ANGLE_STEP + return { direction: [Math.cos(stepped), Math.sin(stepped)], lock: 'angle' } +} + +/** + * The points guides run through: every wall end on the level and the run's + * start, once each, leaving out the start of the wall being drawn (a guide + * through it is the direction lock itself). + */ +function guideAnchors( + walls: readonly WallNode[], + runStart: WallPlanPoint, + start: WallPlanPoint, +): Array<{ point: WallPlanPoint; runStart: boolean }> { + const anchors: Array<{ point: WallPlanPoint; runStart: boolean }> = [] + const add = (point: WallPlanPoint, isRunStart: boolean) => { + if (samePoint(point, start, 1e-4)) return + const existing = anchors.find((anchor) => samePoint(anchor.point, point, 1e-4)) + if (existing) { + existing.runStart ||= isRunStart + return + } + anchors.push({ point: [point[0], point[1]], runStart: isRunStart }) + } + add(runStart, true) + for (const wall of walls) { + add(wall.start, false) + add(wall.end, false) + } + return anchors +} + +/** + * The guide lines near the cursor: a vertical (constant X) line through each + * anchor whose X is within `radius` of the cursor's, and a horizontal one + * likewise. Several anchors on one line give one line, drawn from the anchor + * nearest the cursor; the run's start keeps its own lines. + */ +function nearbyGuideLines( + anchors: Array<{ point: WallPlanPoint; runStart: boolean }>, + cursor: WallPlanPoint, + radius: number, +): GuideLine[] { + const lines: GuideLine[] = [] + for (const axis of [0, 1] as const) { + // axis 0: vertical lines (constant X); axis 1: horizontal lines (constant Z). + const across = axis === 0 ? 1 : 0 + const byCoord = new Map() + for (const anchor of anchors) { + if (Math.abs(anchor.point[axis] - cursor[axis]) > radius) continue + const key = `${anchor.runStart ? 's' : 'a'}:${anchor.point[axis].toFixed(4)}` + const held = byCoord.get(key) + if ( + !held || + Math.abs(anchor.point[across] - cursor[across]) < + Math.abs(held.point[across] - cursor[across]) + ) { + byCoord.set(key, anchor) + } + } + for (const anchor of byCoord.values()) { + lines.push({ + kind: anchor.runStart ? 'run-start' : 'alignment', + anchor: anchor.point, + direction: axis === 0 ? [0, 1] : [1, 0], + }) + } + } + return lines +} + +/** Where two lines cross, or null when they run parallel. */ +function crossLines(a: GuideLine, b: GuideLine): WallPlanPoint | null { + const denom = a.direction[0] * b.direction[1] - a.direction[1] * b.direction[0] + if (Math.abs(denom) < 1e-9) return null + const dx = b.anchor[0] - a.anchor[0] + const dz = b.anchor[1] - a.anchor[1] + const t = (dx * b.direction[1] - dz * b.direction[0]) / denom + return [a.anchor[0] + a.direction[0] * t, a.anchor[1] + a.direction[1] * t] +} + +/** Station along the ray `start + direction · t` where it crosses `line`, or null. */ +function rayStationOnLine( + start: WallPlanPoint, + direction: WallPlanPoint, + line: GuideLine, +): number | null { + const denom = direction[0] * line.direction[1] - direction[1] * line.direction[0] + if (Math.abs(denom) < 1e-9) return null + const dx = line.anchor[0] - start[0] + const dz = line.anchor[1] - start[1] + const t = (dx * line.direction[1] - dz * line.direction[0]) / denom + return t > 1e-6 ? t : null +} + +function passesThrough(line: GuideLine, point: WallPlanPoint): boolean { + const dx = point[0] - line.anchor[0] + const dz = point[1] - line.anchor[1] + return Math.abs(dx * line.direction[1] - dz * line.direction[0]) <= 1e-4 +} + +/** A guide drawn from its anchor through `to` and a little past it. */ +function guideThrough(line: GuideLine, to: WallPlanPoint): WallPullGuide { + const dx = to[0] - line.anchor[0] + const dz = to[1] - line.anchor[1] + const along = dx * line.direction[0] + dz * line.direction[1] + const sign = along >= 0 ? 1 : -1 + return { + kind: line.kind, + from: [line.anchor[0], line.anchor[1]], + to: [ + to[0] + line.direction[0] * sign * GUIDE_OVERSHOOT, + to[1] + line.direction[1] * sign * GUIDE_OVERSHOOT, + ], + } +} + +function extensionGuide( + start: WallPlanPoint, + reference: WallPlanPoint, + cursor: WallPlanPoint, +): WallPullGuide { + const along = (cursor[0] - start[0]) * reference[0] + (cursor[1] - start[1]) * reference[1] + const length = Math.max(EXTENSION_MIN_LENGTH, along + EXTENSION_OVERSHOOT) + return { + kind: 'extension', + from: [start[0], start[1]], + to: [start[0] + reference[0] * length, start[1] + reference[1] * length], + } +} + +type WallLine = { wall: WallNode; ux: number; uz: number; length: number } + +function straightWallLines(walls: readonly WallNode[]): WallLine[] { + return walls.flatMap((wall) => { + if (isCurvedWall(wall)) return [] + const dx = wall.end[0] - wall.start[0] + const dz = wall.end[1] - wall.start[1] + const length = Math.hypot(dx, dz) + return length > 1e-9 ? [{ wall, ux: dx / length, uz: dz / length, length }] : [] + }) +} + +/** True when `segment` meets `wall` square (within 1°). */ +function meetsSquare(segment: WallPlanPoint, line: WallLine): boolean { + const along = unit(segment) + if (!along) return false + return Math.abs(along[0] * line.ux + along[1] * line.uz) <= PERPENDICULAR_SINE +} + +/** + * Snap the end of a pulled wall (or of a wall continuing the run). + * + * The direction holds straight on from the wall it comes from, square to it, or + * along a house axis within about 7°, and on 15° steps past that; the length + * steps by `gridStep` along it. Existing walls win over the held direction so a + * loop closes exactly: a wall end (the run's start among them) first, then a + * wall's middle or a crossing of two walls, then a crossing of two guides; then + * a wall the held direction runs into (or the square foot on a wall near the + * cursor); then a guide the held direction runs into, so the run lines up with + * its start or another wall's end; then the grid length. `free` (Alt, or + * snapping off) leaves the end at the cursor. + */ +export function snapWallPullPoint(input: WallPullSnapInput): WallPullSnapResult { + const { point: cursor, start, runStart, walls, gridStep } = input + const radii = { ...WALL_PULL_SNAP_RADII, ...input.radii } + const reference = input.reference ? unit(input.reference) : null + const extension = reference ? extensionGuide(start, reference, cursor) : null + const extensionLine: GuideLine | null = reference + ? { kind: 'extension', anchor: [start[0], start[1]], direction: reference } + : null + const baseGuides = extension ? [extension] : [] + const result = ( + point: WallPlanPoint, + snap: WallPullSnapKind | null, + lock: WallPullDirectionLock, + extra: Partial> = {}, + intersections: WallPlanPoint[] = [], + ): WallPullSnapResult => ({ + point: [point[0], point[1]], + snap, + label: extra.label ?? (snap ? WALL_PULL_SNAP_LABELS[snap] : null), + lock, + targetWallIds: extra.targetWallIds ?? [], + guides: [...baseGuides, ...(extra.guides ?? [])], + intersections, + }) + + const vector: WallPlanPoint = [cursor[0] - start[0], cursor[1] - start[1]] + if (input.free) return result(cursor, null, 'free') + if (Math.hypot(vector[0], vector[1]) < 1e-6) return result(start, null, 'free') + + // The held direction, and the length along it. + const { direction, lock } = lockWallPullDirection(vector, reference) + const along = vector[0] * direction[0] + vector[1] * direction[1] + const length = gridStep > 0 ? Math.round(along / gridStep) * gridStep : along + const held: WallPlanPoint = [start[0] + direction[0] * length, start[1] + direction[1] * length] + + const anchors = guideAnchors(walls, runStart, start) + const lines = nearbyGuideLines(anchors, cursor, radii.guide) + const allLines = extensionLine ? [extensionLine, ...lines] : lines + // Guide crossings near the cursor, each with the two lines through it. + const crossings: Array<{ point: WallPlanPoint; a: GuideLine; b: GuideLine }> = [] + for (let i = 0; i < allLines.length; i += 1) { + for (let j = i + 1; j < allLines.length; j += 1) { + const a = allLines[i]! + const b = allLines[j]! + const point = crossLines(a, b) + if (!point || samePoint(point, start, 1e-4)) continue + if (distanceSquared(point, cursor) > INTERSECTION_SHOW_RADIUS ** 2) continue + if (crossings.some((crossing) => samePoint(crossing.point, point, 1e-4))) continue + crossings.push({ point, a, b }) + } + } + const intersections = crossings.map((crossing) => crossing.point) + // The guides the final point sits on, then those through each crossing + // shown, drawn from their anchors — each line once. + const guidesThrough = (point: WallPlanPoint) => { + const drawn = new Set() + const guides: WallPullGuide[] = [] + for (const line of lines) { + if (!passesThrough(line, point) || samePoint(line.anchor, point, 1e-4)) continue + drawn.add(line) + guides.push(guideThrough(line, point)) + } + for (const crossing of crossings) { + for (const line of [crossing.a, crossing.b]) { + if (line.kind === 'extension' || drawn.has(line)) continue + drawn.add(line) + guides.push(guideThrough(line, crossing.point)) + } + } + return guides + } + const settle = ( + point: WallPlanPoint, + snap: WallPullSnapKind, + pointLock: WallPullDirectionLock, + extra: Partial> = {}, + ) => + result( + point, + snap, + pointLock, + { ...extra, guides: extra.guides ?? guidesThrough(point) }, + intersections, + ) + + // 1. A wall end, the run's start among them. + let endpoint: WallPlanPoint | null = null + let endpointDistance = radii.endpoint ** 2 + for (const anchor of anchors) { + const distance = distanceSquared(anchor.point, cursor) + if (distance <= endpointDistance) { + endpoint = anchor.point + endpointDistance = distance + } + } + if (endpoint) { + return settle(endpoint, 'endpoint', 'free', { + targetWallIds: wallIdsAtSnapPoint(endpoint, [...walls]), + }) + } + + // 2. A wall's middle, or where two walls cross. + const special = findWallSpecialPointSnap(cursor, [...walls], undefined, { + endpoint: 0, + midpoint: radii.special, + intersection: radii.special, + }) + if (special && special.snap !== 'endpoint' && !samePoint(special.point, start, 1e-4)) { + return settle(special.point, special.snap ?? 'midpoint', 'free', { + targetWallIds: special.targetWallIds, + }) + } + + // 3. Where two guides cross. + let crossing: (typeof crossings)[number] | null = null + let crossingDistance = radii.intersection ** 2 + for (const candidate of crossings) { + const distance = distanceSquared(candidate.point, cursor) + if (distance <= crossingDistance) { + crossing = candidate + crossingDistance = distance + } + } + if (crossing) return settle(crossing.point, 'intersection', 'free') + + // 4. A wall the held direction runs into: its body, its line near the held + // length, or the square foot on a wall line near the cursor. + const wallLines = straightWallLines(walls) + const onWall = (point: WallPlanPoint, pointLock: WallPullDirectionLock) => { + const targetWallIds = wallIdsAtSnapPoint(point, [...walls]) + const atEnd = walls.some( + (wall) => samePoint(point, wall.start, 1e-6) || samePoint(point, wall.end, 1e-6), + ) + const segment: WallPlanPoint = [point[0] - start[0], point[1] - start[1]] + const square = wallLines.some( + (line) => targetWallIds.includes(line.wall.id) && meetsSquare(segment, line), + ) + return settle(point, atEnd ? 'endpoint' : square ? 'perpendicular' : 'wall', pointLock, { + targetWallIds, + }) + } + if (length > ON_LINE) { + const body = findWallBodySnapTarget(cursor, [...walls], { + placed: held, + start, + margin: WALL_CONNECT_SNAP_RADIUS, + }) + if (body && !samePoint(body, start, 1e-4)) return onWall(body, lock) + } + let rayHit: WallPlanPoint | null = null + let rayHitGap = radii.wall + for (const line of wallLines) { + const denom = direction[0] * line.uz - direction[1] * line.ux + if (Math.abs(denom) < 1e-9) continue + const dx = line.wall.start[0] - start[0] + const dz = line.wall.start[1] - start[1] + const t = (dx * line.uz - dz * line.ux) / denom + const s = (dx * direction[1] - dz * direction[0]) / denom + if (!(t > 1e-4) || s <= 1e-6 || s >= line.length - 1e-6) continue + const gap = Math.abs(t - along) + if (gap <= rayHitGap) { + rayHit = [start[0] + direction[0] * t, start[1] + direction[1] * t] + rayHitGap = gap + } + } + if (rayHit) return onWall(rayHit, lock) + let foot: WallPlanPoint | null = null + let footDistance = radii.wall ** 2 + for (const line of wallLines) { + const station = + (start[0] - line.wall.start[0]) * line.ux + (start[1] - line.wall.start[1]) * line.uz + if (station <= 1e-6 || station >= line.length - 1e-6) continue + const point: WallPlanPoint = [ + line.wall.start[0] + line.ux * station, + line.wall.start[1] + line.uz * station, + ] + if (samePoint(point, start, 1e-4)) continue + const distance = distanceSquared(point, cursor) + if (distance <= footDistance) { + foot = point + footDistance = distance + } + } + if (foot) return onWall(foot, 'free') + + // 5. A guide the held direction runs into. + let aligned: { point: WallPlanPoint; line: GuideLine } | null = null + let alignedGap = radii.alignment + for (const line of lines) { + const t = rayStationOnLine(start, direction, line) + if (t === null) continue + const gap = Math.abs(t - along) + if (gap <= alignedGap) { + aligned = { point: [start[0] + direction[0] * t, start[1] + direction[1] * t], line } + alignedGap = gap + } + } + if (aligned) { + return settle(aligned.point, 'alignment', lock, { + label: aligned.line.kind === 'run-start' ? 'In line with start' : undefined, + }) + } + + // 6. The grid length along the held direction. + if (gridStep > 0) return settle(held, 'grid', lock) + return result(held, null, lock, { guides: guidesThrough(held) }, intersections) +} diff --git a/packages/editor/src/components/tools/wall/wall-snap-geometry.test.ts b/packages/editor/src/components/tools/wall/wall-snap-geometry.test.ts index b707fefcf4..b4809c1633 100644 --- a/packages/editor/src/components/tools/wall/wall-snap-geometry.test.ts +++ b/packages/editor/src/components/tools/wall/wall-snap-geometry.test.ts @@ -2,12 +2,18 @@ import { describe, expect, test } from 'bun:test' import type { WallNode } from '@pascal-app/core' import { chainEndJoinsExistingWall, + findWallBodySnapTarget, findWallSnapTarget, findWallSpecialPointSnap, type WallPlanPoint, } from './wall-snap-geometry' -function makeWall(start: WallPlanPoint, end: WallPlanPoint, id?: string): WallNode { +function makeWall( + start: WallPlanPoint, + end: WallPlanPoint, + id?: string, + overrides: Partial = {}, +): WallNode { return { object: 'node', id: (id ?? `wall_${start.join('_')}_${end.join('_')}`) as WallNode['id'], @@ -22,6 +28,7 @@ function makeWall(start: WallPlanPoint, end: WallPlanPoint, id?: string): WallNo thickness: 0.1, frontSide: 'unknown', backSide: 'unknown', + ...overrides, } as unknown as WallNode } @@ -129,3 +136,108 @@ describe('findWallSnapTarget (edge / along-wall)', () => { expect(findWallSnapTarget([1.2, 0.1], walls, { radius: 0.08 })).toBeNull() }) }) + +describe('findWallBodySnapTarget (a wall end aimed into a wall)', () => { + // An 8" wall centred on z = 0: its faces sit at z = ±0.1016. + const host = makeWall([0, 0], [4, 0], 'host', { thickness: 0.2032 }) + + test('an end inside the body or within the margin of a face lands on the reference line', () => { + expect(findWallBodySnapTarget([1.2, 0.05], [host])).toEqual([1.2, 0]) + expect(findWallBodySnapTarget([1.2, 0.14], [host])).toEqual([1.2, 0]) + expect(findWallBodySnapTarget([1.2, -0.14], [host])).toEqual([1.2, 0]) + expect(findWallBodySnapTarget([1.2, 0.16], [host])).toBeNull() + // Past the wall's ends the corner snap decides, not the body. + expect(findWallBodySnapTarget([4.05, 0.05], [host])).toBeNull() + }) + + test('the grid placement keeps its station along the wall, and captures on its own', () => { + // The cursor sits by the face; its lattice point is out of the band. + expect(findWallBodySnapTarget([1.23, 0.12], [host], { placed: [1.25, 0.25] })).toEqual([ + 1.25, 0, + ]) + // The cursor is out of the band; the lattice point fell into it. + expect(findWallBodySnapTarget([1.23, 0.3], [host], { placed: [1.25, 0.1] })).toEqual([1.25, 0]) + }) + + test('with a start, the end slides along the drafted segment onto the line', () => { + const start: WallPlanPoint = [1, 3] + const placed: WallPlanPoint = [1.3, 0.12] + const target = findWallBodySnapTarget(placed, [host], { start, placed }) + expect(target?.[1]).toBeCloseTo(0, 12) + // Still on the drafted line start → placed: the segment keeps its direction. + const cross = + (placed[0] - start[0]) * (target![1] - start[1]) - + (placed[1] - start[1]) * (target![0] - start[0]) + expect(cross).toBeCloseTo(0, 12) + }) + + test('a square segment stays square', () => { + const target = findWallBodySnapTarget([2, 0.13], [host], { start: [2, 3] }) + expect(target?.[0]).toBe(2) + expect(target?.[1]).toBeCloseTo(0, 12) + }) + + test('walls the segment runs alongside, or starts on, are left alone', () => { + expect(findWallBodySnapTarget([2, 0.06], [host], { start: [0.5, 0.05] })).toBeNull() + expect(findWallBodySnapTarget([1.1, 0.12], [host], { start: [1, 0] })).toBeNull() + }) + + test('a justified wall captures across its whole body, measured from its faces', () => { + // Justified to face a: the body runs from the line (z = 0) to z = 0.2032. + const justified = makeWall([0, 0], [4, 0], 'justified', { + thickness: 0.2032, + justification: 'a', + }) + expect(findWallBodySnapTarget([1.2, 0.24], [justified])).toEqual([1.2, 0]) + expect(findWallBodySnapTarget([1.2, -0.04], [justified])).toEqual([1.2, 0]) + expect(findWallBodySnapTarget([1.2, -0.08], [justified])).toBeNull() + }) + + test('an end already on the line stays put', () => { + const onLine: WallPlanPoint = [1.234, 0] + expect(findWallBodySnapTarget(onLine, [host], { start: [1.5, 3], placed: [1.5, 0.5] })).toEqual( + onLine, + ) + }) + + test('picks the wall whose body the end is closest to', () => { + // 0.05 off `near`'s face, 0.018 off the host's. + const near = makeWall([0, 0.22], [4, 0.22], 'near', { thickness: 0.1 }) + expect(findWallBodySnapTarget([1, 0.12], [near, host])).toEqual([1, 0]) + }) + + test('an end in the corner block of an L joins the corner, not an 8 cm stub', () => { + // Two 0.2 m walls meeting at the origin: the corner block is the 0.2 m + // square around it. + const l = [ + makeWall([0, 0], [4, 0], 'south', { thickness: 0.2 }), + makeWall([0, 4], [0, 0], 'west', { thickness: 0.2 }), + ] + expect(findWallBodySnapTarget([0.08, 0.08], l)).toEqual([0, 0]) + // The block's outer quadrant lies in one wall's body only, and joins too. + expect(findWallBodySnapTarget([0.05, -0.05], l)).toEqual([0, 0]) + // Aimed into the block from across the room. + expect(findWallBodySnapTarget([0.08, 0.08], l, { start: [2, 3] })).toEqual([0, 0]) + // Past the other wall's face, the end T-joins as before. + expect(findWallBodySnapTarget([0.3, 0.05], l)).toEqual([0.3, 0]) + }) + + test('an end in the corner block of a T joins the junction', () => { + // The host split at the junction, as the topology leaves a T-join. + const t = [ + makeWall([0, 0], [2, 0], 'left', { thickness: 0.2 }), + makeWall([2, 0], [4, 0], 'right', { thickness: 0.2 }), + makeWall([2, 0], [2, 4], 'stem', { thickness: 0.2 }), + ] + expect(findWallBodySnapTarget([2.08, 0.08], t)).toEqual([2, 0]) + expect(findWallBodySnapTarget([1.92, 0.06], t)).toEqual([2, 0]) + // A host left whole, the stem ending on its interior, from either wall's side. + const whole = makeWall([0, 0], [4, 0], 'whole', { thickness: 0.2 }) + const stem = makeWall([2, 0], [2, 4], 'stem', { thickness: 0.2 }) + expect(findWallBodySnapTarget([2.08, 0.08], [whole, stem])).toEqual([2, 0]) + expect(findWallBodySnapTarget([2.08, 0.08], [stem, whole])).toEqual([2, 0]) + // Clear of the corner block each wall T-joins as before. + expect(findWallBodySnapTarget([2.4, 0.08], [whole, stem])).toEqual([2.4, 0]) + expect(findWallBodySnapTarget([2.06, 0.3], [whole, stem])).toEqual([2, 0.3]) + }) +}) diff --git a/packages/editor/src/components/tools/wall/wall-snap-geometry.ts b/packages/editor/src/components/tools/wall/wall-snap-geometry.ts index 7ef593bc43..8b88b2110e 100644 --- a/packages/editor/src/components/tools/wall/wall-snap-geometry.ts +++ b/packages/editor/src/components/tools/wall/wall-snap-geometry.ts @@ -6,6 +6,7 @@ import { getWallCurveFrameAt, getWallCurveLength, + getWallFaceOffsets, isCurvedWall, type WallNode, } from '@pascal-app/core' @@ -124,6 +125,142 @@ export function findWallSnapTarget( return bestTarget } +// A drafted segment closer than this to a wall's direction (sine of the angle +// between them) runs alongside it: the wall topology stacks such walls rather +// than T-joining them, so the body snap leaves them alone. Two walls meeting +// closer than this aren't a corner either. +const WALL_BODY_SNAP_MIN_SINE = 0.5 + +/** A straight wall's reference line as a frame, with the faces its body spans. */ +type WallBodyFrame = { + wall: WallNode + length: number + ux: number + uz: number + faces: { a: number; b: number } + /** Offset along the wall's left normal, the side its face offsets are measured on. */ + across: (q: WallPlanPoint) => number + /** Station along the reference line from `start`. */ + along: (q: WallPlanPoint) => number +} + +function wallBodyFrame(wall: WallNode): WallBodyFrame | null { + if (isCurvedWall(wall)) return null + const [x1, z1] = wall.start + const length = Math.hypot(wall.end[0] - x1, wall.end[1] - z1) + if (length < 1e-9) return null + const ux = (wall.end[0] - x1) / length + const uz = (wall.end[1] - z1) / length + return { + wall, + length, + ux, + uz, + faces: getWallFaceOffsets(wall), + across: (q) => (q[1] - z1) * ux - (q[0] - x1) * uz, + along: (q) => (q[0] - x1) * ux + (q[1] - z1) * uz, + } +} + +/** + * The corner a join at `target` on `host`'s reference line falls into: where + * `host` meets another straight wall, at an L or a T, with `target` inside that + * wall's drawn body. A T-join there would split `host` into a stub buried in + * the corner block, so the end joins the junction instead. A shared end comes + * back exactly; walls meeting at a shallow angle aren't a corner. + */ +function cornerJunctionAt( + target: WallPlanPoint, + host: WallBodyFrame, + frames: WallBodyFrame[], +): WallPlanPoint | null { + for (const other of frames) { + if (other === host) continue + if (Math.abs(host.ux * other.uz - host.uz * other.ux) < WALL_BODY_SNAP_MIN_SINE) continue + const offset = other.across(target) + if (offset < other.faces.b || offset > other.faces.a) continue + const ends = [host.wall.start, host.wall.end, other.wall.start, other.wall.end] + const crossing = segmentIntersection(ends[0]!, ends[1]!, ends[2]!, ends[3]!) + if (!crossing) continue + const sharedEnd = ends.find((end) => distanceSquared(end, crossing) <= 1e-12) + return sharedEnd ? [sharedEnd[0], sharedEnd[1]] : crossing + } + return null +} + +/** + * Where a drawn wall end joins a wall it is aimed into: the point on a straight + * wall's reference line (`start` → `end`, the line the wall topology T-joins a + * partition end on, whatever the wall's justification) for an end inside that + * wall's drawn body or within `margin` of either face. + * + * `point` is the raw cursor and `placed` its grid / angle placement; either one + * inside a body captures, so the grid can't leave an end a fraction short of a + * face. Given the drafted segment's `start`, the end slides along start → + * `placed` onto the line, so a square or angle-locked segment keeps its + * direction, and a wall the segment runs alongside (or starts on) is skipped. + * Without a start the end drops square onto the line, keeping its position + * along the wall. A join that lands inside a corner block, where the wall + * meets another at an L or a T, takes the junction itself (`cornerJunctionAt`). + * Curved walls are left to the edge snap (`findWallSnapTarget`). + */ +export function findWallBodySnapTarget( + point: WallPlanPoint, + walls: WallNode[], + options?: { + ignoreWallIds?: string[] + placed?: WallPlanPoint + start?: WallPlanPoint + margin?: number + }, +): WallPlanPoint | null { + const ignored = new Set(options?.ignoreWallIds ?? []) + const placed = options?.placed ?? point + const start = options?.start + const margin = options?.margin ?? WALL_CONNECT_SNAP_RADIUS + const frames = walls.flatMap((wall) => { + const frame = ignored.has(wall.id) ? null : wallBodyFrame(wall) + return frame ? [frame] : [] + }) + let best: WallPlanPoint | null = null + let bestOutside = Number.POSITIVE_INFINITY + + for (const frame of frames) { + const { length, ux, uz, faces, across, along } = frame + const [x1, z1] = frame.wall.start + const onWall = (q: WallPlanPoint) => along(q) > 0 && along(q) < length + const outsideBody = (q: WallPlanPoint) => + onWall(q) ? Math.max(0, faces.b - across(q), across(q) - faces.a) : Number.POSITIVE_INFINITY + const outside = Math.min(outsideBody(point), outsideBody(placed)) + if (outside > margin || outside >= bestOutside) continue + + let target: WallPlanPoint | null + if (Math.abs(across(point)) <= 1e-9 && onWall(point)) { + // Already on the line: a joined end snapped again (the plan view hands + // the 3D tool its resolved point) stays put. + target = [point[0], point[1]] + } else if (start) { + const dx = placed[0] - start[0] + const dz = placed[1] - start[1] + const run = Math.hypot(dx, dz) + if (run < 1e-9 || Math.abs(dx * uz - dz * ux) / run < WALL_BODY_SNAP_MIN_SINE) continue + const startAcross = across(start) + const t = startAcross / (startAcross - across(placed)) + if (!(t > 1e-6)) continue + target = [start[0] + dx * t, start[1] + dz * t] + if (!onWall(target)) continue + } else { + const station = along(placed) + if (!(station > 0 && station < length)) continue + target = [x1 + ux * station, z1 + uz * station] + } + best = cornerJunctionAt(target, frame, frames) ?? target + bestOutside = outside + } + + return best +} + /** * Wall ids that contain an already-resolved snap point. * diff --git a/packages/editor/src/components/tools/zone/zone-tool.tsx b/packages/editor/src/components/tools/zone/zone-tool.tsx index 9f8f26797f..7f48b4b4c8 100644 --- a/packages/editor/src/components/tools/zone/zone-tool.tsx +++ b/packages/editor/src/components/tools/zone/zone-tool.tsx @@ -184,9 +184,9 @@ export const ZoneTool: React.FC = () => { updateLines() } - // World-grid snap projected into building-local; rotated buildings - // used to pull the snap off the visible grid lines. Grid quantize only - // in grid mode; off / lines / angles leave the raw cursor. + // Snap on the building's own grid lattice, the one its walls are drafted + // on (square to a turned house). Grid quantize only in grid mode; off / + // lines / angles leave the raw cursor. const gridPointOf = (event: GridEvent): [number, number] => isGridSnapActive() ? snapWorldXZForActiveBuilding( diff --git a/packages/editor/src/components/ui/action-menu/structure-tools.tsx b/packages/editor/src/components/ui/action-menu/structure-tools.tsx index 34aa72d24e..8b9f474b2c 100644 --- a/packages/editor/src/components/ui/action-menu/structure-tools.tsx +++ b/packages/editor/src/components/ui/action-menu/structure-tools.tsx @@ -20,6 +20,7 @@ export const tools: ToolConfig[] = [ { id: 'roof', iconSrc: '/icons/roof.webp', label: /* i18n */ { id: 'editor.actionMenu.structureTools.gableRoof', message: 'Gable Roof' } }, { id: 'fence', iconSrc: '/icons/fence.webp', label: /* i18n */ { id: 'editor.actionMenu.structureTools.fence', message: 'Fence' } }, { id: 'column', iconSrc: '/icons/column.webp', label: /* i18n */ { id: 'editor.actionMenu.structureTools.column', message: 'Column' } }, + { id: 'beam', iconSrc: '/icons/beam.svg', label: /* i18n */ { id: 'editor.actionMenu.structureTools.beam', message: 'Beam' } }, { id: 'elevator', iconSrc: '/icons/elevator.webp', label: /* i18n */ { id: 'editor.actionMenu.structureTools.elevator', message: 'Elevator' } }, { id: 'slab', iconSrc: '/icons/floor.webp', label: /* i18n */ { id: 'editor.actionMenu.structureTools.slab', message: 'Slab' } }, { id: 'ceiling', iconSrc: '/icons/ceiling.webp', label: /* i18n */ { id: 'editor.actionMenu.structureTools.ceiling', message: 'Ceiling' } }, diff --git a/packages/editor/src/components/ui/action-menu/view-toggles.test.ts b/packages/editor/src/components/ui/action-menu/view-toggles.test.ts new file mode 100644 index 0000000000..a24dc742d5 --- /dev/null +++ b/packages/editor/src/components/ui/action-menu/view-toggles.test.ts @@ -0,0 +1,18 @@ +import { describe, expect, test } from 'bun:test' +import { adjacentWallsToggle } from './view-toggles' + +describe('walls below and above button', () => { + test('on the top storey it turns on only the walls below', () => { + expect(adjacentWallsToggle(false, { below: 'level_0', above: null })).toEqual({ below: true }) + }) + + test('on the ground floor it turns on only the walls above', () => { + expect(adjacentWallsToggle(false, { below: null, above: 'level_1' })).toEqual({ above: true }) + }) + + test('between two levels it turns both sides on, then both off', () => { + const levels = { below: 'level_0', above: 'level_2' } + expect(adjacentWallsToggle(false, levels)).toEqual({ below: true, above: true }) + expect(adjacentWallsToggle(true, levels)).toEqual({ below: false, above: false }) + }) +}) diff --git a/packages/editor/src/components/ui/action-menu/view-toggles.tsx b/packages/editor/src/components/ui/action-menu/view-toggles.tsx index f525d49ecb..bfcfb87a12 100644 --- a/packages/editor/src/components/ui/action-menu/view-toggles.tsx +++ b/packages/editor/src/components/ui/action-menu/view-toggles.tsx @@ -1,6 +1,7 @@ 'use client' import { + type AnyNode, type AnyNodeId, type BuildingNode, type GuideNode, @@ -11,15 +12,31 @@ import { usePascalI18n, } from '@pascal-app/core' import { useViewer } from '@pascal-app/viewer' -import { Check, ChevronDown, Eye, EyeOff, Layers2, Plus, Trash2, Waypoints } from 'lucide-react' +import { + Check, + ChevronDown, + Eye, + EyeOff, + Layers2, + Plus, + SquareDashed, + Trash2, + Waypoints, +} from 'lucide-react' import { useCallback, useRef, useState } from 'react' import { useShallow } from 'zustand/react/shallow' import { createLocalGuideImage } from '../../../lib/local-guide-image' import { cn } from '../../../lib/utils' import useEditor from '../../../store/use-editor' import { useUploadStore } from '../../../store/use-upload' +import { + ADJACENT_WALL_COLORS, + adjacentLevelIds, + useWallsBelowSetting, +} from '../../editor-2d/floorplan-adjacent-walls-layer' import { SliderControl } from '../controls/slider-control' import { Popover, PopoverContent, PopoverTrigger } from '../primitives/popover' +import { Switch } from '../primitives/switch' import { ActionButton } from './action-button' import { useActionMenuPopupSide } from './placement' import { localizedLevelName } from '../../../i18n/level-name' @@ -963,6 +980,152 @@ function ReferenceFloorControl() { ) } +// ── Walls below / above control ───────────────────────────────────────────── + +function useAdjacentLevelNames() { + const i18n = usePascalI18n() + const levelId = useViewer((s) => s.selection.levelId) + return useScene( + useShallow((state) => { + const nodes = state.nodes as Record + const ids = adjacentLevelIds(nodes, levelId) + const name = (id: string | null) => { + const level = id ? nodes[id] : undefined + return level?.type === 'level' ? localizedLevelName(level, i18n, i18n.getLocale()) : null + } + return { below: name(ids.below), above: name(ids.above) } + }), + ) +} + +/** + * What the "Walls below / above" button turns each side to: the sides that have a level all on, or + * all off when one shows. A side with no level keeps its setting, which persists for the levels + * that have one: turning the walls below on from the top storey must not trace walls above later. + */ +export function adjacentWallsToggle( + active: boolean, + levels: { below: string | null; above: string | null }, +): { below?: boolean; above?: boolean } { + return { + ...(levels.below ? { below: !active } : {}), + ...(levels.above ? { above: !active } : {}), + } +} + +/** + * "Walls below / above": the plan traces the walls of the neighbouring levels as dashed outlines, + * blue for the level below (on a roof level, the top storey), magenta for the level above. + */ +function AdjacentWallsControl() { + const i18n = usePascalI18n() + const popupSide = useActionMenuPopupSide() + const levelId = useViewer((s) => s.selection.levelId) + const { shown: showBelow, setShown: setShowBelow } = useWallsBelowSetting(levelId) + const showAbove = useEditor((state) => state.showWallsAbove) + const setShowAbove = useEditor((state) => state.setShowWallsAbove) + const names = useAdjacentLevelNames() + const [isOpen, setIsOpen] = useState(false) + const active = (showBelow && !!names.below) || (showAbove && !!names.above) + const available = !!(names.below || names.above) + const rows = [ + { + key: 'below', + label: i18n._({ id: 'editor.actionMenu.viewToggles.wallsBelow', message: 'Walls below' }), + level: names.below, + checked: showBelow, + set: setShowBelow, + color: ADJACENT_WALL_COLORS.below, + }, + { + key: 'above', + label: i18n._({ id: 'editor.actionMenu.viewToggles.wallsAbove', message: 'Walls above' }), + level: names.above, + checked: showAbove, + set: setShowAbove, + color: ADJACENT_WALL_COLORS.above, + }, + ] as const + + return ( + +
+ { + const next = adjacentWallsToggle(active, names) + if (next.below !== undefined) setShowBelow(next.below) + if (next.above !== undefined) setShowAbove(next.above) + }} + size="icon" + variant="ghost" + > + + + + + +
+ +
+
+

{i18n._({ id: 'editor.actionMenu.viewToggles.wallsBelowAndAbove', message: 'Walls below and above' })}

+

+ {i18n._({ id: 'editor.actionMenu.viewToggles.dashedOutlinesOfTheNeighbouringLevels', message: 'Dashed outlines of the neighbouring levels’ walls, to line walls up and check a roof against the walls under it.' })} +

+
+ {rows.map((row) => ( + + ))} +
+
+
+ ) +} + // ── Riser diagram control ──────────────────────────────────────────────────── function RiserControl() { @@ -1003,6 +1166,7 @@ export function ViewToggles() { +
) diff --git a/packages/editor/src/components/ui/build-panel/build-panel.tsx b/packages/editor/src/components/ui/build-panel/build-panel.tsx index 4a6c3f77ed..6692debef0 100644 --- a/packages/editor/src/components/ui/build-panel/build-panel.tsx +++ b/packages/editor/src/components/ui/build-panel/build-panel.tsx @@ -5,9 +5,14 @@ import { ChevronRight } from 'lucide-react' import { type ComponentPropsWithoutRef, type ReactNode, useEffect, useState } from 'react' import { cn } from '../../../lib/utils' import { + selectWallKind, + useWallKind, WALL_DRAW_VARIANTS, + WALL_KINDS, type WallDrawVariant, + type WallKind, } from '../../../lib/wall-draw-variant' +import { SegmentedControl } from '../controls/segmented-control' /** * The Build panel's grouped layout (Rooms / Add to rooms / Outdoor / Advanced), @@ -214,7 +219,9 @@ export function BuildPanelCaption({ caption, lead }: { caption: string; lead?: s /** * The Rooms group: one large tile per wall drawing variant, and the armed - * variant's caption. `activeVariant` is null while the wall tool is not armed. + * variant's caption. While Walls is armed the caption gives way to its kinds + * (Standard, Invisible, Railing) and a line on the one picked. + * `activeVariant` is null while the wall tool is not armed. */ export function BuildPanelRoomsSection({ activeVariant, @@ -259,17 +266,21 @@ export function BuildPanelRoomsSection({ ) })} - + {activeVariant === 'walls' ? ( + + ) : ( + + )} ) } @@ -297,18 +308,12 @@ function roomVariantMessages(variant: WallDrawVariant, i18n: PascalI18n) { } } if (variant === 'walls') { + // Armed, Walls shows its kinds in place of a caption (`BuildPanelWallKinds`). return { label: i18n._({ id: 'editor.buildPanel.rooms.walls.label', message: 'Walls' }), title: i18n._({ id: 'editor.buildPanel.rooms.walls.title', message: 'Walls' }), - lead: i18n._({ - id: 'editor.buildPanel.rooms.walls.lead', - message: 'Draw one wall at a time.', - }), - caption: i18n._({ - id: 'editor.buildPanel.rooms.walls.caption', - message: '{lead} Close a loop and it becomes a room; leave it open for partitions.', - values: { lead: CAPTION_LEAD_MARKER }, - }), + lead: undefined, + caption: undefined, } } return { @@ -328,3 +333,48 @@ function roomVariantMessages(variant: WallDrawVariant, i18n: PascalI18n) { }), } } + +function wallKindHelp(kind: WallKind, i18n: PascalI18n): string { + if (kind === 'invisible') { + return i18n._({ + id: 'editor.buildPanel.rooms.wallKinds.invisibleHelp', + message: + 'Divides a room or closes off a porch without building a wall; rooms close on it. Change any wall later from its controls.', + }) + } + if (kind === 'railing') { + return i18n._({ + id: 'editor.buildPanel.rooms.wallKinds.railingHelp', + message: + 'A guard for stairs, balconies and mezzanines; rooms close on it. Change any wall later from its controls.', + }) + } + return i18n._({ + id: 'editor.buildPanel.rooms.wallKinds.standardHelp', + message: + 'One wall per two clicks. Its sides become exterior or interior from the rooms it bounds. Change any wall later from its controls.', + }) +} + +/** What the armed Walls variant draws: a plain wall, an invisible wall or a railing. */ +function BuildPanelWallKinds() { + const i18n = usePascalI18n() + const kind = useWallKind() + return ( +
+ ({ value: entry.id, label: i18n._(entry.label) }))} + value={kind} + /> +

+ {wallKindHelp(kind, i18n)} +

+
+ ) +} diff --git a/packages/editor/src/components/ui/command-palette/editor-commands.tsx b/packages/editor/src/components/ui/command-palette/editor-commands.tsx index 4c5d7c83b0..d292091502 100644 --- a/packages/editor/src/components/ui/command-palette/editor-commands.tsx +++ b/packages/editor/src/components/ui/command-palette/editor-commands.tsx @@ -37,6 +37,7 @@ import { } from 'lucide-react' import { useEffect } from 'react' import { addStoreyOnTop } from '../../../lib/add-storey' +import { offerExteriorWallCopy } from '../level-wall-copy-prompt' import { getHistoryCommandState, runRedo, runUndo } from '../../../lib/history' import { deleteLevelWithFallbackSelection } from '../../../lib/level-selection' import { getSavedSceneDocument } from '../../../lib/scene' @@ -205,6 +206,7 @@ export function EditorCommands() { if (!building) return const newLevel = addStoreyOnTop(building.id) useViewer.getState().setSelection({ levelId: newLevel.id }) + offerExteriorWallCopy(newLevel.id) }), }, { diff --git a/packages/editor/src/components/ui/controls/finish-swatch.tsx b/packages/editor/src/components/ui/controls/finish-swatch.tsx index 18f4e8f694..e03ff33d85 100644 --- a/packages/editor/src/components/ui/controls/finish-swatch.tsx +++ b/packages/editor/src/components/ui/controls/finish-swatch.tsx @@ -4,6 +4,7 @@ import { type AnyNode, getCatalogMaterialById, getLibraryMaterialIdFromRef, + getMaterialSwatch, getSceneMaterialIdFromRef, nodeRegistry, type PascalI18n, @@ -11,10 +12,11 @@ import { useScene, } from '@pascal-app/core' import { useState } from 'react' +import { materialSwatchStyle } from '../../../lib/material-swatch-style' import { Popover, PopoverContent, PopoverTrigger } from '../primitives/popover' import { MaterialPicker } from './material-picker' -type Swatch = { label: string; color: string | null; image: string | null } +type Swatch = { label: string; color: string | null; image: string | null; tinted?: boolean } /** How a finish reference reads in a panel: its catalog tile, its colour, or its scene material. */ function useFinishSwatch(ref: string | undefined, fallback: string): Swatch { @@ -33,15 +35,19 @@ function describe( i18n: PascalI18n, ) { const library = getCatalogMaterialById(getLibraryMaterialIdFromRef(ref) ?? undefined) - if (library) + if (library) { + const swatch = getMaterialSwatch(library) return { label: library.label, - color: library.previewColor ?? null, - image: library.previewThumbnailUrl ?? null, + color: swatch.color, + image: swatch.imageUrl, + tinted: swatch.tinted, } + } const sceneId = getSceneMaterialIdFromRef(ref) const scene = sceneId ? materials[sceneId as keyof typeof materials] : undefined - if (scene) return { label: scene.name, color: scene.material.properties?.color ?? null, image: null } + if (scene) + return { label: scene.name, color: scene.material.properties?.color ?? null, image: null } if (ref.startsWith('#')) return { label: ref.toUpperCase(), color: ref, image: null } return { label: defaultLabel(i18n), color: null, image: null } } @@ -101,17 +107,22 @@ export function FinishSwatch({ - {swatch.image && } - + style={materialSwatchStyle({ + color: swatch.color ?? 'transparent', + imageUrl: swatch.image, + tinted: swatch.tinted, + })} + /> {swatch.label} { - const live = useScene.getState().nodes[node.id as keyof ReturnType['nodes']] + const live = + useScene.getState().nodes[ + node.id as keyof ReturnType['nodes'] + ] if (live) paintSurface(live, role, ref) setOpen(false) }} diff --git a/packages/editor/src/components/ui/controls/material-picker.tsx b/packages/editor/src/components/ui/controls/material-picker.tsx index 0c6dc0be10..b36117ff94 100644 --- a/packages/editor/src/components/ui/controls/material-picker.tsx +++ b/packages/editor/src/components/ui/controls/material-picker.tsx @@ -1,8 +1,9 @@ 'use client' -import { type MaterialTarget, toLibraryMaterialRef } from '@pascal-app/core' +import { getMaterialSwatch, type MaterialTarget, toLibraryMaterialRef } from '@pascal-app/core' import { Plus } from 'lucide-react' -import { useMaterialCatalogModel, type MaterialSourceFilter } from '../../../lib/material-catalog-model' +import { useMaterialCatalogModel } from '../../../lib/material-catalog-model' +import { materialSwatchStyle } from '../../../lib/material-swatch-style' import { triggerSFX } from '../../../lib/sfx-bus' export type { MaterialSourceFilter } from '../../../lib/material-catalog-model' @@ -35,7 +36,21 @@ export function MaterialPicker({ onCreateMaterialRequest, selectOnCategoryChange = true, }: MaterialPickerProps) { - const { selectedCategory, setSelectedCategory, sourceFilter, setSourceFilter, visibleSourceFilters, availableCategories, catalogItems, select: handleCatalogSelect } = useMaterialCatalogModel(selectedMaterialPreset, onSelectMaterialPreset, disabled, selectOnCategoryChange) + const { + selectedCategory, + setSelectedCategory, + sourceFilter, + setSourceFilter, + visibleSourceFilters, + availableCategories, + catalogItems, + select: handleCatalogSelect, + } = useMaterialCatalogModel( + selectedMaterialPreset, + onSelectMaterialPreset, + disabled, + selectOnCategoryChange, + ) return (
triggerSFX('sfx:menu-hover')} type="button" > -
- {item.previewThumbnailUrl ? ( - {item.label} - ) : ( -
- )} -
+
{item.label} diff --git a/packages/editor/src/components/ui/floating-level-selector.tsx b/packages/editor/src/components/ui/floating-level-selector.tsx index 46a45d2425..90a79f4ed0 100644 --- a/packages/editor/src/components/ui/floating-level-selector.tsx +++ b/packages/editor/src/components/ui/floating-level-selector.tsx @@ -72,6 +72,7 @@ import { useIsMobile } from '../../hooks/use-mobile' import { ActionButton } from './controls/action-button' import { SliderControl } from './controls/slider-control' import { LevelDuplicateDialog } from './level-duplicate-dialog' +import { LevelWallCopyPrompt, offerExteriorWallCopy } from './level-wall-copy-prompt' import { Dialog, DialogContent, @@ -655,12 +656,14 @@ export function FloatingLevelSelector() { if (!resolvedBuildingId) return const newLevel = addStoreyOnTop(resolvedBuildingId) setSelection({ buildingId: resolvedBuildingId, levelId: newLevel.id }) + offerExteriorWallCopy(newLevel.id) }, [resolvedBuildingId, setSelection]) const handleAddBelow = useCallback(() => { if (!resolvedBuildingId) return const newLevel = addStoreyBelow(resolvedBuildingId) setSelection({ buildingId: resolvedBuildingId, levelId: newLevel.id }) + offerExteriorWallCopy(newLevel.id) }, [resolvedBuildingId, setSelection]) const handleInsertBetween = useCallback( @@ -684,6 +687,7 @@ export function FloatingLevelSelector() { .map((l) => ({ id: l.id as AnyNodeId, data: { level: l.level + 1 } as Partial })), }) setSelection({ buildingId: resolvedBuildingId, levelId: newLevel.id }) + offerExteriorWallCopy(newLevel.id, lower.id) }, [resolvedBuildingId, levels, applyNodeChanges, setSelection], ) @@ -876,6 +880,7 @@ export function FloatingLevelSelector() {
+
{/* Delete confirmation dialog */} diff --git a/packages/editor/src/components/ui/helpers/helper-manager.test.tsx b/packages/editor/src/components/ui/helpers/helper-manager.test.tsx index 2c678b3581..4fb362c697 100644 --- a/packages/editor/src/components/ui/helpers/helper-manager.test.tsx +++ b/packages/editor/src/components/ui/helpers/helper-manager.test.tsx @@ -5,7 +5,12 @@ import { snapContextOf } from '../../../lib/snapping-mode' import { cornerHintRows } from '../../../store/use-corner-snap-hint' import { TooltipProvider } from '../primitives/tooltip' import { ContextualHelperPanel } from './contextual-helper-panel' -import { mezzanineHints, openingHints, ROOM_DIVIDE_HINTS } from './helper-manager' +import { + mezzanineHints, + openingHints, + ROOM_DIVIDE_HINTS, + toolHintsOwnPlacing, +} from './helper-manager' describe('Divide HUD', () => { test('uses the wall draft snapping context', () => { @@ -133,3 +138,34 @@ describe('Cut opening HUD', () => { expect(english(mezzanineHints('rectangle'))).toContain('Draw the mezzanine') }) }) + +// The roof tool holds its draft in a placing scope, so the HUD read "Move roof · Left click: Place" +// while a click set a footprint corner; the tool's own hints say what the click does. +describe('a registry tool holding its draft', () => { + const placing = (driver: 'registry-tool' | 'move-tool', nodeType = 'roof') => ({ + kind: 'placing' as const, + node: { id: 'roof_draft', type: nodeType } as never, + nodeId: 'roof_draft', + nodeType, + view: '3d' as const, + pressDrag: false, + driver, + }) + + test("shows the armed tool's hints", () => { + expect(toolHintsOwnPlacing(placing('registry-tool'), 'roof', 3)).toBe(true) + }) + + test('leaves a move, a catalog placement or a tool with no hints to the move rows', () => { + expect(toolHintsOwnPlacing(placing('move-tool'), 'roof', 3)).toBe(false) + expect(toolHintsOwnPlacing(placing('registry-tool', 'item'), 'roof', 3)).toBe(false) + expect(toolHintsOwnPlacing(placing('registry-tool'), 'roof', 0)).toBe(false) + expect( + toolHintsOwnPlacing( + { kind: 'moving', node: { id: 'r', type: 'roof' } as never, nodeId: 'r', nodeType: 'roof', view: '3d' }, + 'roof', + 3, + ), + ).toBe(false) + }) +}) diff --git a/packages/editor/src/components/ui/helpers/helper-manager.tsx b/packages/editor/src/components/ui/helpers/helper-manager.tsx index 663ba7dd0d..60457a82da 100644 --- a/packages/editor/src/components/ui/helpers/helper-manager.tsx +++ b/packages/editor/src/components/ui/helpers/helper-manager.tsx @@ -42,7 +42,7 @@ import { terrainHudTitle, toolHudTitle, } from '../../../lib/hud-title' -import type { ReshapeKind } from '../../../lib/interaction/scope' +import type { InteractionScope, ReshapeKind } from '../../../lib/interaction/scope' import { type MezzanineShape, useMezzanineDraft, @@ -294,6 +294,25 @@ export const MEZZANINE_GESTURE_HINTS: Record 0 + ) +} + export function HelperManager() { const i18n = usePascalI18n() const mode = useEditor((s) => s.mode) @@ -546,7 +565,10 @@ export function HelperManager() { ) } - if (movingNode) { + if ( + movingNode && + !toolHintsOwnPlacing(scope, tool, tool ? (nodeRegistry.get(tool)?.toolHints?.length ?? 0) : 0) + ) { // A fresh placement (e.g. a positioned preset like a shelf) advertises its // once/repeat continuation, exactly like the GLB item tool — but an existing // node being *moved* is not a placement, so it gets no continuation chip. diff --git a/packages/editor/src/components/ui/level-wall-copy-prompt.tsx b/packages/editor/src/components/ui/level-wall-copy-prompt.tsx new file mode 100644 index 0000000000..49852a47e5 --- /dev/null +++ b/packages/editor/src/components/ui/level-wall-copy-prompt.tsx @@ -0,0 +1,124 @@ +'use client' + +import { + type AnyNode, + type AnyNodeId, + getLevelAbove, + getLevelBelow, + getLevelDisplayName, + useScene, usePascalI18n, +} from '@pascal-app/core' +import { buildExteriorWallCopy, levelExteriorWalls } from '@pascal-app/core/building' +import { useViewer } from '@pascal-app/viewer' +import { create } from 'zustand' + +type Offer = { levelId: string; sourceLevelId: string; direction: 'below' | 'above' } + +/** + * The one open "Copy exterior walls?" offer, for the level just added. While it is open the plan + * traces the source level's walls on the new one; that trace is the offer's, never the saved + * Walls below / above preference, and it goes with the offer. + */ +export const useLevelWallCopyOffer = create<{ + offer: Offer | null + setOffer: (offer: Offer | null) => void +}>((set) => ({ offer: null, setOffer: (offer) => set({ offer }) })) + +let stopWatchingLevel: (() => void) | null = null + +/** Opens `offer` (or closes the open one); picking another level closes it. */ +function setOffer(offer: Offer | null) { + stopWatchingLevel?.() + stopWatchingLevel = null + useLevelWallCopyOffer.getState().setOffer(offer) + if (!offer) return + stopWatchingLevel = useViewer.subscribe((state) => { + if (state.selection.levelId !== offer.levelId) setOffer(null) + }) +} + +/** + * After a level is added next to `sourceLevelId` (by default the level under it, else the one over + * it, for a basement), and selected: when that level has an outline, offer to copy its exterior + * walls up or down, tracing them dashed on the plan while the offer is open. + */ +export function offerExteriorWallCopy(levelId: string, sourceLevelId?: string) { + const nodes = useScene.getState().nodes as Record + const graph = nodes as Record + sourceLevelId ??= (getLevelBelow(levelId, graph) ?? getLevelAbove(levelId, graph))?.id + const source = sourceLevelId ? nodes[sourceLevelId] : undefined + const level = nodes[levelId] + if (!sourceLevelId || source?.type !== 'level' || level?.type !== 'level') return setOffer(null) + const direction = source.level < level.level ? 'below' : 'above' + setOffer( + levelExteriorWalls(nodes, sourceLevelId).length ? { levelId, sourceLevelId, direction } : null, + ) +} + +/** Closes the open offer without copying. */ +export function dismissExteriorWallCopy() { + setOffer(null) +} + +/** Copies the offered walls in place, as one undo step of its own. */ +export function acceptExteriorWallCopy(offer: Offer): number { + const walls = buildExteriorWallCopy({ + nodes: useScene.getState().nodes as Record, + fromLevelId: offer.sourceLevelId, + toLevelId: offer.levelId, + }) + if (walls.length) useScene.getState().applyNodeChanges({ create: walls }) + setOffer(null) + return walls.length +} + +/** + * "Copy exterior walls from the level below?" — a small card under the level list, never in the + * way: it goes when answered or when another level is picked, and hides once the level has walls. + */ +export function LevelWallCopyPrompt() { + const i18n = usePascalI18n() + const offer = useLevelWallCopyOffer((state) => state.offer) + const activeLevelId = useViewer((state) => state.selection.levelId) + const sourceName = useScene((state) => { + const source = offer ? state.nodes[offer.sourceLevelId as never] : undefined + return source?.type === 'level' ? getLevelDisplayName(source) : null + }) + const levelHasWalls = useScene((state) => { + const level = offer ? state.nodes[offer.levelId as AnyNodeId] : undefined + return ( + level?.type === 'level' && + level.children.some((id) => state.nodes[id as AnyNodeId]?.type === 'wall') + ) + }) + if (!offer || !sourceName || activeLevelId !== offer.levelId || levelHasWalls) return null + return ( +
+

+ {i18n._({ id: 'editor.levelWallCopyPrompt.copyExteriorWallsFromTheLevel', message: 'Copy exterior walls from the level {direction}?', values: { direction: offer.direction } })}

+

+ {i18n._({ id: 'editor.levelWallCopyPrompt.sourcenameSOutsideWallsInPlace', message: '{sourceName}’s outside walls, in place, so this level lines up with it.', values: { sourceName } })}

+
+ + +
+
+ ) +} diff --git a/packages/editor/src/components/ui/panels/deck-boards-fields.tsx b/packages/editor/src/components/ui/panels/deck-boards-fields.tsx new file mode 100644 index 0000000000..0046cd6947 --- /dev/null +++ b/packages/editor/src/components/ui/panels/deck-boards-fields.tsx @@ -0,0 +1,136 @@ +'use client' + +import { + type AnyNodeId, + DECK_BOARD_GAPS, + DECK_BOARD_SIZES, + DECK_BOARD_STOCK, + type DeckBoardDirection, + type DeckBoardSize, + deckBoardSettings, + deckJoistSpacingLimit, + inchFractionLabel, + type MessageDescriptor, + setZoneIntent, + usePascalI18n, + useScene, +} from '@pascal-app/core' +import type { ReactNode } from 'react' +import { useShallow } from 'zustand/react/shallow' +import { applyRoomPlan } from '../../../lib/room-structure-commands' +import { SegmentedControl } from '../controls/segmented-control' + +const IN = 0.0254 + +const BOARD_OPTIONS = DECK_BOARD_SIZES.map((value) => ({ + label: DECK_BOARD_STOCK[value].label, + value, +})) + +const GAP_OPTIONS = DECK_BOARD_GAPS.map((gap, index) => ({ + label: `${inchFractionLabel(gap)} in`, + value: String(index), +})) + +const RUN_OPTIONS: ReadonlyArray<{ label: MessageDescriptor; value: DeckBoardDirection }> = [ + { + label: /* i18n */ { + id: 'editor.panels.deckBoardsFields.alongHouse', + message: 'Along house', + }, + value: 'parallel', + }, + { + label: /* i18n */ { id: 'editor.panels.deckBoardsFields.diagonal', message: 'Diagonal' }, + value: 'diagonal', + }, + { + label: /* i18n */ { + id: 'editor.panels.deckBoardsFields.outFromHouse', + message: 'Out from house', + }, + value: 'perpendicular', + }, +] + +function Field({ label, children }: { label: string; children: ReactNode }) { + return ( +
+ {label} + {children} +
+ ) +} + +/** + * A deck's boards (`decking`, through core's `setZoneIntent`): their stock, the gap between them + * and the way they run against the house. The engine lays them over the deck's frame, and the + * frame follows: joists 12 in on centre under diagonal 5/4 or composite boards (IRC R507.7), and + * along the house on beams square to it under boards run out from it. + */ +export function DeckBoardsFields({ zoneId }: { zoneId: string }) { + const i18n = usePascalI18n() + const deck = useScene( + useShallow((scene) => { + const zone = scene.nodes[zoneId as AnyNodeId] + if (zone?.type !== 'zone' || zone.roomType !== 'deck') return null + return deckBoardSettings(zone) + }), + ) + if (!deck) return null + const set = (decking: NonNullable[1]['patch']['decking']>) => + applyRoomPlan(setZoneIntent(useScene.getState().nodes, { zoneId, patch: { decking } })) + const stock = DECK_BOARD_STOCK[deck.boardSize] + const gap = DECK_BOARD_GAPS.findIndex((option) => Math.abs(option - deck.gap) < 1e-6) + const spacing = Math.min(16 * IN, deckJoistSpacingLimit(deck)) + return ( +
+

+ {i18n._({ id: 'editor.panels.deckBoardsFields.deckBoards', message: 'Deck boards' })} +

+ + set({ boardSize })} + options={BOARD_OPTIONS} + value={deck.boardSize} + /> + + + set({ gap: DECK_BOARD_GAPS[Number(index)] })} + options={GAP_OPTIONS} + value={String(Math.max(gap, 0))} + /> + + + set({ direction })} + options={RUN_OPTIONS.map((option) => ({ + label: i18n._(option.label), + value: option.value, + }))} + value={deck.direction} + /> + +

+ {i18n._({ + id: 'editor.panels.deckBoardsFields.boardsSummary', + message: + '{label} boards {thickness} × {width} in, {gap} in apart, {direction, select, parallel {along the house, on joists square to it} diagonal {at 45° to the house} other {out from the house, on joists along it, carried by beams square to the house}}; joists {spacing} in on centre.', + values: { + label: stock.label, + thickness: inchFractionLabel(stock.thickness), + width: inchFractionLabel(stock.width), + gap: inchFractionLabel(deck.gap), + direction: deck.direction, + spacing: Math.round(spacing / IN), + }, + })} +

+
+ ) +} diff --git a/packages/editor/src/components/ui/panels/floor-opening-panel.tsx b/packages/editor/src/components/ui/panels/floor-opening-panel.tsx index ca9b412197..bb2997d87e 100644 --- a/packages/editor/src/components/ui/panels/floor-opening-panel.tsx +++ b/packages/editor/src/components/ui/panels/floor-opening-panel.tsx @@ -100,11 +100,17 @@ export function FloorOpeningPanel({ openingId }: { openingId: string }) {

{owned - ? i18n._({ - id: 'editor.panels.floorOpeningPanel.areaOwned', - message: '{area} · Shape follows its owner.', - values: { area: formatAreaLabel(area([{ outer: opening.polygon, holes: [] }]), unit, 2) }, - }) + ? opening.source === 'stair' + ? i18n._({ + id: 'editor.panels.floorOpeningPanel.areaStairResize', + message: '{area} · Drag its sides or corners to resize it; it moves with the stair.', + values: { area: formatAreaLabel(area([{ outer: opening.polygon, holes: [] }]), unit, 2) }, + }) + : i18n._({ + id: 'editor.panels.floorOpeningPanel.areaOwned', + message: '{area} · Shape follows its owner.', + values: { area: formatAreaLabel(area([{ outer: opening.polygon, holes: [] }]), unit, 2) }, + }) : i18n._({ id: 'editor.panels.floorOpeningPanel.areaDragCorners', message: '{area} · Drag its corners to change the shape.', diff --git a/packages/editor/src/components/ui/panels/inspector-extensions.tsx b/packages/editor/src/components/ui/panels/inspector-extensions.tsx new file mode 100644 index 0000000000..ddc2a4185c --- /dev/null +++ b/packages/editor/src/components/ui/panels/inspector-extensions.tsx @@ -0,0 +1,66 @@ +'use client' + +import { Icon } from '@iconify/react' +import { + type AnyNodeId, + getInspectorExtensions, + type IconRef, + useRegistryVersion, + useScene, +} from '@pascal-app/core' +import { useViewer } from '@pascal-app/viewer' +import { lazy, Suspense, useMemo } from 'react' +import { IconRefImage } from '../icon-ref' + +/** + * The plugin inspector extensions (`Plugin.inspectorExtensions`) for the single selected node, + * gated on their plugin being installed, and the one that owns the card body for it + * (`primaryWhen`). Read by the inspector card and by the action menu that opens them. + */ +export function useInspectorExtensions() { + const registryVersion = useRegistryVersion() + const selectedId = useViewer((s) => + s.selection.selectedIds.length === 1 ? s.selection.selectedIds[0] : undefined, + ) as AnyNodeId | undefined + // Subscribe to the selected node's *type* only — a string primitive that + // doesn't change as fields are edited (same trick as ParametricInspector). + const selectedType = useScene((s) => (selectedId ? (s.nodes[selectedId]?.type ?? null) : null)) + const installedPlugins = useScene((s) => s.installedPlugins) + const extensions = useMemo(() => { + // re-derive when plugin extensions register after mount (async plugin load) + void registryVersion + if (!selectedType) return [] + return getInspectorExtensions(selectedType).filter( + (extension) => !extension.pluginId || installedPlugins.includes(extension.pluginId), + ) + }, [selectedType, installedPlugins, registryVersion]) + const primaryExtensionId = useScene((state) => { + const node = selectedId ? state.nodes[selectedId] : undefined + return node ? extensions.find((extension) => extension.primaryWhen?.(node))?.id : undefined + }) + const primaryExtension = extensions.find((extension) => extension.id === primaryExtensionId) + return { selectedId, extensions, primaryExtension } +} + +/** An extension's 16px icon — mirrors the parametric inspector's `renderIcon` (plain so no next/image server deps). */ +export function renderExtensionIcon(ref: IconRef): React.ReactNode { + if (ref.kind === 'url') { + return + } + if (ref.kind === 'iconify') { + return + } + if (ref.kind === 'svg') { + return ( + + + + ) + } + const LazyIcon = lazy(ref.module) + return ( + + + + ) +} diff --git a/packages/editor/src/components/ui/panels/multi-field-value.test.ts b/packages/editor/src/components/ui/panels/multi-field-value.test.ts index dddd6c3d1a..eeefa0c2ac 100644 --- a/packages/editor/src/components/ui/panels/multi-field-value.test.ts +++ b/packages/editor/src/components/ui/panels/multi-field-value.test.ts @@ -15,6 +15,7 @@ import { import { buildMultiNodePatches, commitMultiNodeFields, + fieldTargetIds, fieldVisibleForAll, reduceFieldValue, reduceHeightBoundMode, @@ -57,6 +58,32 @@ describe('reduceFieldValue', () => { expect(reduceFieldValue(['a', 'b'], 'thickness', nodes)).toEqual({ kind: 'mixed' }) }) + test('an omitted value reads as the field default, not as zero', () => { + const nodes = { + a: makeNode('a', 'wall'), + b: makeNode('b', 'wall', { thickness: 0.1 }), + c: makeNode('c', 'wall', { thickness: 0.2 }), + } + expect(reduceFieldValue(['a', 'b'], 'thickness', nodes, 0.1)).toEqual({ + kind: 'same', + value: 0.1, + }) + expect(reduceFieldValue(['a', 'c'], 'thickness', nodes, 0.1)).toEqual({ kind: 'mixed' }) + }) + + test('a field that names the nodes it applies to edits only those', () => { + const nodes = { + a: makeNode('a', 'wall', { thickness: 0.2 }), + b: makeNode('b', 'wall', { thickness: 0.18, assembly: { layers: [] } }), + c: makeNode('c', 'wall', { thickness: 0.2 }), + } + const plain = (node: AnyNode) => !(node as { assembly?: unknown }).assembly + const targets = fieldTargetIds(['a', 'b', 'c'], plain, nodes) + expect(targets).toEqual(['a', 'c']) + expect(reduceFieldValue(targets, 'thickness', nodes)).toEqual({ kind: 'same', value: 0.2 }) + expect(fieldTargetIds(['a', 'b'], undefined, nodes)).toEqual(['a', 'b']) + }) + test('vec3 compares elementwise', () => { const nodes = { a: makeNode('a', 'item', { position: [1, 0, 2] }), diff --git a/packages/editor/src/components/ui/panels/multi-field-value.ts b/packages/editor/src/components/ui/panels/multi-field-value.ts index 11fa7828d1..2af38176c8 100644 --- a/packages/editor/src/components/ui/panels/multi-field-value.ts +++ b/packages/editor/src/components/ui/panels/multi-field-value.ts @@ -20,17 +20,23 @@ function fieldValuesEqual(a: unknown, b: unknown): boolean { return false } +/** + * The value every node holds for `key`, or mixed. `fallback` is what a node + * that omits the key shows (the field's default), so an absent value and an + * explicit default read as the same. + */ export function reduceFieldValue( nodeIds: readonly string[], key: string, nodes: Readonly>, + fallback?: unknown, ): ReducedFieldValue { let seen = false let shared: unknown for (const id of nodeIds) { const node = nodes[id] if (!node) continue - const value = (node as Record)[key] + const value = (node as Record)[key] ?? fallback if (!seen) { seen = true shared = value @@ -78,6 +84,19 @@ export function fieldVisibleForAll( return true } +/** The selected nodes a field edits: every one, unless it names those it `appliesTo`. */ +export function fieldTargetIds( + nodeIds: readonly T[], + appliesTo: ((node: AnyNode) => boolean) | undefined, + nodes: Readonly>, +): T[] { + if (!appliesTo) return [...nodeIds] + return nodeIds.filter((id) => { + const node = nodes[id] + return node ? appliesTo(node) : false + }) +} + export function firstNumericFieldValue( nodeIds: readonly string[], key: string, diff --git a/packages/editor/src/components/ui/panels/multi-parametric-inspector.tsx b/packages/editor/src/components/ui/panels/multi-parametric-inspector.tsx index 407bc0a80e..151388919c 100644 --- a/packages/editor/src/components/ui/panels/multi-parametric-inspector.tsx +++ b/packages/editor/src/components/ui/panels/multi-parametric-inspector.tsx @@ -11,15 +11,17 @@ import { import { useViewer } from '@pascal-app/viewer' import { useCallback, useMemo } from 'react' import { useShallow } from 'zustand/react/shallow' -import { getNodePanelModel } from '../../../lib/panel-rows' +import { getNodePanelModel, type MultiPanelControl } from '../../../lib/panel-rows' import { selectionMatchesSessionGroup } from '../../../lib/session-groups' import useSessionGroups from '../../../store/use-session-groups' import { PanelSection } from '../controls/panel-section' import { SegmentedControl } from '../controls/segmented-control' +import { SelectControl } from '../controls/select-control' import { SliderControl } from '../controls/slider-control' import { resolveUniqueSelectionIds } from './homogeneous-selection' import { commitMultiNodeFields, + fieldTargetIds, fieldVisibleForAll, firstNumericFieldValue, firstVec3FieldValue, @@ -88,6 +90,13 @@ export function MultiParametricInspector({ footer }: { footer?: React.ReactNode ) : null} ))} + {hasKindControls ? ( + group.label)} + nodeIds={nodeIds} + nodeType={nodeType} + /> + ) : null}

@@ -95,10 +104,20 @@ export function MultiParametricInspector({ footer }: { footer?: React.ReactNode ) } +function useMultiKindControls(nodeIds: AnyNodeId[], nodeType: AnyNode['type']) { + const nodes = useScene((s) => s.nodes) + return useMemo(() => { + const model = getNodePanelModel(nodeRegistry.get(nodeType)) + if (!model?.multiControls) return [] + const selection = nodeIds.flatMap((id) => (nodes[id] ? [nodes[id]!] : [])) + return model.multiControls({ selection, nodes }) + }, [nodeIds, nodeType, nodes]) +} + /** * The kind's own multi-selection controls for one section (the wall's - * Reference), from its panel model — the same segmented control the single - * panel shows, mixed when the selection disagrees. + * Reference), from its panel model — the same control the single panel + * shows, mixed when the selection disagrees. */ function MultiKindControls({ nodeIds, @@ -109,32 +128,84 @@ function MultiKindControls({ nodeType: AnyNode['type'] section: string }) { - const nodes = useScene((s) => s.nodes) - const controls = useMemo(() => { - const model = getNodePanelModel(nodeRegistry.get(nodeType)) - if (!model?.multiControls) return [] - const selection = nodeIds.flatMap((id) => (nodes[id] ? [nodes[id]!] : [])) - return model.multiControls({ selection, nodes }).filter((control) => control.section === section) - }, [nodeIds, nodeType, nodes, section]) + const controls = useMultiKindControls(nodeIds, nodeType).filter( + (control) => control.section === section, + ) return ( <> {controls.map((control) => ( -
-
- {control.label} -
- ({ ...option }))} - value={control.value ?? ''} - /> -
+ + ))} + + ) +} + +/** The kind's controls whose section is none of the parametrics groups, each section its own. */ +function MultiKindSections({ + groupTitles, + nodeIds, + nodeType, +}: { + groupTitles: readonly string[] + nodeIds: AnyNodeId[] + nodeType: AnyNode['type'] +}) { + const controls = useMultiKindControls(nodeIds, nodeType).filter( + (control) => !groupTitles.includes(control.section), + ) + const sections = [...new Set(controls.map((control) => control.section))] + return ( + <> + {sections.map((section) => ( + + {controls + .filter((control) => control.section === section) + .map((control) => ( + + ))} + ))} ) } +function MultiKindControlView({ control }: { control: MultiPanelControl }) { + if (control.kind === 'readout') { + return ( +
+ + {control.label} + + + {control.detail ? `${control.value} · ${control.detail}` : control.value} + +
+ ) + } + if (control.kind === 'select') { + return ( + ({ ...option }))} + value={control.value ?? ''} + /> + ) + } + return ( +
+
{control.label}
+ ({ ...option }))} + value={control.value ?? ''} + /> +
+ ) +} + function MultiGroupFields({ defaultExpanded, title, @@ -154,9 +225,16 @@ function MultiGroupFields({ }) { const genericFields = fields.filter((field) => field.kind !== 'custom') const anyVisible = useScene((s) => - genericFields.some((field) => - fieldVisibleForAll(nodeIds, (field as { visibleIf?: (n: AnyNode) => boolean }).visibleIf, s.nodes), - ), + genericFields.some((field) => { + const { visibleIf, appliesTo } = field as { + visibleIf?: (n: AnyNode) => boolean + appliesTo?: (n: AnyNode) => boolean + } + return ( + fieldVisibleForAll(nodeIds, visibleIf, s.nodes) && + fieldTargetIds(nodeIds, appliesTo, s.nodes).length > 0 + ) + }), ) if ((genericFields.length === 0 || !anyVisible) && !children) return null return ( @@ -195,7 +273,7 @@ function MultiGroupFields({ function MultiFieldRenderer({ field, - nodeIds, + nodeIds: selectedIds, parametrics, }: { field: ParamField @@ -203,11 +281,21 @@ function MultiFieldRenderer({ parametrics: ParametricDescriptor }) { const key = String(field.key) + // A field that names the nodes it `appliesTo` reads and edits only those. + const appliesTo = (field as { appliesTo?: (n: AnyNode) => boolean }).appliesTo + const nodeIds = useScene( + useShallow((s) => fieldTargetIds(selectedIds, appliesTo, s.nodes)), + ) const visible = useScene((s) => fieldVisibleForAll(nodeIds, (field as { visibleIf?: (n: AnyNode) => boolean }).visibleIf, s.nodes), ) - const reduced = useScene(useShallow((s) => reduceFieldValue(nodeIds, key, s.nodes))) - const numericOrigin = useScene((s) => firstNumericFieldValue(nodeIds, key, s.nodes)) + const fallback = field.kind === 'number' ? field.default : undefined + const reduced = useScene( + useShallow((s) => reduceFieldValue(nodeIds, key, s.nodes, fallback)), + ) + const numericOrigin = useScene((s) => + firstNumericFieldValue(nodeIds, key, s.nodes, fallback ?? 0), + ) const vecOrigin = useScene(useShallow((s) => firstVec3FieldValue(nodeIds, key, s.nodes))) const preview = useCallback( @@ -223,7 +311,7 @@ function MultiFieldRenderer({ [nodeIds, parametrics], ) - if (!visible) return null + if (!visible || nodeIds.length === 0) return null if (field.kind === 'vec3') { return ( diff --git a/packages/editor/src/components/ui/panels/panel-wrapper.tsx b/packages/editor/src/components/ui/panels/panel-wrapper.tsx index e38f9f8beb..c3c236dab2 100644 --- a/packages/editor/src/components/ui/panels/panel-wrapper.tsx +++ b/packages/editor/src/components/ui/panels/panel-wrapper.tsx @@ -1,16 +1,11 @@ 'use client' -import { Icon } from '@iconify/react' import { type AnyNode, type AnyNodeId, - getInspectorExtensions, - type IconRef, type InspectorExtension, - useRegistryVersion, useScene, usePascalI18n, } from '@pascal-app/core' -import { useViewer } from '@pascal-app/viewer' import { ChevronDown, ChevronLeft, GripHorizontal, RotateCcw, X } from 'lucide-react' import { type ComponentType, @@ -21,18 +16,12 @@ import { useContext, useEffect, useLayoutEffect, - useMemo, useRef, useState, } from 'react' import { useIsMobile } from '../../../hooks/use-mobile' -import { IconRefImage } from '../icon-ref' import { NodeIconImage } from '../node-icon-image' -import { - resolveActiveExtension, - toggleCard, - toggleExtension, -} from '../../../lib/inspector-card-mode' +import { resolveActiveExtension, toggleCard } from '../../../lib/inspector-card-mode' import { cn } from '../../../lib/utils' import { useInspectorExpanded } from '../../../lib/inspector-expanded' import { ActionButton, ActionGroup } from '../controls/action-button' @@ -40,6 +29,7 @@ import { PanelSection } from '../controls/panel-section' import { ErrorBoundary } from '../primitives/error-boundary' import { useInRightStack } from '../right-stack' import { CollectionsPopover } from './collections/collections-popover' +import { renderExtensionIcon, useInspectorExtensions } from './inspector-extensions' const DRAG_MARGIN = 8 // Pointer travel (px) below which a header press is treated as a click @@ -132,35 +122,16 @@ export function PanelWrapper({ // The wrapper self-resolves the selected node instead of taking a prop: // kind-owned `customPanel`s (wall, slab, …) render their own // , so this is the one spot every inspector card flows - // through. Extensions only apply to a single-node selection. - const registryVersion = useRegistryVersion() - const selectedId = useViewer((s) => - s.selection.selectedIds.length === 1 ? s.selection.selectedIds[0] : undefined, - ) as AnyNodeId | undefined - // Subscribe to the selected node's *type* only — a string primitive that - // doesn't change as fields are edited (same trick as ParametricInspector). - const selectedType = useScene((s) => (selectedId ? s.nodes[selectedId]?.type ?? null : null)) - const installedPlugins = useScene((s) => s.installedPlugins) - const extensions = useMemo(() => { - // re-derive when plugin extensions register after mount (async plugin load) - void registryVersion - if (!selectedType) return [] - return getInspectorExtensions(selectedType).filter( - (extension) => !extension.pluginId || installedPlugins.includes(extension.pluginId), - ) - }, [selectedType, installedPlugins, registryVersion]) + // through. Extensions only apply to a single-node selection; the action + // menu opens them (`InspectorExtensionActions`). + const { selectedId, extensions, primaryExtension } = useInspectorExtensions() // Which extension's content fills the card body (extension mode). The two // expanded modes are EITHER/OR: extension mode replaces the regular // controls; null shows the regular controls with no extension sections. - // See `lib/inspector-card-mode.ts` for the transition table. - const [activeExtensionId, setActiveExtensionId] = useState(null) // Stale ids (kind changed, plugin gated off) fall back to regular mode. - const primaryExtensionId = useScene((state) => { - const node = selectedId ? state.nodes[selectedId] : undefined - return node ? extensions.find((extension) => extension.primaryWhen?.(node))?.id : undefined - }) - const primaryExtension = extensions.find((extension) => extension.id === primaryExtensionId) + // See `lib/inspector-card-mode.ts` for the transition table. + const activeExtensionId = useInspectorExpanded((state) => state.activeExtensionId) const activeExtension = primaryExtension ?? resolveActiveExtension(activeExtensionId, extensions) // The panel is collapsed to just its header until the user expands it. The @@ -175,14 +146,6 @@ export function PanelWrapper({ if (primaryExtension) setCollapsed(false) }, [primaryExtension, selectedId, setCollapsed]) - const applyMode = useCallback( - (next: { collapsed: boolean; activeExtensionId: string | null }) => { - setCollapsed(next.collapsed) - setActiveExtensionId(next.activeExtensionId) - }, - [setCollapsed], - ) - // Chevron / header press — collapsed → regular, regular → collapsed, // extension mode → regular (exit the extension first, stay expanded). const handleCardToggle = useCallback(() => { @@ -190,14 +153,12 @@ export function PanelWrapper({ setCollapsed(!collapsed) return } - applyMode(toggleCard({ collapsed, activeExtensionId })) - }, [applyMode, collapsed, activeExtensionId, primaryExtension, setCollapsed]) + useInspectorExpanded.getState().applyMode(toggleCard({ collapsed, activeExtensionId })) + }, [collapsed, activeExtensionId, primaryExtension, setCollapsed]) - // Folding the card forgets the active extension — extension mode is a - // one-shot affordance of the header icon, not sticky panel state. - useEffect(() => { - if (collapsed) setActiveExtensionId(null) - }, [collapsed]) + // Extension mode is an affordance of the card it was opened on: a card that + // closes (selection cleared or changed kind) leaves the next one regular. + useEffect(() => () => useInspectorExpanded.setState({ activeExtensionId: null }), []) // Drag-to-reposition from the header. `offset` is a translation applied on // top of the default `top-20 right-4` anchor; null until first dragged. @@ -398,34 +359,6 @@ export function PanelWrapper({ )} - {/* Extension mode buttons — one icon per registered inspector - extension, left of the chevron. Click swaps the card body to - ONLY that extension's content (either/or with the regular - controls); the active icon (highlighted) or the chevron - returns to the regular controls. */} - {extensions.filter((extension) => extension !== primaryExtension).map((extension) => { - const isActive = !collapsed && activeExtensionId === extension.id - return ( - - ) - })} + + + {BEAM_SIZE_PRESETS.map((preset) => ( + { + if (preset.id !== porch.beamSize) set({ beamSize: preset.id }) + }} + > + {preset.label} + {preset.id === porch.beamSize && } + + ))} + + + + + )} +
+ ) +} + /** * The room's floor construction, edited from the room: its thickness, through * core's `setRoomFloorConstruction` (the command MCP uses too), on whatever the @@ -733,6 +1002,9 @@ export function RoomConstructionRows({ room }: { room: RoomSelectionRecord }) { return (
+ + +

{i18n._({ id: 'editor.panels.roomConstructionRows.builtWith', message: 'Built with' })}

@@ -100,9 +101,7 @@ export function WallPaintRegionList({ wallId }: { wallId: string }) {
) })} - {capNotice && ( -
{capNotice}
- )} + {capNotice &&
{capNotice}
}
diff --git a/packages/editor/src/components/ui/sidebar/panels/settings-panel/index.tsx b/packages/editor/src/components/ui/sidebar/panels/settings-panel/index.tsx index 7c328634bd..85116b532c 100644 --- a/packages/editor/src/components/ui/sidebar/panels/settings-panel/index.tsx +++ b/packages/editor/src/components/ui/sidebar/panels/settings-panel/index.tsx @@ -73,6 +73,7 @@ import { Switch } from './../../../../../components/ui/primitives/switch' import { cn } from './../../../../../lib/utils' import { refusedObjectsNotice } from './../../../../../components/editor/group-actions' import { addStoreyBelow, addStoreyOnTop } from './../../../../../lib/add-storey' +import { offerExteriorWallCopy } from './../../../../../components/ui/level-wall-copy-prompt' import { deleteLevelWithFallbackSelection } from './../../../../../lib/level-selection' import { bringBuildArtifacts } from './../../../../../lib/scene-clipboard' import useEditor, { selectDefaultBuildingAndLevel } from './../../../../../store/use-editor' @@ -423,10 +424,12 @@ function FloorSettingsSection() { const addFloor = () => { const newLevel = addStoreyOnTop(building.id) setSelection({ buildingId: building.id, levelId: newLevel.id }) + offerExteriorWallCopy(newLevel.id) } const addBasement = () => { const newLevel = addStoreyBelow(building.id) setSelection({ buildingId: building.id, levelId: newLevel.id }) + offerExteriorWallCopy(newLevel.id) } return ( diff --git a/packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx b/packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx index 58bff43ee0..e28946d365 100644 --- a/packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +++ b/packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx @@ -1,3 +1,4 @@ +import { type MessageDescriptor, usePascalI18n } from '@pascal-app/core' import { Keyboard } from 'lucide-react' import { Button } from './../../../../../components/ui/primitives/button' import { @@ -12,27 +13,31 @@ import { ShortcutToken, shortcutDisplayValue, } from './../../../../../components/ui/primitives/shortcut-token' +import { TOOL_SHORTCUT_KEYS } from './../../../../../lib/tool-shortcuts' type Shortcut = { - keys: string[] + keys: readonly string[] action: string note?: string } type ShortcutCategory = { - title: string + title: MessageDescriptor shortcuts: Shortcut[] } const SHORTCUT_CATEGORIES: ShortcutCategory[] = [ { - title: 'Editor Navigation', + title: /* i18n */ { + id: 'editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.editorNavigation', + message: 'Editor Navigation', + }, shortcuts: [ { keys: ['1'], action: 'Switch to Site' }, { keys: ['2'], action: 'Switch to Building' }, { keys: ['\\'], action: 'Open or close the split view' }, - { keys: ['F'], action: 'Open the items catalog with the item tool' }, - { keys: ['Z'], action: 'Draw a zone' }, + { keys: TOOL_SHORTCUT_KEYS.item, action: 'Open the items catalog with the item tool' }, + { keys: TOOL_SHORTCUT_KEYS.zone, action: 'Draw a zone' }, { keys: ['Cmd/Ctrl', 'Arrow Up'], action: 'Select next level in the active building', @@ -45,12 +50,21 @@ const SHORTCUT_CATEGORIES: ShortcutCategory[] = [ ], }, { - title: 'Modes & History', + title: /* i18n */ { + id: 'editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.modesHistory', + message: 'Modes & History', + }, shortcuts: [ - { keys: ['V'], action: 'Switch to Select mode' }, - { keys: ['B'], action: 'Switch to Build mode' }, - { keys: ['M'], action: 'Activate the last measurement tool' }, - { keys: ['X'], action: 'Switch to Delete mode' }, + { keys: TOOL_SHORTCUT_KEYS.select, action: 'Switch to Select mode' }, + { + keys: TOOL_SHORTCUT_KEYS.wall, + action: 'Switch to Build mode, drawing with the last Rooms shape', + note: 'Rectangle, Polygon or Walls, whichever you picked last; Rectangle the first time.', + }, + { keys: TOOL_SHORTCUT_KEYS.measurement, action: 'Activate the last measurement tool' }, + { keys: TOOL_SHORTCUT_KEYS.paint, action: 'Switch to Paint mode' }, + { keys: TOOL_SHORTCUT_KEYS.terrain, action: 'Sculpt the ground (terrain)' }, + { keys: TOOL_SHORTCUT_KEYS.delete, action: 'Switch to Delete mode' }, { keys: ['Esc'], action: 'Cancel the active tool and return to Select mode', @@ -63,7 +77,30 @@ const SHORTCUT_CATEGORIES: ShortcutCategory[] = [ ], }, { - title: 'Selection', + title: /* i18n */ { + id: 'editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.buildTools', + message: 'Build Tools', + }, + shortcuts: [ + { + keys: TOOL_SHORTCUT_KEYS.door, + action: 'Place a door', + note: 'D alone pans the view. While placing, the door swings toward the side of the wall the cursor is on; R flips it.', + }, + { keys: TOOL_SHORTCUT_KEYS.window, action: 'Place a window', note: 'W alone pans the view.' }, + { keys: TOOL_SHORTCUT_KEYS.stair, action: 'Place stairs', note: 'S alone pans the view.' }, + { + keys: TOOL_SHORTCUT_KEYS.roof, + action: 'Draw a roof', + note: "R alone still rotates or flips the selection, and while placing it stays the placement's own R.", + }, + ], + }, + { + title: /* i18n */ { + id: 'editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.selection', + message: 'Selection', + }, shortcuts: [ { keys: ['Cmd/Ctrl', 'C'], @@ -78,8 +115,7 @@ const SHORTCUT_CATEGORIES: ShortcutCategory[] = [ { keys: ['Cmd/Ctrl', 'V'], action: 'Paste and place copied objects', - note: - 'Carries a preview under the cursor. Click to place it, or press Escape to cancel.', + note: 'Carries a preview under the cursor. Click to place it, or press Escape to cancel.', }, { keys: ['Cmd/Ctrl', 'Left click'], @@ -105,14 +141,23 @@ const SHORTCUT_CATEGORIES: ShortcutCategory[] = [ { keys: ['Cmd/Ctrl', 'G'], action: 'Group the multi-selection (session only)', - note: - 'Editor-only. Plain click a member later to reselect the whole group. Not saved with the project.', + note: 'Editor-only. Plain click a member later to reselect the whole group. Not saved with the project.', }, { keys: ['Cmd/Ctrl', 'Shift', 'G'], action: 'Ungroup the session selection', note: 'Keeps the current selection; only dissolves the session group.', }, + { + keys: ['Arrow keys'], + action: 'Nudge the selected wall 1 in (1 cm in metric)', + note: 'In the floor plan. Stops where it lines up with a parallel wall; joined walls follow.', + }, + { + keys: ['Tab'], + action: 'Select the next object under the pointer', + note: 'In the floor plan, for walls that overlap or hide under another. Shift+Tab goes back.', + }, { keys: ['Esc'], action: 'Clear the selection', @@ -121,7 +166,10 @@ const SHORTCUT_CATEGORIES: ShortcutCategory[] = [ ], }, { - title: 'Direct Manipulation', + title: /* i18n */ { + id: 'editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.directManipulation', + message: 'Direct Manipulation', + }, shortcuts: [ { keys: ['Cmd/Ctrl', 'Left click'], @@ -141,7 +189,10 @@ const SHORTCUT_CATEGORIES: ShortcutCategory[] = [ ], }, { - title: 'Drawing Tools', + title: /* i18n */ { + id: 'editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.drawingTools', + message: 'Drawing Tools', + }, shortcuts: [ // Shift and Ctrl each mean one thing held and another tapped, and only // the hold was documented — which read as the taps not existing. Both @@ -157,9 +208,9 @@ const SHORTCUT_CATEGORIES: ShortcutCategory[] = [ note: 'Tap and release on its own. Use it when the default half-metre grid is too coarse — placing a window, for instance.', }, { - keys: ['Shift'], - action: 'Bypass guided snapping and angle constraints', - note: 'Hold during the active gesture. Passive guide or measurement feedback may stay visible.', + keys: ['Alt'], + action: 'Bypass snapping, angle constraints and collisions', + note: 'Hold during the active gesture; release to snap again. Passive guide or measurement feedback may stay visible.', }, { keys: ['Shift'], @@ -169,7 +220,10 @@ const SHORTCUT_CATEGORIES: ShortcutCategory[] = [ ], }, { - title: 'Item Placement', + title: /* i18n */ { + id: 'editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.itemPlacement', + message: 'Item Placement', + }, shortcuts: [ { keys: ['R', 'T'], @@ -177,7 +231,8 @@ const SHORTCUT_CATEGORIES: ShortcutCategory[] = [ }, { keys: ['E'], - action: 'Operate the selected node — doors, windows, and cabinet doors/drawers animate open/closed', + action: + 'Operate the selected node — doors, windows, and cabinet doors/drawers animate open/closed', }, { keys: ['Shift'], @@ -187,12 +242,15 @@ const SHORTCUT_CATEGORIES: ShortcutCategory[] = [ ], }, { - title: 'Camera', + title: /* i18n */ { + id: 'editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.camera', + message: 'Camera', + }, shortcuts: [ { keys: ['W', 'A', 'S', 'D'], action: 'Pan camera', - note: 'Moves in screen space, similar to dragging the camera view.', + note: 'Moves in screen space, similar to dragging the camera view. With Shift, W, S and D place a window, stairs and a door instead.', }, { keys: ['Middle click'], @@ -208,7 +266,7 @@ const SHORTCUT_CATEGORIES: ShortcutCategory[] = [ }, ] -function ShortcutKeys({ keys }: { keys: string[] }) { +function ShortcutKeys({ keys }: { keys: readonly string[] }) { return (
{keys.map((key, index) => ( @@ -222,32 +280,44 @@ function ShortcutKeys({ keys }: { keys: string[] }) { } export function KeyboardShortcutsDialog() { + const i18n = usePascalI18n() return ( - Keyboard shortcuts + + {i18n._({ + id: 'editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.keyboardShortcuts', + message: 'Keyboard shortcuts', + })} + - Shortcuts are context-aware. Guided constraints are enabled by default; hold Shift - during an active gesture to build freely. + {i18n._({ + id: 'editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.shortcutsAreContextAwareGuidedConstraints', + message: + 'Shortcuts are context-aware. Snapping is a visible mode: tap Shift to cycle it, hold Alt during a gesture to place freely.', + })}
{SHORTCUT_CATEGORIES.map((category) => ( -
-

{category.title}

+
+

{i18n._(category.title)}

{category.shortcuts.map((shortcut, index) => (
diff --git a/packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx b/packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx index 0626fb399e..e4cc2e5c36 100644 --- a/packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +++ b/packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx @@ -58,6 +58,7 @@ import { type LevelDuplicatePreset, } from '@pascal-app/core/building' import { addStoreyOnTop } from './../../../../../lib/add-storey' +import { offerExteriorWallCopy } from './../../../../../components/ui/level-wall-copy-prompt' import { deleteLevelWithFallbackSelection } from './../../../../../lib/level-selection' import { formatAreaLabel, @@ -1068,6 +1069,7 @@ const LevelsSection = memo(function LevelsSection({ const handleAddLevel = () => { const newLevel = addStoreyOnTop(building.id) setSelection({ buildingId: building.id, levelId: newLevel.id }) + offerExteriorWallCopy(newLevel.id) } return ( diff --git a/packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx b/packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx new file mode 100644 index 0000000000..8f9c1f5503 --- /dev/null +++ b/packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx @@ -0,0 +1,721 @@ +'use client' + +import { + type Assembly, + type AssemblyLayer, + BRICK_AIR_SPACE, + BRICK_VENEER, + FIBER_CEMENT, + GYPSUM_HALF, + GYPSUM_SHEATHING, + type MessageDescriptor, + newWallTypeId, + runAsSingleSceneHistoryStep, + SIDING_LAP, + STONE_VENEER_UNVERIFIED, + STUCCO_3_COAT, + usePascalI18n, + useScene, + WALL_TYPE_CORES, + type WallTypeCore, + type WallTypeDefinition, + WSP_SHEATHING, + wallTypeAssembly, + wallTypeCoreOf, +} from '@pascal-app/core' +import { useViewer } from '@pascal-app/viewer' +import { ArrowDown, ArrowUp, Plus, X } from 'lucide-react' +import { useEffect, useState } from 'react' +import { formatLayerThickness, parseLayerThickness } from '../../../lib/layer-thickness' +import type { LinearUnit } from '../../../lib/measurements' +import { cn } from '../../../lib/utils' +import { + saveProjectWallType, + WALL_TYPE_LAYER_LIMIT, + WALL_TYPE_SAVE_FAILURE, + type WallTypePlacement, + type WallTypeSaveResult, +} from '../../../lib/wall-type' +import { Button } from '../primitives/button' +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '../primitives/dialog' + +/** What the editor opens on: a blank type for a placement, a project type to edit, or a type to copy. */ +export type WallTypeEditorRequest = + | { mode: 'new'; placement: WallTypePlacement } + | { mode: 'edit'; placement: WallTypePlacement; id: string; label: string; assembly: Assembly } + | { mode: 'duplicate'; placement: WallTypePlacement; label: string; assembly: Assembly } + +/** The roles a layer takes in the editor; `core` is the one framing layer. */ +type DraftRole = 'finish' | 'air' | 'sheathing' | 'insulation' | 'core' | 'lining' + +type DraftLayer = { + key: number + role: DraftRole + material: string + thickness: number +} + +const IN = 0.0254 + +const ROLE_LABEL: Record = { + finish: /* i18n */ { id: 'editor.buildPanel.wallTypeEditorDialog.finish', message: 'Finish' }, + air: /* i18n */ { id: 'editor.buildPanel.wallTypeEditorDialog.airSpace', message: 'Air space' }, + sheathing: /* i18n */ { + id: 'editor.buildPanel.wallTypeEditorDialog.sheathing', + message: 'Sheathing', + }, + insulation: /* i18n */ { + id: 'editor.buildPanel.wallTypeEditorDialog.insulation', + message: 'Insulation', + }, + core: /* i18n */ { + id: 'editor.buildPanel.wallTypeEditorDialog.framingCore', + message: 'Framing core', + }, + lining: /* i18n */ { id: 'editor.buildPanel.wallTypeEditorDialog.lining', message: 'Lining' }, +} + +/** + * Each role's materials, as the construction kinds the inspector and the framers + * read, and the cited thickness one starts at (the `wall-assembly.ts` constants; + * insulation is the product's own, typed in). + */ +const LAYER_MATERIALS: Record< + Exclude, + ReadonlyArray<{ value: string; label: MessageDescriptor; thickness: number }> +> = { + finish: [ + { + value: 'siding', + label: /* i18n */ { + id: 'editor.buildPanel.wallTypeEditorDialog.lapSiding', + message: 'Lap siding', + }, + thickness: SIDING_LAP, + }, + { + value: 'fiber-cement', + label: /* i18n */ { + id: 'editor.buildPanel.wallTypeEditorDialog.fiberCement', + message: 'Fiber cement', + }, + thickness: FIBER_CEMENT, + }, + { + value: 'stucco', + label: /* i18n */ { id: 'editor.buildPanel.wallTypeEditorDialog.stucco', message: 'Stucco' }, + thickness: STUCCO_3_COAT, + }, + { + value: 'brick', + label: /* i18n */ { + id: 'editor.buildPanel.wallTypeEditorDialog.brickVeneer', + message: 'Brick veneer', + }, + thickness: BRICK_VENEER, + }, + { + value: 'stone', + label: /* i18n */ { + id: 'editor.buildPanel.wallTypeEditorDialog.stoneVeneer', + message: 'Stone veneer', + }, + thickness: STONE_VENEER_UNVERIFIED, + }, + ], + air: [ + { + value: 'air', + label: /* i18n */ { + id: 'editor.buildPanel.wallTypeEditorDialog.airSpace', + message: 'Air space', + }, + thickness: BRICK_AIR_SPACE, + }, + ], + sheathing: [ + { + value: 'osb', + label: /* i18n */ { id: 'editor.buildPanel.wallTypeEditorDialog.osb', message: 'OSB' }, + thickness: WSP_SHEATHING, + }, + { + value: 'plywood', + label: /* i18n */ { + id: 'editor.buildPanel.wallTypeEditorDialog.plywood', + message: 'Plywood', + }, + thickness: WSP_SHEATHING, + }, + { + value: 'gypsum', + label: /* i18n */ { + id: 'editor.buildPanel.wallTypeEditorDialog.gypsumSheathing', + message: 'Gypsum sheathing', + }, + thickness: GYPSUM_SHEATHING, + }, + ], + insulation: [ + { + value: 'rigid-foam', + label: /* i18n */ { + id: 'editor.buildPanel.wallTypeEditorDialog.rigidFoam', + message: 'Rigid foam', + }, + thickness: 1 * IN, + }, + { + value: 'mineral-wool', + label: /* i18n */ { + id: 'editor.buildPanel.wallTypeEditorDialog.mineralWoolBoard', + message: 'Mineral wool board', + }, + thickness: 1.5 * IN, + }, + ], + lining: [ + { + value: 'drywall', + label: /* i18n */ { + id: 'editor.buildPanel.wallTypeEditorDialog.drywall', + message: 'Drywall', + }, + thickness: GYPSUM_HALF, + }, + { + value: 'plaster', + label: /* i18n */ { + id: 'editor.buildPanel.wallTypeEditorDialog.plaster', + message: 'Plaster', + }, + thickness: STUCCO_3_COAT, + }, + ], +} + +const ADDABLE_ROLES: ReadonlyArray> = [ + 'finish', + 'air', + 'sheathing', + 'insulation', + 'lining', +] + +const DEFAULT_CORE: Record = { + exterior: WALL_TYPE_CORES.find((core) => core.id === 'wood-2x6-16')!, + interior: WALL_TYPE_CORES.find((core) => core.id === 'wood-2x4-16')!, +} + +let nextKey = 1 + +function layerOf(role: Exclude, material?: string): DraftLayer { + const options = LAYER_MATERIALS[role] + const option = options.find((entry) => entry.value === material) ?? options[0]! + return { key: nextKey++, role, material: option.value, thickness: option.thickness } +} + +function coreLayer(core: WallTypeCore): DraftLayer { + return { key: nextKey++, role: 'core', material: core.id, thickness: core.thickness } +} + +function draftRoleOf(layer: AssemblyLayer): DraftRole { + if (layer.core) return 'core' + switch (layer.role) { + case 'finish': + case 'air': + case 'sheathing': + case 'insulation': + case 'lining': + return layer.role + default: + return 'sheathing' + } +} + +/** The editor's layers for a request: a stack to start from, or a typical one for the placement. */ +function initialLayers(request: WallTypeEditorRequest): DraftLayer[] { + if (request.mode === 'new') { + return request.placement === 'exterior' + ? [ + layerOf('finish', 'siding'), + layerOf('sheathing', 'osb'), + coreLayer(DEFAULT_CORE.exterior), + layerOf('lining', 'drywall'), + ] + : [ + layerOf('lining', 'drywall'), + coreLayer(DEFAULT_CORE.interior), + layerOf('lining', 'drywall'), + ] + } + const core = wallTypeCoreOf(request.assembly) ?? DEFAULT_CORE[request.placement] + const layers = request.assembly.layers.map((layer): DraftLayer => { + const role = draftRoleOf(layer) + if (role === 'core') return coreLayer(core) + return { + key: nextKey++, + role, + material: layer.material ?? LAYER_MATERIALS[role][0]!.value, + thickness: layer.thickness, + } + }) + return layers.some((layer) => layer.role === 'core') ? layers : [...layers, coreLayer(core)] +} + +/** Where a new layer of `role` goes: a finish outermost, sheathing and insulation just outside the core, a lining innermost. */ +function insertIndex(layers: readonly DraftLayer[], role: DraftRole): number { + const coreIndex = layers.findIndex((layer) => layer.role === 'core') + if (role === 'finish') return 0 + if (role === 'air') { + const finish = layers.findIndex((layer) => layer.role === 'finish') + return finish < 0 ? 0 : finish + 1 + } + if (role === 'lining') return layers.length + if (role === 'insulation') { + const sheathing = layers.findIndex((layer) => layer.role === 'sheathing') + return sheathing >= 0 && sheathing < coreIndex ? sheathing : coreIndex + } + return coreIndex +} + +/** The saved stack: each layer as an assembly layer, the core with its framing size and spacing. */ +function draftAssembly(id: string, layers: readonly DraftLayer[]): Assembly { + return wallTypeAssembly( + id, + layers.map((layer): Omit => { + if (layer.role === 'core') { + const core = WALL_TYPE_CORES.find((entry) => entry.id === layer.material)! + return { + role: 'structure', + core: true, + material: core.material, + thickness: core.thickness, + ...(core.spacing !== undefined ? { spacing: core.spacing } : {}), + } + } + return { + role: layer.role, + thickness: layer.thickness, + ...(layer.role === 'air' ? {} : { material: layer.material }), + } + }), + ) +} + +const FIELD_CLASS = + 'h-8 w-full min-w-0 rounded-md border border-border bg-background px-2 text-xs text-foreground outline-none focus:border-primary' + +function ThicknessField({ + metres, + onCommit, + unit, +}: { + metres: number + onCommit: (metres: number) => void + unit: LinearUnit +}) { + const i18n = usePascalI18n() + const [draft, setDraft] = useState(null) + return ( + { + if (draft != null) { + const parsed = parseLayerThickness(draft, unit) + if (parsed != null && parsed > 0) onCommit(parsed) + } + setDraft(null) + }} + onChange={(event) => setDraft(event.target.value)} + onKeyDown={(event) => { + if (event.key === 'Enter') event.currentTarget.blur() + if (event.key === 'Escape') { + setDraft(null) + event.currentTarget.blur() + } + }} + spellCheck={false} + value={draft ?? formatLayerThickness(metres, unit)} + /> + ) +} + +const TITLE: Record = { + new: /* i18n */ { + id: 'editor.buildPanel.wallTypeEditorDialog.newWallType', + message: 'New wall type', + }, + edit: /* i18n */ { + id: 'editor.buildPanel.wallTypeEditorDialog.editWallType', + message: 'Edit wall type', + }, + duplicate: /* i18n */ { + id: 'editor.buildPanel.wallTypeEditorDialog.duplicateWallType', + message: 'Duplicate wall type', + }, +} + +/** + * The wall type editor: a name and the + * layers from the outside in — finish, air space, sheathing, insulation, lining — + * around exactly one framing core, whose size and spacing are what the framers stud + * the wall at. The total updates as layers change; saving keeps the type with the + * project (`saveProjectWallType`) and hands it to `onSaved` in the same undo step, + * so a wall the type is applied to there undoes with it. + */ +export function WallTypeEditorDialog({ + onClose, + onSaved, + request, +}: { + onClose: () => void + onSaved: (type: WallTypeDefinition) => void + request: WallTypeEditorRequest | null +}) { + const i18n = usePascalI18n() + const unit = useViewer((state) => state.unit) + const [name, setName] = useState('') + const [layers, setLayers] = useState([]) + const [failure, setFailure] = useState | null>(null) + + useEffect(() => { + if (!request) return + setLayers(initialLayers(request)) + setName( + request.mode === 'new' + ? request.placement === 'exterior' + ? 'My exterior wall' + : 'My interior wall' + : request.mode === 'duplicate' + ? `${request.label} (copy)` + : request.label, + ) + setFailure(null) + }, [request]) + + const total = layers.reduce((sum, layer) => sum + layer.thickness, 0) + const trimmed = name.trim() + const canSave = trimmed.length > 0 && layers.every((layer) => layer.thickness > 0) + // A wall type's stack holds `WALL_TYPE_LAYER_LIMIT` layers at most; past it the type would not save. + const full = layers.length >= WALL_TYPE_LAYER_LIMIT + const fullReason = i18n._({ + id: 'editor.buildPanel.wallTypeEditorDialog.aWallTypeHoldsAtMost', + message: 'A wall type holds at most {limit, plural, one {# layer} other {# layers}}.', + values: { limit: WALL_TYPE_LAYER_LIMIT }, + }) + + const update = (key: number, patch: Partial) => + setLayers((current) => + current.map((layer) => (layer.key === key ? { ...layer, ...patch } : layer)), + ) + const move = (index: number, by: -1 | 1) => + setLayers((current) => { + const target = index + by + if (target < 0 || target >= current.length) return current + const next = [...current] + ;[next[index], next[target]] = [next[target]!, next[index]!] + return next + }) + + const save = () => { + if (!(request && canSave)) return + const id = request.mode === 'edit' ? request.id : newWallTypeId() + const type: WallTypeDefinition = { + id, + label: trimmed.slice(0, 60), + assembly: draftAssembly(id, layers), + } + const result = runAsSingleSceneHistoryStep(useScene, () => { + const saved = saveProjectWallType(type) + if (saved === 'saved') onSaved(type) + return saved + }) + if (result !== 'saved') { + setFailure(result) + return + } + onClose() + } + + return ( + { + if (!open) onClose() + }} + open={request !== null} + > + + + + {request + ? i18n._(TITLE[request.mode]) + : i18n._({ + id: 'editor.buildPanel.wallTypeEditorDialog.wallType', + message: 'Wall type', + })} + + + {i18n._({ + id: 'editor.wallTypeEditorDialog.listTheLayersAppliedToThisWall', + message: + 'List the layers from the outside in, around one framing core. The type is saved with the project and applied to this wall; other walls keep their layers.', + })} + + + + + +
+
+ + {i18n._({ id: 'editor.buildPanel.wallTypeEditorDialog.layer', message: 'Layer' })} + + + {i18n._({ + id: 'editor.buildPanel.wallTypeEditorDialog.material', + message: 'Material', + })} + + + {i18n._({ + id: 'editor.buildPanel.wallTypeEditorDialog.thickness', + message: 'Thickness', + })} + + +
+
+ {i18n._({ id: 'editor.buildPanel.wallTypeEditorDialog.outside', message: 'Outside' })} +
+ {layers.map((layer, index) => ( +
+ {layer.role === 'core' ? ( + {i18n._(ROLE_LABEL.core)} + ) : ( + + )} + {layer.role === 'core' ? ( + + ) : ( + + )} + {layer.role === 'core' ? ( + + {formatLayerThickness(layer.thickness, unit)} + + ) : ( + update(layer.key, { thickness })} + unit={unit} + /> + )} +
+ + + +
+
+ ))} +
+ {i18n._({ id: 'editor.buildPanel.wallTypeEditorDialog.inside', message: 'Inside' })} +
+
+ + {i18n._({ id: 'editor.buildPanel.wallTypeEditorDialog.add', message: 'Add' })} + + {ADDABLE_ROLES.map((role) => ( + + ))} + {full ? ( + + {i18n._({ + id: 'editor.buildPanel.wallTypeEditorDialog.fullreasonRemoveOneToAddAnother', + message: '{fullReason} Remove one to add another.', + values: { fullReason }, + })} + + ) : null} +
+
+ +
+ + {i18n._({ + id: 'editor.buildPanel.wallTypeEditorDialog.totalThickness', + message: 'Total {thickness}', + values: { thickness: formatLayerThickness(total, unit) }, + })} + +
+ {failure ? ( +

{WALL_TYPE_SAVE_FAILURE[failure]}

+ ) : null} + + + + + +
+
+ ) +} diff --git a/packages/editor/src/components/ui/wall-type/wall-type-menu.tsx b/packages/editor/src/components/ui/wall-type/wall-type-menu.tsx new file mode 100644 index 0000000000..e76336268e --- /dev/null +++ b/packages/editor/src/components/ui/wall-type/wall-type-menu.tsx @@ -0,0 +1,167 @@ +'use client' + +import { + type Assembly, + getWallAssemblyPreset, + usePascalI18n, + type WallTypeDefinition, +} from '@pascal-app/core' +import { Copy, Pencil, Plus, Trash2 } from 'lucide-react' +import { useState } from 'react' +import { cn } from '../../../lib/utils' +import { + deleteProjectWallType, + newWallTypeBlockedReason, + useProjectWallTypes, + type WallTypePlacement, + wallTypePlacementOf, +} from '../../../lib/wall-type' +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '../primitives/dropdown-menu' +import { type WallTypeEditorRequest, WallTypeEditorDialog } from './wall-type-editor-dialog' + +/** + * A wall's project wall types, beside its Assembly preset: make a new type, edit the project + * type the wall is built with, duplicate its stack (a preset's, a project type's or its own + * custom layers) into a new type, or delete the project type. A type saved here is applied to + * the wall (`onApply`) in the same undo step. "New" and "Duplicate" are off, and say why, once + * the project keeps as many types as it can (`newWallTypeBlockedReason`). + */ +export function WallTypeMenu({ + assembly, + className, + onApply, + placement, +}: { + /** The wall's stack; absent for a plain single-layer wall. */ + assembly: Assembly | undefined + className?: string + onApply: (type: WallTypeDefinition) => void + /** The kind of wall a new type starts as when the wall has no stack to read it from. */ + placement: WallTypePlacement +}) { + const i18n = usePascalI18n() + const projectTypes = useProjectWallTypes() + const [editing, setEditing] = useState(null) + const presetId = assembly?.presetId + const project = presetId ? projectTypes.find((type) => type.id === presetId) : undefined + const preset = presetId ? getWallAssemblyPreset(presetId) : undefined + const label = + project?.label ?? + preset?.label ?? + (assembly + ? i18n._({ id: 'editor.wallTypeMenu.custom', message: 'Custom' }) + : i18n._({ id: 'editor.buildPanel.wallTypes.plainWall', message: 'Plain wall' })) + const blocked = newWallTypeBlockedReason(projectTypes) + const startPlacement = assembly ? wallTypePlacementOf(assembly) : placement + + return ( + <> + + + + + + + {label} + + + project && + setEditing({ + mode: 'edit', + placement: wallTypePlacementOf(project.assembly), + id: project.id, + label: project.label, + assembly: project.assembly, + }) + } + > + + {i18n._({ + id: 'editor.buildPanel.wallTypeControls.editLayers', + message: 'Edit layers…', + })} + + + assembly && + setEditing({ mode: 'duplicate', placement: startPlacement, label, assembly }) + } + > + + {i18n._({ + id: 'editor.buildPanel.wallTypeControls.duplicateAsANewType', + message: 'Duplicate as a new type…', + })} + + {project ? ( + deleteProjectWallType(project.id)} + variant="destructive" + > + + {i18n._({ + id: 'editor.buildPanel.wallTypeControls.deleteFromThisProject', + message: 'Delete from this project', + })} + + ) : null} + + setEditing({ mode: 'new', placement: startPlacement })} + > + + {i18n._({ + id: 'editor.buildPanel.wallTypeControls.newWallType', + message: 'New wall type…', + })} + + {blocked ? ( +

+ {blocked} +

+ ) : preset ? ( +

+ {i18n._({ + id: 'editor.buildPanel.wallTypeControls.presetsStayAsCitedDuplicateOne', + message: 'Presets stay as cited. Duplicate one to change its layers.', + })} +

+ ) : null} +
+
+ setEditing(null)} + onSaved={onApply} + request={editing} + /> + + ) +} diff --git a/packages/editor/src/hooks/use-keyboard.test.ts b/packages/editor/src/hooks/use-keyboard.test.ts index 606535ed82..5b88df1d2f 100644 --- a/packages/editor/src/hooks/use-keyboard.test.ts +++ b/packages/editor/src/hooks/use-keyboard.test.ts @@ -18,7 +18,9 @@ import { useSidebarStore } from '../components/ui/primitives/sidebar' import { runRedo, runUndo } from '../lib/history' import { meshEditScope } from '../lib/interaction/scope' import { setSidebarTabIds } from '../lib/sidebar-panel' -import useEditor from '../store/use-editor' +import { armToolShortcut, toolShortcutForKey, withToolShortcut } from '../lib/tool-shortcuts' +import { getWallDrawVariant, selectWallDrawVariant } from '../lib/wall-draw-variant' +import useEditor, { normalizePersistedEditorLayoutState } from '../store/use-editor' import useInteractionScope from '../store/use-interaction-scope' import { armPaintFromShortcut, @@ -164,6 +166,14 @@ describe('rotation shortcut ownership', () => { expect(isToolOwnedRotation()).toBe(true) }) + test('leaves R and T, and so Shift+R, to the stair and elevator placement tools', () => { + useEditor.getState().armToolMode({ mode: 'build', tool: 'stair' }) + expect(isToolOwnedRotation()).toBe(true) + + useEditor.getState().armToolMode({ mode: 'build', tool: 'elevator' }) + expect(isToolOwnedRotation()).toBe(true) + }) + test('does not reserve R for the wall tool: its shape is picked in the Build panel', () => { useEditor.getState().armToolMode({ mode: 'build', tool: 'wall' }) @@ -418,20 +428,35 @@ describe('B and P open their panel', () => { expect(useSidebarStore.getState().isCollapsed).toBe(false) }) - test('B arms the wall tool on Rectangle and shows the Build panel', () => { + test('B arms the wall tool on the Rooms shape picked last and shows the Build panel', () => { setSidebarTabIds(['site', 'build', 'paint', 'items']) useEditor.getState().setActiveSidebarPanel('items') useSidebarStore.getState().setIsCollapsed(true) - useEditor.getState().setContinuation('wall', 'single') + selectWallDrawVariant('walls') + useEditor.getState().armToolMode({ mode: 'select' }) armWallToolFromShortcut() const editor = useEditor.getState() expect(editor.mode).toBe('build') expect(editor.tool).toBe('wall') - expect(editor.getContinuation('wall')).toBe('rectangle') + expect(getWallDrawVariant()).toBe('walls') expect(editor.activeSidebarPanel).toBe('build') expect(useSidebarStore.getState().isCollapsed).toBe(false) + // The pick is a preference: it comes back with the saved editor layout. + expect( + normalizePersistedEditorLayoutState({ continuationByContext: { wall: 'single' } } as never) + .continuationByContext.wall, + ).toBe('single') + }) + + test('B draws a Rectangle until a Rooms shape is picked', () => { + expect(normalizePersistedEditorLayoutState({}).continuationByContext.wall).toBe('rectangle') + useEditor.setState({ + continuationByContext: normalizePersistedEditorLayoutState({}).continuationByContext, + }) + armWallToolFromShortcut() + expect(getWallDrawVariant()).toBe('rectangle') }) // A host may drop the armed tool when the panel changes (the community does, @@ -473,3 +498,59 @@ describe('B and P open their panel', () => { expect(useEditor.getState().activeSidebarPanel).toBe('build') }) }) + +describe('drafting tool shortcuts', () => { + const press = (code: string, mods: Partial = {}) => + toolShortcutForKey({ + code, + shiftKey: false, + metaKey: false, + ctrlKey: false, + altKey: false, + repeat: false, + ...mods, + }) + + afterEach(() => { + setSidebarTabIds([]) + useInteractionScope.getState().endIf(() => true) + useEditor.getState().setContinuation('wall', 'room') + useEditor.getState().armToolMode({ mode: 'select' }) + }) + + test('keep the bare keys they would collide with: pan, rotate and operate', () => { + expect(press('KeyD', { shiftKey: true })).toBe('door') + expect(press('KeyW', { shiftKey: true })).toBe('window') + expect(press('KeyS', { shiftKey: true })).toBe('stair') + expect(press('KeyR', { shiftKey: true })).toBe('roof') + expect(press('KeyE', { shiftKey: true })).toBeNull() + for (const code of ['KeyD', 'KeyW', 'KeyS', 'KeyR', 'KeyE', 'KeyI', 'KeyA']) + expect(press(code)).toBeNull() + expect(press('KeyD', { shiftKey: true, ctrlKey: true })).toBeNull() + expect(press('KeyD', { shiftKey: true, repeat: true })).toBeNull() + }) + + test('stand down while a gesture holds Shift', () => { + useInteractionScope.getState().begin({ kind: 'box-select' }) + expect(press('KeyD', { shiftKey: true })).toBeNull() + }) + + test('arm their tool with the Build panel showing, and name their key in tooltips', () => { + setSidebarTabIds(['build', 'items']) + useEditor.getState().setActiveSidebarPanel('items') + for (const [id, tool] of [ + ['door', 'door'], + ['window', 'window'], + ['stair', 'stair'], + ['roof', 'roof'], + ] as const) { + armToolShortcut(id) + expect(useEditor.getState().mode).toBe('build') + expect(useEditor.getState().tool).toBe(tool) + expect(useEditor.getState().activeSidebarPanel).toBe('build') + } + expect(withToolShortcut('Door', 'door')).toBe('Door (Shift+D)') + expect(withToolShortcut('Wall', 'wall')).toBe('Wall (B)') + expect(withToolShortcut('Fence', 'fence')).toBe('Fence') + }) +}) diff --git a/packages/editor/src/hooks/use-keyboard.ts b/packages/editor/src/hooks/use-keyboard.ts index a6b2cf9c19..cffc4d182a 100644 --- a/packages/editor/src/hooks/use-keyboard.ts +++ b/packages/editor/src/hooks/use-keyboard.ts @@ -34,12 +34,15 @@ import { isActive } from '../lib/interaction/scope' import { paintRegionModeActive } from '../lib/paint-region-mode' import { popRoomSelection } from '../lib/room-selection-commands' import { copySelectedNodesToEditorClipboard } from '../lib/scene-clipboard' +import { cycleSelectionAtPointer, trackSelectionCyclePointer } from '../lib/selection-cycle' import { sfxEmitter } from '../lib/sfx-bus' import { openSidebarPanel } from '../lib/sidebar-panel' import { activeSiteNode, clampBrushRadius } from '../lib/terrain-sculpt' +import { armToolShortcut, toolShortcutForKey } from '../lib/tool-shortcuts' import { isTypingTarget } from '../lib/typing-target' import { leaveUnitFocus } from '../lib/units' -import { selectWallDrawVariant } from '../lib/wall-draw-variant' +import { subscribeWallKindReset } from '../lib/wall-draw-variant' +import { isWallNudgeKey, nudgeSelectedWall } from '../lib/wall-nudge' import useDeleteConfirmation from '../store/use-delete-confirmation' import useEditor, { getActiveContinuationContext, getActiveSnapContext } from '../store/use-editor' import useInteractionScope, { @@ -49,6 +52,14 @@ import useInteractionScope, { import { groupCurrentSelection, ungroupCurrentSelection } from '../store/use-session-groups' import { activeViewLayout } from '../store/view-layout' +const pickKeyFields = (e: KeyboardEvent) => ({ + code: e.code, + shiftKey: e.shiftKey, + metaKey: e.metaKey, + ctrlKey: e.ctrlKey, + altKey: e.altKey, +}) + export function hasSceneKeyboardFocus(): boolean { const layout = activeViewLayout(useEditor.getState()) return isSceneView(layout.panes[layout.focus]) @@ -208,13 +219,12 @@ export const runHistoryShortcut = (direction: 'undo' | 'redo') => { } /** - * B: the wall tool on Rectangle — the quickest room — with the Build panel - * showing, so the lit tile says what is in hand. The panel's tiles still pick - * another shape for the session. The panel opens before the tool is armed: a - * host may drop the armed tool when the panel changes. + * B: the wall tool on the Rooms shape picked last (Rectangle, Polygon or Walls, + * kept with the editor preferences; Rectangle until one is picked), with the + * Build panel showing, so the lit tile says what is in hand. The panel opens + * before the tool is armed: a host may drop the armed tool when the panel changes. */ export const armWallToolFromShortcut = () => { - selectWallDrawVariant('rectangle') openSidebarPanel(['build']) useEditor.getState().armToolMode({ mode: 'build', tool: 'wall' }) } @@ -257,6 +267,8 @@ export const isToolOwnedRotation = () => { (editor.tool === 'door' || editor.tool === 'window' || editor.tool === 'roof' || + editor.tool === 'stair' || + editor.tool === 'elevator' || // The item tool is mounted for the build mode, but it only owns R/T // when a catalog item is actually selected and a placement draft can // exist. Without this check, selecting an existing item in the 2D plan @@ -312,6 +324,7 @@ export const useKeyboard = ({ if (disabled) { return } + trackSelectionCyclePointer() // True while an active placement tool owns R/T. Door/window tools flip the // draft, item / lean-to placement rotates its draft, and the roof tool turns @@ -467,6 +480,18 @@ export const useKeyboard = ({ } } + // Drafting tools on Shift with D / W / S / R, where the bare key pans or + // rotates (lib/tool-shortcuts). An armed placement keeps Shift+R as its own R. + const toolShortcut = isVersionPreviewMode + ? null + : toolShortcutForKey({ ...pickKeyFields(e), repeat: false }) + if (toolShortcut && !(toolShortcut === 'roof' && isToolOwnedRotation())) { + e.preventDefault() + // A held chord repeats: arm once, and never let a repeat fall through to bare R. + if (!e.repeat) armToolShortcut(toolShortcut) + return + } + if (e.key === 'Escape') { e.preventDefault() @@ -585,6 +610,31 @@ export const useKeyboard = ({ } } } + } else if (isWallNudgeKey(e.key) && !e.metaKey && !e.ctrlKey && !e.altKey && !e.shiftKey) { + // Bare arrows nudge a selected wall an inch in the floor plan. + const editor = useEditor.getState() + if ( + isVersionPreviewMode || + editor.mode !== 'select' || + useInteractionScope.getState().scope.kind !== 'idle' || + editor.isFirstPersonMode + ) { + return + } + if (nudgeSelectedWall(e.key)) e.preventDefault() + } else if (e.key === 'Tab' && !e.metaKey && !e.ctrlKey && !e.altKey) { + // Tab steps the selection to the next object under the pointer in the + // floor plan (Shift+Tab back): a wall hidden under another is reachable. + const editor = useEditor.getState() + if ( + isVersionPreviewMode || + editor.mode !== 'select' || + useInteractionScope.getState().scope.kind !== 'idle' || + editor.isFirstPersonMode + ) { + return + } + if (cycleSelectionAtPointer(e.shiftKey)) e.preventDefault() } else if ( (e.key === 'r' || e.key === 'R') && !e.metaKey && @@ -600,7 +650,7 @@ export const useKeyboard = ({ // open/close toggle lives on E. Windows still use R to toggle // their open/closed state. // - // Skipped while an item, door, window, or roof placement owns rotation. + // Skipped while a placement tool (item, door, window, roof, stair…) owns rotation. // The user can still have a node selected during placement; without this // guard both the draft and the selection would rotate. // @@ -847,7 +897,9 @@ export const useKeyboard = ({ window.addEventListener('keydown', handleSessionGroupKeyDown, true) window.addEventListener('keydown', handleKeyDown) window.addEventListener('keyup', handleKeyUp) + const unsubscribeWallKind = subscribeWallKindReset() return () => { + unsubscribeWallKind() window.removeEventListener('keydown', handleSessionGroupKeyDown, true) window.removeEventListener('keydown', handleKeyDown) window.removeEventListener('keyup', handleKeyUp) diff --git a/packages/editor/src/hooks/use-selected-room.ts b/packages/editor/src/hooks/use-selected-room.ts index 547772ac0f..f77fbca0eb 100644 --- a/packages/editor/src/hooks/use-selected-room.ts +++ b/packages/editor/src/hooks/use-selected-room.ts @@ -1,8 +1,9 @@ 'use client' -import { type AnyNode, type AnyNodeId, useScene } from '@pascal-app/core' +import { type AnyNode, type AnyNodeId, nodeRegistry, useScene } from '@pascal-app/core' import { useViewer } from '@pascal-app/viewer' import { useCallback, useSyncExternalStore } from 'react' +import { getFloorplanNodeExtension } from '../lib/floorplan/floorplan-extension' import { selectionEnabled } from '../lib/interaction/scope' import { type RoomKey, @@ -134,8 +135,18 @@ export function hoverRoomFromHit( return !!room } +/** + * The room a plan hit picks first. A kind whose plan extension declares + * `planHitSelectsNode` (a wall: a thin band between two rooms whose interiors + * are clickable in their own right) keeps the hit: picking a room by which + * half of the band the pointer landed on made thin partitions take several + * clicks. 3D keeps them room-first, where a room's floor is often hidden + * behind its walls. + */ export function resolvePlanRoomHit(nodeId: string | null, point: readonly [number, number]) { const node = nodeId ? useScene.getState().nodes[nodeId as AnyNodeId] : null + if (node && getFloorplanNodeExtension(nodeRegistry.get(node.type))?.planHitSelectsNode) + return null const levelId = node?.parentId ?? useViewer.getState().selection.levelId return levelId ? resolveEditorRoomHit(node ?? null, levelId, point, '2d') : null } diff --git a/packages/editor/src/i18n/locales/en-XA/messages.ts b/packages/editor/src/i18n/locales/en-XA/messages.ts index 3976829758..a034d15614 100644 --- a/packages/editor/src/i18n/locales/en-XA/messages.ts +++ b/packages/editor/src/i18n/locales/en-XA/messages.ts @@ -1 +1 @@ -/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"app.appShell.pascalHome\":[\"[Þášçáļ ĥöɱé ~~~]\"],\"app.buildTab.addGate\":[\"[Åðð Ĝáţé ~~~]\"],\"app.buildTab.addOpenPassage\":[\"[Åðð Öþéñ Þáššáĝé ~~~~~]\"],\"app.buildTab.addToRooms\":[\"[Åðð ţö ŕööɱš ~~~]\"],\"app.buildTab.allBuildTools\":[\"[← Åļļ ƀûîļð ţööļš ~~~~]\"],\"app.buildTab.chooseGateOrOpenPassageThen\":[\"[Çĥööšé Ĝáţé öŕ Öþéñ Þáššáĝé, ţĥéñ çļîçķ îţš þöšîţîöñ öñ áñý ƒéñçé. Ƒîñð þļáçéð ĝáţéš áñð öþéñîñĝš ûñðéŕ ţĥéîŕ ƒéñçé îñ ţĥé šçéñé ĝŕáþĥ. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"app.buildTab.clickALinesetToLayThe\":[\"[Çļîçķ á ļîñéšéţ ţö ļáý ţĥé ļîñé ƀéšîðé îţ. ~~~~~~~~~~]\"],\"app.buildTab.doubleGate\":[\"[Ðöûƀļé ĝáţé ~~~]\"],\"app.buildTab.featuresExtensions\":[\"[Ƒéáţûŕéš & éẋţéñšîöñš ~~~~~~]\"],\"app.buildTab.fenceFeatures\":[\"[Ƒéñçé ƒéáţûŕéš ~~~~]\"],\"app.buildTab.followLineset\":[\"[Ƒöļļöŵ ļîñéšéţ ~~~~]\"],\"app.buildTab.gate\":[\"[Ĝáţé ~~]\"],\"app.buildTab.gateStyle\":[\"[Ĝáţé šţýļé ~~~]\"],\"app.buildTab.horizontalBoards\":[\"[Ĥöŕîžöñţáļ ƀöáŕðš ~~~~~]\"],\"app.buildTab.hoverAFenceToPreviewClick\":[\"[Ĥöṽéŕ á ƒéñçé ţö þŕéṽîéŵ. Çļîçķ ţö þļáçé. Éšç çáñçéļš. Ļéáṽé ŕööɱ ƀéţŵééñ öþéñîñĝš. ~~~~~~~~~~~~~~~~~~~~]\"],\"app.buildTab.leaves\":[\"[Ļéáṽéš ~~]\"],\"app.buildTab.liquidLine\":[\"[Ļîǫûîð Ļîñé ~~~]\"],\"app.buildTab.matchFenceStyle\":[\"[Ṁáţçĥ ƒéñçé šţýļé ~~~~~]\"],\"app.buildTab.mep\":[\"[ṀÉÞ ~]\"],\"app.buildTab.off\":[\"[Öƒƒ ~]\"],\"app.buildTab.on\":[\"[Öñ ~]\"],\"app.buildTab.openRails\":[\"[Öþéñ ŕáîļš ~~~]\"],\"app.buildTab.opening\":[\"[Öþéñîñĝ ~~~]\"],\"app.buildTab.openingWidthM\":[\"[Öþéñîñĝ ŵîðţĥ (ɱ) ~~~~]\"],\"app.buildTab.outdoor\":[\"[Öûţðööŕ ~~~]\"],\"app.buildTab.picket\":[\"[Þîçķéţ ~~]\"],\"app.buildTab.roofType\":[\"[Ŕööƒ ţýþé ~~~]\"],\"app.buildTab.roomsAlreadyCreateTheirFloorAnd\":[\"[Ŕööɱš áļŕéáðý çŕéáţé ţĥéîŕ ƒļööŕ áñð çéîļîñĝ. Ûšé ţĥéšé ƒöŕ þļáţƒöŕɱš áñð öñé-öƒƒ šţŕûçţûŕé. ~~~~~~~~~~~~~~~~~~~~~~~]\"],\"app.buildTab.searchBuildToolsAndKitchenItems\":[\"[Šéáŕçĥ ƀûîļð ţööļš áñð ķîţçĥéñ îţéɱš ~~~~~~~~~~]\"],\"app.buildTab.searchToolsFridgeSink\":[\"[Šéáŕçĥ ţööļš, ƒŕîðĝé, šîñķ… ~~~~~~~]\"],\"app.buildTab.selectACurvedWallToMatch\":[\"[Šéļéçţ á çûŕṽéð ŵáļļ ţö ɱáţçĥ îţš ŕáðîûš áñð áŕç. ~~~~~~~~~~~~]\"],\"app.buildTab.singleGate\":[\"[Šîñĝļé ĝáţé ~~~]\"],\"app.buildTab.slabCeilingColumn\":[\"[Šļáƀ, çéîļîñĝ, çöļûɱñ… ~~~~~~]\"],\"app.buildTab.solidPrivacy\":[\"[Šöļîð þŕîṽáçý ~~~~]\"],\"app.buildTab.traceALineAlongsideAnExisting\":[\"[Ţŕáçé á ļîñé áļöñĝšîðé áñ éẋîšţîñĝ ļîñéšéţ (Ƒ). ~~~~~~~~~~~~]\"],\"app.buildTab.verticalSlats\":[\"[Ṽéŕţîçáļ šļáţš ~~~~]\"],\"app.editorNavbar.allProjects\":[\"[Åļļ þŕöĵéçţš ~~~~]\"],\"app.editorNavbar.preview\":[\"[Þŕéṽîéŵ ~~~]\"],\"app.editorNavbar.projectName\":[\"[Þŕöĵéçţ ñáɱé ~~~~]\"],\"app.editorNavbar.renameProject\":[\"[Ŕéñáɱé þŕöĵéçţ ~~~~]\"],\"app.editorNavbar.share\":[\"[Šĥáŕé ~~]\"],\"app.kitchenBrowser.addLabel\":[\"[Åðð \",[\"label\"],\" ~]\"],\"app.kitchenBrowser.addToKitchen\":[\"[Åðð ţö ķîţçĥéñ ~~~~]\"],\"app.kitchenBrowser.chooseAnItemThenClickTo\":[\"[Çĥööšé áñ îţéɱ, ţĥéñ çļîçķ ţö þļáçé îţ. Åþþļîáñçéš îñçļûðé ţĥéîŕ çáƀîñéţŕý. ~~~~~~~~~~~~~~~~~~~]\"],\"app.kitchenBrowser.findInThisProjectLength\":[\"[Ƒîñð îñ ţĥîš þŕöĵéçţ · \",[\"length\"],\" ~~~~~~]\"],\"app.kitchenBrowser.findName\":[\"[Ƒîñð \",[\"name\"],\" ~~]\"],\"app.kitchenBrowser.groupAdd\":[\"[Ķîţçĥéñ · Åðð ~~~]\"],\"app.kitchenBrowser.groupInThisProject\":[\"[Ķîţçĥéñ · Îñ ţĥîš þŕöĵéçţ ~~~~~~]\"],\"app.kitchenBrowser.kitchenCabinet\":[\"[Ķîţçĥéñ çáƀîñéţ ~~~~~]\"],\"app.kitchenBrowser.noMatchingKitchenItemsPlacedYet\":[\"[Ñö ɱáţçĥîñĝ ķîţçĥéñ îţéɱš þļáçéð ýéţ. ~~~~~~~~~~]\"],\"app.kitchenBrowser.selectAndShowInScene\":[\"[Šéļéçţ áñð šĥöŵ îñ šçéñé ~~~~~~]\"],\"app.lib.buildPalette.ceiling\":[\"[Çéîļîñĝ ~~~]\"],\"app.lib.buildPalette.column\":[\"[Çöļûɱñ ~~]\"],\"app.lib.buildPalette.door\":[\"[Ðööŕ ~~]\"],\"app.lib.buildPalette.duct\":[\"[Ðûçţ ~~]\"],\"app.lib.buildPalette.dwvPipe\":[\"[ÐŴṼ Þîþé ~~~]\"],\"app.lib.buildPalette.elevator\":[\"[Éļéṽáţöŕ ~~~]\"],\"app.lib.buildPalette.fence\":[\"[Ƒéñçé ~~]\"],\"app.lib.buildPalette.hvacUnit\":[\"[ĤṼÅÇ Ûñîţ ~~~]\"],\"app.lib.buildPalette.kitchen\":[\"[Ķîţçĥéñ ~~~]\"],\"app.lib.buildPalette.lineset\":[\"[Ļîñéšéţ ~~~]\"],\"app.lib.buildPalette.liquidLine\":[\"[Ļîǫûîð Ļîñé ~~~]\"],\"app.lib.buildPalette.mep\":[\"[ṀÉÞ ~]\"],\"app.lib.buildPalette.register\":[\"[Ŕéĝîšţéŕ ~~~]\"],\"app.lib.buildPalette.roof\":[\"[Ŕööƒ ~~]\"],\"app.lib.buildPalette.shelf\":[\"[Šĥéļƒ ~~]\"],\"app.lib.buildPalette.slab\":[\"[Šļáƀ ~~]\"],\"app.lib.buildPalette.spawnPoint\":[\"[Šþáŵñ þöîñţ ~~~]\"],\"app.lib.buildPalette.stairs\":[\"[Šţáîŕš ~~]\"],\"app.lib.buildPalette.terrace\":[\"[Ţéŕŕáçé ~~~]\"],\"app.lib.buildPalette.terrain\":[\"[Ţéŕŕáîñ ~~~]\"],\"app.lib.buildPalette.wall\":[\"[Ŵáļļ ~~]\"],\"app.lib.buildPalette.window\":[\"[Ŵîñðöŵ ~~]\"],\"app.lib.buildPanelModel.addFitting\":[\"[Åðð Ƒîţţîñĝ ~~~]\"],\"app.lib.buildPanelModel.addGate\":[\"[Åðð Ĝáţé ~~~]\"],\"app.lib.buildPanelModel.addOpenPassage\":[\"[Åðð Öþéñ Þáššáĝé ~~~~~]\"],\"app.lib.buildPanelModel.addTrap\":[\"[Åðð Ţŕáþ ~~~]\"],\"app.lib.buildPanelModel.build\":[\"[Ɓûîļð ~~]\"],\"app.lib.buildPanelModel.createFrom\":[\"[Çŕéáţé ƒŕöɱ ~~~]\"],\"app.lib.buildPanelModel.drawTheRoofFootprintWithTwo\":[\"[Ðŕáŵ ţĥé ŕööƒ ƒööţþŕîñţ ŵîţĥ ţŵö çöŕñéŕ çļîçķš. ~~~~~~~~~~~~]\"],\"app.lib.buildPanelModel.duct\":[\"[Ðûçţ ~~]\"],\"app.lib.buildPanelModel.dwvPipe\":[\"[ÐŴṼ Þîþé ~~~]\"],\"app.lib.buildPanelModel.featuresExtensions\":[\"[Ƒéáţûŕéš & éẋţéñšîöñš ~~~~~~]\"],\"app.lib.buildPanelModel.fence\":[\"[Ƒéñçé ~~]\"],\"app.lib.buildPanelModel.followLineset\":[\"[Ƒöļļöŵ ļîñéšéţ ~~~~]\"],\"app.lib.buildPanelModel.gatesOpenings\":[\"[Ĝáţéš & öþéñîñĝš ~~~~]\"],\"app.lib.buildPanelModel.hoverARoomToPreviewIts\":[\"[Ĥöṽéŕ á ŕööɱ ţö þŕéṽîéŵ îţš ƀöûñðáŕý, ţĥéñ çļîçķ ţö þļáçé. ~~~~~~~~~~~~~~]\"],\"app.lib.buildPanelModel.kitchen\":[\"[Ķîţçĥéñ ~~~]\"],\"app.lib.buildPanelModel.mep\":[\"[ṀÉÞ ~]\"],\"app.lib.buildPanelModel.modularCabinet\":[\"[Ṁöðûļáŕ Çáƀîñéţ ~~~~~]\"],\"app.lib.buildPanelModel.off\":[\"[Öƒƒ ~]\"],\"app.lib.buildPanelModel.on\":[\"[Öñ ~]\"],\"app.lib.buildPanelModel.painting\":[\"[Þáîñţîñĝ ~~~]\"],\"app.lib.buildPanelModel.roof\":[\"[Ŕööƒ ~~]\"],\"app.lib.buildPanelModel.roofType\":[\"[Ŕööƒ ţýþé ~~~]\"],\"app.lib.buildPanelModel.toolCount\":[\"[\",[\"count\",\"plural\",{\"one\":[\"#\",\" ţööļ\"],\"other\":[\"#\",\" ţööļš\"]}],\" ~~~]\"],\"app.lib.buildTabState.conical\":[\"[Çöñîçáļ ~~~]\"],\"app.lib.buildTabState.draw\":[\"[Ðŕáŵ ~~]\"],\"app.lib.buildTabState.dutch\":[\"[Ðûţçĥ ~~]\"],\"app.lib.buildTabState.flat\":[\"[Ƒļáţ ~~]\"],\"app.lib.buildTabState.gable\":[\"[Ĝáƀļé ~~]\"],\"app.lib.buildTabState.gambrel\":[\"[Ĝáɱƀŕéļ ~~~]\"],\"app.lib.buildTabState.hip\":[\"[Ĥîþ ~]\"],\"app.lib.buildTabState.mansard\":[\"[Ṁáñšáŕð ~~~]\"],\"app.lib.buildTabState.room\":[\"[Ŕööɱ ~~]\"],\"app.lib.buildTabState.shed\":[\"[Šĥéð ~~]\"],\"app.lib.buildTabState.wall\":[\"[Ŵáļļ ~~]\"],\"app.sceneLoader.anotherSessionSavedFirstRefresh\":[\"[Åñöţĥéŕ šéššîöñ šáṽéð ƒîŕšţ — ŕéƒŕéšĥ? ~~~~~~~~~~]\"],\"app.sceneLoader.build\":[\"[Ɓûîļð ~~]\"],\"app.sceneLoader.dismiss\":[\"[Ðîšɱîšš ~~~]\"],\"app.sceneLoader.items\":[\"[Îţéɱš ~~]\"],\"app.sceneLoader.paint\":[\"[Þáîñţ ~~]\"],\"app.sceneLoader.reload\":[\"[Ŕéļöáð ~~]\"],\"app.sceneLoader.scene\":[\"[Šçéñé ~~]\"],\"app.sceneLoader.settings\":[\"[Šéţţîñĝš ~~~]\"],\"app.sceneLoader.yourChangesHavenTBeenSaved\":[\"[Ýöûŕ çĥáñĝéš ĥáṽéñ'ţ ƀééñ šáṽéð. Ŕéļöáð ţö þîçķ ûþ ţĥé ļáţéšţ ṽéŕšîöñ. ~~~~~~~~~~~~~~~~~]\"],\"app.sharePanel.anyoneWithTheLinkCanView\":[\"[Åñýöñé ŵîţĥ ţĥé ļîñķ çáñ ṽîéŵ ţĥîš þŕöĵéçţ. Ţĥéý çáññöţ éðîţ îţ. ~~~~~~~~~~~~~~~~]\"],\"app.sharePanel.copied\":[\"[Çöþîéð ~~]\"],\"app.sharePanel.copy\":[\"[Çöþý ~~]\"],\"app.sharePanel.couldNotReadTheSharingState\":[\"[Çöûļð ñöţ ŕéáð ţĥé šĥáŕîñĝ šţáţé. ~~~~~~~~~]\"],\"app.sharePanel.couldNotTurnOffThePublic\":[\"[Çöûļð ñöţ ţûŕñ öƒƒ ţĥé þûƀļîç ļîñķ. ~~~~~~~~~]\"],\"app.sharePanel.couldNotTurnOnThePublic\":[\"[Çöûļð ñöţ ţûŕñ öñ ţĥé þûƀļîç ļîñķ. ~~~~~~~~~]\"],\"app.sharePanel.embedCode\":[\"[Éɱƀéð çöðé ~~~]\"],\"app.sharePanel.embedLink\":[\"[Éɱƀéð ļîñķ ~~~]\"],\"app.sharePanel.hideControls\":[\"[Ĥîðé çöñţŕöļš ~~~~]\"],\"app.sharePanel.link\":[\"[Ļîñķ ~~]\"],\"app.sharePanel.onlyThe3dViewNoHeader\":[\"[Öñļý ţĥé 3Ð ṽîéŵ, ñö ĥéáðéŕ öŕ ţööļƀáŕ. ~~~~~~~~~]\"],\"app.sharePanel.open\":[\"[Öþéñ ~~]\"],\"app.sharePanel.publicLink\":[\"[Þûƀļîç ļîñķ ~~~]\"],\"app.sharePanel.shareProject\":[\"[Šĥáŕé þŕöĵéçţ ~~~~]\"],\"app.viewerToolbar.automaticDimensions\":[\"[Åûţöɱáţîç ðîɱéñšîöñš ~~~~~~]\"],\"app.viewerToolbar.camera\":[\"[Çáɱéŕá ~~]\"],\"app.viewerToolbar.cleanPlanDimensionsAppearWithSelection\":[\"[Çļéáñ þļáñ; ðîɱéñšîöñš áþþéáŕ ŵîţĥ šéļéçţîöñ ~~~~~~~~~~~~]\"],\"app.viewerToolbar.collapseSidebar\":[\"[Çöļļáþšé šîðéƀáŕ ~~~~~]\"],\"app.viewerToolbar.crispOpaqueEdgeLines\":[\"[Çŕîšþ, öþáǫûé éðĝé ļîñéš ~~~~~~]\"],\"app.viewerToolbar.cutaway\":[\"[Çûţáŵáý ~~~]\"],\"app.viewerToolbar.default\":[\"[Ðéƒáûļţ ~~~]\"],\"app.viewerToolbar.display\":[\"[Ðîšþļáý ~~~]\"],\"app.viewerToolbar.displaySettings\":[\"[Ðîšþļáý šéţţîñĝš ~~~~~]\"],\"app.viewerToolbar.doorWindowMarks\":[\"[Ðööŕ/ŵîñðöŵ ɱáŕķš ~~~~~]\"],\"app.viewerToolbar.edges\":[\"[Éðĝéš ~~]\"],\"app.viewerToolbar.enterVr\":[\"[Éñţéŕ ṼŔ ~~~]\"],\"app.viewerToolbar.exitVr\":[\"[Éẋîţ ṼŔ ~~]\"],\"app.viewerToolbar.expandSidebar\":[\"[Éẋþáñð šîðéƀáŕ ~~~~]\"],\"app.viewerToolbar.expert\":[\"[Éẋþéŕţ ~~]\"],\"app.viewerToolbar.exploded\":[\"[Éẋþļöðéð ~~~]\"],\"app.viewerToolbar.faceOfStud\":[\"[Ƒáçé öƒ šţûð ~~~]\"],\"app.viewerToolbar.faintOutlineOfMajorCreases\":[\"[Ƒáîñţ öûţļîñé öƒ ɱáĵöŕ çŕéášéš ~~~~~~~~]\"],\"app.viewerToolbar.feetInches\":[\"[Ƒééţ & îñçĥéš ~~~]\"],\"app.viewerToolbar.finishedFaces\":[\"[Ƒîñîšĥéð ƒáçéš ~~~~]\"],\"app.viewerToolbar.flatAndFastNoAmbientOcclusion\":[\"[Ƒļáţ áñð ƒášţ — ñö áɱƀîéñţ öççļûšîöñ ~~~~~~~~~]\"],\"app.viewerToolbar.floorPlanAnnotations\":[\"[Ƒļööŕ þļáñ áññöţáţîöñš ~~~~~~]\"],\"app.viewerToolbar.floorPlanMode\":[\"[Ƒļööŕ þļáñ ɱöðé ~~~~]\"],\"app.viewerToolbar.fullAmbientOcclusion\":[\"[Ƒûļļ áɱƀîéñţ öççļûšîöñ ~~~~~~]\"],\"app.viewerToolbar.fullDocumentationAndAnnotationControls\":[\"[Ƒûļļ ðöçûɱéñţáţîöñ áñð áññöţáţîöñ çöñţŕöļš ~~~~~~~~~~~~]\"],\"app.viewerToolbar.fullHeight\":[\"[Ƒûļļ ĥéîĝĥţ ~~~]\"],\"app.viewerToolbar.fullWallThickness\":[\"[Ƒûļļ ŵáļļ ţĥîçķñéšš ~~~~~~]\"],\"app.viewerToolbar.grid\":[\"[Ĝŕîð ~~]\"],\"app.viewerToolbar.levelsMode\":[\"[Ļéṽéļš: \",[\"mode\"],\" ~~]\"],\"app.viewerToolbar.low\":[\"[Ļöŵ ~]\"],\"app.viewerToolbar.magneticSnap\":[\"[Ṁáĝñéţîç šñáþ ~~~~]\"],\"app.viewerToolbar.manual\":[\"[Ṁáñûáļ ~~]\"],\"app.viewerToolbar.manualDimensions\":[\"[Ṁáñûáļ ðîɱéñšîöñš ~~~~~]\"],\"app.viewerToolbar.measurements\":[\"[Ṁéášûŕéɱéñţš ~~~~]\"],\"app.viewerToolbar.meters\":[\"[Ṁéţéŕš ~~]\"],\"app.viewerToolbar.millimeters\":[\"[Ṁîļļîɱéţéŕš ~~~~]\"],\"app.viewerToolbar.n3dMeasurements\":[\"[3Ð ɱéášûŕéɱéñţš ~~~~]\"],\"app.viewerToolbar.noEdgeLines\":[\"[Ñö éðĝé ļîñéš ~~~~]\"],\"app.viewerToolbar.off\":[\"[Öƒƒ ~]\"],\"app.viewerToolbar.on\":[\"[Öñ ~]\"],\"app.viewerToolbar.orthographic\":[\"[Öŕţĥöĝŕáþĥîç ~~~~]\"],\"app.viewerToolbar.perspective\":[\"[Þéŕšþéçţîṽé ~~~~]\"],\"app.viewerToolbar.preview\":[\"[Þŕéṽîéŵ ~~~]\"],\"app.viewerToolbar.previewMode\":[\"[Þŕéṽîéŵ ɱöðé ~~~~]\"],\"app.viewerToolbar.render\":[\"[Ŕéñðéŕ ~~]\"],\"app.viewerToolbar.rendered\":[\"[Ŕéñðéŕéð ~~~]\"],\"app.viewerToolbar.roomLabels\":[\"[Ŕööɱ ļáƀéļš ~~~]\"],\"app.viewerToolbar.sceneTheme\":[\"[Šçéñé ţĥéɱé ~~~]\"],\"app.viewerToolbar.shadows\":[\"[Šĥáðöŵš ~~~]\"],\"app.viewerToolbar.singleWallAxis\":[\"[Šîñĝļé ŵáļļ áẋîš ~~~~~]\"],\"app.viewerToolbar.soft\":[\"[Šöƒţ ~~]\"],\"app.viewerToolbar.solid\":[\"[Šöļîð ~~]\"],\"app.viewerToolbar.solo\":[\"[Šöļö ~~]\"],\"app.viewerToolbar.stack\":[\"[Šţáçķ ~~]\"],\"app.viewerToolbar.stairAnnotations\":[\"[Šţáîŕ áññöţáţîöñš ~~~~~]\"],\"app.viewerToolbar.strong\":[\"[Šţŕöñĝ ~~]\"],\"app.viewerToolbar.structuralCoreFace\":[\"[Šţŕûçţûŕáļ çöŕé ƒáçé ~~~~~~]\"],\"app.viewerToolbar.structuralGridsColumnCenters\":[\"[Šţŕûçţûŕáļ ĝŕîðš & çöļûɱñ çéñţéŕš ~~~~~~~~~]\"],\"app.viewerToolbar.translucent\":[\"[Ţŕáñšļûçéñţ ~~~~]\"],\"app.viewerToolbar.units\":[\"[Ûñîţš ~~]\"],\"app.viewerToolbar.walkthrough\":[\"[Ŵáļķţĥŕöûĝĥ ~~~~]\"],\"app.viewerToolbar.wallCenterline\":[\"[Ŵáļļ çéñţéŕļîñé ~~~~~]\"],\"app.viewerToolbar.wallDimensions\":[\"[Ŵáļļ ðîɱéñšîöñš ~~~~~]\"],\"app.viewerToolbar.wallsLabel\":[\"[Ŵáļļš: \",[\"label\"],\" ~~]\"],\"core.level.basement\":[\"[Ɓášéɱéñţ ~~~]\"],\"core.level.basementNumber\":[\"[Ɓášéɱéñţ \",[\"number\"],\" ~~~]\"],\"core.level.floorNumber\":[\"[Ƒļööŕ \",[\"number\"],\" ~~]\"],\"core.level.groundFloor\":[\"[Ĝŕöûñð ƒļööŕ ~~~~]\"],\"editor.actionMenu.cameraActions.orbitLeft\":[\"[Öŕƀîţ Ļéƒţ ~~~]\"],\"editor.actionMenu.cameraActions.orbitRight\":[\"[Öŕƀîţ Ŕîĝĥţ ~~~]\"],\"editor.actionMenu.cameraActions.topView\":[\"[Ţöþ Ṽîéŵ ~~~]\"],\"editor.actionMenu.controlModes.delete\":[\"[Ðéļéţé ~~]\"],\"editor.actionMenu.controlModes.select\":[\"[Šéļéçţ ~~]\"],\"editor.actionMenu.followPascalPill.resumeFollowing\":[\"[Ŕéšûɱé ƒöļļöŵîñĝ ~~~~~]\"],\"editor.actionMenu.followPascalToggle.off\":[\"[Ƒöļļöŵ Þášçáļ: Öƒƒ ~~~~~]\"],\"editor.actionMenu.followPascalToggle.on\":[\"[Ƒöļļöŵ Þášçáļ: Öñ ~~~~~]\"],\"editor.actionMenu.furnishTools.appliance\":[\"[Åþþļîáñçé ~~~]\"],\"editor.actionMenu.furnishTools.bathroom\":[\"[Ɓáţĥŕööɱ ~~~]\"],\"editor.actionMenu.furnishTools.furniture\":[\"[Ƒûŕñîţûŕé ~~~]\"],\"editor.actionMenu.furnishTools.kitchen\":[\"[Ķîţçĥéñ ~~~]\"],\"editor.actionMenu.furnishTools.outdoor\":[\"[Öûţðööŕ ~~~]\"],\"editor.actionMenu.measurementControl.angle\":[\"[Åñĝļé ~~]\"],\"editor.actionMenu.measurementControl.angularDimension\":[\"[Åñĝûļáŕ ðîɱéñšîöñ ~~~~~]\"],\"editor.actionMenu.measurementControl.arcLength\":[\"[Åŕç ļéñĝţĥ ~~~]\"],\"editor.actionMenu.measurementControl.area\":[\"[Åŕéá ~~]\"],\"editor.actionMenu.measurementControl.centerMark\":[\"[Çéñţéŕ ɱáŕķ ~~~]\"],\"editor.actionMenu.measurementControl.chordDimension\":[\"[Çĥöŕð ðîɱéñšîöñ ~~~~~]\"],\"editor.actionMenu.measurementControl.continuousDimension\":[\"[Çöñţîñûöûš ðîɱéñšîöñ ~~~~~~]\"],\"editor.actionMenu.measurementControl.coordinateDimensions\":[\"[Çööŕðîñáţé ðîɱéñšîöñš ~~~~~~]\"],\"editor.actionMenu.measurementControl.diameterDimension\":[\"[Ðîáɱéţéŕ ðîɱéñšîöñ ~~~~~~]\"],\"editor.actionMenu.measurementControl.distance\":[\"[Ðîšţáñçé ~~~]\"],\"editor.actionMenu.measurementControl.floorPlan\":[\"[Ƒļööŕ þļáñ ~~~]\"],\"editor.actionMenu.measurementControl.linearDimension\":[\"[Ļîñéáŕ ðîɱéñšîöñ ~~~~~]\"],\"editor.actionMenu.measurementControl.measureSelectedlabel\":[\"[Ṁéášûŕé: \",[\"selectedLabel\"],\" ~~~]\"],\"editor.actionMenu.measurementControl.measurementOptions\":[\"[Ṁéášûŕéɱéñţ öþţîöñš ~~~~~~]\"],\"editor.actionMenu.measurementControl.measurementType\":[\"[Ṁéášûŕéɱéñţ ţýþé ~~~~~]\"],\"editor.actionMenu.measurementControl.perimeter\":[\"[Þéŕîɱéţéŕ ~~~]\"],\"editor.actionMenu.measurementControl.radiusDimension\":[\"[Ŕáðîûš ðîɱéñšîöñ ~~~~~]\"],\"editor.actionMenu.measurementControl.smart\":[\"[Šɱáŕţ ~~]\"],\"editor.actionMenu.measurementControl.volume\":[\"[Ṽöļûɱé ~~]\"],\"editor.actionMenu.pointAskButton.pointAndAsk\":[\"[Þöîñţ áñð ášķ ~~~~]\"],\"editor.actionMenu.pointAskButton.pointAndAskC\":[\"[Þöîñţ áñð ášķ (Ç) ~~~~]\"],\"editor.actionMenu.pointAskButton.pointAndAskWorksInThe\":[\"[Þöîñţ áñð ášķ ŵöŕķš îñ ţĥé 3Ð ṽîéŵ ~~~~~~~~]\"],\"editor.actionMenu.structureTools.ceiling\":[\"[Çéîļîñĝ ~~~]\"],\"editor.actionMenu.structureTools.column\":[\"[Çöļûɱñ ~~]\"],\"editor.actionMenu.structureTools.door\":[\"[Ðööŕ ~~]\"],\"editor.actionMenu.structureTools.duct\":[\"[Ðûçţ ~~]\"],\"editor.actionMenu.structureTools.ductFitting\":[\"[Ðûçţ Ƒîţţîñĝ ~~~~]\"],\"editor.actionMenu.structureTools.dwvPipe\":[\"[ÐŴṼ Þîþé ~~~]\"],\"editor.actionMenu.structureTools.elevator\":[\"[Éļéṽáţöŕ ~~~]\"],\"editor.actionMenu.structureTools.fence\":[\"[Ƒéñçé ~~]\"],\"editor.actionMenu.structureTools.gableRoof\":[\"[Ĝáƀļé Ŕööƒ ~~~]\"],\"editor.actionMenu.structureTools.hvacUnit\":[\"[ĤṼÅÇ Ûñîţ ~~~]\"],\"editor.actionMenu.structureTools.lineset\":[\"[Ļîñéšéţ ~~~]\"],\"editor.actionMenu.structureTools.liquidLine\":[\"[Ļîǫûîð Ļîñé ~~~]\"],\"editor.actionMenu.structureTools.pipeFitting\":[\"[Þîþé Ƒîţţîñĝ ~~~~]\"],\"editor.actionMenu.structureTools.register\":[\"[Ŕéĝîšţéŕ ~~~]\"],\"editor.actionMenu.structureTools.shelf\":[\"[Šĥéļƒ ~~]\"],\"editor.actionMenu.structureTools.slab\":[\"[Šļáƀ ~~]\"],\"editor.actionMenu.structureTools.spawnPoint\":[\"[Šþáŵñ Þöîñţ ~~~]\"],\"editor.actionMenu.structureTools.stairs\":[\"[Šţáîŕš ~~]\"],\"editor.actionMenu.structureTools.trap\":[\"[Ţŕáþ ~~]\"],\"editor.actionMenu.structureTools.wall\":[\"[Ŵáļļ ~~]\"],\"editor.actionMenu.structureTools.window\":[\"[Ŵîñðöŵ ~~]\"],\"editor.actionMenu.structureTools.zone\":[\"[Žöñé ~~]\"],\"editor.actionMenu.viewToggles.deleteGuideImage\":[\"[Ðéļéţé ĝûîðé îɱáĝé ~~~~~]\"],\"editor.actionMenu.viewToggles.deleteScan\":[\"[Ðéļéţé šçáñ ~~~]\"],\"editor.actionMenu.viewToggles.guideCount\":[\"[\",[\"count\",\"plural\",{\"one\":[\"#\",\" ĝûîðé îɱáĝé öñ ţĥîš ļéṽéļ\"],\"other\":[\"#\",\" ĝûîðé îɱáĝéš öñ ţĥîš ļéṽéļ\"]}],\" ~~~~~~~~~~~~~]\"],\"editor.actionMenu.viewToggles.guideImageNumber\":[\"[Ĝûîðé îɱáĝé \",[\"number\"],\" ~~~]\"],\"editor.actionMenu.viewToggles.guideImageSettings\":[\"[Ĝûîðé îɱáĝé šéţţîñĝš ~~~~~~]\"],\"editor.actionMenu.viewToggles.guideImages\":[\"[Ĝûîðé îɱáĝéš ~~~~]\"],\"editor.actionMenu.viewToggles.guides\":[\"[Ĝûîðéš ~~]\"],\"editor.actionMenu.viewToggles.guidesHidden\":[\"[Ĝûîðéš: Ĥîððéñ ~~~~]\"],\"editor.actionMenu.viewToggles.guidesVisible\":[\"[Ĝûîðéš: Ṽîšîƀļé ~~~~]\"],\"editor.actionMenu.viewToggles.hideGuideImages\":[\"[Ĥîðé ĝûîðé îɱáĝéš ~~~~~]\"],\"editor.actionMenu.viewToggles.hideReferenceFloor\":[\"[Ĥîðé ŕéƒéŕéñçé ƒļööŕ ~~~~~~]\"],\"editor.actionMenu.viewToggles.hideScans\":[\"[Ĥîðé šçáñš ~~~]\"],\"editor.actionMenu.viewToggles.levelsBelow\":[\"[\",[\"count\"],\" ƀéļöŵ ~~]\"],\"editor.actionMenu.viewToggles.noLowerFloorAvailable\":[\"[Ñö ļöŵéŕ ƒļööŕ áṽáîļáƀļé. ~~~~~~~]\"],\"editor.actionMenu.viewToggles.opacity\":[\"[Öþáçîţý ~~~]\"],\"editor.actionMenu.viewToggles.referenceFloor\":[\"[Ŕéƒéŕéñçé ƒļööŕ ~~~~~]\"],\"editor.actionMenu.viewToggles.referenceFloorSelectedlevelname\":[\"[Ŕéƒéŕéñçé ƒļööŕ: \",[\"selectedLevelName\"],\" ~~~~~]\"],\"editor.actionMenu.viewToggles.referenceFloorSettings\":[\"[Ŕéƒéŕéñçé ƒļööŕ šéţţîñĝš ~~~~~~~]\"],\"editor.actionMenu.viewToggles.referenceSettings\":[\"[Ŕéƒéŕéñçé šéţţîñĝš ~~~~~~]\"],\"editor.actionMenu.viewToggles.references\":[\"[Ŕéƒéŕéñçéš ~~~]\"],\"editor.actionMenu.viewToggles.referencesEmpty\":[\"[Ûþļöáð ĜĻƁ ɱéšĥéš áš šçáñ ŕéƒéŕéñçéš öŕ ƀļûéþŕîñţ îɱáĝéš áš ĝûîðé ŕéƒéŕéñçéš. ~~~~~~~~~~~~~~~~~~~~]\"],\"editor.actionMenu.viewToggles.referencesHidden\":[\"[Ŕéƒéŕéñçéš: Ĥîððéñ ~~~~~]\"],\"editor.actionMenu.viewToggles.referencesVisible\":[\"[Ŕéƒéŕéñçéš: Ṽîšîƀļé ~~~~~~]\"],\"editor.actionMenu.viewToggles.riserDiagram\":[\"[Ŕîšéŕ ðîáĝŕáɱ ~~~~]\"],\"editor.actionMenu.viewToggles.scanCount\":[\"[\",[\"count\",\"plural\",{\"one\":[\"#\",\" šçáñ öñ ţĥîš ļéṽéļ\"],\"other\":[\"#\",\" šçáñš öñ ţĥîš ļéṽéļ\"]}],\" ~~~~~~~~~~]\"],\"editor.actionMenu.viewToggles.scanNumber\":[\"[Šçáñ \",[\"number\"],\" ~~]\"],\"editor.actionMenu.viewToggles.scanSettings\":[\"[Šçáñ šéţţîñĝš ~~~~]\"],\"editor.actionMenu.viewToggles.scans\":[\"[Šçáñš ~~]\"],\"editor.actionMenu.viewToggles.scansHidden\":[\"[Šçáñš: Ĥîððéñ ~~~~]\"],\"editor.actionMenu.viewToggles.scansVisible\":[\"[Šçáñš: Ṽîšîƀļé ~~~~]\"],\"editor.actionMenu.viewToggles.showGuideImages\":[\"[Šĥöŵ ĝûîðé îɱáĝéš ~~~~~]\"],\"editor.actionMenu.viewToggles.showReferenceFloor\":[\"[Šĥöŵ ŕéƒéŕéñçé ƒļööŕ ~~~~~~]\"],\"editor.actionMenu.viewToggles.showScans\":[\"[Šĥöŵ šçáñš ~~~]\"],\"editor.actionMenu.viewToggles.uploadScanOrGuideImage\":[\"[Ûþļöáð šçáñ öŕ ĝûîðé îɱáĝé ~~~~~~~]\"],\"editor.backToHome\":[\"[Ɓáçķ ţö ĥöɱé ~~~]\"],\"editor.buildPanel.advanced\":[\"[Åðṽáñçéð ~~~]\"],\"editor.buildPanel.rooms.hint\":[\"[ŵáļļš · ƒļööŕ · çéîļîñĝ ~~~~~~]\"],\"editor.buildPanel.rooms.idle\":[\"[Þîçķ á šĥáþé ţö šţáŕţ. Éṽéŕý ŕööɱ ƀŕîñĝš îţš öŵñ ŵáļļš, ƒļööŕ áñð çéîļîñĝ. ~~~~~~~~~~~~~~~~~~]\"],\"editor.buildPanel.rooms.polygon.caption\":[\"[\",[\"lead\"],\" ţĥéñ ţĥé ƒîŕšţ öñé áĝáîñ ţö çļöšé. Ƒöŕ Ļ-šĥáþéš áñð áñĝļéð ŕööɱš. ~~~~~~~~~~~~~~~~]\"],\"editor.buildPanel.rooms.polygon.label\":[\"[Þöļýĝöñ ~~~]\"],\"editor.buildPanel.rooms.polygon.lead\":[\"[Çļîçķ éáçĥ çöŕñéŕ, ~~~~~]\"],\"editor.buildPanel.rooms.polygon.title\":[\"[Þöļýĝöñ ŕööɱ ~~~~]\"],\"editor.buildPanel.rooms.rectangle.caption\":[\"[\",[\"lead\"],\" öñ ţĥé ĝŕîð. Ŵáļļš, ƒļööŕ áñð çéîļîñĝ áŕé çŕéáţéð ţöĝéţĥéŕ. ~~~~~~~~~~~~~~~]\"],\"editor.buildPanel.rooms.rectangle.label\":[\"[Ŕéçţáñĝļé ~~~]\"],\"editor.buildPanel.rooms.rectangle.lead\":[\"[Çļîçķ ţŵö çöŕñéŕš ~~~~~]\"],\"editor.buildPanel.rooms.rectangle.title\":[\"[Ŕéçţáñĝļé ŕööɱ ~~~~]\"],\"editor.buildPanel.rooms.title\":[\"[Ŕööɱš ~~]\"],\"editor.buildPanel.rooms.walls.caption\":[\"[\",[\"lead\"],\" Çļöšé á ļööþ áñð îţ ƀéçöɱéš á ŕööɱ; ļéáṽé îţ öþéñ ƒöŕ þáŕţîţîöñš. ~~~~~~~~~~~~~~~~]\"],\"editor.buildPanel.rooms.walls.label\":[\"[Ŵáļļš ~~]\"],\"editor.buildPanel.rooms.walls.lead\":[\"[Ðŕáŵ öñé ŵáļļ áţ á ţîɱé. ~~~~~~]\"],\"editor.buildPanel.rooms.walls.title\":[\"[Ŵáļļš ~~]\"],\"editor.cameraControlsHint\":[\"[Çáɱéŕá çöñţŕöļš ĥîñţ ~~~~~~]\"],\"editor.cameraHint.pan\":[\"[Þáñ ~]\"],\"editor.cameraHint.rotate\":[\"[Ŕöţáţé ~~]\"],\"editor.cameraHint.zoom\":[\"[Žööɱ ~~]\"],\"editor.controls.finishSwatch.ariaLabel\":[[\"label\"],\": \",[\"finish\"]],\"editor.controls.finishSwatch.default\":[\"[Ðéƒáûļţ ~~~]\"],\"editor.dismiss\":[\"[Ðîšɱîšš ~~~]\"],\"editor.dismissCameraControlsHint\":[\"[Ðîšɱîšš çáɱéŕá çöñţŕöļš ĥîñţ ~~~~~~~~]\"],\"editor.expandSidebar\":[\"[Éẋþáñð šîðéƀáŕ ~~~~]\"],\"editor.floatingActionMenu.axis\":[\"[Åẋîš ~~]\"],\"editor.floatingActionMenu.axis2\":[\"[⌥ áẋîš ~~]\"],\"editor.floatingActionMenu.noEquipment\":[\"[⚠ ñö éǫûîþɱéñţ ~~~~]\"],\"editor.floatingActionMenu.rTRotate\":[\"[Ŕ/Ţ ŕöţáţé ~~~]\"],\"editor.floatingActionMenu.registerCount\":[\"[\",[\"count\",\"plural\",{\"one\":[\"#\",\" ŕéĝîšţéŕ\"],\"other\":[\"#\",\" ŕéĝîšţéŕš\"]}],\" ~~~~~~]\"],\"editor.floatingActionMenu.runCount\":[\"[\",[\"count\",\"plural\",{\"one\":[[\"number\"],\" ŕûñ\"],\"other\":[[\"number\"],\" ŕûñš\"]}],\" ~~~]\"],\"editor.floatingActionMenu.system\":[\"[Šýšţéɱ ~~]\"],\"editor.floatingLevelSelector.addAFloorUnderTheRoof\":[\"[Åðð á ƒļööŕ ûñðéŕ ţĥé ŕööƒ ~~~~~~~]\"],\"editor.floatingLevelSelector.addLevelAbove\":[\"[Åðð ļéṽéļ áƀöṽé ~~~~]\"],\"editor.floatingLevelSelector.addLevelBelow\":[\"[Åðð ļéṽéļ ƀéļöŵ ~~~~]\"],\"editor.floatingLevelSelector.cancel\":[\"[Çáñçéļ ~~]\"],\"editor.floatingLevelSelector.delete\":[\"[Ðéļéţé ~~]\"],\"editor.floatingLevelSelector.deleteLevel\":[\"[Ðéļéţé ļéṽéļ ~~~~]\"],\"editor.floatingLevelSelector.deleteLevelConfirm\":[\"[Åŕé ýöû šûŕé ýöû ŵáñţ ţö ðéļéţé \",[\"levelName\"],\"? Åļļ ŵáļļš, ƒļööŕš, áñð öƀĵéçţš öñ ţĥîš ļéṽéļ ŵîļļ ƀé þéŕɱáñéñţļý ŕéɱöṽéð. ~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.floatingLevelSelector.dragToReorder\":[\"[Ðŕáĝ ţö ŕéöŕðéŕ ~~~~]\"],\"editor.floatingLevelSelector.duplicateLevel\":[\"[Ðûþļîçáţé ļéṽéļ ~~~~~]\"],\"editor.floatingLevelSelector.duplicateWithOptions\":[\"[Ðûþļîçáţé ŵîţĥ öþţîöñš... ~~~~~~]\"],\"editor.floatingLevelSelector.exitUnitFocus\":[\"[Éẋîţ ûñîţ ƒöçûš ~~~~]\"],\"editor.floatingLevelSelector.focusedUnitHasZonesHere\":[\"[Ƒöçûšéð ûñîţ ĥáš žöñéš ĥéŕé ~~~~~~~]\"],\"editor.floatingLevelSelector.groundFloorOverGrade\":[\"[Ţĥé ĝŕöûñð ƒļööŕ šţáñðš \",[\"distance\"],\" öṽéŕ ĝŕáðé. Šéáţ ţĥé ĝŕöûñð ƒļööŕ 8 îñ öṽéŕ ĝŕáðé ~~~~~~~~~~~~~~~~~~]\"],\"editor.floatingLevelSelector.groundFloorUnderGrade\":[\"[Ţĥé ĝŕöûñð ƒļööŕ šţáñðš \",[\"distance\"],\" ûñðéŕ ĝŕáðé. Šéáţ ţĥé ĝŕöûñð ƒļööŕ 8 îñ öṽéŕ ĝŕáðé ~~~~~~~~~~~~~~~~~~]\"],\"editor.floatingLevelSelector.groundLineTheLevelsUnderIt\":[\"[Ĝŕöûñð ļîñé: ţĥé ļéṽéļš ûñðéŕ îţ áŕé ƀéļöŵ ĝŕáðé ~~~~~~~~~~~~]\"],\"editor.floatingLevelSelector.groundOffset\":[\"[Ĝŕöûñð · \",[\"offset\"],\" ~~]\"],\"editor.floatingLevelSelector.insertLevelHere\":[\"[Îñšéŕţ ļéṽéļ ĥéŕé ~~~~~]\"],\"editor.floatingLevelSelector.levelHeight\":[\"[Ļéṽéļ ĥéîĝĥţ ~~~~]\"],\"editor.floatingLevelSelector.pasteCopiedSelection\":[\"[Þášţé çöþîéð šéļéçţîöñ ~~~~~~]\"],\"editor.floatingLevelSelector.reorderLevelname\":[\"[Ŕéöŕðéŕ \",[\"levelName\"],\" ~~~]\"],\"editor.floatingLevelSelector.seatTheBuildingSoThisFloor\":[\"[Šéáţ ţĥé ƀûîļðîñĝ šö ţĥîš ƒļööŕ šţáñðš áţ ĝŕáðé; ţĥé ƒļööŕš ûñðéŕ îţ áŕé ƀéļöŵ ĝŕáðé ~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.floatingLevelSelector.setAsGroundFloor\":[\"[Šéţ áš ĝŕöûñð ƒļööŕ ~~~~~]\"],\"editor.floatingLevelSelector.theGroundLevelCannotBeDeleted\":[\"[Ţĥé ĝŕöûñð ļéṽéļ çáññöţ ƀé ðéļéţéð ~~~~~~~~~]\"],\"editor.floatingLevelSelector.thisFloorStandsAtGrade\":[\"[Ţĥîš ƒļööŕ šţáñðš áţ ĝŕáðé ~~~~~~~]\"],\"editor.floatingLevelSelector.unit\":[\"[Ûñîţ ~~]\"],\"editor.floorFootprint.area\":[\"[Ƒļööŕ áŕéá ~~~]\"],\"editor.floorFootprint.room\":[\"[\",[\"room\"],\" ƒļööŕ ~~]\"],\"editor.floorFootprint.shared\":[\"[Šĥáŕéð ƒļööŕ ~~~~]\"],\"editor.helpers.buildingHelper.cancel\":[\"[Çáñçéļ ~~]\"],\"editor.helpers.buildingHelper.placeBuilding\":[\"[Þļáçé ƀûîļðîñĝ ~~~~]\"],\"editor.helpers.buildingHelper.rotate\":[\"[Ŕöţáţé ~~]\"],\"editor.helpers.contextualHelperPanel.cancelPlacement\":[\"[Çáñçéļ þļáçéɱéñţ ~~~~~]\"],\"editor.helpers.contextualHelperPanel.continuationClickOrPressCTo\":[\"[Çöñţîñûáţîöñ — çļîçķ öŕ þŕéšš Ç ţö çýçļé ~~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.continuationLabel\":[\"[Çöñţîñûáţîöñ: \",[\"label\"],\" ~~~~]\"],\"editor.helpers.contextualHelperPanel.dragToDrawFence\":[\"[Ðŕáĝ ţö ðŕáŵ ƒéñçé ~~~~~]\"],\"editor.helpers.contextualHelperPanel.eraseScope\":[\"[Éŕášé: \",[\"scope\"],\" ~~]\"],\"editor.helpers.contextualHelperPanel.eraseScopeClickOrPressShift\":[\"[Éŕášé šçöþé — çļîçķ öŕ þŕéšš Šĥîƒţ ţö çýçļé ~~~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.eraseScopeLabel\":[\"[Éŕášé šçöþé: \",[\"scope\"],\" ~~~]\"],\"editor.helpers.contextualHelperPanel.fenceTypeClickOrPressT\":[\"[Ƒéñçé ţýþé — çļîçķ öŕ þŕéšš Ţ ţö šŵîţçĥ ƀéţŵééñ šţŕáîĝĥţ, çûŕṽéð áñð ƒŕééĥáñð ~~~~~~~~~~~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.fewerShortcuts\":[\"[Ƒéŵéŕ šĥöŕţçûţš ~~~~~]\"],\"editor.helpers.contextualHelperPanel.finishCurveOrDoubleClick\":[\"[Ƒîñîšĥ çûŕṽé (öŕ ðöûƀļé-çļîçķ) ~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.gridLength\":[\"[Ĝŕîð: \",[\"length\"],\" ~~]\"],\"editor.helpers.contextualHelperPanel.gridStepClickOrTapCtrl\":[\"[Ĝŕîð šţéþ — çļîçķ öŕ ţáþ Çţŕļ ţö çýçļé ~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.gridStepLength\":[\"[Ĝŕîð šţéþ: \",[\"length\"],\" ~~~]\"],\"editor.helpers.contextualHelperPanel.hoverAPaintedSurfaceToErase\":[\"[Ĥöṽéŕ á þáîñţéð šûŕƒáçé ţö éŕášé ~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.hoverASurfaceToPaint\":[\"[Ĥöṽéŕ á šûŕƒáçé ţö þáîñţ ~~~~~~]\"],\"editor.helpers.contextualHelperPanel.hoverASurfaceToPickIts\":[\"[Ĥöṽéŕ á šûŕƒáçé ţö þîçķ îţš ɱáţéŕîáļ ~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.moreShortcuts\":[\"[Ṁöŕé šĥöŕţçûţš ~~~~]\"],\"editor.helpers.contextualHelperPanel.paintScope\":[\"[Þáîñţ: \",[\"scope\"],\" ~~]\"],\"editor.helpers.contextualHelperPanel.paintScopeClickOrPressShift\":[\"[Þáîñţ šçöþé — çļîçķ öŕ þŕéšš Šĥîƒţ ţö çýçļé ~~~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.paintScopeLabel\":[\"[Þáîñţ šçöþé: \",[\"scope\"],\" ~~~]\"],\"editor.helpers.contextualHelperPanel.pickScope\":[\"[Þîçķ: \",[\"scope\"],\" ~~]\"],\"editor.helpers.contextualHelperPanel.placeGateOnAFence\":[\"[Þļáçé ĝáţé öñ á ƒéñçé ~~~~~~]\"],\"editor.helpers.contextualHelperPanel.placePassageOnAFence\":[\"[Þļáçé þáššáĝé öñ á ƒéñçé ~~~~~~]\"],\"editor.helpers.contextualHelperPanel.selectAMaterialToPaint\":[\"[Šéļéçţ á ɱáţéŕîáļ ţö þáîñţ ~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.snappingAngles\":[\"[Šñáþþîñĝ: Åñĝļéš ~~~~~]\"],\"editor.helpers.contextualHelperPanel.snappingGrid\":[\"[Šñáþþîñĝ: Ĝŕîð ~~~~]\"],\"editor.helpers.contextualHelperPanel.snappingLines\":[\"[Šñáþþîñĝ: Ļîñéš ~~~~]\"],\"editor.helpers.contextualHelperPanel.snappingModeClickOrPressShift\":[\"[Šñáþþîñĝ ɱöðé — çļîçķ öŕ þŕéšš Šĥîƒţ ţö çýçļé ~~~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.snappingOff\":[\"[Šñáþþîñĝ: Öƒƒ ~~~~]\"],\"editor.helpers.contextualHelperPanel.straightContinuationIsUnavailableForCurved\":[\"[Šţŕáîĝĥţ çöñţîñûáţîöñ îš ûñáṽáîļáƀļé ƒöŕ çûŕṽéð öŕ ƒŕééĥáñð ƒéñçéš ~~~~~~~~~~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.straightContinuous\":[\"[Šţŕáîĝĥţ: Çöñţîñûöûš ~~~~~~]\"],\"editor.helpers.contextualHelperPanel.straightFenceContinuationClickOrPress\":[\"[Šţŕáîĝĥţ ƒéñçé çöñţîñûáţîöñ — çļîçķ öŕ þŕéšš Ç ţö ţöĝĝļé ~~~~~~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.straightSingle\":[\"[Šţŕáîĝĥţ: Šîñĝļé ~~~~~]\"],\"editor.helpers.helperManager.addPoint\":[\"[Åðð þöîñţ ~~~]\"],\"editor.helpers.helperManager.addPointClickTheFirstTo\":[\"[Åðð þöîñţ · çļîçķ ţĥé ƒîŕšţ ţö çļöšé ~~~~~~~~~]\"],\"editor.helpers.helperManager.brushSize\":[\"[Ɓŕûšĥ šîžé ~~~]\"],\"editor.helpers.helperManager.cancel\":[\"[Çáñçéļ ~~]\"],\"editor.helpers.helperManager.cancelPicking\":[\"[Çáñçéļ þîçķîñĝ ~~~~]\"],\"editor.helpers.helperManager.cancelStroke\":[\"[Çáñçéļ šţŕöķé ~~~~]\"],\"editor.helpers.helperManager.done\":[\"[Ðöñé ~~]\"],\"editor.helpers.helperManager.drawTheMezzanine\":[\"[Ðŕáŵ ţĥé ɱéžžáñîñé ~~~~~]\"],\"editor.helpers.helperManager.drawTheOpening\":[\"[Ðŕáŵ ţĥé öþéñîñĝ ~~~~~]\"],\"editor.helpers.helperManager.drawTheTerrace\":[\"[Ðŕáŵ ţĥé ţéŕŕáçé ~~~~~]\"],\"editor.helpers.helperManager.exitSmartMeasure\":[\"[Éẋîţ šɱáŕţ ɱéášûŕé ~~~~~]\"],\"editor.helpers.helperManager.finish\":[\"[Ƒîñîšĥ ~~]\"],\"editor.helpers.helperManager.finishAtTheEdge\":[\"[Ƒîñîšĥ áţ ţĥé éðĝé ~~~~~]\"],\"editor.helpers.helperManager.freeMove\":[\"[Ƒŕéé ɱöṽé ~~~]\"],\"editor.helpers.helperManager.freeMoveSlideDoorsAndWindows\":[\"[Ƒŕéé ɱöṽé · šļîðé ðööŕš áñð ŵîñðöŵš ~~~~~~~~~]\"],\"editor.helpers.helperManager.holdToPickAMaterial\":[\"[Ĥöļð ţö þîçķ á ɱáţéŕîáļ ~~~~~~]\"],\"editor.helpers.helperManager.inspectSurfaceDimensions\":[\"[Îñšþéçţ šûŕƒáçé ðîɱéñšîöñš ~~~~~~~~]\"],\"editor.helpers.helperManager.paintWithThisMaterial\":[\"[Þáîñţ ŵîţĥ ţĥîš ɱáţéŕîáļ ~~~~~~~]\"],\"editor.helpers.helperManager.pickTargetHeight\":[\"[Þîçķ ţáŕĝéţ ĥéîĝĥţ ~~~~~]\"],\"editor.helpers.helperManager.pinMeasurementLens\":[\"[Þîñ ɱéášûŕéɱéñţ ļéñš ~~~~~~]\"],\"editor.helpers.helperManager.place\":[\"[Þļáçé ~~]\"],\"editor.helpers.helperManager.placeInsideTheRoom\":[\"[Þļáçé îñšîðé ţĥé ŕööɱ ~~~~~~]\"],\"editor.helpers.helperManager.pressAnywhereDragToTheOpposite\":[\"[Þŕéšš áñýŵĥéŕé, ðŕáĝ ţö ţĥé öþþöšîţé çöŕñéŕ ~~~~~~~~~~~]\"],\"editor.helpers.helperManager.raiseOrLower\":[\"[Ŕáîšé öŕ ļöŵéŕ ~~~~]\"],\"editor.helpers.helperManager.removeAPaintedPartOrReset\":[\"[Ŕéɱöṽé á þáîñţéð þáŕţ, öŕ ŕéšéţ á šûŕƒáçé ~~~~~~~~~~]\"],\"editor.helpers.helperManager.removeLastPoint\":[\"[Ŕéɱöṽé ļášţ þöîñţ ~~~~~]\"],\"editor.helpers.helperManager.resize\":[\"[Ŕéšîžé ~~]\"],\"editor.helpers.helperManager.rotate45\":[\"[Ŕöţáţé ±45° ~~]\"],\"editor.helpers.helperManager.rotateTheSelection45\":[\"[Ŕöţáţé ţĥé šéļéçţîöñ ±45° ~~~~~~]\"],\"editor.helpers.helperManager.setOneCornerThenTheOpposite\":[\"[Šéţ öñé çöŕñéŕ, ţĥéñ ţĥé öþþöšîţé ~~~~~~~~~]\"],\"editor.helpers.itemHelper.cancel\":[\"[Çáñçéļ ~~]\"],\"editor.helpers.itemHelper.forcePlace\":[\"[Ƒöŕçé þļáçé ~~~]\"],\"editor.helpers.itemHelper.place\":[\"[Þļáçé ~~]\"],\"editor.helpers.itemHelper.rotate\":[\"[Ŕöţáţé ~~]\"],\"editor.helpers.registeredToolHelper.guidedConstraintsBypassed\":[\"[Ĝûîðéð çöñšţŕáîñţš ƀýþáššéð ~~~~~~~~]\"],\"editor.inspector.field.angle.g10zaw\":[\"[Åñĝļé ~~]\"],\"editor.inspector.field.armLengthM.1jclqgw\":[\"[Åŕɱ ļéñĝţĥ ɱ ~~~]\"],\"editor.inspector.field.attachmentSide.6n9s5v\":[\"[Åţţáçĥɱéñţ šîðé ~~~~~]\"],\"editor.inspector.field.autoHangers.10554ka\":[\"[Åûţö ĥáñĝéŕš ~~~~]\"],\"editor.inspector.field.autoMiterCorners.zxr5lt\":[\"[Åûţö ɱîţéŕ çöŕñéŕš ~~~~~]\"],\"editor.inspector.field.autoSpan.1gas9r6\":[\"[Åûţö šþáñ ~~~]\"],\"editor.inspector.field.backRatio.1ughd99\":[\"[Ɓáçķ ŕáţîö ~~~]\"],\"editor.inspector.field.baseHeight.1hs4zdf\":[\"[Ɓášé ĥéîĝĥţ ~~~]\"],\"editor.inspector.field.baseStyle.24vty5\":[\"[Ɓášé šţýļé ~~~]\"],\"editor.inspector.field.beamHeight.1kq0oh1\":[\"[Ɓéáɱ ĥéîĝĥţ ~~~]\"],\"editor.inspector.field.beamWidth.1q1mzbe\":[\"[Ɓéáɱ ŵîðţĥ ~~~]\"],\"editor.inspector.field.bodyShape.arvkuw\":[\"[Ɓöðý šĥáþé ~~~]\"],\"editor.inspector.field.bracketStyle.1vvoptm\":[\"[Ɓŕáçķéţ šţýļé ~~~~]\"],\"editor.inspector.field.branchAngle.v56zme\":[\"[Ɓŕáñçĥ áñĝļé ~~~~]\"],\"editor.inspector.field.cabHeight.1yn34mk\":[\"[Çáƀ ĥéîĝĥţ ~~~]\"],\"editor.inspector.field.canopyForm.1czzggp\":[\"[Çáñöþý ƒöŕɱ ~~~]\"],\"editor.inspector.field.cap.s0thej\":[\"[Çáþ ~]\"],\"editor.inspector.field.capOverhang.kxxz9j\":[\"[Çáþ öṽéŕĥáñĝ ~~~~]\"],\"editor.inspector.field.capShape.17mbxhu\":[\"[Çáþ šĥáþé ~~~]\"],\"editor.inspector.field.capThickness.u835q9\":[\"[Çáþ ţĥîçķñéšš ~~~~]\"],\"editor.inspector.field.carcassHeight.1aks0zy\":[\"[Çáŕçášš ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.cleanoutStyle.127zz6z\":[\"[Çļéáñöûţ šţýļé ~~~~]\"],\"editor.inspector.field.collarDiameter.1d5k28r\":[\"[Çöļļáŕ ðîáɱéţéŕ ~~~~~]\"],\"editor.inspector.field.collarHeight.1dqwsrf\":[\"[Çöļļáŕ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.collarShape.1gacv11\":[\"[Çöļļáŕ šĥáþé ~~~~]\"],\"editor.inspector.field.collarWidth.qvc9ik\":[\"[Çöļļáŕ ŵîðţĥ ~~~~]\"],\"editor.inspector.field.columns.1sy73ks\":[\"[Çöļûɱñš ~~~]\"],\"editor.inspector.field.conicalFullCircle.1pgkpz5\":[\"[Çöñîçáļ ƒûļļ çîŕçļé ~~~~~~]\"],\"editor.inspector.field.connectionMode.1nty478\":[\"[Çöññéçţîöñ ɱöðé ~~~~~]\"],\"editor.inspector.field.connectionOffset.2m70s8\":[\"[Çöññéçţîöñ öƒƒšéţ ~~~~~]\"],\"editor.inspector.field.cornerBevel.16iniho\":[\"[Çöŕñéŕ ƀéṽéļ ~~~~]\"],\"editor.inspector.field.coveringType.95yd3k\":[\"[Çöṽéŕîñĝ ţýþé ~~~~]\"],\"editor.inspector.field.cricketHeight.pok31n\":[\"[Çŕîçķéţ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.cricketLength.i2aht8\":[\"[Çŕîçķéţ ļéñĝţĥ ~~~~]\"],\"editor.inspector.field.cricketSide.1xnwil7\":[\"[Çŕîçķéţ šîðé ~~~~]\"],\"editor.inspector.field.cricketStyle.10j0lat\":[\"[Çŕîçķéţ šţýļé ~~~~]\"],\"editor.inspector.field.curb.5xi2ol\":[\"[Çûŕƀ ~~]\"],\"editor.inspector.field.curbHeight.1yn97sg\":[\"[Çûŕƀ ĥéîĝĥţ ~~~]\"],\"editor.inspector.field.curveOffset.l4xhvr\":[\"[Çûŕṽé öƒƒšéţ ~~~~]\"],\"editor.inspector.field.damperAngle.h5fxn7\":[\"[Ðáɱþéŕ áñĝļé ~~~~]\"],\"editor.inspector.field.deckThickness.4jmqze\":[\"[Ðéçķ ţĥîçķñéšš ~~~~]\"],\"editor.inspector.field.defaultLevelId.xmrjzp\":[\"[Ðéƒáûļţ ļéṽéļ îð ~~~~~]\"],\"editor.inspector.field.depth.1lu11u2\":[\"[Ðéþţĥ ~~]\"],\"editor.inspector.field.diameter.s3robe\":[\"[Ðîáɱéţéŕ ~~~]\"],\"editor.inspector.field.diameter2.pm6cl4\":[\"[Ðîáɱéţéŕ2 ~~~]\"],\"editor.inspector.field.doorDurationMs.13nx909\":[\"[Ðööŕ ðûŕáţîöñ ɱš ~~~~~]\"],\"editor.inspector.field.doorHeight.92r9k4\":[\"[Ðööŕ ĥéîĝĥţ ~~~]\"],\"editor.inspector.field.doorPanelStyle.2qog4q\":[\"[Ðööŕ þáñéļ šţýļé ~~~~~]\"],\"editor.inspector.field.doorStyle.gerpos\":[\"[Ðööŕ šţýļé ~~~]\"],\"editor.inspector.field.doorWidth.sy732l\":[\"[Ðööŕ ŵîðţĥ ~~~]\"],\"editor.inspector.field.downspoutEnabled.1gn00nv\":[\"[Ðöŵñšþöûţ éñáƀļéð ~~~~~]\"],\"editor.inspector.field.downspoutPosition.fxcsop\":[\"[Ðöŵñšþöûţ þöšîţîöñ ~~~~~~]\"],\"editor.inspector.field.ductMaterial.i8eonq\":[\"[Ðûçţ ɱáţéŕîáļ ~~~~]\"],\"editor.inspector.field.dutchGabletRake.6paydp\":[\"[Ðûţçĥ ĝáƀļéţ ŕáķé ~~~~~]\"],\"editor.inspector.field.dutchHipHeightRatio.1etnwgg\":[\"[Ðûţçĥ ĥîþ ĥéîĝĥţ ŕáţîö ~~~~~~]\"],\"editor.inspector.field.dutchHipWidthRatio.1dopfvb\":[\"[Ðûţçĥ ĥîþ ŵîðţĥ ŕáţîö ~~~~~~]\"],\"editor.inspector.field.dutchTopRakeThickness.1w9khxt\":[\"[Ðûţçĥ ţöþ ŕáķé ţĥîçķñéšš ~~~~~~~]\"],\"editor.inspector.field.dutchWaistLengthRatio.agtoxw\":[\"[Ðûţçĥ ŵáîšţ ļéñĝţĥ ŕáţîö ~~~~~~~]\"],\"editor.inspector.field.dwellMs.1lkk0o5\":[\"[Ðŵéļļ ɱš ~~~]\"],\"editor.inspector.field.edgeInset.1obeimx\":[\"[Éðĝé îñšéţ ~~~]\"],\"editor.inspector.field.elevation.4jbp44\":[\"[Éļéṽáţîöñ ~~~]\"],\"editor.inspector.field.endCapLeft.19jel4v\":[\"[Éñð çáþ ļéƒţ ~~~]\"],\"editor.inspector.field.endCapRight.lhse9c\":[\"[Éñð çáþ ŕîĝĥţ ~~~~]\"],\"editor.inspector.field.endCaps.4fsb5b\":[\"[Éñð çáþš ~~~]\"],\"editor.inspector.field.endPost.1guwsk0\":[\"[Éñð þöšţ ~~~]\"],\"editor.inspector.field.equipmentType.1mc2ywt\":[\"[Éǫûîþɱéñţ ţýþé ~~~~]\"],\"editor.inspector.field.fillToFloor.1oppnkf\":[\"[Ƒîļļ ţö ƒļööŕ ~~~~]\"],\"editor.inspector.field.finial.1ertf4s\":[\"[Ƒîñîáļ ~~]\"],\"editor.inspector.field.fittingType.18mz17s\":[\"[Ƒîţţîñĝ ţýþé ~~~~]\"],\"editor.inspector.field.flashingHeight.3e8nn6\":[\"[Ƒļášĥîñĝ ĥéîĝĥţ ~~~~~]\"],\"editor.inspector.field.flashingProjection.hhf0fk\":[\"[Ƒļášĥîñĝ þŕöĵéçţîöñ ~~~~~~]\"],\"editor.inspector.field.flueCount.j3t2ci\":[\"[Ƒļûé çöûñţ ~~~]\"],\"editor.inspector.field.flueDiameter.cjhubg\":[\"[Ƒļûé ðîáɱéţéŕ ~~~~]\"],\"editor.inspector.field.flueHeight.1dhc4y4\":[\"[Ƒļûé ĥéîĝĥţ ~~~]\"],\"editor.inspector.field.flueShape.1ealiy4\":[\"[Ƒļûé šĥáþé ~~~]\"],\"editor.inspector.field.flueSpacing.exhzco\":[\"[Ƒļûé šþáçîñĝ ~~~~]\"],\"editor.inspector.field.footingStyle.e3btg6\":[\"[Ƒööţîñĝ šţýļé ~~~~]\"],\"editor.inspector.field.frameDepth.1934a5n\":[\"[Ƒŕáɱé ðéþţĥ ~~~]\"],\"editor.inspector.field.frameThickness.1agxzd8\":[\"[Ƒŕáɱé ţĥîçķñéšš ~~~~~]\"],\"editor.inspector.field.framingStrategy.3jx9qe\":[\"[Ƒŕáɱîñĝ šţŕáţéĝý ~~~~~]\"],\"editor.inspector.field.fromLevelId.15ieejs\":[\"[Ƒŕöɱ ļéṽéļ îð ~~~~]\"],\"editor.inspector.field.gableOverhang.2z0obw\":[\"[Ĝáƀļé öṽéŕĥáñĝ ~~~~]\"],\"editor.inspector.field.gambrelLowerHeightRatio.wqq7lg\":[\"[Ĝáɱƀŕéļ ļöŵéŕ ĥéîĝĥţ ŕáţîö ~~~~~~~]\"],\"editor.inspector.field.gambrelLowerWidthRatio.uvyb1v\":[\"[Ĝáɱƀŕéļ ļöŵéŕ ŵîðţĥ ŕáţîö ~~~~~~~]\"],\"editor.inspector.field.gapX.wjxa7\":[\"[Ĝáþ ẋ ~~]\"],\"editor.inspector.field.gapY.mkbl8\":[\"[Ĝáþ ý ~~]\"],\"editor.inspector.field.glassThickness.s97b0x\":[\"[Ĝļášš ţĥîçķñéšš ~~~~~]\"],\"editor.inspector.field.groundClearance.4os7f0\":[\"[Ĝŕöûñð çļéáŕáñçé ~~~~~]\"],\"editor.inspector.field.guardInfill.16heiig\":[\"[Ĝûáŕð îñƒîļļ ~~~~]\"],\"editor.inspector.field.gutterEnabled.1oxiltf\":[\"[Ĝûţţéŕ éñáƀļéð ~~~~]\"],\"editor.inspector.field.gutterProfile.1ngzqi3\":[\"[Ĝûţţéŕ þŕöƒîļé ~~~~]\"],\"editor.inspector.field.gutterSize.jgavtz\":[\"[Ĝûţţéŕ šîžé ~~~]\"],\"editor.inspector.field.hangerMaxReach.1869epv\":[\"[Ĥáñĝéŕ ɱáẋ ŕéáçĥ ~~~~~]\"],\"editor.inspector.field.hangerSpacing.i2b5d7\":[\"[Ĥáñĝéŕ šþáçîñĝ ~~~~]\"],\"editor.inspector.field.hangerStyle.l7v7gb\":[\"[Ĥáñĝéŕ šţýļé ~~~~]\"],\"editor.inspector.field.height.7puwki\":[\"[Ĥéîĝĥţ ~~]\"],\"editor.inspector.field.height2.7b3jlc\":[\"[Ĥéîĝĥţ2 ~~]\"],\"editor.inspector.field.heightAboveRidge.1k99brk\":[\"[Ĥéîĝĥţ áƀöṽé ŕîðĝé ~~~~~]\"],\"editor.inspector.field.highEdgeHeight.1s7v90t\":[\"[Ĥîĝĥ éðĝé ĥéîĝĥţ ~~~~~]\"],\"editor.inspector.field.highOverhang.67w55d\":[\"[Ĥîĝĥ öṽéŕĥáñĝ ~~~~]\"],\"editor.inspector.field.highSideMode.1rc1r5j\":[\"[Ĥîĝĥ šîðé ɱöðé ~~~~]\"],\"editor.inspector.field.hoodOverhang.1q1hcin\":[\"[Ĥööð öṽéŕĥáñĝ ~~~~]\"],\"editor.inspector.field.infillPlacement.11dxzpo\":[\"[Îñƒîļļ þļáçéɱéñţ ~~~~~]\"],\"editor.inspector.field.inletShape.ypayh2\":[\"[Îñļéţ šĥáþé ~~~]\"],\"editor.inspector.field.innerRadius.1fkmg0j\":[\"[Îññéŕ ŕáðîûš ~~~~]\"],\"editor.inspector.field.insulated.iwziey\":[\"[Îñšûļáţéð ~~~]\"],\"editor.inspector.field.insulationR.663ufx\":[\"[Îñšûļáţîöñ ŕ ~~~~]\"],\"editor.inspector.field.lanternHeight.oz7zpm\":[\"[Ļáñţéŕñ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.lanternTopScale.hkmpp2\":[\"[Ļáñţéŕñ ţöþ šçáļé ~~~~~]\"],\"editor.inspector.field.ledgerDepth.7av8k9\":[\"[Ļéðĝéŕ ðéþţĥ ~~~~]\"],\"editor.inspector.field.ledgerHeight.zo2oif\":[\"[Ļéðĝéŕ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.ledgerVerticalOffset.1athbgt\":[\"[Ļéðĝéŕ ṽéŕţîçáļ öƒƒšéţ ~~~~~~]\"],\"editor.inspector.field.leftEndCondition.1syqlaw\":[\"[Ļéƒţ éñð çöñðîţîöñ ~~~~~]\"],\"editor.inspector.field.leftOverhang.1ydl9ma\":[\"[Ļéƒţ öṽéŕĥáñĝ ~~~~]\"],\"editor.inspector.field.length.1kpdcfp\":[\"[Ļéñĝţĥ ~~]\"],\"editor.inspector.field.liquidDiameter.w3pk7c\":[\"[Ļîǫûîð ðîáɱéţéŕ ~~~~~]\"],\"editor.inspector.field.louverCount.lhw2gr\":[\"[Ļöûṽéŕ çöûñţ ~~~~]\"],\"editor.inspector.field.lowBeamInset.1g7yw5l\":[\"[Ļöŵ ƀéáɱ îñšéţ ~~~~]\"],\"editor.inspector.field.lowEdgeHeight.47mae1\":[\"[Ļöŵ éðĝé ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.lowOverhang.t4nz1h\":[\"[Ļöŵ öṽéŕĥáñĝ ~~~~]\"],\"editor.inspector.field.mansardSteepHeightRatio.1hbb8rq\":[\"[Ṁáñšáŕð šţééþ ĥéîĝĥţ ŕáţîö ~~~~~~~]\"],\"editor.inspector.field.mansardSteepWidthRatio.6xk6vd\":[\"[Ṁáñšáŕð šţééþ ŵîðţĥ ŕáţîö ~~~~~~~]\"],\"editor.inspector.field.matchHostRoofMaterial.s56zwj\":[\"[Ṁáţçĥ ĥöšţ ŕööƒ ɱáţéŕîáļ ~~~~~~~]\"],\"editor.inspector.field.matchHostRoofStructure.bojht3\":[\"[Ṁáţçĥ ĥöšţ ŕööƒ šţŕûçţûŕé ~~~~~~~]\"],\"editor.inspector.field.mount.h80tay\":[\"[Ṁöûñţ ~~]\"],\"editor.inspector.field.mountingType.1xvin1e\":[\"[Ṁöûñţîñĝ ţýþé ~~~~]\"],\"editor.inspector.field.neckHeight.19ym8n1\":[\"[Ñéçķ ĥéîĝĥţ ~~~]\"],\"editor.inspector.field.opacity.1pmpfd2\":[\"[Öþáçîţý ~~~]\"],\"editor.inspector.field.openingAngle.brhi7c\":[\"[Öþéñîñĝ áñĝļé ~~~~]\"],\"editor.inspector.field.openingOffset.wpoqt6\":[\"[Öþéñîñĝ öƒƒšéţ ~~~~]\"],\"editor.inspector.field.openingSide.18l2iwe\":[\"[Öþéñîñĝ šîðé ~~~~]\"],\"editor.inspector.field.operationState.1lwrz07\":[\"[Öþéŕáţîöñ šţáţé ~~~~~]\"],\"editor.inspector.field.outletShape.lgpqhx\":[\"[Öûţļéţ šĥáþé ~~~~]\"],\"editor.inspector.field.overhang.b5ljpv\":[\"[Öṽéŕĥáñĝ ~~~]\"],\"editor.inspector.field.panelHeight.1kf31vk\":[\"[Þáñéļ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.panelWidth.946581\":[\"[Þáñéļ ŵîðţĥ ~~~]\"],\"editor.inspector.field.patternAlignment.jd1ht0\":[\"[Þáţţéŕñ áļîĝñɱéñţ ~~~~~]\"],\"editor.inspector.field.patternCount.1r37pve\":[\"[Þáţţéŕñ çöûñţ ~~~~]\"],\"editor.inspector.field.patternDistribution.fmam51\":[\"[Þáţţéŕñ ðîšţŕîƀûţîöñ ~~~~~~]\"],\"editor.inspector.field.patternRemainder.i47p5y\":[\"[Þáţţéŕñ ŕéɱáîñðéŕ ~~~~~]\"],\"editor.inspector.field.picketProfile.1xgzuyc\":[\"[Þîçķéţ þŕöƒîļé ~~~~]\"],\"editor.inspector.field.picketRailCount.atgt6w\":[\"[Þîçķéţ ŕáîļ çöûñţ ~~~~~]\"],\"editor.inspector.field.picketSpacing.p8d98w\":[\"[Þîçķéţ šþáçîñĝ ~~~~]\"],\"editor.inspector.field.picketTop.1tskplu\":[\"[Þîçķéţ ţöþ ~~~]\"],\"editor.inspector.field.picketTopClearance.16eq1k0\":[\"[Þîçķéţ ţöþ çļéáŕáñçé ~~~~~~]\"],\"editor.inspector.field.picketVariation.f7vl1c\":[\"[Þîçķéţ ṽáŕîáţîöñ ~~~~~]\"],\"editor.inspector.field.picketWidth.3fr3rh\":[\"[Þîçķéţ ŵîðţĥ ~~~~]\"],\"editor.inspector.field.pipeMaterial.1ggc2wy\":[\"[Þîþé ɱáţéŕîáļ ~~~~]\"],\"editor.inspector.field.pitch.xe6ekx\":[\"[Þîţçĥ ~~]\"],\"editor.inspector.field.position.1quewx6\":[\"[Þöšîţîöñ ~~~]\"],\"editor.inspector.field.postBracing.crq8nn\":[\"[Þöšţ ƀŕáçîñĝ ~~~~]\"],\"editor.inspector.field.postCap.1xcvxrv\":[\"[Þöšţ çáþ ~~~]\"],\"editor.inspector.field.postCount.22r56c\":[\"[Þöšţ çöûñţ ~~~]\"],\"editor.inspector.field.postDepth.1ko6j1m\":[\"[Þöšţ ðéþţĥ ~~~]\"],\"editor.inspector.field.postInset.le36li\":[\"[Þöšţ îñšéţ ~~~]\"],\"editor.inspector.field.postLayoutMode.16jre62\":[\"[Þöšţ ļáýöûţ ɱöðé ~~~~~]\"],\"editor.inspector.field.postSize.1jodxek\":[\"[Þöšţ šîžé ~~~]\"],\"editor.inspector.field.postSpacing.voppfi\":[\"[Þöšţ šþáçîñĝ ~~~~]\"],\"editor.inspector.field.postThrough.1abgu4a\":[\"[Þöšţ ţĥŕöûĝĥ ~~~~]\"],\"editor.inspector.field.postWidth.rk26fz\":[\"[Þöšţ ŵîðţĥ ~~~]\"],\"editor.inspector.field.profile.1kwlci6\":[\"[Þŕöƒîļé ~~~]\"],\"editor.inspector.field.projection.jhtig0\":[\"[Þŕöĵéçţîöñ ~~~]\"],\"editor.inspector.field.purlinHeight.eo9cjm\":[\"[Þûŕļîñ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.purlinSpacing.4gbzb2\":[\"[Þûŕļîñ šþáçîñĝ ~~~~]\"],\"editor.inspector.field.purlinWidth.r6tu3j\":[\"[Þûŕļîñ ŵîðţĥ ~~~~]\"],\"editor.inspector.field.rafterEndInset.14c0wy5\":[\"[Ŕáƒţéŕ éñð îñšéţ ~~~~~]\"],\"editor.inspector.field.rafterHeight.1e1n99w\":[\"[Ŕáƒţéŕ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.rafterSpacing.19subc0\":[\"[Ŕáƒţéŕ šþáçîñĝ ~~~~]\"],\"editor.inspector.field.rafterWidth.eksj4t\":[\"[Ŕáƒţéŕ ŵîðţĥ ~~~~]\"],\"editor.inspector.field.railingHeight.6wf4bm\":[\"[Ŕáîļîñĝ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.railingMode.ov7xpu\":[\"[Ŕáîļîñĝ ɱöðé ~~~~]\"],\"editor.inspector.field.railingStyle.1nyd2u\":[\"[Ŕáîļîñĝ šţýļé ~~~~]\"],\"editor.inspector.field.resizeLock.b2hbr0\":[\"[Ŕéšîžé ļöçķ ~~~]\"],\"editor.inspector.field.returnDiameter.166ozhe\":[\"[Ŕéţûŕñ ðîáɱéţéŕ ~~~~~]\"],\"editor.inspector.field.returnHeight.b9sq6y\":[\"[Ŕéţûŕñ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.returnShape.1e3a27i\":[\"[Ŕéţûŕñ šĥáþé ~~~~]\"],\"editor.inspector.field.returnWidth.z9r3h3\":[\"[Ŕéţûŕñ ŵîðţĥ ~~~~]\"],\"editor.inspector.field.rightEndCondition.tjlw3l\":[\"[Ŕîĝĥţ éñð çöñðîţîöñ ~~~~~~]\"],\"editor.inspector.field.rightOverhang.yqbeft\":[\"[Ŕîĝĥţ öṽéŕĥáñĝ ~~~~]\"],\"editor.inspector.field.roofHeight.1uhy6qy\":[\"[Ŕööƒ ĥéîĝĥţ ~~~]\"],\"editor.inspector.field.roofStyle.pawqfy\":[\"[Ŕööƒ šţýļé ~~~]\"],\"editor.inspector.field.roofThickness.1xlr3rx\":[\"[Ŕööƒ ţĥîçķñéšš ~~~~]\"],\"editor.inspector.field.roofType.1m9kv5h\":[\"[Ŕööƒ ţýþé ~~~]\"],\"editor.inspector.field.rotation.ly2rj\":[\"[Ŕöţáţîöñ ~~~]\"],\"editor.inspector.field.rows.1ba1neg\":[\"[Ŕöŵš ~~]\"],\"editor.inspector.field.scale.b6rpxt\":[\"[Šçáļé ~~]\"],\"editor.inspector.field.seamDetail.197za48\":[\"[Šéáɱ ðéţáîļ ~~~]\"],\"editor.inspector.field.segmentType.l667sy\":[\"[Šéĝɱéñţ ţýþé ~~~~]\"],\"editor.inspector.field.shaftStyle.1i5ampa\":[\"[Šĥáƒţ šţýļé ~~~]\"],\"editor.inspector.field.shaftWallThickness.bduslr\":[\"[Šĥáƒţ ŵáļļ ţĥîçķñéšš ~~~~~~]\"],\"editor.inspector.field.shape.iq9t52\":[\"[Šĥáþé ~~]\"],\"editor.inspector.field.shape2.fi0nx8\":[\"[Šĥáþé2 ~~]\"],\"editor.inspector.field.shedHighSide.bzzddg\":[\"[Šĥéð ĥîĝĥ šîðé ~~~~]\"],\"editor.inspector.field.shingleThickness.1hn5wxr\":[\"[Šĥîñĝļé ţĥîçķñéšš ~~~~~]\"],\"editor.inspector.field.shoulderExtent.11j8uiv\":[\"[Šĥöûļðéŕ éẋţéñţ ~~~~~]\"],\"editor.inspector.field.shoulderHeight.xyqn6g\":[\"[Šĥöûļðéŕ ĥéîĝĥţ ~~~~~]\"],\"editor.inspector.field.shoulderStyle.1hkcv2w\":[\"[Šĥöûļðéŕ šţýļé ~~~~]\"],\"editor.inspector.field.showCenterColumn.1uggg45\":[\"[Šĥöŵ çéñţéŕ çöļûɱñ ~~~~~]\"],\"editor.inspector.field.showInfill.33rv7u\":[\"[Šĥöŵ îñƒîļļ ~~~]\"],\"editor.inspector.field.showStepSupports.1kg8h8m\":[\"[Šĥöŵ šţéþ šûþþöŕţš ~~~~~]\"],\"editor.inspector.field.sideFlashing.cv744o\":[\"[Šîðé ƒļášĥîñĝ ~~~~]\"],\"editor.inspector.field.size.1a4x3zw\":[\"[Šîžé ~~]\"],\"editor.inspector.field.skylightType.1a5vj3i\":[\"[Šķýļîĝĥţ ţýþé ~~~~]\"],\"editor.inspector.field.slabOpeningMode.g4f730\":[\"[Šļáƀ öþéñîñĝ ɱöðé ~~~~~]\"],\"editor.inspector.field.slatGap.slmk93\":[\"[Šļáţ ĝáþ ~~~]\"],\"editor.inspector.field.slideDirection.1527q13\":[\"[Šļîðé ðîŕéçţîöñ ~~~~~]\"],\"editor.inspector.field.span.1bmmuw1\":[\"[Šþáñ ~~]\"],\"editor.inspector.field.speed.2w2xwg\":[\"[Šþééð ~~]\"],\"editor.inspector.field.spinSpeed.1ozx746\":[\"[Šþîñ šþééð ~~~]\"],\"editor.inspector.field.stairType.1u05e02\":[\"[Šţáîŕ ţýþé ~~~]\"],\"editor.inspector.field.standoff.4wv2g0\":[\"[Šţáñðöƒƒ ~~~]\"],\"editor.inspector.field.standoffHeight.1qdnff\":[\"[Šţáñðöƒƒ ĥéîĝĥţ ~~~~~]\"],\"editor.inspector.field.startPost.1ood9kv\":[\"[Šţáŕţ þöšţ ~~~]\"],\"editor.inspector.field.stepCount.nzorrw\":[\"[Šţéþ çöûñţ ~~~]\"],\"editor.inspector.field.strapSpacing.1cyt3dc\":[\"[Šţŕáþ šþáçîñĝ ~~~~]\"],\"editor.inspector.field.strapStyle.fh1oy4\":[\"[Šţŕáþ šţýļé ~~~]\"],\"editor.inspector.field.style.nf3vcm\":[\"[Šţýļé ~~]\"],\"editor.inspector.field.suctionDiameter.nutxtj\":[\"[Šûçţîöñ ðîáɱéţéŕ ~~~~~]\"],\"editor.inspector.field.supplyDiameter.h5ldh5\":[\"[Šûþþļý ðîáɱéţéŕ ~~~~~]\"],\"editor.inspector.field.supplyHeight.zy6ru1\":[\"[Šûþþļý ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.supplyShape.k39wnb\":[\"[Šûþþļý šĥáþé ~~~~]\"],\"editor.inspector.field.supplyWidth.g66axi\":[\"[Šûþþļý ŵîðţĥ ~~~~]\"],\"editor.inspector.field.supportOffset.1w4cocr\":[\"[Šûþþöŕţ öƒƒšéţ ~~~~]\"],\"editor.inspector.field.sweepAngle.ucmmlw\":[\"[Šŵééþ áñĝļé ~~~]\"],\"editor.inspector.field.system.13qbhrw\":[\"[Šýšţéɱ ~~]\"],\"editor.inspector.field.terminal.1501knl\":[\"[Ţéŕɱîñáļ ~~~]\"],\"editor.inspector.field.terminalType.1ne8lgb\":[\"[Ţéŕɱîñáļ ţýþé ~~~~]\"],\"editor.inspector.field.thickness.1l8hu45\":[\"[Ţĥîçķñéšš ~~~]\"],\"editor.inspector.field.tiltAngle.1312yw1\":[\"[Ţîļţ áñĝļé ~~~]\"],\"editor.inspector.field.toLevelId.8i5qx7\":[\"[Ţö ļéṽéļ îð ~~~]\"],\"editor.inspector.field.topLandingDepth.ki7gk2\":[\"[Ţöþ ļáñðîñĝ ðéþţĥ ~~~~~]\"],\"editor.inspector.field.topLandingMode.zk0h7e\":[\"[Ţöþ ļáñðîñĝ ɱöðé ~~~~~]\"],\"editor.inspector.field.topRailHeight.fscisv\":[\"[Ţöþ ŕáîļ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.transitionMode.f3evgt\":[\"[Ţŕáñšîţîöñ ɱöðé ~~~~~]\"],\"editor.inspector.field.transitionWidth.rtgz3m\":[\"[Ţŕáñšîţîöñ ŵîðţĥ ~~~~~]\"],\"editor.inspector.field.vaneCount.55vtye\":[\"[Ṽáñé çöûñţ ~~~]\"],\"editor.inspector.field.wallHeight.18vmh5c\":[\"[Ŵáļļ ĥéîĝĥţ ~~~]\"],\"editor.inspector.field.wallShell.vqsyhv\":[\"[Ŵáļļ šĥéļļ ~~~]\"],\"editor.inspector.field.wallSkirtHeight.1uea2ad\":[\"[Ŵáļļ šķîŕţ ĥéîĝĥţ ~~~~~]\"],\"editor.inspector.field.wallThickness.17wn4iv\":[\"[Ŵáļļ ţĥîçķñéšš ~~~~]\"],\"editor.inspector.field.width.gfxz9b\":[\"[Ŵîðţĥ ~~]\"],\"editor.inspector.field.width2.1nqawvr\":[\"[Ŵîðţĥ2 ~~]\"],\"editor.inspector.field.withBack.1ay8nus\":[\"[Ŵîţĥ ƀáçķ ~~~]\"],\"editor.inspector.field.withBottom.1x1z1vo\":[\"[Ŵîţĥ ƀöţţöɱ ~~~]\"],\"editor.inspector.field.withSides.uq066x\":[\"[Ŵîţĥ šîðéš ~~~]\"],\"editor.inspector.group.advanced.qwfkor\":[\"[Åðṽáñçéð ~~~]\"],\"editor.inspector.group.air.15jotdj\":[\"[Åîŕ ~]\"],\"editor.inspector.group.appearance.dli9wf\":[\"[Åþþéáŕáñçé ~~~]\"],\"editor.inspector.group.body.ign4wl\":[\"[Ɓöðý ~~]\"],\"editor.inspector.group.cab.o4z1ox\":[\"[Çáƀ ~]\"],\"editor.inspector.group.cabinet.rzvymr\":[\"[Çáƀîñéţ ~~~]\"],\"editor.inspector.group.cap.s0thej\":[\"[Çáþ ~]\"],\"editor.inspector.group.collar.1am2iqo\":[\"[Çöļļáŕ ~~]\"],\"editor.inspector.group.connection.2r1h4p\":[\"[Çöññéçţîöñ ~~~]\"],\"editor.inspector.group.connections.ai4w8u\":[\"[Çöññéçţîöñš ~~~~]\"],\"editor.inspector.group.construction.j6p9kc\":[\"[Çöñšţŕûçţîöñ ~~~~]\"],\"editor.inspector.group.cricket.6iwg8g\":[\"[Çŕîçķéţ ~~~]\"],\"editor.inspector.group.curb.5xi2ol\":[\"[Çûŕƀ ~~]\"],\"editor.inspector.group.curvePoints.ztdcnn\":[\"[Çûŕṽé þöîñţš ~~~~]\"],\"editor.inspector.group.dimensions.pewa8g\":[\"[Ðîɱéñšîöñš ~~~]\"],\"editor.inspector.group.doors.18w2kpa\":[\"[Ðööŕš ~~]\"],\"editor.inspector.group.dormer.1fjs5tq\":[\"[Ðöŕɱéŕ ~~]\"],\"editor.inspector.group.dormerRoof.u9uy2g\":[\"[Ðöŕɱéŕ ŕööƒ ~~~]\"],\"editor.inspector.group.drainage.7easy0\":[\"[Ðŕáîñáĝé ~~~]\"],\"editor.inspector.group.elevation.4jbp44\":[\"[Éļéṽáţîöñ ~~~]\"],\"editor.inspector.group.endCaps.4fsb5b\":[\"[Éñð çáþš ~~~]\"],\"editor.inspector.group.equipment.1xtq0ev\":[\"[Éǫûîþɱéñţ ~~~]\"],\"editor.inspector.group.face.1531fr0\":[\"[Ƒáçé ~~]\"],\"editor.inspector.group.fitting.171z1r4\":[\"[Ƒîţţîñĝ ~~~]\"],\"editor.inspector.group.flues.nq6pye\":[\"[Ƒļûéš ~~]\"],\"editor.inspector.group.footprint.g8q2pg\":[\"[Ƒööţþŕîñţ ~~~]\"],\"editor.inspector.group.frame.q7q9fq\":[\"[Ƒŕáɱé ~~]\"],\"editor.inspector.group.geometry.a21os1\":[\"[Ĝéöɱéţŕý ~~~]\"],\"editor.inspector.group.grid.d8gwxd\":[\"[Ĝŕîð ~~]\"],\"editor.inspector.group.hangers.agnfzn\":[\"[Ĥáñĝéŕš ~~~]\"],\"editor.inspector.group.hardware.1nygwm1\":[\"[Ĥáŕðŵáŕé ~~~]\"],\"editor.inspector.group.hungWall.1ftr1gz\":[\"[Ĥûñĝ ŵáļļ ~~~]\"],\"editor.inspector.group.insulation.1kyo5e7\":[\"[Îñšûļáţîöñ ~~~]\"],\"editor.inspector.group.lantern.1h7o2xb\":[\"[Ļáñţéŕñ ~~~]\"],\"editor.inspector.group.levels.1s6yaru\":[\"[Ļéṽéļš ~~]\"],\"editor.inspector.group.line.166mv5z\":[\"[Ļîñé ~~]\"],\"editor.inspector.group.lines.12bghr0\":[\"[Ļîñéš ~~]\"],\"editor.inspector.group.motion.1be7sjr\":[\"[Ṁöţîöñ ~~]\"],\"editor.inspector.group.mounting.feutd2\":[\"[Ṁöûñţîñĝ ~~~]\"],\"editor.inspector.group.opening.dfet3\":[\"[Öþéñîñĝ ~~~]\"],\"editor.inspector.group.panelDimensions.b59qe6\":[\"[Þáñéļ ðîɱéñšîöñš ~~~~~]\"],\"editor.inspector.group.patternDistribution.fmam51\":[\"[Þáţţéŕñ ðîšţŕîƀûţîöñ ~~~~~~]\"],\"editor.inspector.group.placement.13lcvts\":[\"[Þļáçéɱéñţ ~~~]\"],\"editor.inspector.group.position.1quewx6\":[\"[Þöšîţîöñ ~~~]\"],\"editor.inspector.group.profile.1kwlci6\":[\"[Þŕöƒîļé ~~~]\"],\"editor.inspector.group.railing.19a5bnr\":[\"[Ŕáîļîñĝ ~~~]\"],\"editor.inspector.group.return.1klrjrz\":[\"[Ŕéţûŕñ ~~]\"],\"editor.inspector.group.settings.ktdb8o\":[\"[Šéţţîñĝš ~~~]\"],\"editor.inspector.group.shaft.mad9cv\":[\"[Šĥáƒţ ~~]\"],\"editor.inspector.group.shape.iq9t52\":[\"[Šĥáþé ~~]\"],\"editor.inspector.group.shoulder.1nyfx25\":[\"[Šĥöûļðéŕ ~~~]\"],\"editor.inspector.group.size.1a4x3zw\":[\"[Šîžé ~~]\"],\"editor.inspector.group.structure.gezdra\":[\"[Šţŕûçţûŕé ~~~]\"],\"editor.inspector.group.style.nf3vcm\":[\"[Šţýļé ~~]\"],\"editor.inspector.group.supply.1oy2zwu\":[\"[Šûþþļý ~~]\"],\"editor.inspector.group.surface.wtamqk\":[\"[Šûŕƒáçé ~~~]\"],\"editor.inspector.group.terminal.1501knl\":[\"[Ţéŕɱîñáļ ~~~]\"],\"editor.inspector.group.topology.18t8dyc\":[\"[Ţöþöļöĝý ~~~]\"],\"editor.inspector.group.transform.1c55ayj\":[\"[Ţŕáñšƒöŕɱ ~~~]\"],\"editor.inspector.group.trap.1qc7vhe\":[\"[Ţŕáþ ~~]\"],\"editor.inspector.group.type.1m2zofh\":[\"[Ţýþé ~~]\"],\"editor.inspector.option.abs.132mz8b\":[\"[Åƀš ~]\"],\"editor.inspector.option.accessPanel.13sptb5\":[\"[Åççéšš þáñéļ ~~~~]\"],\"editor.inspector.option.airHandler.1crnyg3\":[\"[Åîŕ ĥáñðļéŕ ~~~]\"],\"editor.inspector.option.alternating.5jashi\":[\"[Åļţéŕñáţîñĝ ~~~~]\"],\"editor.inspector.option.arched.14188w0\":[\"[Åŕçĥéð ~~]\"],\"editor.inspector.option.auto.540b06\":[\"[Åûţö ~~]\"],\"editor.inspector.option.automatic.r122ro\":[\"[Åûţöɱáţîç ~~~]\"],\"editor.inspector.option.back.1hzmxtu\":[\"[Ɓáçķ ~~]\"],\"editor.inspector.option.balusters.1j3w6ng\":[\"[Ɓáļûšţéŕš ~~~]\"],\"editor.inspector.option.band.160umau\":[\"[Ɓáñð ~~]\"],\"editor.inspector.option.basePlate.17fcg8k\":[\"[Ɓášé þļáţé ~~~]\"],\"editor.inspector.option.boards.u14hig\":[\"[Ɓöáŕðš ~~]\"],\"editor.inspector.option.bookshelf.ls0zqk\":[\"[Ɓööķšĥéļƒ ~~~]\"],\"editor.inspector.option.both.mkyb42\":[\"[Ɓöţĥ ~~]\"],\"editor.inspector.option.bottom.9mpruy\":[\"[Ɓöţţöɱ ~~]\"],\"editor.inspector.option.box.1nbjcuq\":[\"[Ɓöẋ ~]\"],\"editor.inspector.option.break.17spnvc\":[\"[Ɓŕéáķ ~~]\"],\"editor.inspector.option.butterfly.pvv0g4\":[\"[Ɓûţţéŕƒļý ~~~]\"],\"editor.inspector.option.cable.fp50zq\":[\"[Çáƀļé ~~]\"],\"editor.inspector.option.castIron.1q2z4qk\":[\"[Çášţ îŕöñ ~~~]\"],\"editor.inspector.option.ceiling.1t2zaqo\":[\"[Çéîļîñĝ ~~~]\"],\"editor.inspector.option.center.kzdxno\":[\"[Çéñţéŕ ~~]\"],\"editor.inspector.option.centerOpening.bn1rvw\":[\"[Çéñţéŕ öþéñîñĝ ~~~~]\"],\"editor.inspector.option.cleanout.lww8bm\":[\"[Çļéáñöûţ ~~~]\"],\"editor.inspector.option.concretePad.m1zdij\":[\"[Çöñçŕéţé þáð ~~~~]\"],\"editor.inspector.option.condenser.a74nps\":[\"[Çöñðéñšéŕ ~~~]\"],\"editor.inspector.option.corbeled.bovs4v\":[\"[Çöŕƀéļéð ~~~]\"],\"editor.inspector.option.count.1qoi4r8\":[\"[Çöûñţ ~~]\"],\"editor.inspector.option.coupling.111aap2\":[\"[Çöûþļîñĝ ~~~]\"],\"editor.inspector.option.coveringSpecific.1h9fo8w\":[\"[Çöṽéŕîñĝ šþéçîƒîç ~~~~~]\"],\"editor.inspector.option.cross.1elubzv\":[\"[Çŕöšš ~~]\"],\"editor.inspector.option.cubby.ivq4qc\":[\"[Çûƀƀý ~~]\"],\"editor.inspector.option.curved.6noz1s\":[\"[Çûŕṽéð ~~]\"],\"editor.inspector.option.cylinder.eol6vj\":[\"[Çýļîñðéŕ ~~~]\"],\"editor.inspector.option.damper.wgri80\":[\"[Ðáɱþéŕ ~~]\"],\"editor.inspector.option.destination.gfzm1r\":[\"[Ðéšţîñáţîöñ ~~~~]\"],\"editor.inspector.option.diffuser.1igj0jh\":[\"[Ðûšéŕ ~~~]\"],\"editor.inspector.option.dogEar.xhtvjt\":[\"[Ðöĝ éáŕ ~~]\"],\"editor.inspector.option.dome.1c87e56\":[\"[Ðöɱé ~~]\"],\"editor.inspector.option.double.13h5354\":[\"[Ðöûƀļé ~~]\"],\"editor.inspector.option.ductBoard.lc3o4t\":[\"[Ðûçţ ƀöáŕð ~~~]\"],\"editor.inspector.option.dutch.1djx429\":[\"[Ðûţçĥ ~~]\"],\"editor.inspector.option.elbow.1flup74\":[\"[Éļƀöŵ ~~]\"],\"editor.inspector.option.end.1llf32i\":[\"[Éñð ~]\"],\"editor.inspector.option.endCap.1p4v4na\":[\"[Éñð çáþ ~~]\"],\"editor.inspector.option.equalFit.11vw52c\":[\"[Éǫûáļ ƒîţ ~~~]\"],\"editor.inspector.option.fixedCount.1o3dznu\":[\"[Ƒîẋéð çöûñţ ~~~]\"],\"editor.inspector.option.fixedSpacing.hl4dr4\":[\"[Ƒîẋéð šþáçîñĝ ~~~~]\"],\"editor.inspector.option.flat.ly0bei\":[\"[Ƒļáţ ~~]\"],\"editor.inspector.option.flex.ktpamq\":[\"[Ƒļéẋ ~~]\"],\"editor.inspector.option.floating.1oadpln\":[\"[Ƒļöáţîñĝ ~~~]\"],\"editor.inspector.option.floor.q9caf1\":[\"[Ƒļööŕ ~~]\"],\"editor.inspector.option.flush.olwwu5\":[\"[Ƒļûšĥ ~~]\"],\"editor.inspector.option.front.uhugl4\":[\"[Ƒŕöñţ ~~]\"],\"editor.inspector.option.furnace.w0mzpf\":[\"[Ƒûŕñáçé ~~~]\"],\"editor.inspector.option.gable.1ekyx6\":[\"[Ĝáƀļé ~~]\"],\"editor.inspector.option.gambrel.1yo90d9\":[\"[Ĝáɱƀŕéļ ~~~]\"],\"editor.inspector.option.generic.1074oey\":[\"[Ĝéñéŕîç ~~~]\"],\"editor.inspector.option.glass.163tc5n\":[\"[Ĝļášš ~~]\"],\"editor.inspector.option.glassFrame.jp9s3m\":[\"[Ĝļášš ƒŕáɱé ~~~]\"],\"editor.inspector.option.globe.1avkqoy\":[\"[Ĝļöƀé ~~]\"],\"editor.inspector.option.grounded.jwoq73\":[\"[Ĝŕöûñðéð ~~~]\"],\"editor.inspector.option.guard.1m575se\":[\"[Ĝûáŕð ~~]\"],\"editor.inspector.option.halfRound.m5hob0\":[\"[Ĥáļƒ ŕöûñð ~~~]\"],\"editor.inspector.option.hidden.gp48rd\":[\"[Ĥîððéñ ~~]\"],\"editor.inspector.option.hip.r0jnjy\":[\"[Ĥîþ ~]\"],\"editor.inspector.option.horizontal.tyapah\":[\"[Ĥöŕîžöñţáļ ~~~]\"],\"editor.inspector.option.include.1a27vnr\":[\"[Îñçļûðé ~~~]\"],\"editor.inspector.option.independentHighBeam.1tn0zvy\":[\"[Îñðéþéñðéñţ ĥîĝĥ ƀéáɱ ~~~~~~]\"],\"editor.inspector.option.industrial.8sd9u\":[\"[Îñðûšţŕîáļ ~~~]\"],\"editor.inspector.option.inline.1uh05lg\":[\"[Îñļîñé ~~]\"],\"editor.inspector.option.integrated.1xd9lv0\":[\"[Îñţéĝŕáţéð ~~~]\"],\"editor.inspector.option.joined.1x2o8ds\":[\"[Ĵöîñéð ~~]\"],\"editor.inspector.option.kStyle.m8kfwz\":[\"[Ķ šţýļé ~~]\"],\"editor.inspector.option.kickout.vt8s6p\":[\"[Ķîçķöûţ ~~~]\"],\"editor.inspector.option.knee.186hcui\":[\"[Ķñéé ~~]\"],\"editor.inspector.option.landing.tyqarg\":[\"[Ļáñðîñĝ ~~~]\"],\"editor.inspector.option.lantern.1h7o2xb\":[\"[Ļáñţéŕñ ~~~]\"],\"editor.inspector.option.leave.1xf0sbk\":[\"[Ļéáṽé ~~]\"],\"editor.inspector.option.left.14n06mo\":[\"[Ļéƒţ ~~]\"],\"editor.inspector.option.level.i4lhtp\":[\"[Ļéṽéļ ~~]\"],\"editor.inspector.option.lowProfile.1h9lgzg\":[\"[Ļöŵ þŕöƒîļé ~~~]\"],\"editor.inspector.option.mansard.dwzck9\":[\"[Ṁáñšáŕð ~~~]\"],\"editor.inspector.option.manual.1wu7r43\":[\"[Ṁáñûáļ ~~]\"],\"editor.inspector.option.maximumSpacing.n1fzl4\":[\"[Ṁáẋîɱûɱ šþáçîñĝ ~~~~~]\"],\"editor.inspector.option.metal.1az9fgc\":[\"[Ṁéţáļ ~~]\"],\"editor.inspector.option.metalPanel.1xdz476\":[\"[Ṁéţáļ þáñéļ ~~~]\"],\"editor.inspector.option.minimal.fwmiwg\":[\"[Ṁîñîɱáļ ~~~]\"],\"editor.inspector.option.mono.oszvd6\":[\"[Ṁöñö ~~]\"],\"editor.inspector.option.none.deku7v\":[\"[Ñöñé ~~]\"],\"editor.inspector.option.omit.okcs7w\":[\"[Öɱîţ ~~]\"],\"editor.inspector.option.open.n6hn1l\":[\"[Öþéñ ~~]\"],\"editor.inspector.option.openRack.mvt1x0\":[\"[Öþéñ ŕáçķ ~~~]\"],\"editor.inspector.option.opening.dfet3\":[\"[Öþéñîñĝ ~~~]\"],\"editor.inspector.option.oval.1jiqzxx\":[\"[Öṽáļ ~~]\"],\"editor.inspector.option.picket.zyeoy1\":[\"[Þîçķéţ ~~]\"],\"editor.inspector.option.pointed.effedk\":[\"[Þöîñţéð ~~~]\"],\"editor.inspector.option.postAndRail.lajk2u\":[\"[Þöšţ áñð ŕáîļ ~~~~]\"],\"editor.inspector.option.preserveHighEdge.y6ywf0\":[\"[Þŕéšéŕṽé ĥîĝĥ éðĝé ~~~~~]\"],\"editor.inspector.option.preserveLowEdge.196m5pk\":[\"[Þŕéšéŕṽé ļöŵ éðĝé ~~~~~]\"],\"editor.inspector.option.preservePitch.1uq973r\":[\"[Þŕéšéŕṽé þîţçĥ ~~~~]\"],\"editor.inspector.option.privacy.1th4hrb\":[\"[Þŕîṽáçý ~~~]\"],\"editor.inspector.option.purlins.od124c\":[\"[Þûŕļîñš ~~~]\"],\"editor.inspector.option.pvc.1oc4u2w\":[\"[Þṽç ~]\"],\"editor.inspector.option.pyramid.17ucsqv\":[\"[Þýŕáɱîð ~~~]\"],\"editor.inspector.option.rafters.16tzbby\":[\"[Ŕáƒţéŕš ~~~]\"],\"editor.inspector.option.rail.39zqc9\":[\"[Ŕáîļ ~~]\"],\"editor.inspector.option.raised.4kyx9h\":[\"[Ŕáîšéð ~~]\"],\"editor.inspector.option.rect.tpfvaf\":[\"[Ŕéçţ ~~]\"],\"editor.inspector.option.reducer.18byt67\":[\"[Ŕéðûçéŕ ~~~]\"],\"editor.inspector.option.return.1klrjrz\":[\"[Ŕéţûŕñ ~~]\"],\"editor.inspector.option.returnGrille.r28ncm\":[\"[Ŕéţûŕñ ĝŕîļļé ~~~~]\"],\"editor.inspector.option.right.8humpx\":[\"[Ŕîĝĥţ ~~]\"],\"editor.inspector.option.round.1vx0wyj\":[\"[Ŕöûñð ~~]\"],\"editor.inspector.option.rounded.199nwpm\":[\"[Ŕöûñðéð ~~~]\"],\"editor.inspector.option.sanitaryTee.oro3d4\":[\"[Šáñîţáŕý ţéé ~~~~]\"],\"editor.inspector.option.scalloped.1eltba0\":[\"[Šçáļļöþéð ~~~]\"],\"editor.inspector.option.scoop.qy5zdv\":[\"[Šçööþ ~~]\"],\"editor.inspector.option.segmentedPanel.5r3hwl\":[\"[Šéĝɱéñţéð þáñéļ ~~~~~]\"],\"editor.inspector.option.shed.6t994v\":[\"[Šĥéð ~~]\"],\"editor.inspector.option.sheetMetal.l164lv\":[\"[Šĥééţ ɱéţáļ ~~~]\"],\"editor.inspector.option.shingle.pfmynh\":[\"[Šĥîñĝļé ~~~]\"],\"editor.inspector.option.shingled.1nm9inf\":[\"[Šĥîñĝļéð ~~~]\"],\"editor.inspector.option.simple.12mfu73\":[\"[Šîɱþļé ~~]\"],\"editor.inspector.option.single.1uzxurt\":[\"[Šîñĝļé ~~]\"],\"editor.inspector.option.singleLeft.1atdh02\":[\"[Šîñĝļé ļéƒţ ~~~]\"],\"editor.inspector.option.singleRight.1axbu67\":[\"[Šîñĝļé ŕîĝĥţ ~~~~]\"],\"editor.inspector.option.slantBox.1ta99vy\":[\"[Šļáñţ ƀöẋ ~~~]\"],\"editor.inspector.option.slat.1p9njbz\":[\"[Šļáţ ~~]\"],\"editor.inspector.option.sliding.cd0jox\":[\"[Šļîðîñĝ ~~~]\"],\"editor.inspector.option.slope.1bn2qw\":[\"[Šļöþé ~~]\"],\"editor.inspector.option.sloped.lo4sh0\":[\"[Šļöþéð ~~]\"],\"editor.inspector.option.solid.o4uy6s\":[\"[Šöļîð ~~]\"],\"editor.inspector.option.solidPanel.2yaw62\":[\"[Šöļîð þáñéļ ~~~]\"],\"editor.inspector.option.spiral.91hcl4\":[\"[Šþîŕáļ ~~]\"],\"editor.inspector.option.splash.1uke4cm\":[\"[Šþļášĥ ~~]\"],\"editor.inspector.option.spread.1g1zysu\":[\"[Šþŕéáð ~~]\"],\"editor.inspector.option.square.1xl1lk6\":[\"[Šǫûáŕé ~~]\"],\"editor.inspector.option.stair.1xf86e\":[\"[Šţáîŕ ~~]\"],\"editor.inspector.option.standard.vuco\":[\"[Šţáñðáŕð ~~~]\"],\"editor.inspector.option.start.30xvgf\":[\"[Šţáŕţ ~~]\"],\"editor.inspector.option.step.jtn9kf\":[\"[Šţéþ ~~]\"],\"editor.inspector.option.stepped.naxzh0\":[\"[Šţéþþéð ~~~]\"],\"editor.inspector.option.straight.lxqbfr\":[\"[Šţŕáîĝĥţ ~~~]\"],\"editor.inspector.option.strap.14q0ps9\":[\"[Šţŕáþ ~~]\"],\"editor.inspector.option.supply.1oy2zwu\":[\"[Šûþþļý ~~]\"],\"editor.inspector.option.supplyRegister.1lzdbbn\":[\"[Šûþþļý ŕéĝîšţéŕ ~~~~~]\"],\"editor.inspector.option.tapered.3y5blo\":[\"[Ţáþéŕéð ~~~]\"],\"editor.inspector.option.targetSpacing.14uibc9\":[\"[Ţáŕĝéţ šþáçîñĝ ~~~~]\"],\"editor.inspector.option.tee.7d6tjp\":[\"[Ţéé ~]\"],\"editor.inspector.option.tilted.6n0u5j\":[\"[Ţîļţéð ~~]\"],\"editor.inspector.option.top.2nypcs\":[\"[Ţöþ ~]\"],\"editor.inspector.option.transition.1rziz9e\":[\"[Ţŕáñšîţîöñ ~~~]\"],\"editor.inspector.option.vent.xda5j2\":[\"[Ṽéñţ ~~]\"],\"editor.inspector.option.walkOn.1n5sg9l\":[\"[Ŵáļķ öñ ~~]\"],\"editor.inspector.option.wall.blj585\":[\"[Ŵáļļ ~~]\"],\"editor.inspector.option.wallAbutment.lza941\":[\"[Ŵáļļ áƀûţɱéñţ ~~~~]\"],\"editor.inspector.option.wallLedger.5m8ana\":[\"[Ŵáļļ ļéðĝéŕ ~~~]\"],\"editor.inspector.option.wallShelf.yiozfl\":[\"[Ŵáļļ šĥéļƒ ~~~]\"],\"editor.inspector.option.waste.3xrp79\":[\"[Ŵášţé ~~]\"],\"editor.inspector.option.wye.14vupc8\":[\"[Ŵýé ~]\"],\"editor.layers.collapse\":[\"[Çöļļáþšé ~~~]\"],\"editor.layers.defaultName.ceiling\":[\"[Çéîļîñĝ (\",[\"area\"],\") ~~~]\"],\"editor.layers.defaultName.collection\":[\"[Çöļļéçţîöñ ~~~]\"],\"editor.layers.defaultName.flight\":[\"[Ƒļîĝĥţ (\",[\"width\"],\"×\",[\"length\"],\"ɱ) ~~~]\"],\"editor.layers.defaultName.landing\":[\"[Ļáñðîñĝ (\",[\"width\"],\"×\",[\"length\"],\"ɱ) ~~~]\"],\"editor.layers.defaultName.node\":[\"[Ñöðé ~~]\"],\"editor.layers.defaultName.roof\":[\"[Ŕööƒ (\",[\"count\",\"plural\",{\"one\":[\"#\",\" šéĝɱéñţ\"],\"other\":[\"#\",\" šéĝɱéñţš\"]}],\") ~~~~~~]\"],\"editor.layers.defaultName.roofSegment\":[\"[\",[\"roofType\",\"select\",{\"hip\":[\"Ĥîþ\"],\"gable\":[\"Ĝáƀļé\"],\"shed\":[\"Šĥéð\"],\"gambrel\":[\"Ĝáɱƀŕéļ\"],\"dutch\":[\"Ðûţçĥ\"],\"mansard\":[\"Ṁáñšáŕð\"],\"flat\":[\"Ƒļáţ\"],\"conical\":[\"Çöñîçáļ\"],\"barrel\":[\"Ɓáŕŕéļ\"],\"other\":[\"Ŕööƒ\"]}],\" (\",[\"width\"],\"×\",[\"depth\"],\"ɱ) ~~~~~~~~~~~~~~~~]\"],\"editor.layers.defaultName.room\":[\"[Ŕööɱ (\",[\"area\"],\") ~~]\"],\"editor.layers.defaultName.slab\":[\"[Šļáƀ (\",[\"area\"],\") ~~]\"],\"editor.layers.defaultName.staircase\":[\"[Šţáîŕçášé (\",[\"count\",\"plural\",{\"one\":[\"#\",\" šéĝɱéñţ\"],\"other\":[\"#\",\" šéĝɱéñţš\"]}],\") ~~~~~~~~]\"],\"editor.layers.defaultName.zone\":[\"[Žöñé (\",[\"area\"],\") ~~]\"],\"editor.layers.expand\":[\"[Éẋþáñð ~~]\"],\"editor.layers.levelOptions\":[\"[\",[\"levelName\"],\" öþţîöñš ~~~]\"],\"editor.layers.rename\":[\"[Ŕéñáɱé ~~]\"],\"editor.layers.spaceColour\":[\"[\",[\"role\",\"select\",{\"room\":[\"Ŕööɱ çöļöûŕ\"],\"other\":[\"Žöñé çöļöûŕ\"]}],\" ~~~~~~]\"],\"editor.layers.unitColour\":[\"[Ûñîţ çöļöûŕ ~~~]\"],\"editor.levelDuplicateDialog.cancel\":[\"[Çáñçéļ ~~]\"],\"editor.levelDuplicateDialog.chooseWhatToCopyFromLevel\":[\"[Çĥööšé ŵĥáţ ţö çöþý ƒŕöɱ \",[\"levelName\"],\". ~~~~~~]\"],\"editor.levelDuplicateDialog.chooseWhatToCopyFromThisLevel\":[\"[Çĥööšé ŵĥáţ ţö çöþý ƒŕöɱ ţĥîš ļéṽéļ. ~~~~~~~~~]\"],\"editor.levelDuplicateDialog.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"editor.levelDuplicateDialog.duplicateLevel\":[\"[Ðûþļîçáţé Ļéṽéļ ~~~~~]\"],\"editor.levelDuplicateDialog.everything\":[\"[Éṽéŕýţĥîñĝ ~~~]\"],\"editor.levelDuplicateDialog.structureFinishesAndPlacedItemsWithout\":[\"[Šţŕûçţûŕé, ƒîñîšĥéš, áñð þļáçéð îţéɱš, ŵîţĥöûţ ĝûîðé ŕéƒéŕéñçéš. ~~~~~~~~~~~~~~~~]\"],\"editor.levelDuplicateDialog.structureFurniture\":[\"[Šţŕûçţûŕé + ƒûŕñîţûŕé ~~~~~~]\"],\"editor.levelDuplicateDialog.structureMaterials\":[\"[Šţŕûçţûŕé + ɱáţéŕîáļš ~~~~~~]\"],\"editor.levelDuplicateDialog.structureMaterialsFurnitureAndReferences\":[\"[Šţŕûçţûŕé, ɱáţéŕîáļš, ƒûŕñîţûŕé, áñð ŕéƒéŕéñçéš. ~~~~~~~~~~~~]\"],\"editor.levelDuplicateDialog.structureOnly\":[\"[Šţŕûçţûŕé öñļý ~~~~]\"],\"editor.levelDuplicateDialog.structureWithTheCurrentMaterialAnd\":[\"[Šţŕûçţûŕé ŵîţĥ ţĥé çûŕŕéñţ ɱáţéŕîáļ áñð ƒîñîšĥ áššîĝñɱéñţš. ~~~~~~~~~~~~~~~~]\"],\"editor.levelDuplicateDialog.wallsSlabsRoofsStairsWindowsAnd\":[\"[Ŵáļļš, šļáƀš, ŕööƒš, šţáîŕš, ŵîñðöŵš, áñð ðööŕš ŵîţĥöûţ ƒîñîšĥéš. ~~~~~~~~~~~~~~~~]\"],\"editor.lib.contextualHelp.addOrRemoveObjectsFromThe\":[\"[Åðð öŕ ŕéɱöṽé öƀĵéçţš ƒŕöɱ ţĥé šéļéçţîöñ ~~~~~~~~~~~]\"],\"editor.lib.contextualHelp.adjustOneSideSCornerRadius\":[\"[Åðĵûšţ öñé šîðé’š çöŕñéŕ ŕáðîûš ~~~~~~~~]\"],\"editor.lib.contextualHelp.clearTheSelectionOrClickOutside\":[\"[Çļéáŕ ţĥé šéļéçţîöñ (öŕ çļîçķ öûţšîðé) ~~~~~~~~~~]\"],\"editor.lib.contextualHelp.clickAHandleDotToShow\":[\"[Çļîçķ á ĥáñðļé ðöţ ţö šĥöŵ ɱöṽé áŕŕöŵš ~~~~~~~~~~]\"],\"editor.lib.contextualHelp.clickOrDragTheSelectionTo\":[\"[Çļîçķ öŕ ðŕáĝ ţĥé šéļéçţîöñ ţö ɱöṽé îţ áš öñé ~~~~~~~~~~~]\"],\"editor.lib.contextualHelp.clickTheHandleDotToShow\":[\"[Çļîçķ ţĥé ĥáñðļé ðöţ ţö šĥöŵ ɱöṽé + ŕöţáţé ĥáñðļéš ~~~~~~~~~~~~]\"],\"editor.lib.contextualHelp.detachTheJointWhileDraggingAn\":[\"[Ðéţáçĥ ţĥé ĵöîñţ ŵĥîļé ðŕáĝĝîñĝ áñ áŕŕöŵ ~~~~~~~~~~~]\"],\"editor.lib.contextualHelp.dragLeftOrRightToRotate\":[\"[Ðŕáĝ ļéƒţ öŕ ŕîĝĥţ ţö ŕöţáţé šéļéçţéð öƀĵéçţ ~~~~~~~~~~~~]\"],\"editor.lib.contextualHelp.dragSelectedMovableObject\":[\"[Ðŕáĝ šéļéçţéð ɱöṽáƀļé öƀĵéçţ ~~~~~~~~]\"],\"editor.lib.contextualHelp.groupSelectionSessionOnly\":[\"[Ĝŕöûþ šéļéçţîöñ (šéššîöñ öñļý) ~~~~~~~~]\"],\"editor.lib.contextualHelp.holdToRotateFreely\":[\"[Ĥöļð ţö ŕöţáţé ƒŕééļý ~~~~~~]\"],\"editor.lib.contextualHelp.rotate45\":[\"[Ŕöţáţé ±45° ~~]\"],\"editor.lib.contextualHelp.rotateTheSelection45\":[\"[Ŕöţáţé ţĥé šéļéçţîöñ ±45° ~~~~~~]\"],\"editor.lib.contextualHelp.rotatingFreely\":[\"[Ŕöţáţîñĝ ƒŕééļý (ñö áñĝļé šţéþ) ~~~~~~~~]\"],\"editor.lib.contextualHelp.switchTheRotationAxisYX\":[\"[Šŵîţçĥ ţĥé ŕöţáţîöñ áẋîš (Ý → Ẋ → Ž) ~~~~~~~~]\"],\"editor.lib.contextualHelp.ungroupSessionSelection\":[\"[Ûñĝŕöûþ šéššîöñ šéļéçţîöñ ~~~~~~~]\"],\"editor.lib.continuation.continuous\":[\"[Çöñţîñûöûš ~~~]\"],\"editor.lib.continuation.continuousCanopy\":[\"[Çöñţîñûöûš çáñöþý ~~~~~]\"],\"editor.lib.continuation.continuousRun\":[\"[Çöñţîñûöûš ŕûñ ~~~~]\"],\"editor.lib.continuation.curvedFence\":[\"[Çûŕṽéð ƒéñçé ~~~~]\"],\"editor.lib.continuation.freehandFence\":[\"[Ƒŕééĥáñð ƒéñçé ~~~~]\"],\"editor.lib.continuation.placeMultiple\":[\"[Þļáçé ɱûļţîþļé ~~~~]\"],\"editor.lib.continuation.placeOnce\":[\"[Þļáçé öñçé ~~~]\"],\"editor.lib.continuation.polygonRoom\":[\"[Þöļýĝöñ ŕööɱ ~~~~]\"],\"editor.lib.continuation.rectangleRoom\":[\"[Ŕéçţáñĝļé ŕööɱ ~~~~]\"],\"editor.lib.continuation.singleCabinet\":[\"[Šîñĝļé çáƀîñéţ ~~~~]\"],\"editor.lib.continuation.singleCanopy\":[\"[Šîñĝļé çáñöþý ~~~~]\"],\"editor.lib.continuation.singleFence\":[\"[Šîñĝļé ƒéñçé ~~~~]\"],\"editor.lib.continuation.walls\":[\"[Ŵáļļš ~~]\"],\"editor.lib.hudTitle.cutOpening\":[\"[Çûţ öþéñîñĝ ~~~]\"],\"editor.lib.hudTitle.divideRoom\":[\"[Ðîṽîðé ŕööɱ ~~~]\"],\"editor.lib.hudTitle.editKind\":[\"[Éðîţ \",[\"kind\"],\" ~~]\"],\"editor.lib.hudTitle.erase\":[\"[Éŕášé ~~]\"],\"editor.lib.hudTitle.levelTerrain\":[\"[Ļéṽéļ ţéŕŕáîñ ~~~~]\"],\"editor.lib.hudTitle.lowerTerrain\":[\"[Ļöŵéŕ ţéŕŕáîñ ~~~~]\"],\"editor.lib.hudTitle.mezzanine\":[\"[Ṁéžžáñîñé ~~~]\"],\"editor.lib.hudTitle.moveKind\":[\"[Ṁöṽé \",[\"kind\"],\" ~~]\"],\"editor.lib.hudTitle.moveRoom\":[\"[Ṁöṽé ŕööɱ ~~~]\"],\"editor.lib.hudTitle.moveSelection\":[\"[Ṁöṽé šéļéçţîöñ ~~~~]\"],\"editor.lib.hudTitle.paint\":[\"[Þáîñţ ~~]\"],\"editor.lib.hudTitle.paintARectangle\":[\"[Þáîñţ á ŕéçţáñĝļé ~~~~~]\"],\"editor.lib.hudTitle.paintAShape\":[\"[Þáîñţ á šĥáþé ~~~~]\"],\"editor.lib.hudTitle.pickMaterial\":[\"[Þîçķ ɱáţéŕîáļ ~~~~]\"],\"editor.lib.hudTitle.raiseTerrain\":[\"[Ŕáîšé ţéŕŕáîñ ~~~~]\"],\"editor.lib.hudTitle.resize\":[\"[Ŕéšîžé ~~]\"],\"editor.lib.hudTitle.rotate\":[\"[Ŕöţáţé ~~]\"],\"editor.lib.hudTitle.select\":[\"[Šéļéçţ ~~]\"],\"editor.lib.hudTitle.smartMeasure\":[\"[Šɱáŕţ ɱéášûŕé ~~~~]\"],\"editor.lib.hudTitle.smoothTerrain\":[\"[Šɱööţĥ ţéŕŕáîñ ~~~~]\"],\"editor.lib.hudTitle.splitKind\":[\"[Šþļîţ \",[\"kind\"],\" ~~]\"],\"editor.lib.hudTitle.terrace\":[\"[Ţéŕŕáçé ~~~]\"],\"editor.lib.wallDrawVariant.polygonRoom\":[\"[Þöļýĝöñ ŕööɱ ~~~~]\"],\"editor.lib.wallDrawVariant.rectangleRoom\":[\"[Ŕéçţáñĝļé ŕööɱ ~~~~]\"],\"editor.lib.wallDrawVariant.walls\":[\"[Ŵáļļš ~~]\"],\"editor.mechanismAction\":[\"[\",[\"action\",\"select\",{\"close\":[\"Çļöšé\"],\"open\":[\"Öþéñ\"],\"stop\":[\"Šţöþ\"],\"other\":[\"Þļáý\"]}],\" ~~~~~~]\"],\"editor.nodeActionMenu.curve\":[\"[Çûŕṽé ~~]\"],\"editor.nodeActionMenu.cutOut\":[\"[Çûţ öûţ ~~]\"],\"editor.nodeActionMenu.delete\":[\"[Ðéļéţé ~~]\"],\"editor.nodeActionMenu.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"editor.nodeActionMenu.editMesh\":[\"[Éðîţ ɱéšĥ ~~~]\"],\"editor.nodeActionMenu.findInCatalog\":[\"[Ƒîñð îñ çáţáļöĝ ~~~~]\"],\"editor.nodeActionMenu.groupSelection\":[\"[Ĝŕöûþ šéļéçţîöñ ~~~~~]\"],\"editor.nodeActionMenu.move\":[\"[Ṁöṽé ~~]\"],\"editor.nodeActionMenu.rotateLeft\":[\"[Ŕöţáţé ļéƒţ ~~~]\"],\"editor.nodeActionMenu.rotateRight\":[\"[Ŕöţáţé ŕîĝĥţ ~~~~]\"],\"editor.nodeActionMenu.ungroupSelection\":[\"[Ûñĝŕöûþ šéļéçţîöñ ~~~~~]\"],\"editor.nodeDisplay.ceiling\":[\"[Çéîļîñĝ ~~~]\"],\"editor.nodeDisplay.column\":[\"[Çöļûɱñ ~~]\"],\"editor.nodeDisplay.door\":[\"[Ðööŕ ~~]\"],\"editor.nodeDisplay.elevator\":[\"[Éļéṽáţöŕ ~~~]\"],\"editor.nodeDisplay.fence\":[\"[Ƒéñçé ~~]\"],\"editor.nodeDisplay.guide\":[\"[Ĝûîðé îɱáĝé ~~~]\"],\"editor.nodeDisplay.item\":[\"[Îţéɱ ~~]\"],\"editor.nodeDisplay.roof\":[\"[Ŕööƒ ~~]\"],\"editor.nodeDisplay.roofSegment\":[\"[Ŕööƒ šéĝɱéñţ ~~~~]\"],\"editor.nodeDisplay.room\":[\"[Ŕööɱ ~~]\"],\"editor.nodeDisplay.scan\":[\"[3Ð Šçáñ ~~]\"],\"editor.nodeDisplay.selection\":[\"[Šéļéçţîöñ ~~~]\"],\"editor.nodeDisplay.slab\":[\"[Šļáƀ ~~]\"],\"editor.nodeDisplay.stair\":[\"[Šţáîŕ ~~]\"],\"editor.nodeDisplay.stairSegment\":[\"[Šţáîŕ šéĝɱéñţ ~~~~]\"],\"editor.nodeDisplay.wall\":[\"[Ŵáļļ ~~]\"],\"editor.nodeDisplay.window\":[\"[Ŵîñðöŵ ~~]\"],\"editor.nodeDisplay.zone\":[\"[Žöñé ~~]\"],\"editor.panels.collections.collectionsPopover.cancel\":[\"[Çáñçéļ ~~]\"],\"editor.panels.collections.collectionsPopover.collectionName\":[\"[Çöļļéçţîöñ ñáɱé… ~~~~~]\"],\"editor.panels.collections.collectionsPopover.collections\":[\"[Çöļļéçţîöñš ~~~~]\"],\"editor.panels.collections.collectionsPopover.delete\":[\"[Ðéļéţé ~~]\"],\"editor.panels.collections.collectionsPopover.deleteName\":[\"[Ðéļéţé \\\"\",[\"name\"],\"\\\"? ~~]\"],\"editor.panels.collections.collectionsPopover.new\":[\"[Ñéŵ ~]\"],\"editor.panels.collections.collectionsPopover.noCollectionsYetCreateOneTo\":[\"[Ñö çöļļéçţîöñš ýéţ. Çŕéáţé öñé ţö ĝŕöûþ éļéɱéñţš ţöĝéţĥéŕ. ~~~~~~~~~~~~~~~]\"],\"editor.panels.collections.collectionsPopover.rename\":[\"[Ŕéñáɱé ~~]\"],\"editor.panels.floorFoundationPanel.aThickerFloorGrowsUpwardThe\":[\"[Å ţĥîçķéŕ ƒļööŕ ĝŕöŵš ûþŵáŕð: ţĥé ŕööɱš ƀéļöŵ ķééþ ţĥéîŕ ĥéîĝĥţ. ~~~~~~~~~~~~~~~~]\"],\"editor.panels.floorFoundationPanel.edgeFinish\":[\"[Éðĝé ƒîñîšĥ ~~~]\"],\"editor.panels.floorFoundationPanel.floorPlate\":[\"[Ƒļööŕ þļáţé ~~~]\"],\"editor.panels.floorFoundationPanel.floorPlateThicknesslabelThickRestingOn\":[\"[Ƒļööŕ þļáţé \",[\"thicknessLabel\"],\" ţĥîçķ, ŕéšţîñĝ öñ ţĥé ŵáļļš ƀéļöŵ ~~~~~~~~~~~~]\"],\"editor.panels.floorFoundationPanel.floorThickness\":[\"[Ƒļööŕ ţĥîçķñéšš ~~~~~]\"],\"editor.panels.floorFoundationPanel.floorTopAbove\":[\"[Ƒļööŕ ţöþ +\",[\"height\"],\" ~~~]\"],\"editor.panels.floorFoundationPanel.floorTopValue\":[\"[Ƒļööŕ ţöþ \",[\"height\"],\" ~~~]\"],\"editor.panels.floorFoundationPanel.foundationFinish\":[\"[Ƒöûñðáţîöñ ƒîñîšĥ ~~~~~]\"],\"editor.panels.floorFoundationPanel.foundationHeight\":[\"[Ƒöûñðáţîöñ ĥéîĝĥţ ~~~~~]\"],\"editor.panels.floorFoundationPanel.kicker\":[\"[Ƒļööŕ þļáţé ~~~]\"],\"editor.panels.floorFoundationPanel.kickerLevel\":[\"[Ƒļööŕ þļáţé · \",[\"level\"],\" ~~~]\"],\"editor.panels.floorFoundationPanel.kickerRestsOn\":[\"[Ƒļööŕ þļáţé · \",[\"level\"],\" · ŕéšţš öñ \",[\"below\"],\" ~~~~~~]\"],\"editor.panels.floorFoundationPanel.lowerTogether\":[\"[\",[\"count\",\"plural\",{\"2\":[\"Ļöŵéŕ ƀöţĥ\"],\"other\":[\"Ļöŵéŕ áļļ \",[\"number\"]]}],\" ~~~~~~]\"],\"editor.panels.floorFoundationPanel.notToScale\":[\"[Ñöţ ţö šçáļé ~~~]\"],\"editor.panels.floorFoundationPanel.onTheGround\":[\"[Öñ ţĥé ĝŕöûñð ~~~~]\"],\"editor.panels.floorFoundationPanel.raiseTogether\":[\"[\",[\"count\",\"plural\",{\"2\":[\"Ŕáîšé ƀöţĥ\"],\"other\":[\"Ŕáîšé áļļ \",[\"number\"]]}],\" ~~~~~~]\"],\"editor.panels.floorFoundationPanel.raisedOnAFoundation\":[\"[Ŕáîšéð öñ á ƒöûñðáţîöñ ~~~~~~]\"],\"editor.panels.floorFoundationPanel.section.floorPlate\":[\"[Ƒļööŕ þļáţé · \",[\"thickness\"],\" ~~~]\"],\"editor.panels.floorFoundationPanel.section.floorTop\":[\"[Ƒļööŕ ţöþ ~~~]\"],\"editor.panels.floorFoundationPanel.section.foundation\":[\"[Ƒöûñðáţîöñ ~~~]\"],\"editor.panels.floorFoundationPanel.section.foundationKind\":[\"[Ƒöûñðáţîöñ · \",[\"foundation\"],\" ~~~]\"],\"editor.panels.floorFoundationPanel.section.ground\":[\"[Ĝŕöûñð ~~]\"],\"editor.panels.floorFoundationPanel.section.slab\":[\"[Šļáƀ · \",[\"thickness\"],\" ~~]\"],\"editor.panels.floorFoundationPanel.section.wallsBelow\":[\"[Ŵáļļš ƀéļöŵ ~~~]\"],\"editor.panels.floorFoundationPanel.sectionOnGround\":[\"[Šļáƀ \",[\"thickness\"],\" ţĥîçķ öñ ţĥé ĝŕöûñð, ƒļööŕ ţöþ \",[\"top\"],\" áƀöṽé ţĥé ĝŕöûñð ~~~~~~~~~~~~~]\"],\"editor.panels.floorFoundationPanel.sectionRaised\":[\"[Šļáƀ \",[\"thickness\"],\" ţĥîçķ öñ á \",[\"foundation\"],\" ƒöûñðáţîöñ, ƒļööŕ ţöþ \",[\"top\"],\" áƀöṽé ţĥé ĝŕöûñð ~~~~~~~~~~~~~~]\"],\"editor.panels.floorFoundationPanel.slab\":[\"[Šļáƀ ~~]\"],\"editor.panels.floorFoundationPanel.slabThickness\":[\"[Šļáƀ ţĥîçķñéšš ~~~~]\"],\"editor.panels.floorFoundationPanel.theFloorSOutsideEdgeAll\":[\"[Ţĥé ƒļööŕ'š öûţšîðé éðĝé, áļļ áŕöûñð ţĥé ƒööţþŕîñţ. ~~~~~~~~~~~~~]\"],\"editor.panels.floorFoundationPanel.theFoundationStandsOnTheGround\":[\"[Ţĥé ƒöûñðáţîöñ šţáñðš öñ ţĥé ĝŕöûñð; ţĥé šļáƀ šîţš öñ îţ. ~~~~~~~~~~~~~~]\"],\"editor.panels.floorFoundationPanel.theSlabSitsOnTheFoundation\":[\"[Ţĥé šļáƀ šîţš öñ ţĥé ƒöûñðáţîöñ (öŕ ţĥé ĝŕöûñð): á ţĥîçķéŕ šļáƀ ŕáîšéš ţĥé ƒļööŕ ţöþ áñð éṽéŕýţĥîñĝ öñ îţ. ~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.floorFoundationPanel.underTheFloor\":[\"[Ûñðéŕ ţĥé ƒļööŕ ~~~~]\"],\"editor.panels.floorOpeningPanel.aHatchInTheMezzanineIt\":[\"[Å ĥáţçĥ îñ ţĥé ɱéžžáñîñé: îţ çûţš öñļý ţĥé ɱéžžáñîñé’š ƒļööŕ. ~~~~~~~~~~~~~~~]\"],\"editor.panels.floorOpeningPanel.alsoCutTheCeilingBelow\":[\"[Åļšö çûţ ţĥé çéîļîñĝ ƀéļöŵ ~~~~~~~]\"],\"editor.panels.floorOpeningPanel.alsoCutTheFloorAbove\":[\"[Åļšö çûţ ţĥé ƒļööŕ áƀöṽé ~~~~~~]\"],\"editor.panels.floorOpeningPanel.areaDragCorners\":[\"[\",[\"area\"],\" · Ðŕáĝ îţš çöŕñéŕš ţö çĥáñĝé ţĥé šĥáþé. ~~~~~~~~~]\"],\"editor.panels.floorOpeningPanel.areaOwned\":[\"[\",[\"area\"],\" · Šĥáþé ƒöļļöŵš îţš öŵñéŕ. ~~~~~~]\"],\"editor.panels.floorOpeningPanel.delete\":[\"[Ðéļéţé ~~]\"],\"editor.panels.floorOpeningPanel.done\":[\"[Ðöñé ~~]\"],\"editor.panels.floorOpeningPanel.kicker\":[\"[Öþéñîñĝ ~~~]\"],\"editor.panels.floorOpeningPanel.kickerLevel\":[\"[Öþéñîñĝ · \",[\"level\"],\" ~~~]\"],\"editor.panels.floorOpeningPanel.kickerRoom\":[\"[Öþéñîñĝ · îñ \",[\"room\"],\" ~~~]\"],\"editor.panels.floorOpeningPanel.kickerRoomLevel\":[\"[Öþéñîñĝ · îñ \",[\"room\"],\" · \",[\"level\"],\" ~~~]\"],\"editor.panels.floorOpeningPanel.oneVoidWith\":[\"[Öñ \",[\"level\"],\", áš öñé ṽöîð ŵîţĥ ţĥîš öþéñîñĝ. ~~~~~~~~]\"],\"editor.panels.floorOpeningPanel.ownedByElevator\":[\"[Öŵñéð ƀý Éļéṽáţöŕ ~~~~~]\"],\"editor.panels.floorOpeningPanel.ownedByStaircase\":[\"[Öŵñéð ƀý Šţáîŕçášé ~~~~~]\"],\"editor.panels.floorOpeningPanel.room\":[\"[Ŕööɱ ~~]\"],\"editor.panels.floorOpeningPanel.thereIsNoFloorAboveThis\":[\"[Ţĥéŕé îš ñö ƒļööŕ áƀöṽé ţĥîš šţöŕéý. ~~~~~~~~~]\"],\"editor.panels.floorOpeningPanel.thereIsNoStoreyBelow\":[\"[Ţĥéŕé îš ñö šţöŕéý ƀéļöŵ. ~~~~~~]\"],\"editor.panels.floorOpeningPanel.title\":[\"[\",[\"source\",\"select\",{\"stair\":[\"Šţáîŕ öþéñîñĝ\"],\"elevator\":[\"Éļéṽáţöŕ öþéñîñĝ\"],\"ceiling\":[\"Çéîļîñĝ öþéñîñĝ\"],\"other\":[\"Ƒļööŕ öþéñîñĝ\"]}],\" ~~~~~~~~~~~~~~~~]\"],\"editor.panels.mergeRefusal.alreadyJoined\":[\"[Öñé öƒ ţĥéɱ áļŕéáðý ŵŕáþš áñöţĥéŕ çöŕñéŕ. Ûñŵŕáþ îţ ƒîŕšţ. ~~~~~~~~~~~~~~~]\"],\"editor.panels.mergeRefusal.between\":[\"[\",[\"kind\",\"select\",{\"item\":[\"Ţĥéŕé îš áñ îţéɱ ƀéţŵééñ ţĥéɱ.\"],\"door\":[\"Ţĥéŕé îš á ðööŕ ƀéţŵééñ ţĥéɱ.\"],\"window\":[\"Ţĥéŕé îš á ŵîñðöŵ ƀéţŵééñ ţĥéɱ.\"],\"shelf\":[\"Ţĥéŕé îš á šĥéļƒ ƀéţŵééñ ţĥéɱ.\"],\"other\":[\"Ţĥéŕé îš šöɱéţĥîñĝ ƀéţŵééñ ţĥéɱ.\"]}],\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.mergeRefusal.cannotMerge\":[\"[Ţĥéšé ŵîñðöŵš çáññöţ ƀé ɱéŕĝéð. ~~~~~~~~]\"],\"editor.panels.mergeRefusal.cornerAngle\":[\"[Ţĥéîŕ ŵáļļš ɱééţ áţ ţöö šĥáŕþ öŕ ţöö ƒļáţ áñ áñĝļé ƒöŕ á çöŕñéŕ ŵîñðöŵ. ~~~~~~~~~~~~~~~~~]\"],\"editor.panels.mergeRefusal.heightExceedsWall\":[\"[Ţĥé ŵîñðöŵ šéļéçţéð ƒîŕšţ îš ţáļļéŕ ţĥáñ ţĥé öţĥéŕ ŵáļļ. Šéļéçţ ţĥé öţĥéŕ öñé ƒîŕšţ. ~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.mergeRefusal.notAdjacent\":[\"[Ţĥéý áŕé ţöö ƒáŕ áþáŕţ. Ŵîñðöŵš ɱéŕĝé ŵîţĥ áţ ɱöšţ \",[\"reach\"],\" ƀéţŵééñ ţĥéɱ. ~~~~~~~~~~~~~~~~]\"],\"editor.panels.mergeRefusal.notAtCorner\":[\"[Öñé öƒ ţĥéɱ îš ţöö ƒáŕ ƒŕöɱ ţĥé çöŕñéŕ. Å ŵîñðöŵ ĵöîñš öñé ŵîţĥîñ \",[\"reach\"],\" öƒ îţ. ~~~~~~~~~~~~~~~~~]\"],\"editor.panels.mergeRefusal.notOnWall\":[\"[Å ŕööƒ öŕ ðöŕɱéŕ ŵîñðöŵ çáññöţ ĵöîñ áñöţĥéŕ ŵîñðöŵ. ~~~~~~~~~~~~~]\"],\"editor.panels.mergeRefusal.overlap\":[\"[\",[\"kind\",\"select\",{\"item\":[\"Šļîðîñĝ ţĥéɱ ţö ţĥé çöŕñéŕ ŵöûļð öṽéŕļáþ áñ îţéɱ.\"],\"door\":[\"Šļîðîñĝ ţĥéɱ ţö ţĥé çöŕñéŕ ŵöûļð öṽéŕļáþ á ðööŕ.\"],\"window\":[\"Šļîðîñĝ ţĥéɱ ţö ţĥé çöŕñéŕ ŵöûļð öṽéŕļáþ á ŵîñðöŵ.\"],\"shelf\":[\"Šļîðîñĝ ţĥéɱ ţö ţĥé çöŕñéŕ ŵöûļð öṽéŕļáþ á šĥéļƒ.\"],\"other\":[\"Šļîðîñĝ ţĥéɱ ţö ţĥé çöŕñéŕ ŵöûļð öṽéŕļáþ šöɱéţĥîñĝ.\"]}],\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.mergeRefusal.wallsNotMeeting\":[\"[Ţĥéîŕ ŵáļļš ðö ñöţ ɱééţ áţ á çöŕñéŕ. ~~~~~~~~~]\"],\"editor.panels.mixed\":[\"[Ṁîẋéð ~~]\"],\"editor.panels.mobilePanelSheet.close\":[\"[Çļöšé ~~]\"],\"editor.panels.mobileSelectionBar.delete\":[\"[Ðéļéţé ~~]\"],\"editor.panels.mobileSelectionBar.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"editor.panels.mobileSelectionBar.editProperties\":[\"[Éðîţ þŕöþéŕţîéš ~~~~~]\"],\"editor.panels.mobileSelectionBar.editResolvedlabel\":[\"[Éðîţ \",[\"resolvedLabel\"],\" ~~]\"],\"editor.panels.mobileSelectionBar.move\":[\"[Ṁöṽé ~~]\"],\"editor.panels.multiHeightMode.currentlyCurrentlabel\":[\"[Çûŕŕéñţļý \",[\"currentLabel\"],\" ~~~]\"],\"editor.panels.multiHeightMode.customHeight\":[\"[Çûšţöɱ ĥéîĝĥţ ~~~~]\"],\"editor.panels.multiHeightMode.followsLevel\":[\"[Ƒöļļöŵš ļéṽéļ ~~~~]\"],\"editor.panels.multiHeightMode.height\":[\"[Ĥéîĝĥţ ~~]\"],\"editor.panels.multiHeightMode.top\":[\"[Ţöþ ~]\"],\"editor.panels.multiParametricInspector.labelSessionOnlyPlainClickReselects\":[\"[\",[\"label\"],\" (šéššîöñ öñļý). Þļáîñ çļîçķ ŕéšéļéçţš áļļ ɱéɱƀéŕš. Ñöţ šáṽéð ŵîţĥ ţĥé þŕöĵéçţ. ~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.multiSelectionPanel.delete\":[\"[Ðéļéţé ~~]\"],\"editor.panels.multiSelectionPanel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"editor.panels.multiSelectionPanel.group\":[\"[Ĝŕöûþ ~~]\"],\"editor.panels.multiSelectionPanel.groupCtrlCmdG\":[\"[Ĝŕöûþ (Çţŕļ/Çɱð+Ĝ) ~~~~]\"],\"editor.panels.multiSelectionPanel.labelSessionOnlyPlainClickReselects\":[\"[\",[\"label\"],\" (šéššîöñ öñļý). Þļáîñ çļîçķ ŕéšéļéçţš áļļ ɱéɱƀéŕš. Ñöţ šáṽéð ŵîţĥ ţĥé þŕöĵéçţ. ~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.multiSelectionPanel.lengthSelected\":[\"[\",[\"length\"],\" šéļéçţéð ~~~]\"],\"editor.panels.multiSelectionPanel.mergeWindows\":[\"[Ṁéŕĝé ŵîñðöŵš ~~~~]\"],\"editor.panels.multiSelectionPanel.mergeWindowsIntoACornerWindow\":[\"[Ṁéŕĝé ŵîñðöŵš îñţö á çöŕñéŕ ŵîñðöŵ: ƀöţĥ ţáķé ţĥé ĥéîĝĥţ, šîļļ áñð ţýþé öƒ ţĥé öñé ýöû šéļéçţéð ƒîŕšţ ~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.multiSelectionPanel.mergeWindowsIntoOneAcrossBoth\":[\"[Ṁéŕĝé ŵîñðöŵš îñţö öñé áçŕöšš ƀöţĥ: îţ ķééþš ţĥé ţýþé áñð šţýļé öƒ ţĥé öñé ýöû šéļéçţéð ƒîŕšţ ~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.multiSelectionPanel.selectBuilding\":[\"[Šéļéçţ ƀûîļðîñĝ ~~~~~]\"],\"editor.panels.multiSelectionPanel.selectTheWholeBuildingToMove\":[\"[Šéļéçţ ţĥé ŵĥöļé ƀûîļðîñĝ ţö ɱöṽé áļļ îţš ļéṽéļš ~~~~~~~~~~~~]\"],\"editor.panels.multiSelectionPanel.ungroup\":[\"[Ûñĝŕöûþ ~~~]\"],\"editor.panels.multiSelectionPanel.ungroupCtrlCmdShiftG\":[\"[Ûñĝŕöûþ (Çţŕļ/Çɱð+Šĥîƒţ+Ĝ) ~~~~~~]\"],\"editor.panels.multiSelectionPanel.unwrapTheCorner\":[\"[Ûñŵŕáþ ţĥé çöŕñéŕ ~~~~~]\"],\"editor.panels.multiSelectionPanel.unwrapTheCornerBothWindowsStay\":[\"[Ûñŵŕáþ ţĥé çöŕñéŕ: ƀöţĥ ŵîñðöŵš šţáý, éáçĥ ƒŕáɱéð áţ ţĥé çöŕñéŕ ~~~~~~~~~~~~~~~~]\"],\"editor.panels.panelManager.selection\":[\"[Šéļéçţîöñ ~~~]\"],\"editor.panels.panelWrapper.back\":[\"[Ɓáçķ ~~]\"],\"editor.panels.panelWrapper.close\":[\"[Çļöšé ~~]\"],\"editor.panels.panelWrapper.closeTitle\":[\"[Çļöšé \",[\"title\"],\" ~~]\"],\"editor.panels.panelWrapper.collapsePanel\":[\"[Çöļļáþšé þáñéļ ~~~~]\"],\"editor.panels.panelWrapper.collections\":[\"[Çöļļéçţîöñš ~~~~]\"],\"editor.panels.panelWrapper.expandPanel\":[\"[Éẋþáñð þáñéļ ~~~~]\"],\"editor.panels.panelWrapper.manageCollections\":[\"[Ṁáñáĝé çöļļéçţîöñš… ~~~~~~]\"],\"editor.panels.panelWrapper.openTitle\":[\"[Öþéñ \",[\"title\"],\" ~~]\"],\"editor.panels.panelWrapper.reset\":[\"[Ŕéšéţ ~~]\"],\"editor.panels.panelWrapper.titleHitAnErrorAndWas\":[\"[“\",[\"title\"],\"” ĥîţ áñ éŕŕöŕ áñð ŵáš ûñļöáðéð ƒöŕ ţĥîš šéššîöñ. ~~~~~~~~~~~~]\"],\"editor.panels.parametricFieldControl.mixed\":[\"[Ṁîẋéð ~~]\"],\"editor.panels.parametricInspector.actions\":[\"[Åçţîöñš ~~~]\"],\"editor.panels.parametricInspector.delete\":[\"[Ðéļéţé ~~]\"],\"editor.panels.parametricInspector.deleteWithContents\":[\"[Ðéļéţé ŵîţĥ çöñţéñţš ~~~~~~]\"],\"editor.panels.parametricInspector.move\":[\"[Ṁöṽé ~~]\"],\"editor.panels.referencePanel.cancel\":[\"[Çáñçéļ ~~]\"],\"editor.panels.referencePanel.capture\":[\"[Çáþţûŕé ~~~]\"],\"editor.panels.referencePanel.center\":[\"[Çéñţéŕ ~~]\"],\"editor.panels.referencePanel.clearScale\":[\"[Çļéáŕ Šçáļé ~~~]\"],\"editor.panels.referencePanel.clickBothEndsOfAKnown\":[\"[Çļîçķ ƀöţĥ éñðš öƒ á ķñöŵñ ðîšţáñçé öñ ţĥé þļáñ, ţĥéñ ţýþé îţš ŕéáļ ļéñĝţĥ. ~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.referencePanel.delete\":[\"[Ðéļéţé ~~]\"],\"editor.panels.referencePanel.drawALineOverAKnown\":[\"[Ðŕáŵ á ļîñé öṽéŕ á ķñöŵñ ðîɱéñšîöñ öñ ţĥé þļáñ, ţĥéñ ţýþé îţš ŕéáļ ļéñĝţĥ ţö šçáļé ţĥé îɱáĝé éẋáçţļý. ~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.referencePanel.editScale\":[\"[Éðîţ Šçáļé ~~~]\"],\"editor.panels.referencePanel.guideImage\":[\"[Ĝûîðé Îɱáĝé ~~~]\"],\"editor.panels.referencePanel.hide\":[\"[Ĥîðé ~~]\"],\"editor.panels.referencePanel.hideScale\":[\"[Ĥîðé Šçáļé ~~~]\"],\"editor.panels.referencePanel.image\":[\"[Îɱáĝé ~~]\"],\"editor.panels.referencePanel.lock\":[\"[Ļöçķ ~~]\"],\"editor.panels.referencePanel.move\":[\"[Ṁöṽé ~~]\"],\"editor.panels.referencePanel.opacity\":[\"[Öþáçîţý ~~~]\"],\"editor.panels.referencePanel.overlayImageUnavailableReplaceTheImage\":[\"[Öṽéŕļáý îɱáĝé ûñáṽáîļáƀļé. Ŕéþļáçé ţĥé îɱáĝé ţö ŕéšţöŕé îţ. ~~~~~~~~~~~~~~~]\"],\"editor.panels.referencePanel.pos\":[\"[þöš ~]\"],\"editor.panels.referencePanel.position\":[\"[Þöšîţîöñ ~~~]\"],\"editor.panels.referencePanel.quickActions\":[\"[Ǫûîçķ Åçţîöñš ~~~~]\"],\"editor.panels.referencePanel.referenceScale\":[\"[Ŕéƒéŕéñçé Šçáļé ~~~~~]\"],\"editor.panels.referencePanel.replace\":[\"[Ŕéþļáçé ~~~]\"],\"editor.panels.referencePanel.replacing\":[\"[Ŕéþļáçîñĝ... ~~~]\"],\"editor.panels.referencePanel.resetImageScale\":[\"[Ŕéšéţ Îɱáĝé Šçáļé ~~~~~]\"],\"editor.panels.referencePanel.resetRotation\":[\"[Ŕéšéţ Ŕöţáţîöñ ~~~~]\"],\"editor.panels.referencePanel.rot\":[\"[ŕöţ ~]\"],\"editor.panels.referencePanel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"editor.panels.referencePanel.scale\":[\"[šçáļé ~~]\"],\"editor.panels.referencePanel.scaleOpacity\":[\"[Šçáļé & Öþáçîţý ~~~~]\"],\"editor.panels.referencePanel.scaled\":[\"[Šçáļéð · \",[\"scale\"],\" ~~]\"],\"editor.panels.referencePanel.scaledHidden\":[\"[Šçáļéð (ĥîððéñ) · \",[\"scale\"],\" ~~~~]\"],\"editor.panels.referencePanel.setScale\":[\"[Šéţ Šçáļé ~~~]\"],\"editor.panels.referencePanel.show\":[\"[Šĥöŵ ~~]\"],\"editor.panels.referencePanel.showScale\":[\"[Šĥöŵ Šçáļé ~~~]\"],\"editor.panels.referencePanel.uncalibrated\":[\"[Ûñçáļîƀŕáţéð ~~~~]\"],\"editor.panels.referencePanel.unlock\":[\"[Ûñļöçķ ~~]\"],\"editor.panels.referencePanel.xyz\":[\"[ẊÝŽ ~]\"],\"editor.panels.roomConstructionRows.aDrawnSlabSetItsThickness\":[\"[Å ðŕáŵñ šļáƀ: šéţ îţš ţĥîçķñéšš áñð ƒîñîšĥéš ĥéŕé. Îţ ĥáš ñö ƒööţþŕîñţ ĥéîĝĥţ öŕ ƒöûñðáţîöñ. ~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.roomConstructionRows.addMezzanine\":[\"[+ Åðð ɱéžžáñîñé ~~~~]\"],\"editor.panels.roomConstructionRows.atFloorLevel\":[\"[Åţ ƒļööŕ ļéṽéļ ~~~~]\"],\"editor.panels.roomConstructionRows.builtOn\":[\"[Ɓûîļţ öñ ~~~]\"],\"editor.panels.roomConstructionRows.builtWith\":[\"[Ɓûîļţ ŵîţĥ ~~~]\"],\"editor.panels.roomConstructionRows.ceiling\":[\"[Çéîļîñĝ ~~~]\"],\"editor.panels.roomConstructionRows.ceilingAt\":[\"[Åţ \",[\"height\"],\" ~]\"],\"editor.panels.roomConstructionRows.closeWithWalls\":[\"[Çļöšé ŵîţĥ ŵáļļš ~~~~~]\"],\"editor.panels.roomConstructionRows.drawnFloor\":[\"[\",[\"ambiguous\",\"select\",{\"yes\":[\"Ƒļööŕ îš šéṽéŕáļ ðŕáŵñ šļáƀš, ɱöšţļý \",[\"name\"]],\"other\":[\"Ƒļööŕ îš á ðŕáŵñ šļáƀ: \",[\"name\"]]}],[\"shared\",\"plural\",{\"0\":[],\"one\":[\" (šĥáŕéð ŵîţĥ \",[\"sharedCount\"],\" ŕööɱ)\"],\"other\":[\" (šĥáŕéð ŵîţĥ \",[\"sharedCount\"],\" ŕööɱš)\"]}],\" ~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.roomConstructionRows.drawnFloorSwitchHint\":[\"[Ţĥîš ƒļööŕ îš á ðŕáŵñ šļáƀ: šéļéçţ îţ ţö éðîţ öŕ ðéļéţé îţ. ~~~~~~~~~~~~~~]\"],\"editor.panels.roomConstructionRows.drawnSlab\":[\"[Ðŕáŵñ šļáƀ ~~~]\"],\"editor.panels.roomConstructionRows.drawnSlabAt\":[\"[Ðŕáŵñ šļáƀ áţ \",[\"height\"],\" ~~~~]\"],\"editor.panels.roomConstructionRows.editShape\":[\"[Éðîţ šĥáþé ~~~]\"],\"editor.panels.roomConstructionRows.flatAtWallHeight\":[\"[Ƒļáţ, áţ ŵáļļ ĥéîĝĥţ ~~~~~]\"],\"editor.panels.roomConstructionRows.floor\":[\"[Ƒļööŕ ~~]\"],\"editor.panels.roomConstructionRows.floorDown\":[\"[\",[\"distance\"],\" ðöŵñ ~~]\"],\"editor.panels.roomConstructionRows.floorThickness\":[\"[Ƒļööŕ ţĥîçķñéšš ~~~~~]\"],\"editor.panels.roomConstructionRows.floorUp\":[\"[\",[\"distance\"],\" ûþ ~]\"],\"editor.panels.roomConstructionRows.handDrawnCeiling\":[\"[Ĥáñð-ðŕáŵñ çéîļîñĝ ~~~~~]\"],\"editor.panels.roomConstructionRows.height\":[\"[Ĥéîĝĥţ ~~]\"],\"editor.panels.roomConstructionRows.includeFloor\":[\"[Îñçļûðé ƒļööŕ ~~~~]\"],\"editor.panels.roomConstructionRows.includePart\":[\"[\",[\"part\",\"select\",{\"floor\":[\"Îñçļûðé ƒļööŕ\"],\"walls\":[\"Îñçļûðé ŵáļļš\"],\"other\":[\"Îñçļûðé çéîļîñĝ\"]}],\" ~~~~~~~~~~~~]\"],\"editor.panels.roomConstructionRows.includeWalls\":[\"[Îñçļûðé ŵáļļš ~~~~]\"],\"editor.panels.roomConstructionRows.keepOutsideDimensions\":[\"[Ķééþ öûţšîðé ðîɱéñšîöñš ~~~~~~~]\"],\"editor.panels.roomConstructionRows.lowered\":[\"[Ļöŵéŕéð \",[\"lift\"],\" ~~~]\"],\"editor.panels.roomConstructionRows.newFloor\":[\"[+ Ñéŵ ƒļööŕ ~~~]\"],\"editor.panels.roomConstructionRows.noFloor\":[\"[Ñö ƒļööŕ ~~~]\"],\"editor.panels.roomConstructionRows.notIncluded\":[\"[Ñöţ îñçļûðéð ~~~~]\"],\"editor.panels.roomConstructionRows.nothingToChange\":[\"[Ñöţĥîñĝ ţö çĥáñĝé. ~~~~~]\"],\"editor.panels.roomConstructionRows.onTheGround\":[\"[Öñ ţĥé ĝŕöûñð ~~~~]\"],\"editor.panels.roomConstructionRows.onTheWallsBelow\":[\"[Öñ ţĥé ŵáļļš ƀéļöŵ ~~~~~]\"],\"editor.panels.roomConstructionRows.openSides\":[\"[\",[\"openSides\",\"plural\",{\"one\":[[\"openSideCount\"],\" öþéñ šîðé\"],\"other\":[[\"openSideCount\"],\" öþéñ šîðéš\"]}],\" ~~~~~~]\"],\"editor.panels.roomConstructionRows.partialCovered\":[\"[Þáŕţîáļ · \",[\"coverage\",\"number\",\"percent\"],\" çöṽéŕéð ~~~~~]\"],\"editor.panels.roomConstructionRows.partialWalls\":[\"[Þáŕţîáļ · \",[\"walls\",\"plural\",{\"one\":[[\"wallCount\"],\" ŵáļļ\"],\"other\":[[\"wallCount\"],\" ŵáļļš\"]}],\", \",[\"openSides\",\"plural\",{\"one\":[[\"openSideCount\"],\" öþéñ šîðé\"],\"other\":[[\"openSideCount\"],\" öþéñ šîðéš\"]}],\" ~~~~~~~~~~]\"],\"editor.panels.roomConstructionRows.raised\":[\"[Ŕáîšéð \",[\"lift\"],\" ~~]\"],\"editor.panels.roomConstructionRows.replace\":[\"[Ŕéþļáçé ~~~]\"],\"editor.panels.roomConstructionRows.select\":[\"[Šéļéçţ ~~]\"],\"editor.panels.roomConstructionRows.shape\":[\"[Šĥáþé ~~]\"],\"editor.panels.roomConstructionRows.sharedWallsNote\":[\"[Ţûŕñîñĝ ŵáļļš öƒƒ ķééþš ţĥé öñéš šĥáŕéð ŵîţĥ \",[\"rooms\"],\". ~~~~~~~~~~~~]\"],\"editor.panels.roomConstructionRows.sitsOnPreset\":[\"[Šîţš öñ: \",[\"name\"],\" · \",[\"preset\"],\" ~~]\"],\"editor.panels.roomConstructionRows.theNextRoom\":[\"[ţĥé ñéẋţ ŕööɱ ~~~~]\"],\"editor.panels.roomConstructionRows.useExisting\":[\"[Ûšé éẋîšţîñĝ ~~~~]\"],\"editor.panels.roomConstructionRows.wallCount\":[\"[\",[\"walls\",\"plural\",{\"one\":[[\"wallCount\"],\" ŵáļļ\"],\"other\":[[\"wallCount\"],\" ŵáļļš\"]}],\" ~~~]\"],\"editor.panels.roomConstructionRows.walls\":[\"[Ŵáļļš ~~]\"],\"editor.panels.roomConstructionRows.wallsThickenInwardSoTheBuilding\":[\"[Ŵáļļš ţĥîçķéñ îñŵáŕð, šö ţĥé ƀûîļðîñĝ'š öûţéŕ šîžé šţáýš ţĥé šáɱé. ~~~~~~~~~~~~~~~~]\"],\"editor.panels.roomOpeningsField.cutOpening\":[\"[Çûţ öþéñîñĝ ~~~]\"],\"editor.panels.roomOpeningsField.done\":[\"[Ðöñé ~~]\"],\"editor.panels.roomOpeningsField.editFloor\":[\"[Éðîţ ƒļööŕ ~~~]\"],\"editor.panels.roomOpeningsField.elevatorOpening\":[\"[Éļéṽáţöŕ öþéñîñĝ ~~~~~]\"],\"editor.panels.roomOpeningsField.noOpeningsYetCutOneFor\":[\"[Ñö öþéñîñĝš ýéţ. Çûţ öñé ƒöŕ á šţáîŕ ṽöîð öŕ á ĥáţçĥ. ~~~~~~~~~~~~]\"],\"editor.panels.roomOpeningsField.openingNumber\":[\"[Öþéñîñĝ \",[\"number\"],\" ~~~]\"],\"editor.panels.roomOpeningsField.openings\":[\"[\",[\"count\",\"plural\",{\"0\":[\"Ñö öþéñîñĝš\"],\"one\":[[\"number\"],\" öþéñîñĝ\"],\"other\":[[\"number\"],\" öþéñîñĝš\"]}],\" ~~~~~~~~]\"],\"editor.panels.roomOpeningsField.stairOpening\":[\"[Šţáîŕ öþéñîñĝ ~~~~]\"],\"editor.panels.roomPanel.addStairs\":[\"[Åðð šţáîŕš ~~~]\"],\"editor.panels.roomPanel.addToAUnit\":[\"[Åðð ţö á ûñîţ ~~~]\"],\"editor.panels.roomPanel.area\":[\"[Åŕéá ~~]\"],\"editor.panels.roomPanel.browse\":[\"[Ɓŕöŵšé ~~]\"],\"editor.panels.roomPanel.builtWith\":[\"[Ɓûîļţ ŵîţĥ ~~~]\"],\"editor.panels.roomPanel.ceiling\":[\"[Çéîļîñĝ ~~~]\"],\"editor.panels.roomPanel.deleteRoom\":[\"[Ðéļéţé ŕööɱ ~~~]\"],\"editor.panels.roomPanel.editShape\":[\"[Éðîţ šĥáþé ~~~]\"],\"editor.panels.roomPanel.floor\":[\"[Ƒļööŕ ~~]\"],\"editor.panels.roomPanel.headroom\":[\"[\",[\"height\"],\" ĥéáðŕööɱ ~~~]\"],\"editor.panels.roomPanel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"editor.panels.roomPanel.hideCode\":[\"[Ĥîðé çöðé ~~~]\"],\"editor.panels.roomPanel.kickerLevel\":[\"[Ŕööɱ · \",[\"level\"],\" ~~]\"],\"editor.panels.roomPanel.kickerMezzanineIn\":[\"[Ṁéžžáñîñé · îñ \",[\"room\"],\" ~~~~]\"],\"editor.panels.roomPanel.kickerNotEnclosed\":[\"[Ŕööɱ · ñöţ éñçļöšéð ~~~~~]\"],\"editor.panels.roomPanel.loading\":[\"[Ļöáðîñĝ… ~~~]\"],\"editor.panels.roomPanel.mezzanine\":[\"[Ṁéžžáñîñé ~~~]\"],\"editor.panels.roomPanel.mezzanineName\":[\"[Ṁéžžáñîñé ñáɱé ~~~~]\"],\"editor.panels.roomPanel.mezzanineNames\":[\"[Ṁéžžáñîñé ñáɱéš ~~~~~]\"],\"editor.panels.roomPanel.newUnit\":[\"[Ñéŵ ûñîţ ~~~]\"],\"editor.panels.roomPanel.none\":[\"[Ñöñé ~~]\"],\"editor.panels.roomPanel.notEnoughHeadroom\":[\"[Ñöţ éñöûĝĥ ĥéáðŕööɱ ~~~~~~]\"],\"editor.panels.roomPanel.openRoomArea\":[\"[\",[\"area\"],\" · Çļöšé îţš ŵáļļš ţö ƀûîļð îţš ƒļööŕ áñð çéîļîñĝ. ~~~~~~~~~~~~]\"],\"editor.panels.roomPanel.openingCounts\":[\"[\",[\"doors\",\"plural\",{\"one\":[[\"doorCount\"],\" ðööŕ\"],\"other\":[[\"doorCount\"],\" ðööŕš\"]}],\" · \",[\"windows\",\"plural\",{\"one\":[[\"windowCount\"],\" ŵîñðöŵ\"],\"other\":[[\"windowCount\"],\" ŵîñðöŵš\"]}],\" ~~~~~~~]\"],\"editor.panels.roomPanel.overTheMezzanine\":[\"[Öṽéŕ ţĥé ɱéžžáñîñé ~~~~~]\"],\"editor.panels.roomPanel.perimeter\":[\"[Þéŕîɱéţéŕ ~~~]\"],\"editor.panels.roomPanel.pick\":[\"[Þîçķ ~~]\"],\"editor.panels.roomPanel.pickingItAddsANumber\":[\"[Þîçķîñĝ îţ áððš á ñûɱƀéŕ ~~~~~~]\"],\"editor.panels.roomPanel.remove\":[\"[Ŕéɱöṽé ~~]\"],\"editor.panels.roomPanel.removeFromUnit\":[\"[Ŕéɱöṽé ƒŕöɱ ûñîţ ~~~~~]\"],\"editor.panels.roomPanel.removeFromUnitNamed\":[\"[Ŕéɱöṽé ƒŕöɱ \",[\"unit\"],\" ~~~]\"],\"editor.panels.roomPanel.rename\":[\"[Ŕéñáɱé ~~]\"],\"editor.panels.roomPanel.renameNamed\":[\"[\",[\"name\"],\" · Ŕéñáɱé ~~]\"],\"editor.panels.roomPanel.revert\":[\"[Ŕéṽéŕţ ~~]\"],\"editor.panels.roomPanel.room\":[\"[Ŕööɱ ~~]\"],\"editor.panels.roomPanel.roomColourUsedInThePlan\":[\"[Ŕööɱ çöļöûŕ — ûšéð îñ ţĥé þļáñ áñð ļáƀéļš ~~~~~~~~~~]\"],\"editor.panels.roomPanel.roomName\":[\"[Ŕööɱ ñáɱé ~~~]\"],\"editor.panels.roomPanel.roomNames\":[\"[Ŕööɱ ñáɱéš ~~~]\"],\"editor.panels.roomPanel.scriptedFinish\":[\"[Šçŕîþţéð ƒîñîšĥ ~~~~~]\"],\"editor.panels.roomPanel.shape\":[\"[Šĥáþé ~~]\"],\"editor.panels.roomPanel.showMezzanineNames\":[\"[Šĥöŵ ɱéžžáñîñé ñáɱéš ~~~~~~]\"],\"editor.panels.roomPanel.showRoomNames\":[\"[Šĥöŵ ŕööɱ ñáɱéš ~~~~]\"],\"editor.panels.roomPanel.stairs\":[\"[Šţáîŕš ~~]\"],\"editor.panels.roomPanel.unit\":[\"[Ûñîţ ~~]\"],\"editor.panels.roomPanel.use\":[\"[Ûšé ~]\"],\"editor.panels.roomPanel.useTyped\":[[\"use\"],\" “\",[\"name\"],\"”\"],\"editor.panels.roomPanel.usedOnThisLevel\":[\"[\",[\"used\"],\" öñ ţĥîš ļéṽéļ ~~~~]\"],\"editor.panels.roomPanel.viewCode\":[\"[Ṽîéŵ çöðé ~~~]\"],\"editor.panels.scriptUnreadable\":[\"[Ţĥé šçŕîþţ çöûļð ñöţ ƀé ŕéáð. ~~~~~~~]\"],\"editor.panels.shapeChoice.polygon\":[\"[Þöļýĝöñ ~~~]\"],\"editor.panels.shapeChoice.rectangle\":[\"[Ŕéçţáñĝļé ~~~]\"],\"editor.panels.wallRegionList.deleteRegion\":[\"[Ðéļéţé ŕéĝîöñ ~~~~]\"],\"editor.panels.wallRegionList.paintRegions\":[\"[Þáîñţ ŕéĝîöñš ~~~~]\"],\"editor.proceduralItems.inspector.adjustDesign\":[\"[Åðĵûšţ ðéšîĝñ ~~~~]\"],\"editor.proceduralItems.inspector.back\":[\"[Ɓáçķ ~~]\"],\"editor.proceduralItems.inspector.editParts\":[\"[Éðîţ þáŕţš ~~~]\"],\"editor.proceduralItems.inspector.invalidAttachment\":[\"[Îñṽáļîð áţţáçĥɱéñţ ~~~~~~]\"],\"editor.proceduralItems.inspector.invalidEdit\":[\"[Îñṽáļîð éðîţ ~~~~]\"],\"editor.proceduralItems.inspector.invalidPlacement\":[\"[Îñṽáļîð þļáçéɱéñţ ~~~~~]\"],\"editor.proceduralItems.inspector.invalidPosition\":[\"[Îñṽáļîð þöšîţîöñ ~~~~~]\"],\"editor.proceduralItems.inspector.invalidReset\":[\"[Îñṽáļîð ŕéšéţ ~~~~]\"],\"editor.proceduralItems.inspector.pos\":[\"[þöš ~]\"],\"editor.proceduralItems.inspector.position\":[\"[Þöšîţîöñ ~~~]\"],\"editor.proceduralItems.inspector.resetThisPart\":[\"[Ŕéšéţ ţĥîš þáŕţ ~~~~]\"],\"editor.reloadEditor\":[\"[Ŕéļöáð éðîţöŕ ~~~~]\"],\"editor.riserDiagramPanel.close\":[\"[Çļöšé ŕîšéŕ ðîáĝŕáɱ ~~~~~~]\"],\"editor.riserDiagramPanel.dwvPlumbingIsometric\":[\"[ÐŴṼ þļûɱƀîñĝ îšöɱéţŕîç ~~~~~~]\"],\"editor.riserDiagramPanel.dwvRiserDiagram\":[\"[ÐŴṼ ŕîšéŕ ðîáĝŕáɱ ~~~~~]\"],\"editor.riserDiagramPanel.noDrainWasteOrVentPipes\":[\"[Ñö ðŕáîñ, ŵášţé, öŕ ṽéñţ þîþéš ýéţ. Ðŕáŵ þļûɱƀîñĝ ţö šéé ţĥé ŕîšéŕ ðîáĝŕáɱ. ~~~~~~~~~~~~~~~~~~]\"],\"editor.riserDiagramPanel.riserDiagram\":[\"[Ŕîšéŕ Ðîáĝŕáɱ ~~~~]\"],\"editor.riserDiagramPanel.trap\":[\"[\",[\"diameter\"],\"\\\" Þ-ţŕáþ ~~]\"],\"editor.riserDiagramPanel.vent\":[\"[Ṽéñţ ~~]\"],\"editor.riserDiagramPanel.ventTermination\":[\"[\",[\"diameter\"],\"\\\" ṼŢŔ ~]\"],\"editor.riserDiagramPanel.waste\":[\"[Ŵášţé ~~]\"],\"editor.room.builtOn.above\":[\"[\",[\"current\"],\" · \",[\"distance\"],\" áƀöṽé \",[\"shared\"],\" ~~]\"],\"editor.room.builtOn.below\":[\"[\",[\"current\"],\" · \",[\"distance\"],\" ƀéļöŵ \",[\"shared\"],\" ~~]\"],\"editor.room.builtOn.levelWith\":[\"[\",[\"current\"],\" · ļéṽéļ ŵîţĥ \",[\"shared\"],\" ~~~]\"],\"editor.roomLabel.room\":[\"[Ŕööɱ ~~]\"],\"editor.roomLabel.zone\":[\"[Žöñé ~~]\"],\"editor.roomName.attic\":[\"[Åţţîç ~~]\"],\"editor.roomName.balcony\":[\"[Ɓáļçöñý ~~~]\"],\"editor.roomName.basement\":[\"[Ɓášéɱéñţ ~~~]\"],\"editor.roomName.bathroom\":[\"[Ɓáţĥŕööɱ ~~~]\"],\"editor.roomName.bedroom\":[\"[Ɓéðŕööɱ ~~~]\"],\"editor.roomName.boilerRoom\":[\"[Ɓöîļéŕ ŕööɱ ~~~]\"],\"editor.roomName.carport\":[\"[Çáŕþöŕţ ~~~]\"],\"editor.roomName.cellar\":[\"[Çéļļáŕ ~~]\"],\"editor.roomName.closet\":[\"[Çļöšéţ ~~]\"],\"editor.roomName.corridor\":[\"[Çöŕŕîðöŕ ~~~]\"],\"editor.roomName.courtyard\":[\"[Çöûŕţýáŕð ~~~]\"],\"editor.roomName.deck\":[\"[Ðéçķ ~~]\"],\"editor.roomName.den\":[\"[Ðéñ ~]\"],\"editor.roomName.diningRoom\":[\"[Ðîñîñĝ ŕööɱ ~~~]\"],\"editor.roomName.dressingRoom\":[\"[Ðŕéššîñĝ ŕööɱ ~~~~]\"],\"editor.roomName.enSuite\":[\"[Éñ-šûîţé ~~~]\"],\"editor.roomName.entrance\":[\"[Éñţŕáñçé ~~~]\"],\"editor.roomName.familyRoom\":[\"[Ƒáɱîļý ŕööɱ ~~~]\"],\"editor.roomName.gallery\":[\"[Ĝáļļéŕý ~~~]\"],\"editor.roomName.gamesRoom\":[\"[Ĝáɱéš ŕööɱ ~~~]\"],\"editor.roomName.garage\":[\"[Ĝáŕáĝé ~~]\"],\"editor.roomName.garden\":[\"[Ĝáŕðéñ ~~]\"],\"editor.roomName.gardenShed\":[\"[Ĝáŕðéñ šĥéð ~~~]\"],\"editor.roomName.guestRoom\":[\"[Ĝûéšţ ŕööɱ ~~~]\"],\"editor.roomName.gym\":[\"[Ĝýɱ ~]\"],\"editor.roomName.hallway\":[\"[Ĥáļļŵáý ~~~]\"],\"editor.roomName.homeCinema\":[\"[Ĥöɱé çîñéɱá ~~~]\"],\"editor.roomName.kidsRoom\":[\"[Ķîðš' ŕööɱ ~~~]\"],\"editor.roomName.kitchen\":[\"[Ķîţçĥéñ ~~~]\"],\"editor.roomName.kitchenette\":[\"[Ķîţçĥéñéţţé ~~~~]\"],\"editor.roomName.landing\":[\"[Ļáñðîñĝ ~~~]\"],\"editor.roomName.laundry\":[\"[Ļáûñðŕý ~~~]\"],\"editor.roomName.library\":[\"[Ļîƀŕáŕý ~~~]\"],\"editor.roomName.livingRoom\":[\"[Ļîṽîñĝ ŕööɱ ~~~]\"],\"editor.roomName.loft\":[\"[Ļöƒţ ~~]\"],\"editor.roomName.lounge\":[\"[Ļöûñĝé ~~]\"],\"editor.roomName.mezzanine\":[\"[Ṁéžžáñîñé ~~~]\"],\"editor.roomName.mudroom\":[\"[Ṁûðŕööɱ ~~~]\"],\"editor.roomName.nursery\":[\"[Ñûŕšéŕý ~~~]\"],\"editor.roomName.office\":[\"[Öƒƒîçé ~~]\"],\"editor.roomName.pantry\":[\"[Þáñţŕý ~~]\"],\"editor.roomName.patio\":[\"[Þáţîö ~~]\"],\"editor.roomName.playroom\":[\"[Þļáýŕööɱ ~~~]\"],\"editor.roomName.poolArea\":[\"[Þööļ áŕéá ~~~]\"],\"editor.roomName.porch\":[\"[Þöŕçĥ ~~]\"],\"editor.roomName.powderRoom\":[\"[Þöŵðéŕ ŕööɱ ~~~]\"],\"editor.roomName.primaryBedroom\":[\"[Þŕîɱáŕý ƀéðŕööɱ ~~~~~]\"],\"editor.roomName.readingNook\":[\"[Ŕéáðîñĝ ñööķ ~~~~]\"],\"editor.roomName.section.bathrooms\":[\"[Ɓáţĥŕööɱš ~~~]\"],\"editor.roomName.section.circulation\":[\"[Çîŕçûļáţîöñ ~~~~]\"],\"editor.roomName.section.living\":[\"[Ļîṽîñĝ ~~]\"],\"editor.roomName.section.mezzanine\":[\"[Ṁéžžáñîñé ~~~]\"],\"editor.roomName.section.outdoor\":[\"[Öûţðööŕ ~~~]\"],\"editor.roomName.section.sleeping\":[\"[Šļééþîñĝ ~~~]\"],\"editor.roomName.section.utility\":[\"[Ûţîļîţý & šţöŕáĝé ~~~~~]\"],\"editor.roomName.section.work\":[\"[Ŵöŕķ & ĥöƀƀîéš ~~~~]\"],\"editor.roomName.showerRoom\":[\"[Šĥöŵéŕ ŕööɱ ~~~]\"],\"editor.roomName.stairwell\":[\"[Šţáîŕŵéļļ ~~~]\"],\"editor.roomName.storage\":[\"[Šţöŕáĝé ~~~]\"],\"editor.roomName.studio\":[\"[Šţûðîö ~~]\"],\"editor.roomName.study\":[\"[Šţûðý ~~]\"],\"editor.roomName.sunroom\":[\"[Šûñŕööɱ ~~~]\"],\"editor.roomName.terrace\":[\"[Ţéŕŕáçé ~~~]\"],\"editor.roomName.toilet\":[\"[Ţöîļéţ ~~]\"],\"editor.roomName.utilityRoom\":[\"[Ûţîļîţý ŕööɱ ~~~~]\"],\"editor.roomName.veranda\":[\"[Ṽéŕáñðá ~~~]\"],\"editor.roomName.walkInCloset\":[\"[Ŵáļķ-îñ çļöšéţ ~~~~]\"],\"editor.roomName.workshop\":[\"[Ŵöŕķšĥöþ ~~~]\"],\"editor.sidebar.iconRail.settings\":[\"[Šéţţîñĝš ~~~]\"],\"editor.sidebar.iconRail.site\":[\"[Šîţé ~~]\"],\"editor.sidebar.panels.itemsPanel.all\":[\"[Åļļ ~]\"],\"editor.sidebar.panels.itemsPanel.community\":[\"[Çöɱɱûñîţý ~~~]\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.all\":[\"[Åļļ ~]\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.community\":[\"[Çöɱɱûñîţý ~~~]\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.library\":[\"[Ļîƀŕáŕý ~~~]\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.mine\":[\"[Ṁîñé ~~]\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.noResultsForSearch\":[\"[Ñö ŕéšûļţš ƒöŕ “\",[\"search\"],\"” ~~~~]\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.search\":[\"[Šéáŕçĥ... ~~]\"],\"editor.sidebar.panels.itemsPanel.library\":[\"[Ļîƀŕáŕý ~~~]\"],\"editor.sidebar.panels.itemsPanel.mine\":[\"[Ṁîñé ~~]\"],\"editor.sidebar.panels.itemsPanel.noResultsForSearch\":[\"[Ñö ŕéšûļţš ƒöŕ “\",[\"search\"],\"” ~~~~]\"],\"editor.sidebar.panels.itemsPanel.search\":[\"[Šéáŕçĥ... ~~]\"],\"editor.sidebar.panels.sitePanel.addLevel\":[\"[Åðð ļéṽéļ ~~~]\"],\"editor.sidebar.panels.sitePanel.addPoint\":[\"[Åðð þöîñţ ~~~]\"],\"editor.sidebar.panels.sitePanel.area\":[\"[Åŕéá: ~~]\"],\"editor.sidebar.panels.sitePanel.baseElevation\":[\"[Ɓášé éļéṽáţîöñ ~~~~]\"],\"editor.sidebar.panels.sitePanel.building\":[\"[Ɓûîļðîñĝ ~~~]\"],\"editor.sidebar.panels.sitePanel.buildingTreeNode.addNewLevel\":[\"[Åðð ñéŵ ļéṽéļ ~~~~]\"],\"editor.sidebar.panels.sitePanel.buildingTreeNode.building\":[\"[Ɓûîļðîñĝ ~~~]\"],\"editor.sidebar.panels.sitePanel.cameraSnapshot\":[\"[Çáɱéŕá šñáþšĥöţ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.capture\":[\"[Çáþţûŕé ~~~]\"],\"editor.sidebar.panels.sitePanel.clearSelection\":[\"[Çļéáŕ šéļéçţîöñ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.clearSnapshot\":[\"[Çļéáŕ šñáþšĥöţ ~~~~]\"],\"editor.sidebar.panels.sitePanel.closeWallsAroundASpaceTo\":[\"[Çļöšé ŵáļļš áŕöûñð á šþáçé ţö ɱáķé á ŕööɱ. ~~~~~~~~~~]\"],\"editor.sidebar.panels.sitePanel.collectionTreeNode.collectionColour\":[\"[Çöļļéçţîöñ çöļöûŕ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.collectionTreeNode.collections\":[\"[Çöļļéçţîöñš ~~~~]\"],\"editor.sidebar.panels.sitePanel.collectionTreeNode.deleteCollection\":[\"[Ðéļéţé çöļļéçţîöñ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.delete\":[\"[Ðéļéţé ~~]\"],\"editor.sidebar.panels.sitePanel.deleteLevel\":[\"[Ðéļéţé ļéṽéļ ~~~~]\"],\"editor.sidebar.panels.sitePanel.drawAZone\":[\"[Ðŕáŵ á žöñé ~~~]\"],\"editor.sidebar.panels.sitePanel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"editor.sidebar.panels.sitePanel.duplicateLevel\":[\"[Ðûþļîçáţé ļéṽéļ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.duplicateLevelWithOptions\":[\"[Ðûþļîçáţé ļéṽéļ ŵîţĥ öþţîöñš ~~~~~~~~]\"],\"editor.sidebar.panels.sitePanel.duplicateWithOptions\":[\"[Ðûþļîçáţé ŵîţĥ öþţîöñš... ~~~~~~]\"],\"editor.sidebar.panels.sitePanel.elements\":[\"[Éļéɱéñţš ~~~]\"],\"editor.sidebar.panels.sitePanel.guide\":[\"[Ĝûîðé ~~]\"],\"editor.sidebar.panels.sitePanel.hide\":[\"[Ĥîðé ~~]\"],\"editor.sidebar.panels.sitePanel.level\":[\"[Ļéṽéļ ~~]\"],\"editor.sidebar.panels.sitePanel.newUnit\":[\"[Ñéŵ ûñîţ ~~~]\"],\"editor.sidebar.panels.sitePanel.noBuildingsYet\":[\"[Ñö ƀûîļðîñĝš ýéţ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.noElementsOnThisLevel\":[\"[Ñö éļéɱéñţš öñ ţĥîš ļéṽéļ ~~~~~~~]\"],\"editor.sidebar.panels.sitePanel.noLevelsYet\":[\"[Ñö ļéṽéļš ýéţ ~~~~]\"],\"editor.sidebar.panels.sitePanel.objectsSelected\":[\"[\",[\"count\",\"plural\",{\"one\":[\"#\",\" öƀĵéçţ šéļéçţéð\"],\"other\":[\"#\",\" öƀĵéçţš šéļéçţéð\"]}],\" ~~~~~~~~~]\"],\"editor.sidebar.panels.sitePanel.otherZones\":[\"[Öţĥéŕ žöñéš ~~~]\"],\"editor.sidebar.panels.sitePanel.perimeter\":[\"[Þéŕîɱéţéŕ: ~~~]\"],\"editor.sidebar.panels.sitePanel.propertyLine\":[\"[Þŕöþéŕţý Ļîñé ~~~~]\"],\"editor.sidebar.panels.sitePanel.rooms\":[\"[Ŕööɱš ~~]\"],\"editor.sidebar.panels.sitePanel.selectALevelToViewContent\":[\"[Šéļéçţ á ļéṽéļ ţö ṽîéŵ çöñţéñţ ~~~~~~~~]\"],\"editor.sidebar.panels.sitePanel.show\":[\"[Šĥöŵ ~~]\"],\"editor.sidebar.panels.sitePanel.site\":[\"[Šîţé ~~]\"],\"editor.sidebar.panels.sitePanel.takeSnapshot\":[\"[Ţáķé šñáþšĥöţ ~~~~]\"],\"editor.sidebar.panels.sitePanel.theGroundLevelCannotBeDeleted\":[\"[Ţĥé ĝŕöûñð ļéṽéļ çáññöţ ƀé ðéļéţéð ~~~~~~~~~]\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.cameraSnapshot\":[\"[Çáɱéŕá šñáþšĥöţ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.clearSnapshot\":[\"[Çļéáŕ šñáþšĥöţ ~~~~]\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.hide\":[\"[Ĥîðé ~~]\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.show\":[\"[Šĥöŵ ~~]\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.takeSnapshot\":[\"[Ţáķé šñáþšĥöţ ~~~~]\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.updateSnapshot\":[\"[Ûþðáţé šñáþšĥöţ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.viewSnapshot\":[\"[Ṽîéŵ šñáþšĥöţ ~~~~]\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.deleteUnit\":[\"[Ðéļéţé ûñîţ ~~~]\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.focused\":[\"[Ƒöçûšéð ~~~]\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.removeFromUnit\":[\"[Ŕéɱöṽé ƒŕöɱ ûñîţ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.room\":[\"[Ŕööɱ ~~]\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.zone\":[\"[Žöñé ~~]\"],\"editor.sidebar.panels.sitePanel.units\":[\"[Ûñîţš ~~]\"],\"editor.sidebar.panels.sitePanel.updateSnapshot\":[\"[Ûþðáţé šñáþšĥöţ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.uploadScanFloorplan\":[\"[Ûþļöáð šçáñ/ƒļööŕþļáñ ~~~~~~]\"],\"editor.sidebar.panels.sitePanel.uploadingProgress\":[\"[\",[\"assetType\",\"select\",{\"guide\":[\"Ûþļöáðîñĝ ĝûîðé... \",[\"progress\"],\"%\"],\"other\":[\"Ûþļöáðîñĝ šçáñ... \",[\"progress\"],\"%\"]}],\" ~~~~~~~~~]\"],\"editor.sidebar.panels.sitePanel.viewSnapshot\":[\"[Ṽîéŵ šñáþšĥöţ ~~~~]\"],\"editor.sidebar.panels.sitePanel.zoneMembershipCheckbox.inUnitname\":[\"[Îñ \",[\"unitName\"],\" ~]\"],\"editor.sidebar.panels.zonePanel.actions\":[\"[Åçţîöñš ~~~]\"],\"editor.sidebar.panels.zonePanel.addOne\":[\"[Åðð öñé ~~]\"],\"editor.sidebar.panels.zonePanel.cameraSnapshot\":[\"[Çáɱéŕá šñáþšĥöţ ~~~~~]\"],\"editor.sidebar.panels.zonePanel.clearSnapshot\":[\"[Çļéáŕ šñáþšĥöţ ~~~~]\"],\"editor.sidebar.panels.zonePanel.delete\":[\"[Ðéļéţé ~~]\"],\"editor.sidebar.panels.zonePanel.deleteWithContents\":[\"[Ðéļéţé ŵîţĥ çöñţéñţš ~~~~~~]\"],\"editor.sidebar.panels.zonePanel.noZonesOnThisLevel\":[\"[Ñö žöñéš öñ ţĥîš ļéṽéļ. ~~~~~~]\"],\"editor.sidebar.panels.zonePanel.saveToCatalog\":[\"[Šáṽé ţö çáţáļöĝ ~~~~]\"],\"editor.sidebar.panels.zonePanel.selectALevelToViewAnd\":[\"[Šéļéçţ á ļéṽéļ ţö ṽîéŵ áñð çŕéáţé žöñéš ~~~~~~~~~~]\"],\"editor.sidebar.panels.zonePanel.takeSnapshot\":[\"[Ţáķé šñáþšĥöţ ~~~~]\"],\"editor.sidebar.panels.zonePanel.updateSnapshot\":[\"[Ûþðáţé šñáþšĥöţ ~~~~~]\"],\"editor.sidebar.panels.zonePanel.viewSnapshot\":[\"[Ṽîéŵ šñáþšĥöţ ~~~~]\"],\"editor.sidebar.usePluginPanels.labelPluginCrashed\":[\"[\\\"\",[\"label\"],\"\\\" þļûĝîñ çŕášĥéð ~~~~]\"],\"editor.sidebar.usePluginPanels.loading\":[\"[Ļöáðîñĝ… ~~~]\"],\"editor.sidebar.usePluginPanels.plugins\":[\"[Þļûĝîñš ~~~]\"],\"editor.sidebar.usePluginPanels.thisPanelHitAnErrorAnd\":[\"[Ţĥîš þáñéļ ĥîţ áñ éŕŕöŕ áñð ŵáš ûñļöáðéð ƒöŕ ţĥîš šéššîöñ. Ţĥé ŕéšţ öƒ ţĥé éðîţöŕ îš ûñჃéçţéð — ŕéļöáð ţö ţŕý áĝáîñ. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.snapTarget.ceiling\":[\"[Çéîļîñĝ áţţáçĥɱéñţ ~~~~~~]\"],\"editor.snapTarget.roof\":[\"[Ŕööƒ áţţáçĥɱéñţ ~~~~~]\"],\"editor.snapTarget.wall\":[\"[Ŵáļļ áţţáçĥɱéñţ ~~~~~]\"],\"editor.theEditorSceneFailedToRender\":[\"[Ţĥé éðîţöŕ šçéñé ƒáîļéð ţö ŕéñðéŕ ~~~~~~~~~]\"],\"editor.toolHint.aCurtainWallTakesNoCorner.1qxjv5i\":[\"[Å çûŕţáîñ ŵáļļ ţáķéš ñö çöŕñéŕ ŵîñðöŵ ~~~~~~~~~~]\"],\"editor.toolHint.aCurvedWallTakesNoCorner.1vdnaw5\":[\"[Å çûŕṽéð ŵáļļ ţáķéš ñö çöŕñéŕ ŵîñðöŵ ~~~~~~~~~]\"],\"editor.toolHint.addACornerClickTheFirst.o4r67t\":[\"[Åðð á çöŕñéŕ · çļîçķ ţĥé ƒîŕšţ ţö çļöšé ~~~~~~~~~]\"],\"editor.toolHint.anotherOpeningIsInTheWay.11l9dd0\":[\"[Åñöţĥéŕ öþéñîñĝ îš îñ ţĥé ŵáý áţ ţĥé çöŕñéŕ ~~~~~~~~~~~]\"],\"editor.toolHint.autoHangers.10554ka\":[\"[Åûţö ĥáñĝéŕš ~~~~]\"],\"editor.toolHint.autoHangersClickOrPressH.rwa3ka\":[\"[Åûţö ĥáñĝéŕš - çļîçķ öŕ þŕéšš Ĥ ţö ţöĝĝļé ~~~~~~~~~~]\"],\"editor.toolHint.autoHangersOff.7yx01x\":[\"[Åûţö ĥáñĝéŕš: Öƒƒ ~~~~~]\"],\"editor.toolHint.autoHangersOn.10b1umh\":[\"[Åûţö ĥáñĝéŕš: Öñ ~~~~]\"],\"editor.toolHint.bypassSnapping.w5lmdv\":[\"[Ɓýþášš šñáþþîñĝ ~~~~~]\"],\"editor.toolHint.cancel.ew9em3\":[\"[Çáñçéļ ~~]\"],\"editor.toolHint.cancelMove.lvp31c\":[\"[Çáñçéļ ɱöṽé ~~~]\"],\"editor.toolHint.cancelRunExit.zqjf3h\":[\"[Çáñçéļ ŕûñ / éẋîţ ~~~~]\"],\"editor.toolHint.cancelStartPoint.1xbq2lh\":[\"[Çáñçéļ šţáŕţ þöîñţ ~~~~~]\"],\"editor.toolHint.cornerWindow.1avkzpo\":[\"[Çöŕñéŕ ŵîñðöŵ ~~~~]\"],\"editor.toolHint.cuts.1y0axps\":[\"[Çûţš ~~]\"],\"editor.toolHint.cutsValue.ouzhvb\":[\"[Çûţš: \",[\"value\"],\" ~~]\"],\"editor.toolHint.cutsValueEven.1ngsz3\":[\"[Çûţš: \",[\"value\"],\", éṽéñ ~~~]\"],\"editor.toolHint.cycleMonoGableButterfly.1poga3m\":[\"[Çýçļé ɱöñö / ĝáƀļé / ƀûţţéŕƒļý ~~~~~~~]\"],\"editor.toolHint.cycleSnappingMode.1ct0gn6\":[\"[Çýçļé šñáþþîñĝ ɱöðé ~~~~~~]\"],\"editor.toolHint.doorStyleClickOrPressL.33pe65\":[\"[Ðööŕ šţýļé — çļîçķ öŕ þŕéšš Ļ ţö çýçļé ~~~~~~~~~]\"],\"editor.toolHint.doorTypeClickOrPressO.1hhh8gt\":[\"[Ðööŕ ţýþé — çļîçķ öŕ þŕéšš Ö ţö çýçļé ~~~~~~~~~]\"],\"editor.toolHint.dropDownspoutFromOutlet.1k4h1m4\":[\"[Ðŕöþ ðöŵñšþöûţ ƒŕöɱ öûţļéţ ~~~~~~~]\"],\"editor.toolHint.ductDiameterDownUp.1wdz5vq\":[\"[Ðûçţ ðîáɱéţéŕ ðöŵñ / ûþ ~~~~~~]\"],\"editor.toolHint.endRunCancel.59dh2w\":[\"[Éñð ŕûñ / çáñçéļ ~~~~]\"],\"editor.toolHint.exit.engmg5\":[\"[Éẋîţ ~~]\"],\"editor.toolHint.exitDrawing.9noxyb\":[\"[Éẋîţ ðŕáŵîñĝ ~~~~]\"],\"editor.toolHint.finishAndContinue.1gpfsks\":[\"[Ƒîñîšĥ áñð çöñţîñûé ~~~~~~]\"],\"editor.toolHint.finishCeiling.1c1lfel\":[\"[Ƒîñîšĥ çéîļîñĝ ~~~~]\"],\"editor.toolHint.finishGridAxis.1wvrfhr\":[\"[Ƒîñîšĥ ĝŕîð áẋîš ~~~~~]\"],\"editor.toolHint.finishMeasurement.1e4gv16\":[\"[Ƒîñîšĥ ɱéášûŕéɱéñţ ~~~~~~]\"],\"editor.toolHint.finishMultiPointWitnesses.8wzskz\":[\"[Ƒîñîšĥ ɱûļţî-þöîñţ ŵîţñéššéš ~~~~~~~~]\"],\"editor.toolHint.finishSlab.xmnm8e\":[\"[Ƒîñîšĥ šļáƀ ~~~]\"],\"editor.toolHint.flipSide.172xku9\":[\"[Ƒļîþ šîðé ~~~]\"],\"editor.toolHint.followTraceALineset.mgquwe\":[\"[Ƒöļļöŵ: ţŕáçé á ļîñéšéţ ~~~~~~]\"],\"editor.toolHint.forcePlace.1hq1nr\":[\"[Ƒöŕçé þļáçé ~~~]\"],\"editor.toolHint.freePlacement.1nztdac\":[\"[Ƒŕéé þļáçéɱéñţ ~~~~]\"],\"editor.toolHint.goVerticalClickToPlace.dg8g6m\":[\"[Ĝö ṽéŕţîçáļ ↕, çļîçķ ţö þļáçé ~~~~~~~]\"],\"editor.toolHint.highlightOutlet.65hoq8\":[\"[Ĥîĝĥļîĝĥţ öûţļéţ ~~~~~]\"],\"editor.toolHint.joinAsACornerWindow.jvdp4j\":[\"[Ĵöîñ áš á çöŕñéŕ ŵîñðöŵ ~~~~~~]\"],\"editor.toolHint.key.altDrag.ai3wn9\":[\"[Åļţ + ðŕáĝ ~~~]\"],\"editor.toolHint.key.backspace.qy6qx8\":[\"[Ɓáçķšþáçé ~~~]\"],\"editor.toolHint.key.click.m8sun\":[\"[Çļîçķ ~~]\"],\"editor.toolHint.key.clickAgain.190ws9j\":[\"[Çļîçķ áĝáîñ ~~~]\"],\"editor.toolHint.key.command.1j2mkia\":[\"[Çöɱɱáñð ~~~]\"],\"editor.toolHint.key.control.10fbl8e\":[\"[Çöñţŕöļ ~~~]\"],\"editor.toolHint.key.delete.oay2cq\":[\"[Ðéļéţé ~~]\"],\"editor.toolHint.key.doubleClick.vlma6o\":[\"[Ðöûƀļé çļîçķ ~~~~]\"],\"editor.toolHint.key.drag.8pwtpf\":[\"[Ðŕáĝ ~~]\"],\"editor.toolHint.key.enter.1ctpui5\":[\"[Éñţéŕ ~~]\"],\"editor.toolHint.key.hover.6xw79p\":[\"[Ĥöṽéŕ ~~]\"],\"editor.toolHint.key.hoverADuctEnd.19axr3b\":[\"[Ĥöṽéŕ á ðûçţ éñð ~~~~]\"],\"editor.toolHint.key.hoverAPipeEnd.1jbum5f\":[\"[Ĥöṽéŕ á þîþé éñð ~~~~]\"],\"editor.toolHint.key.hoverGutter.1dwcsno\":[\"[Ĥöṽéŕ ĝûţţéŕ ~~~~]\"],\"editor.toolHint.key.leftClick.s4gwfc\":[\"[Ļéƒţ çļîçķ ~~~]\"],\"editor.toolHint.key.middleClick.1jbaan4\":[\"[Ṁîððļé çļîçķ ~~~~]\"],\"editor.toolHint.key.rShiftR.13bnobh\":[\"[Ŕ / Šĥîƒţ+Ŕ ~~~]\"],\"editor.toolHint.key.rightClick.1ovld0h\":[\"[Ŕîĝĥţ çļîçķ ~~~]\"],\"editor.toolHint.key.scroll.ai6wr0\":[\"[Šçŕöļļ ~~]\"],\"editor.toolHint.key.scrollWheel.18j0ix7\":[\"[Šçŕöļļ ŵĥééļ ~~~~]\"],\"editor.toolHint.key.space.1hrh82t\":[\"[Šþáçé ~~]\"],\"editor.toolHint.key.tab.1xsal0s\":[\"[Ţáƀ ~]\"],\"editor.toolHint.mountFloorCeilingWall.32dxpv\":[\"[Ṁöûñţ: ƒļööŕ / çéîļîñĝ / ŵáļļ ~~~~~~~]\"],\"editor.toolHint.noRoomForTheMatchingWindow.1755948\":[\"[Ñö ŕööɱ ƒöŕ ţĥé ɱáţçĥîñĝ ŵîñðöŵ öñ ţĥé öţĥéŕ ŵáļļ ~~~~~~~~~~~~]\"],\"editor.toolHint.noWallMeetsHere.19n99yc\":[\"[Ñö ŵáļļ ɱééţš ĥéŕé ~~~~~]\"],\"editor.toolHint.numberOfCutsScrollOrClick.1kqe84b\":[\"[Ñûɱƀéŕ öƒ çûţš — šçŕöļļ öŕ çļîçķ ţö çĥáñĝé ~~~~~~~~~~]\"],\"editor.toolHint.pickWitnessPoint.k3hgh1\":[\"[Þîçķ ŵîţñéšš þöîñţ ~~~~~]\"],\"editor.toolHint.pipeSizeDownUp.wp04og\":[\"[Þîþé šîžé ðöŵñ / ûþ ~~~~~]\"],\"editor.toolHint.placeAndContinue.qfwkrq\":[\"[Þļáçé áñð çöñţîñûé ~~~~~]\"],\"editor.toolHint.placeBlock.1aylwrx\":[\"[Þļáçé ƀļöçķ ~~~]\"],\"editor.toolHint.placeBoxVentOnRoof.kf88e5\":[\"[Þļáçé ƀöẋ ṽéñţ öñ ŕööƒ ~~~~~~]\"],\"editor.toolHint.placeCabinet.b0ouyk\":[\"[Þļáçé çáƀîñéţ ~~~~]\"],\"editor.toolHint.placeCanopyOrSetTheNext.12l7zf8\":[\"[Þļáçé çáñöþý öŕ šéţ ţĥé ñéẋţ ŕûñ þöîñţ ~~~~~~~~~~]\"],\"editor.toolHint.placeChimneyOnRoof.19dbqu\":[\"[Þļáçé çĥîɱñéý öñ ŕööƒ ~~~~~~]\"],\"editor.toolHint.placeColumn.1w2vq86\":[\"[Þļáçé çöļûɱñ ~~~~]\"],\"editor.toolHint.placeCupolaOnRoof.ofx3bn\":[\"[Þļáçé çûþöļá öñ ŕööƒ ~~~~~~]\"],\"editor.toolHint.placeDimensionLineWhenNeeded.bjw2cj\":[\"[Þļáçé ðîɱéñšîöñ ļîñé ŵĥéñ ñééðéð ~~~~~~~~~]\"],\"editor.toolHint.placeDoorOnWall.1jwadf\":[\"[Þļáçé ðööŕ öñ ŵáļļ ~~~~~]\"],\"editor.toolHint.placeDormerOnRoof.1w518a6\":[\"[Þļáçé ðöŕɱéŕ öñ ŕööƒ ~~~~~~]\"],\"editor.toolHint.placeElevator.1f65zva\":[\"[Þļáçé éļéṽáţöŕ ~~~~]\"],\"editor.toolHint.placeEyebrowVentOnRoof.1h1tqxn\":[\"[Þļáçé éýéƀŕöŵ ṽéñţ öñ ŕööƒ ~~~~~~~]\"],\"editor.toolHint.placeFitting.1pmx3vn\":[\"[Þļáçé ƒîţţîñĝ ~~~~]\"],\"editor.toolHint.placeGutterOnRoofEave.llwzf9\":[\"[Þļáçé ĝûţţéŕ öñ ŕööƒ éáṽé ~~~~~~~]\"],\"editor.toolHint.placeItLockedTo45.16e4csk\":[\"[Þļáçé îţ (ļöçķéð ţö 45°) ~~~~~]\"],\"editor.toolHint.placeItem.teynf\":[\"[Þļáçé îţéɱ ~~~]\"],\"editor.toolHint.placeMeasurementPoint.bsatli\":[\"[Þļáçé ɱéášûŕéɱéñţ þöîñţ ~~~~~~~]\"],\"editor.toolHint.placeOnAFence.1dptstr\":[\"[Þļáçé öñ á ƒéñçé ~~~~]\"],\"editor.toolHint.placeRegister.1uebycd\":[\"[Þļáçé ŕéĝîšţéŕ ~~~~]\"],\"editor.toolHint.placeRidgeVentOnRoof.2tpd8r\":[\"[Þļáçé ŕîðĝé ṽéñţ öñ ŕööƒ ~~~~~~]\"],\"editor.toolHint.placeShelf.y4l3iw\":[\"[Þļáçé šĥéļƒ ~~~]\"],\"editor.toolHint.placeSkylightOnRoof.e215pe\":[\"[Þļáçé šķýļîĝĥţ öñ ŕööƒ ~~~~~~]\"],\"editor.toolHint.placeSolarPanelArrayOnRoof.kk11fn\":[\"[Þļáçé šöļáŕ þáñéļ áŕŕáý öñ ŕööƒ ~~~~~~~~]\"],\"editor.toolHint.placeSpawnPoint.205o25\":[\"[Þļáçé šþáŵñ þöîñţ ~~~~~]\"],\"editor.toolHint.placeStairs.zwxxu2\":[\"[Þļáçé šţáîŕš ~~~~]\"],\"editor.toolHint.placeTrap.1gxemn3\":[\"[Þļáçé ţŕáþ ~~~]\"],\"editor.toolHint.placeTurbineVentOnRoof.1iqeluf\":[\"[Þļáçé ţûŕƀîñé ṽéñţ öñ ŕööƒ ~~~~~~~]\"],\"editor.toolHint.placeUnit.8zkx4q\":[\"[Þļáçé ûñîţ ~~~]\"],\"editor.toolHint.placeWindowOnWall.1k3qnfb\":[\"[Þļáçé ŵîñðöŵ öñ ŵáļļ ~~~~~~]\"],\"editor.toolHint.placeWithoutTheCornerSnap.1nifqew\":[\"[Þļáçé ŵîţĥöûţ ţĥé çöŕñéŕ šñáþ ~~~~~~~~]\"],\"editor.toolHint.placement.13lcvts\":[\"[Þļáçéɱéñţ ~~~]\"],\"editor.toolHint.placementAuto.1caa52d\":[\"[Þļáçéɱéñţ: Åûţö ~~~~]\"],\"editor.toolHint.placementGround.1ruz145\":[\"[Þļáçéɱéñţ: Ĝŕöûñð ~~~~~]\"],\"editor.toolHint.placementRoof.renkw8\":[\"[Þļáçéɱéñţ: Ŕööƒ ~~~~]\"],\"editor.toolHint.placementSurfaceClickOrPressP.w56h19\":[\"[Þļáçéɱéñţ šûŕƒáçé - çļîçķ öŕ þŕéšš Þ ţö çýçļé ~~~~~~~~~~~]\"],\"editor.toolHint.placementType.1mdpl60\":[\"[Þļáçéɱéñţ ţýþé ~~~~]\"],\"editor.toolHint.placementTypeClickOrPressI.10cgxh2\":[\"[Þļáçéɱéñţ ţýþé — çļîçķ öŕ þŕéšš Î ţö ţöĝĝļé ~~~~~~~~~~~]\"],\"editor.toolHint.removeLastPoint.2dmdcx\":[\"[Ŕéɱöṽé ļášţ þöîñţ ~~~~~]\"],\"editor.toolHint.removeLastWitness.1b6vvzw\":[\"[Ŕéɱöṽé ļášţ ŵîţñéšš ~~~~~~]\"],\"editor.toolHint.rotate.1thqa0a\":[\"[Ŕöţáţé ~~]\"],\"editor.toolHint.rotate45.9zq68u\":[\"[Ŕöţáţé ±45° ~~]\"],\"editor.toolHint.rotate45FloorCeiling.m9t57d\":[\"[Ŕöţáţé ±45° (ƒļööŕ / çéîļîñĝ) ~~~~~~]\"],\"editor.toolHint.rotateGhost15.rsa52c\":[\"[Ŕöţáţé ĝĥöšţ ±15° ~~~~]\"],\"editor.toolHint.rotateOrFlipTheRunSide.t5ior7\":[\"[Ŕöţáţé öŕ ƒļîþ ţĥé ŕûñ šîðé ~~~~~~~]\"],\"editor.toolHint.rotateRoofDirection90.tvbji2\":[\"[Ŕöţáţé ŕööƒ ðîŕéçţîöñ 90° ~~~~~~]\"],\"editor.toolHint.rotateSpawnPoint.1opcuu7\":[\"[Ŕöţáţé šþáŵñ þöîñţ ~~~~~]\"],\"editor.toolHint.roundRectangularOval.e4nh6x\":[\"[Ŕöûñð / ŕéçţáñĝûļáŕ / öṽáļ ~~~~~~]\"],\"editor.toolHint.setFenceStartEnd.1phbwsq\":[\"[Šéţ ƒéñçé šţáŕţ / éñð ~~~~~]\"],\"editor.toolHint.setOneCornerThenTheOpposite.8tsl49\":[\"[Šéţ öñé çöŕñéŕ, ţĥéñ ţĥé öþþöšîţé ~~~~~~~~~]\"],\"editor.toolHint.setRoofFootprint.p50n0o\":[\"[Šéţ ŕööƒ ƒööţþŕîñţ ~~~~~]\"],\"editor.toolHint.setWallStartEnd.1r8ubcx\":[\"[Šéţ ŵáļļ šţáŕţ / éñð ~~~~~]\"],\"editor.toolHint.slopeLevel.ftqp67\":[\"[Šļöþé / ļéṽéļ ~~~]\"],\"editor.toolHint.snapOntoTheRun.86yhmp\":[\"[Šñáþ öñţö ţĥé ŕûñ ~~~~~]\"],\"editor.toolHint.splitAtTheMarks.x5tpdd\":[\"[Šþļîţ áţ ţĥé ɱáŕķš ~~~~~]\"],\"editor.toolHint.startGridAxis.k92yza\":[\"[Šţáŕţ ĝŕîð áẋîš ~~~~]\"],\"editor.toolHint.startLineset.23q8dh\":[\"[Šţáŕţ ļîñéšéţ ~~~~]\"],\"editor.toolHint.startLiquidLine.1rlxsgd\":[\"[Šţáŕţ ļîǫûîð ļîñé ~~~~~]\"],\"editor.toolHint.startRun.r6fc5u\":[\"[Šţáŕţ ŕûñ ~~~]\"],\"editor.toolHint.startSegment.rolym6\":[\"[Šţáŕţ šéĝɱéñţ ~~~~]\"],\"editor.toolHint.stepBackOrCancel.zbfdkn\":[\"[Šţéþ ƀáçķ öŕ çáñçéļ ~~~~~]\"],\"editor.toolHint.style.nf3vcm\":[\"[Šţýļé ~~]\"],\"editor.toolHint.styleBarn.k9n1x\":[\"[Šţýļé: Ɓáŕñ ~~~]\"],\"editor.toolHint.styleCasement.ziklec\":[\"[Šţýļé: Çášéɱéñţ ~~~~]\"],\"editor.toolHint.styleCraftsman.52e6a9\":[\"[Šţýļé: Çŕáƒţšɱáñ ~~~~~]\"],\"editor.toolHint.styleDoubleHung.1lg8pkg\":[\"[Šţýļé: Ðöûƀļé-ĥûñĝ ~~~~~]\"],\"editor.toolHint.styleFrench.1ue3j64\":[\"[Šţýļé: Ƒŕéñçĥ ~~~~]\"],\"editor.toolHint.styleGlass.qudnb4\":[\"[Šţýļé: Ĝļášš ~~~]\"],\"editor.toolHint.styleGrid.1vuq4po\":[\"[Šţýļé: Ĝŕîð ~~~]\"],\"editor.toolHint.styleHalfLouvered.13b1few\":[\"[Šţýļé: Ĥáļƒ-ļöûṽéŕéð ~~~~~~]\"],\"editor.toolHint.styleHorizontalBands.12ethxk\":[\"[Šţýļé: Ĥöŕîžöñţáļ ƀáñðš ~~~~~~]\"],\"editor.toolHint.styleModern.1fh8hhn\":[\"[Šţýļé: Ṁöðéŕñ ~~~~]\"],\"editor.toolHint.stylePanel.922jze\":[\"[Šţýļé: Þáñéļ ~~~]\"],\"editor.toolHint.stylePaneledGlass.17a17en\":[\"[Šţýļé: Þáñéļéð ĝļášš ~~~~~~]\"],\"editor.toolHint.styleShaker.49z17k\":[\"[Šţýļé: Šĥáķéŕ ~~~~]\"],\"editor.toolHint.styleSingle.6f3cm0\":[\"[Šţýļé: Šîñĝļé ~~~~]\"],\"editor.toolHint.styleSixPanel.u49laj\":[\"[Šţýļé: Šîẋ-þáñéļ ~~~~]\"],\"editor.toolHint.styleSliding.q81s0i\":[\"[Šţýļé: Šļîðîñĝ ~~~~]\"],\"editor.toolHint.styleTallGrid.1eotg3x\":[\"[Šţýļé: Ţáļļ ĝŕîð ~~~~]\"],\"editor.toolHint.styleTransom.kb9bh6\":[\"[Šţýļé: Ţŕáñšöɱ ~~~~]\"],\"editor.toolHint.styleTripleHung.pxnqi3\":[\"[Šţýļé: Ţŕîþļé-ĥûñĝ ~~~~~]\"],\"editor.toolHint.styleWideGrid.12n27et\":[\"[Šţýļé: Ŵîðé ĝŕîð ~~~~]\"],\"editor.toolHint.switchRotationAxisYXZ.15lohm6\":[\"[Šŵîţçĥ ŕöţáţîöñ áẋîš (Ý → Ẋ → Ž) ~~~~~~~]\"],\"editor.toolHint.theWallsMeetAtTooSharp.kh3wi3\":[\"[Ţĥé ŵáļļš ɱééţ áţ ţöö šĥáŕþ öŕ ţöö ƒļáţ áñ áñĝļé ~~~~~~~~~~~~]\"],\"editor.toolHint.theWindowWaitingThereIsTaller.1tqwez4\":[\"[Ţĥé ŵîñðöŵ ŵáîţîñĝ ţĥéŕé îš ţáļļéŕ ţĥáñ ţĥîš ŵáļļ ~~~~~~~~~~~~~]\"],\"editor.toolHint.threeOrMoreWallsMeetHere.rgifif\":[\"[Ţĥŕéé öŕ ɱöŕé ŵáļļš ɱééţ ĥéŕé ~~~~~~~~]\"],\"editor.toolHint.traceCeilingOutline.1b639wv\":[\"[Ţŕáçé çéîļîñĝ öûţļîñé ~~~~~~]\"],\"editor.toolHint.traceSlabOutline.z0j2lc\":[\"[Ţŕáçé šļáƀ öûţļîñé ~~~~~]\"],\"editor.toolHint.type.1m2zofh\":[\"[Ţýþé ~~]\"],\"editor.toolHint.typeAwning.1cj59al\":[\"[Ţýþé: Åŵñîñĝ ~~~]\"],\"editor.toolHint.typeBarn.sbnygq\":[\"[Ţýþé: Ɓáŕñ ~~~]\"],\"editor.toolHint.typeBay.1200hc1\":[\"[Ţýþé: Ɓáý ~~~]\"],\"editor.toolHint.typeBow.14s2t9p\":[\"[Ţýþé: Ɓöŵ ~~~]\"],\"editor.toolHint.typeCabinet.1r68je5\":[\"[Ţýþé: Çáƀîñéţ ~~~~]\"],\"editor.toolHint.typeCasement.176uo9j\":[\"[Ţýþé: Çášéɱéñţ ~~~~]\"],\"editor.toolHint.typeDouble.af7w4i\":[\"[Ţýþé: Ðöûƀļé ~~~]\"],\"editor.toolHint.typeDoubleHung.t482fu\":[\"[Ţýþé: Ðöûƀļé Ĥûñĝ ~~~~~]\"],\"editor.toolHint.typeFixed.v1cjez\":[\"[Ţýþé: Ƒîẋéð ~~~]\"],\"editor.toolHint.typeFolding.sxxyng\":[\"[Ţýþé: Ƒöļðîñĝ ~~~~]\"],\"editor.toolHint.typeFrench.1y57z1b\":[\"[Ţýþé: Ƒŕéñçĥ ~~~]\"],\"editor.toolHint.typeHinged.1xrcfju\":[\"[Ţýþé: Ĥîñĝéð ~~~]\"],\"editor.toolHint.typeIsland.ufr3ce\":[\"[Ţýþé: Κļáñð ~~~]\"],\"editor.toolHint.typeLouvered.oxl1cz\":[\"[Ţýþé: Ļöûṽéŕéð ~~~~]\"],\"editor.toolHint.typePocket.hc65x9\":[\"[Ţýþé: Þöçķéţ ~~~]\"],\"editor.toolHint.typeSingleHung.p53pyl\":[\"[Ţýþé: Šîñĝļé Ĥûñĝ ~~~~~]\"],\"editor.toolHint.typeSliding.nwmr3f\":[\"[Ţýþé: Šļîðîñĝ ~~~~]\"],\"editor.toolHint.verticalStackClickToPlace.ijcn4q\":[\"[Ṽéŕţîçáļ šţáçķ ↕, çļîçķ ţö þļáçé ~~~~~~~~]\"],\"editor.toolHint.wasteVent.1hvi3vj\":[\"[Ŵášţé / ṽéñţ ~~~]\"],\"editor.toolHint.windowStyleClickOrPressL.ah7qm9\":[\"[Ŵîñðöŵ šţýļé — çļîçķ öŕ þŕéšš Ļ ţö çýçļé ~~~~~~~~~~]\"],\"editor.toolHint.windowTypeClickOrPressO.wv4x35\":[\"[Ŵîñðöŵ ţýþé — çļîçķ öŕ þŕéšš Ö ţö çýçļé ~~~~~~~~~]\"],\"editor.tools.distribution.distributionRunTool.lengthField\":[\"[Ļéñĝţĥ: \",[\"field\"],\" ɱ ~~~]\"],\"editor.tools.distribution.distributionRunTool.tabDirection\":[\"[Ţáƀ: ðîŕéçţîöñ ~~~~]\"],\"editor.tools.distribution.distributionRunTool.typeALength\":[\"[ţýþé á ļéñĝţĥ ~~~~]\"],\"editor.views.plugins\":[\"[Þļûĝîñš ~~~]\"],\"editor.views.view2d\":[\"[2Ð ~]\"],\"editor.views.view3d\":[\"[3Ð ~]\"],\"editor.views.viewBar.auto\":[\"[Åûţö ~~]\"],\"editor.views.viewBar.browsePlugins\":[\"[Ɓŕöŵšé þļûĝîñš ~~~~]\"],\"editor.views.viewBar.closeLabel\":[\"[Çļöšé \",[\"label\"],\" ~~]\"],\"editor.views.viewBar.closeSplit\":[\"[Çļöšé šþļîţ (\\\\) ~~~]\"],\"editor.views.viewBar.ground\":[\"[Ĝŕöûñð ~~]\"],\"editor.views.viewBar.groundSolid\":[\"[\",[\"standing\",\"select\",{\"partly\":[\"Þáŕţļý ƀéļöŵ ĝŕáðé · ĝŕöûñð šöļîð\"],\"below\":[\"Ɓéļöŵ ĝŕáðé · ĝŕöûñð šöļîð\"],\"other\":[\"Ĝŕöûñð šöļîð\"]}],\" ~~~~~~~~~~~~~~~~~~]\"],\"editor.views.viewBar.groundVeiled\":[\"[\",[\"standing\",\"select\",{\"partly\":[\"Þáŕţļý ƀéļöŵ ĝŕáðé · ĝŕöûñð ṽéîļéð\"],\"below\":[\"Ɓéļöŵ ĝŕáðé · ĝŕöûñð ṽéîļéð\"],\"other\":[\"Ĝŕöûñð ṽéîļéð\"]}],\" ~~~~~~~~~~~~~~~~~~~]\"],\"editor.views.viewBar.keepTheGroundSolid\":[\"[Ķééþ ţĥé ĝŕöûñð šöļîð ~~~~~~]\"],\"editor.views.viewBar.moreViews\":[\"[Ṁöŕé ṽîéŵš ~~~]\"],\"editor.views.viewBar.paneViews\":[\"[Þáñé \",[\"pane\"],\" ṽîéŵš ~~~]\"],\"editor.views.viewBar.pinLabel\":[\"[Þîñ \",[\"label\"],\" ~]\"],\"editor.views.viewBar.pinToTheViewBar\":[\"[Þîñ ţö ţĥé ṽîéŵ ƀáŕ ~~~~~]\"],\"editor.views.viewBar.solid\":[\"[Šöļîð ~~]\"],\"editor.views.viewBar.split\":[\"[Šþļîţ (\\\\) ~~]\"],\"editor.views.viewBar.split2\":[\"[Šþļîţ ~~]\"],\"editor.views.viewBar.swapPanes\":[\"[Šŵáþ þáñéš ~~~]\"],\"editor.views.viewBar.unpinFromTheViewBar\":[\"[Ûñþîñ ƒŕöɱ ţĥé ṽîéŵ ƀáŕ ~~~~~~]\"],\"editor.views.viewBar.unpinLabel\":[\"[Ûñþîñ \",[\"label\"],\" ~~]\"],\"editor.views.viewBar.veilTheGroundOverALevel\":[\"[Ṽéîļ ţĥé ĝŕöûñð öṽéŕ á ļéṽéļ ƀéļöŵ ĝŕáðé ~~~~~~~~~~]\"],\"editor.views.viewBar.views\":[\"[Ṽîéŵš ~~]\"],\"editor.youCanRetryTheSceneOr\":[\"[Ýöû çáñ ŕéţŕý ţĥé šçéñé öŕ ŕéţûŕñ ĥöɱé ŵîţĥöûţ ŕéļöáðîñĝ ţĥé ŵĥöļé áþþ šĥéļļ. ~~~~~~~~~~~~~~~~~~~]\"],\"node.block.description\":[\"[Å ţöþöļöĝý-ƀáçķéð šöļîð éðîţéð ðîŕéçţļý îñ ţĥé çáñṽáš. ~~~~~~~~~~~~~~]\"],\"node.block.label\":[\"[Ɓļöçķ ~~]\"],\"node.boxVent.description\":[\"[Šɱáļļ ļöûṽéŕéð éẋĥáûšţ ṽéñţ ţĥáţ šîţš öñ á ŕööƒ šļöþé. ~~~~~~~~~~~~~~]\"],\"node.boxVent.label\":[\"[Ɓöẋ Ṽéñţ ~~~]\"],\"node.boxVent.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.boxVent.panel.baseFlange\":[\"[Ɓášé Ƒļáñĝé ~~~]\"],\"node.boxVent.panel.baseHeight\":[\"[Ɓášé Ĥéîĝĥţ ~~~]\"],\"node.boxVent.panel.baseInset\":[\"[Ɓášé Îñšéţ ~~~]\"],\"node.boxVent.panel.box\":[\"[Ɓöẋ ~]\"],\"node.boxVent.panel.boxVent\":[\"[Ɓöẋ Ṽéñţ ~~~]\"],\"node.boxVent.panel.cap\":[\"[Çáþ ~]\"],\"node.boxVent.panel.capHeight\":[\"[Çáþ Ĥéîĝĥţ ~~~]\"],\"node.boxVent.panel.cornerBevel\":[\"[Çöŕñéŕ Ɓéṽéļ ~~~~]\"],\"node.boxVent.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.boxVent.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.boxVent.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.boxVent.panel.dome\":[\"[Ðöɱé ~~]\"],\"node.boxVent.panel.domeCurvature\":[\"[Ðöɱé Çûŕṽáţûŕé ~~~~]\"],\"node.boxVent.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.boxVent.panel.gapHeight\":[\"[Ĝáþ Ĥéîĝĥţ ~~~]\"],\"node.boxVent.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.boxVent.panel.hoodOverhang\":[\"[Ĥööð Öṽéŕĥáñĝ ~~~~]\"],\"node.boxVent.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.boxVent.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.boxVent.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.boxVent.panel.style\":[\"[Šţýļé ~~]\"],\"node.boxVent.panel.topTaper\":[\"[Ţöþ Ţáþéŕ ~~~]\"],\"node.boxVent.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.building.description\":[\"[Å ƀûîļðîñĝ çöñţáîñéŕ ĥöļðîñĝ öñé öŕ ɱöŕé ļéṽéļš. ~~~~~~~~~~~~]\"],\"node.building.label\":[\"[Ɓûîļðîñĝ ~~~]\"],\"node.cabinet.compartmentCard.baskets\":[\"[Ɓášķéţš ~~~]\"],\"node.cabinet.compartmentCard.bottom\":[\"[Ɓöţţöɱ ~~]\"],\"node.cabinet.compartmentCard.bottomFreezer\":[\"[Ɓöţţöɱ Ƒŕééžéŕ ~~~~]\"],\"node.cabinet.compartmentCard.bowls\":[\"[Ɓöŵļš ~~]\"],\"node.cabinet.compartmentCard.burnersOn\":[\"[Ɓûŕñéŕš öñ ~~~]\"],\"node.cabinet.compartmentCard.chimney\":[\"[Çĥîɱñéý ~~~]\"],\"node.cabinet.compartmentCard.decrease\":[\"[Ðéçŕéášé \",[\"label\"],\" ~~~]\"],\"node.cabinet.compartmentCard.door\":[\"[Ðööŕ ~~]\"],\"node.cabinet.compartmentCard.double\":[\"[Ðöûƀļé ~~]\"],\"node.cabinet.compartmentCard.drawer\":[\"[Ðŕáŵéŕ ~~]\"],\"node.cabinet.compartmentCard.drawers\":[\"[Ðŕáŵéŕš ~~~]\"],\"node.cabinet.compartmentCard.flipHinge\":[\"[Ƒļîþ ĥîñĝé ~~~]\"],\"node.cabinet.compartmentCard.flipTheDoorHingeToThe\":[\"[Ƒļîþ ţĥé ðööŕ ĥîñĝé ţö ţĥé öþþöšîţé šîðé ~~~~~~~~~~]\"],\"node.cabinet.compartmentCard.fridge\":[\"[Ƒŕîðĝé ~~]\"],\"node.cabinet.compartmentCard.gas\":[\"[Ĝáš ~]\"],\"node.cabinet.compartmentCard.glass\":[\"[Ĝļášš ~~]\"],\"node.cabinet.compartmentCard.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.cabinet.compartmentCard.hob\":[\"[Ĥöƀ ~]\"],\"node.cabinet.compartmentCard.increase\":[\"[Îñçŕéášé \",[\"label\"],\" ~~~]\"],\"node.cabinet.compartmentCard.induction\":[\"[Îñðûçţîöñ ~~~]\"],\"node.cabinet.compartmentCard.layout\":[\"[Ļáýöûţ ~~]\"],\"node.cabinet.compartmentCard.left\":[\"[Ļéƒţ ~~]\"],\"node.cabinet.compartmentCard.micro\":[\"[Ṁîçŕö ~~]\"],\"node.cabinet.compartmentCard.moveDown\":[\"[Ṁöṽé ðöŵñ ~~~]\"],\"node.cabinet.compartmentCard.moveUp\":[\"[Ṁöṽé ûþ ~~]\"],\"node.cabinet.compartmentCard.oven\":[\"[Öṽéñ ~~]\"],\"node.cabinet.compartmentCard.pullout\":[\"[Þûļļöûţ ~~~]\"],\"node.cabinet.compartmentCard.rack\":[\"[Ŕáçķ ~~]\"],\"node.cabinet.compartmentCard.removeCompartment\":[\"[Ŕéɱöṽé çöɱþáŕţɱéñţ ~~~~~~]\"],\"node.cabinet.compartmentCard.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.cabinet.compartmentCard.shelf\":[\"[Šĥéļƒ ~~]\"],\"node.cabinet.compartmentCard.shelves\":[\"[Šĥéļṽéš ~~~]\"],\"node.cabinet.compartmentCard.shelvesInside\":[\"[Šĥéļṽéš îñšîðé ~~~~]\"],\"node.cabinet.compartmentCard.single\":[\"[Šîñĝļé ~~]\"],\"node.cabinet.compartmentCard.sink\":[\"[Šîñķ ~~]\"],\"node.cabinet.compartmentCard.style\":[\"[Šţýļé ~~]\"],\"node.cabinet.compartmentCard.surface\":[\"[Šûŕƒáçé ~~~]\"],\"node.cabinet.compartmentCard.top\":[\"[Ţöþ ~]\"],\"node.cabinet.compartmentCard.topFreezer\":[\"[Ţöþ Ƒŕééžéŕ ~~~]\"],\"node.cabinet.compartmentCard.topGrate\":[\"[Ţöþ ĝŕáţé ~~~]\"],\"node.cabinet.compartmentCard.tray\":[\"[Ţŕáý ~~]\"],\"node.cabinet.compartmentCard.type\":[\"[Ţýþé ~~]\"],\"node.cabinet.compartmentCard.washer\":[\"[Ŵášĥéŕ ~~]\"],\"node.cabinet.compartmentCard.wire\":[\"[Ŵîŕé ~~]\"],\"node.cabinet.description\":[\"[Å çöñƒîĝûŕáƀļé þáŕáɱéţŕîç ƀášé çáƀîñéţ. ~~~~~~~~~~~]\"],\"node.cabinet.essentialControls.bottomFreezer\":[\"[Ɓöţţöɱ ƒŕééžéŕ ~~~~]\"],\"node.cabinet.essentialControls.cooktopType\":[\"[Çööķţöþ ţýþé ~~~~]\"],\"node.cabinet.essentialControls.doorDirection\":[\"[Ðööŕ ðîŕéçţîöñ ~~~~]\"],\"node.cabinet.essentialControls.double\":[\"[Ðöûƀļé ~~]\"],\"node.cabinet.essentialControls.fridgeType\":[\"[Ƒŕîðĝé ţýþé ~~~]\"],\"node.cabinet.essentialControls.gas\":[\"[Ĝáš ~]\"],\"node.cabinet.essentialControls.glass\":[\"[Ĝļášš ~~]\"],\"node.cabinet.essentialControls.induction\":[\"[Îñðûçţîöñ ~~~]\"],\"node.cabinet.essentialControls.itemOptions\":[\"[Îţéɱ öþţîöñš ~~~~]\"],\"node.cabinet.essentialControls.leftHinge\":[\"[Ļéƒţ ĥîñĝé ~~~]\"],\"node.cabinet.essentialControls.rightHinge\":[\"[Ŕîĝĥţ ĥîñĝé ~~~]\"],\"node.cabinet.essentialControls.single\":[\"[Šîñĝļé ~~]\"],\"node.cabinet.essentialControls.sinkLayout\":[\"[Šîñķ ļáýöûţ ~~~]\"],\"node.cabinet.essentialControls.topFreezer\":[\"[Ţöþ ƒŕééžéŕ ~~~]\"],\"node.cabinet.kitchenCollection.chooseLabel\":[\"[Çĥööšé \",[\"label\"],\" ~~]\"],\"node.cabinet.kitchenCollection.noKitchenItemsMatchTryFridge\":[\"[Ñö ķîţçĥéñ îţéɱš ɱáţçĥ. Ţŕý “ƒŕîðĝé”, “šîñķ”, öŕ “çáƀîñéţ”. ~~~~~~~~~~~~~]\"],\"node.cabinet.kitchenCollection.searchFridgeSinkCabinets\":[\"[Šéáŕçĥ ƒŕîðĝé, šîñķ, çáƀîñéţš… ~~~~~~~~]\"],\"node.cabinet.kitchenCollection.searchKitchenItems\":[\"[Šéáŕçĥ ķîţçĥéñ îţéɱš ~~~~~~]\"],\"node.cabinet.kitchenGroup.appliances\":[\"[Åþþļîáñçéš & ƒîẋţûŕéš ~~~~~~]\"],\"node.cabinet.kitchenGroup.cabinets\":[\"[Çáƀîñéţš ~~~]\"],\"node.cabinet.kitchenModuleActions.addBeside\":[\"[Åðð ƀéšîðé ~~~]\"],\"node.cabinet.kitchenModuleActions.addBesideSelectedItem\":[\"[Åðð ƀéšîðé šéļéçţéð îţéɱ ~~~~~~~]\"],\"node.cabinet.kitchenModuleActions.addLabel\":[\"[Åðð \",[\"label\"],\" ~]\"],\"node.cabinet.kitchenModuleActions.anUpperCabinetAttachedToThis\":[\"[Åñ ûþþéŕ çáƀîñéţ áţţáçĥéð ţö ţĥîš îţéɱ ŵîļļ ƀé ŕéɱöṽéð ţö ɱáķé ŕööɱ. ~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.kitchenModuleActions.cabinet\":[\"[Çáƀîñéţ ~~~]\"],\"node.cabinet.kitchenModuleActions.cancel\":[\"[Çáñçéļ ~~]\"],\"node.cabinet.kitchenModuleActions.cannotFit\":[\"[Ţĥîš \",[\"width\"],\" îţéɱ çáññöţ ƒîţ ŵîţĥîñ ţĥé çûŕŕéñţ ŕûñ áñð îţš ŵáļļ öŕ çöŕñéŕ ļîɱîţš. Ṁöṽé áñ éñð çáƀîñéţ öŕ ƒŕéé šþáçé, ţĥéñ ţŕý áĝáîñ. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.kitchenModuleActions.insertsBeside\":[\"[\",[\"side\",\"select\",{\"left\":[\"Îñšéŕţš öñ ţĥé ļéƒţ öƒ ţĥé šéļéçţéð îţéɱ.\"],\"other\":[\"Îñšéŕţš öñ ţĥé ŕîĝĥţ öƒ ţĥé šéļéçţéð îţéɱ.\"]}],\" ~~~~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.kitchenModuleActions.kitchenChanged\":[\"[Ţĥé ķîţçĥéñ çĥáñĝéð. Šéļéçţ áñ îţéɱ áĝáîñ ţö ŕéƒŕéšĥ ţĥé þŕéṽîéŵ. ~~~~~~~~~~~~~~~~]\"],\"node.cabinet.kitchenModuleActions.kitchenRunPreviewHighlightedItemIs\":[\"[Ķîţçĥéñ ŕûñ þŕéṽîéŵ, ĥîĝĥļîĝĥţéð îţéɱ îš ţĥé þŕöþöšéð çĥáñĝé ~~~~~~~~~~~~~~~~]\"],\"node.cabinet.kitchenModuleActions.leftSide\":[\"[Ļéƒţ šîðé ~~~]\"],\"node.cabinet.kitchenModuleActions.moved\":[\"[\",[\"name\"],\": ɱöṽéš \",[\"distance\"],\" ~~]\"],\"node.cabinet.kitchenModuleActions.previewItem\":[[\"name\"],\": \",[\"width\"]],\"node.cabinet.kitchenModuleActions.replaceSelectedItem\":[\"[Ŕéþļáçé šéļéçţéð îţéɱ ~~~~~~]\"],\"node.cabinet.kitchenModuleActions.replaceWith\":[\"[Ŕéþļáçé ŵîţĥ… ~~~~]\"],\"node.cabinet.kitchenModuleActions.replaceWithLabel\":[\"[Ŕéþļáçé ŵîţĥ \",[\"label\"],\" ~~~~]\"],\"node.cabinet.kitchenModuleActions.replacesOnlyTheSelectedItem\":[\"[Ŕéþļáçéš öñļý ţĥé šéļéçţéð îţéɱ. ~~~~~~~~~]\"],\"node.cabinet.kitchenModuleActions.resized\":[[\"name\"],\": \",[\"before\"],\" → \",[\"after\"]],\"node.cabinet.kitchenModuleActions.rightSide\":[\"[Ŕîĝĥţ šîðé ~~~]\"],\"node.cabinet.kitchenModuleActions.unableToUpdateThisKitchen\":[\"[Ûñáƀļé ţö ûþðáţé ţĥîš ķîţçĥéñ. ~~~~~~~~]\"],\"node.cabinet.label\":[\"[Ṁöðûļáŕ Çáƀîñéţ ~~~~~]\"],\"node.cabinet.panel.aboveCeiling\":[\"[Ƒîñîšĥéð ĥéîĝĥţ éẋţéñðš \",[\"overflow\"],\" ɱɱ áƀöṽé ţĥé çéîļîñĝ. ~~~~~~~~~~~~]\"],\"node.cabinet.panel.addChimney\":[\"[Åðð çĥîɱñéý ~~~]\"],\"node.cabinet.panel.addCompartment\":[\"[Åðð çöɱþáŕţɱéñţ ~~~~~]\"],\"node.cabinet.panel.addWallCabinet\":[\"[Åðð ŵáļļ çáƀîñéţ ~~~~~]\"],\"node.cabinet.panel.advanced\":[\"[Åðṽáñçéð ~~~]\"],\"node.cabinet.panel.appliance\":[\"[Åþþļîáñçé ~~~]\"],\"node.cabinet.panel.applianceFront\":[\"[Åþþļîáñçé ƒŕöñţ ~~~~~]\"],\"node.cabinet.panel.auto\":[\"[Åûţö ~~]\"],\"node.cabinet.panel.bar\":[\"[Ɓáŕ ~]\"],\"node.cabinet.panel.baseCabinet\":[\"[Ɓášé Çáƀîñéţ ~~~~]\"],\"node.cabinet.panel.cabinetConstructionCompartmentsAndOpeningPreview\":[\"[Çáƀîñéţ çöñšţŕûçţîöñ, çöɱþáŕţɱéñţš, áñð öþéñîñĝ þŕéṽîéŵ. ~~~~~~~~~~~~~~~]\"],\"node.cabinet.panel.cabinetPanel\":[\"[Çáƀîñéţ þáñéļ ~~~~]\"],\"node.cabinet.panel.cabinetType\":[\"[Çáƀîñéţ Ţýþé ~~~~]\"],\"node.cabinet.panel.center\":[\"[Çéñţéŕ ~~]\"],\"node.cabinet.panel.close\":[\"[Çļöšé ~~]\"],\"node.cabinet.panel.closeCabinet\":[\"[Çļöšé çáƀîñéţ ~~~~]\"],\"node.cabinet.panel.commonWallCabinetHeightsUseThe\":[\"[Çöɱɱöñ ŵáļļ-çáƀîñéţ ĥéîĝĥţš. Ûšé ţĥé šļîðéŕ ƀéļöŵ ƒöŕ á çûšţöɱ ĥéîĝĥţ. ~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.panel.compartments\":[\"[Çöɱþáŕţɱéñţš ~~~~]\"],\"node.cabinet.panel.cutout\":[\"[Çûţöûţ ~~]\"],\"node.cabinet.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.cabinet.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.cabinet.panel.editKitchenRun\":[\"[Éðîţ ķîţçĥéñ ŕûñ ~~~~~]\"],\"node.cabinet.panel.fillToCeiling\":[\"[Ƒîļļ ţö çéîļîñĝ ~~~~]\"],\"node.cabinet.panel.finish\":[\"[Ƒîñîšĥ ~~]\"],\"node.cabinet.panel.frontConstruction\":[\"[Ƒŕöñţ çöñšţŕûçţîöñ ~~~~~~]\"],\"node.cabinet.panel.handles\":[\"[Ĥáñðļéš ~~~]\"],\"node.cabinet.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.cabinet.panel.heightPreset\":[\"[Ĥéîĝĥţ þŕéšéţ ~~~~]\"],\"node.cabinet.panel.hole\":[\"[Ĥöļé ~~]\"],\"node.cabinet.panel.inset\":[\"[Îñšéţ ~~]\"],\"node.cabinet.panel.kitchen\":[\"[Ķîţçĥéñ ~~~]\"],\"node.cabinet.panel.kitchenRun\":[\"[Ķîţçĥéñ ŕûñ ~~~]\"],\"node.cabinet.panel.knob\":[\"[Ķñöƀ ~~]\"],\"node.cabinet.panel.mounting\":[\"[Ṁöûñţîñĝ ~~~]\"],\"node.cabinet.panel.none\":[\"[Ñöñé ~~]\"],\"node.cabinet.panel.open\":[\"[Öþéñ ~~]\"],\"node.cabinet.panel.openAnimation\":[\"[Öþéñ Åñîɱáţîöñ ~~~~]\"],\"node.cabinet.panel.openCabinet\":[\"[Öþéñ çáƀîñéţ ~~~~]\"],\"node.cabinet.panel.overlay\":[\"[Öṽéŕļáý ~~~]\"],\"node.cabinet.panel.panelReady\":[\"[Þáñéļ-ŕéáðý ~~~]\"],\"node.cabinet.panel.planningChecks\":[\"[Þļáññîñĝ çĥéçķš ~~~~~]\"],\"node.cabinet.panel.play\":[\"[Þļáý ~~]\"],\"node.cabinet.panel.playAnimation\":[\"[Þļáý áñîɱáţîöñ ~~~~]\"],\"node.cabinet.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.cabinet.panel.raisedArch\":[\"[Ŕáîšéð Åŕçĥ ~~~]\"],\"node.cabinet.panel.removeWallCabinet\":[\"[Ŕéɱöṽé ŵáļļ çáƀîñéţ ~~~~~~]\"],\"node.cabinet.panel.replaceWith\":[\"[Ŕéþļáçé ŵîţĥ… ~~~~]\"],\"node.cabinet.panel.revealGap\":[\"[Ŕéṽéáļ ĝáþ ~~~]\"],\"node.cabinet.panel.shaker\":[\"[Šĥáķéŕ ~~]\"],\"node.cabinet.panel.sharedCountertopPlinthAndFinishes\":[\"[Šĥáŕéð çöûñţéŕţöþ, þļîñţĥ, áñð ƒîñîšĥéš ~~~~~~~~~~]\"],\"node.cabinet.panel.slab\":[\"[Šļáƀ ~~]\"],\"node.cabinet.panel.solidMatchingFrontBetweenTheCabinet\":[\"[Šöļîð ɱáţçĥîñĝ ƒŕöñţ ƀéţŵééñ ţĥé çáƀîñéţ áñð ŵáļļ. Çöûñţéŕţöþ áñð ţöé-ķîçķ çöñţîñûé áçŕöšš ţĥîš ƒîļļéŕ. ~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.panel.standardWidth\":[\"[Šţáñðáŕð ŵîðţĥ ~~~~]\"],\"node.cabinet.panel.stop\":[\"[Šţöþ ~~]\"],\"node.cabinet.panel.stopAnimation\":[\"[Šţöþ áñîɱáţîöñ ~~~~]\"],\"node.cabinet.panel.style\":[\"[Šţýļé ~~]\"],\"node.cabinet.panel.tallCabinet\":[\"[Ţáļļ Çáƀîñéţ ~~~~]\"],\"node.cabinet.panel.top\":[\"[Ţöþ ~]\"],\"node.cabinet.panel.topCabinet\":[\"[Ţöþ Çáƀîñéţ ~~~]\"],\"node.cabinet.panel.topCeiling\":[\"[Ţöþ / Çéîļîñĝ ~~~]\"],\"node.cabinet.panel.topDepth\":[\"[Ţöþ ðéþţĥ ~~~]\"],\"node.cabinet.panel.topHeight\":[\"[Ţöþ ĥéîĝĥţ ~~~]\"],\"node.cabinet.panel.trimSoffit\":[\"[Ţŕîɱ / Šöƒƒîţ ~~~]\"],\"node.cabinet.panel.usesTheCabinetFrontStyleReveal\":[\"[Ûšéš ţĥé çáƀîñéţ ƒŕöñţ šţýļé, ŕéṽéáļ, ĥáñðļé, áñð ƒŕöñţ ɱáţéŕîáļ šéţţîñĝš ƀéļöŵ. ~~~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.panel.wallFiller\":[\"[Ŵáļļ ƒîļļéŕ ~~~]\"],\"node.cabinet.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.cabinet.preset.baseCabinet\":[\"[Ɓášé çáƀîñéţ ~~~~]\"],\"node.cabinet.preset.dishwasher\":[\"[Ðîšĥŵášĥéŕ ~~~]\"],\"node.cabinet.preset.drawerCabinet\":[\"[Ðŕáŵéŕ çáƀîñéţ ~~~~]\"],\"node.cabinet.preset.fridge\":[\"[Ƒŕîðĝé ~~]\"],\"node.cabinet.preset.gasCooktop\":[\"[Ĝáš çööķţöþ ~~~]\"],\"node.cabinet.preset.inductionCooktop\":[\"[Îñðûçţîöñ çööķţöþ ~~~~~]\"],\"node.cabinet.preset.ovenTower\":[\"[Öṽéñ Ţöŵéŕ ~~~]\"],\"node.cabinet.preset.sinkCabinet\":[\"[Šîñķ çáƀîñéţ ~~~~]\"],\"node.cabinet.preset.tallPantry\":[\"[Ţáļļ Þáñţŕý ~~~]\"],\"node.cabinet.preset.wallCabinet\":[\"[Ŵáļļ çáƀîñéţ ~~~~]\"],\"node.cabinet.runPanel.addLeft\":[\"[Åðð ļéƒţ ~~~]\"],\"node.cabinet.runPanel.addRight\":[\"[Åðð ŕîĝĥţ ~~~]\"],\"node.cabinet.runPanel.alignCabinetsHandles\":[\"[Åļîĝñ çáƀîñéţš & ĥáñðļéš ~~~~~~]\"],\"node.cabinet.runPanel.appliesDepthCarcassPlinthAndCountertop\":[\"[Åþþļîéš ðéþţĥ, çáŕçášš, þļîñţĥ, áñð çöûñţéŕţöþ ţĥîçķñéšš ţö ţĥîš ŕûñ. ~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.arrayCreate\":[\"[\",[\"count\",\"plural\",{\"one\":[\"Çŕéáţé \",[\"number\"],\" ɱöðûļé çöþý\"],\"other\":[\"Çŕéáţé \",[\"number\"],\" ɱöðûļé çöþîéš\"]}],\" ~~~~~~~~~~~]\"],\"node.cabinet.runPanel.arrayCreateNamed\":[\"[\",[\"count\",\"plural\",{\"one\":[\"Çŕéáţé \",[\"number\"],\" \",[\"name\"],\" çöþý\"],\"other\":[\"Çŕéáţé \",[\"number\"],\" \",[\"name\"],\" çöþîéš\"]}],\" ~~~~~~~]\"],\"node.cabinet.runPanel.arrayInvalidOptions\":[\"[Çĥööšé á çöþý çöûñţ ƒŕöɱ 1 ţö 20 áñð šþáçîñĝ ƒŕöɱ 0 ţö 2 ɱ ~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.arrayNoRoom\":[\"[Ţĥéŕé îš ñöţ éñöûĝĥ ŕööɱ îñ ţĥîš ŕûñ ƒöŕ ţĥé ŕéǫûéšţéð áŕŕáý ~~~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.arrayNoSource\":[\"[Çĥööšé á šţáñðáŕð öŕ áþþļîáñçé ɱöðûļé áš ţĥé šöûŕçé ~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.auto\":[\"[Åûţö ~~]\"],\"node.cabinet.runPanel.back\":[\"[Ɓáçķ ~~]\"],\"node.cabinet.runPanel.balancesStandardBaseCabinetsWhileKeeping\":[\"[Ɓáļáñçéš šţáñðáŕð ƀášé çáƀîñéţš ŵĥîļé ķééþîñĝ áþþļîáñçé áñð çöŕñéŕ-ƒîļļéŕ ŵîðţĥš ƒîẋéð. ~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.bar\":[\"[Ɓáŕ ~]\"],\"node.cabinet.runPanel.barCounter\":[\"[Ɓáŕ çöûñţéŕ ~~~]\"],\"node.cabinet.runPanel.barDepth\":[\"[Ɓáŕ ðéþţĥ ~~~]\"],\"node.cabinet.runPanel.barHeight\":[\"[Ɓáŕ ĥéîĝĥţ ~~~]\"],\"node.cabinet.runPanel.carcassHeight\":[\"[Çáŕçášš ĥéîĝĥţ ~~~~]\"],\"node.cabinet.runPanel.center\":[\"[Çéñţéŕ ~~]\"],\"node.cabinet.runPanel.commonWallCabinetHeightsUseThe\":[\"[Çöɱɱöñ ŵáļļ-çáƀîñéţ ĥéîĝĥţš. Ûšé ţĥé šļîðéŕ ƀéļöŵ ƒöŕ á çûšţöɱ ĥéîĝĥţ. ~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.copies\":[\"[Çöþîéš ~~]\"],\"node.cabinet.runPanel.copiesIncludeTheSourceCabinetStructure\":[\"[Çöþîéš îñçļûðé ţĥé šöûŕçé çáƀîñéţ šţŕûçţûŕé áñð áñý áţţáçĥéð ŵáļļ çáƀîñéţ. Éẋîšţîñĝ ɱöðûļéš šţáý ƒîẋéð; ţĥé ŕéǫûéšţéð áŕŕáý ɱûšţ ƒîţ îñ ţĥé áṽáîļáƀļé ŕûñ šþáçé. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.cornerFillersCannotBeUsedAs\":[\"[Çöŕñéŕ ƒîļļéŕš çáññöţ ƀé ûšéð áš áŕŕáý šöûŕçéš ~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.countertopDepth\":[\"[Çöûñţéŕţöþ ðéþţĥ ~~~~~]\"],\"node.cabinet.runPanel.countertopHeight\":[\"[Çöûñţéŕţöþ ĥéîĝĥţ ~~~~~]\"],\"node.cabinet.runPanel.createArray\":[\"[Çŕéáţé áŕŕáý ~~~~]\"],\"node.cabinet.runPanel.cutout\":[\"[Çûţöûţ ~~]\"],\"node.cabinet.runPanel.deleteModule\":[\"[Ðéļéţé \",[\"name\"],\" ~~]\"],\"node.cabinet.runPanel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.cabinet.runPanel.direction\":[\"[Ðîŕéçţîöñ ~~~]\"],\"node.cabinet.runPanel.duplicateAlongRun\":[\"[Ðûþļîçáţé áļöñĝ ŕûñ ~~~~~~]\"],\"node.cabinet.runPanel.equalizeAll\":[\"[Éǫûáļîžé áļļ ŕéšîžéáƀļé šţáñðáŕð ƀášé çáƀîñéţš îñ ţĥîš ŕûñ ~~~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.equalizeAlreadyEqual\":[\"[Ţĥé ŕéšîžéáƀļé çáƀîñéţ ŵîðţĥš áŕé áļŕéáðý éǫûáļ ~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.equalizeNeedsTwo\":[\"[Åţ ļéášţ ţŵö šţáñðáŕð ƀášé çáƀîñéţš áŕé ŕéǫûîŕéð ~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.equalizeNoFit\":[\"[Ţĥé áṽáîļáƀļé ŕûñ ŵîðţĥ çáññöţ šáţý ţĥé çáƀîñéţ ŵîðţĥ ļîɱîţš ~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.equalizeWidths\":[\"[Éǫûáļîžé ŵîðţĥš ~~~~~]\"],\"node.cabinet.runPanel.fillerPlanSide\":[\"[\",[\"side\",\"select\",{\"left\":[\"Ļéƒţ: \",[\"width\"],\" ɱɱ\"],\"other\":[\"Ŕîĝĥţ: \",[\"width\"],\" ɱɱ\"]}],\" ~~~~]\"],\"node.cabinet.runPanel.finishAlign\":[\"[Ƒîñîšĥ & áļîĝñ ~~~~]\"],\"node.cabinet.runPanel.finishedBack\":[\"[Ƒîñîšĥéð ƀáçķ ~~~~]\"],\"node.cabinet.runPanel.finishedExposedEnds\":[\"[Ƒîñîšĥéð éẋþöšéð éñðš ~~~~~~]\"],\"node.cabinet.runPanel.fitWallFillers\":[\"[Ƒîţ ŵáļļ ƒîļļéŕš ~~~~~]\"],\"node.cabinet.runPanel.fits50150MmGapsAt\":[\"[Ƒîţš 50–150 ɱɱ ĝáþš áţ ŕûñ éñðš ƀéšîðé þéŕþéñðîçûļáŕ ŵáļļš. ~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.fronts\":[\"[Ƒŕöñţš ~~]\"],\"node.cabinet.runPanel.handles\":[\"[Ĥáñðļéš ~~~]\"],\"node.cabinet.runPanel.heightPreset\":[\"[Ĥéîĝĥţ þŕéšéţ ~~~~]\"],\"node.cabinet.runPanel.hole\":[\"[Ĥöļé ~~]\"],\"node.cabinet.runPanel.inset\":[\"[Îñšéţ ~~]\"],\"node.cabinet.runPanel.islandBar\":[\"[Κļáñð & Ɓáŕ ~~~]\"],\"node.cabinet.runPanel.kitchenRun\":[\"[Ķîţçĥéñ ŕûñ ~~~]\"],\"node.cabinet.runPanel.knob\":[\"[Ķñöƀ ~~]\"],\"node.cabinet.runPanel.left\":[\"[Ļéƒţ ~~]\"],\"node.cabinet.runPanel.matchBaseHeightsBacksRevealsAnd\":[\"[Ṁáţçĥ ƀášé ĥéîĝĥţš, ƀáçķš, ŕéṽéáļš áñð ĥáñðļéš. Åļîĝñ ûþþéŕ çáƀîñéţš; þŕéšéŕṽé ţáļļ áþþļîáñçéš áñð çûšţöɱ çöɱþáŕţɱéñţš. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.metricProfile\":[\"[Ṁéţŕîç · 600 ɱɱ ~~~]\"],\"node.cabinet.runPanel.moduleNumber\":[\"[Ṁöðûļé \",[\"number\"],\" ~~]\"],\"node.cabinet.runPanel.modules\":[\"[Ṁöðûļéš ~~~]\"],\"node.cabinet.runPanel.mounting\":[\"[Ṁöûñţîñĝ ~~~]\"],\"node.cabinet.runPanel.noEligibleModule\":[\"[Ñö éļîĝîƀļé ɱöðûļé ~~~~~]\"],\"node.cabinet.runPanel.none\":[\"[Ñöñé ~~]\"],\"node.cabinet.runPanel.overlay\":[\"[Öṽéŕļáý ~~~]\"],\"node.cabinet.runPanel.plinthHeight\":[\"[Þļîñţĥ ĥéîĝĥţ ~~~~]\"],\"node.cabinet.runPanel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.cabinet.runPanel.raisedArch\":[\"[Ŕáîšéð Åŕçĥ ~~~]\"],\"node.cabinet.runPanel.revealGap\":[\"[Ŕéṽéáļ ĝáþ ~~~]\"],\"node.cabinet.runPanel.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.cabinet.runPanel.seatingOverhang\":[\"[Šéáţîñĝ öṽéŕĥáñĝ ~~~~~]\"],\"node.cabinet.runPanel.shaker\":[\"[Šĥáķéŕ ~~]\"],\"node.cabinet.runPanel.sharedPlinthCountertop\":[\"[Šĥáŕéð Þļîñţĥ & Çöûñţéŕţöþ ~~~~~~~]\"],\"node.cabinet.runPanel.showCountertop\":[\"[Šĥöŵ çöûñţéŕţöþ ~~~~~]\"],\"node.cabinet.runPanel.showPlinth\":[\"[Šĥöŵ þļîñţĥ ~~~]\"],\"node.cabinet.runPanel.slab\":[\"[Šļáƀ ~~]\"],\"node.cabinet.runPanel.sourceModule\":[\"[Šöûŕçé ɱöðûļé ~~~~]\"],\"node.cabinet.runPanel.spacing\":[\"[Šþáçîñĝ ~~~]\"],\"node.cabinet.runPanel.standardDimensions\":[\"[Šţáñðáŕð ðîɱéñšîöñš ~~~~~~]\"],\"node.cabinet.runPanel.style\":[\"[Šţýļé ~~]\"],\"node.cabinet.runPanel.summaryCompartment\":[\"[\",[\"type\",\"select\",{\"shelf\":[\"Šĥéļƒ\"],\"drawer\":[\"Ðŕáŵéŕ\"],\"door\":[\"Ðööŕ\"],\"oven\":[\"Öṽéñ\"],\"microwave\":[\"Ṁîçŕöŵáṽé\"],\"dishwasher\":[\"Ðîšĥŵášĥéŕ\"],\"sink\":[\"Šîñķ\"],\"cooktop_gas\":[\"Ĝáš çööķţöþ\"],\"cooktop_induction\":[\"Îñðûçţîöñ çööķţöþ\"],\"pull_out_pantry\":[\"Þûļļ-öûţ þáñţŕý\"],\"fridge_single\":[\"Ƒŕîðĝé\"],\"fridge_double\":[\"Ðöûƀļé ƒŕîðĝé\"],\"fridge_top_freezer\":[\"Ţöþ-ƒŕééžéŕ ƒŕîðĝé\"],\"fridge_bottom_freezer\":[\"Ɓöţţöɱ-ƒŕééžéŕ ƒŕîðĝé\"],\"hood_pyramid\":[\"Þýŕáɱîð ĥööð\"],\"hood_curved_glass\":[\"Çûŕṽéð ĝļášš ĥööð\"],\"other\":[[\"raw\"]]}],\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.summaryCompartments\":[\"[\",[\"count\",\"plural\",{\"one\":[[\"number\"],\" çöɱþáŕţɱéñţ\"],\"other\":[[\"number\"],\" çöɱþáŕţɱéñţš\"]}],\" ~~~~~~~]\"],\"node.cabinet.runPanel.summaryEmpty\":[\"[Éɱþţý ~~]\"],\"node.cabinet.runPanel.summaryTall\":[\"[Ţáļļ çáƀîñéţ ~~~~]\"],\"node.cabinet.runPanel.top\":[\"[Ţöþ ~]\"],\"node.cabinet.runPanel.unableToFinish\":[\"[Ûñáƀļé ţö ƒîñîšĥ ţĥîš ķîţçĥéñ ŕûñ. ~~~~~~~~~]\"],\"node.cabinet.runPanel.usProfile\":[\"[ÛŠ · 24 îñ ~~]\"],\"node.cabinet.runPanel.useAsArraySource\":[\"[Ûšé \",[\"name\"],\" áš áŕŕáý šöûŕçé ~~~~~]\"],\"node.cabinet.runPanel.useThisModuleAsTheArray\":[\"[Ûšé ţĥîš ɱöðûļé áš ţĥé áŕŕáý šöûŕçé ~~~~~~~~~]\"],\"node.cabinet.runPanel.waterfallEnds\":[\"[Ŵáţéŕƒáļļ éñðš ~~~~]\"],\"node.cabinetModule.description\":[\"[Åñ éðîţáƀļé ɱöðûļé îñšîðé á ɱöðûļáŕ çáƀîñéţ ŕûñ. ~~~~~~~~~~~~]\"],\"node.cabinetModule.label\":[\"[Çáƀîñéţ Ṁöðûļé ~~~~]\"],\"node.ceiling.description\":[\"[Å þöļýĝöñ-ƀöûñðéð çéîļîñĝ šûŕƒáçé ţĥáţ ĥöšţš çéîļîñĝ-ɱöûñţéð îţéɱš. ~~~~~~~~~~~~~~~~~~]\"],\"node.ceiling.label\":[\"[Çéîļîñĝ ~~~]\"],\"node.ceiling.panel.addHole\":[\"[Åðð Ĥöļé ~~~]\"],\"node.ceiling.panel.area\":[\"[Åŕéá ~~]\"],\"node.ceiling.panel.auto\":[\"[Åûţö ~~]\"],\"node.ceiling.panel.ceiling\":[\"[Çéîļîñĝ ~~~]\"],\"node.ceiling.panel.customHeight\":[\"[Çûšţöɱ ĥéîĝĥţ ~~~~]\"],\"node.ceiling.panel.cutOpening\":[\"[Çûţ öþéñîñĝ ~~~]\"],\"node.ceiling.panel.done\":[\"[Ðöñé ~~]\"],\"node.ceiling.panel.followsLevel\":[\"[Ƒöļļöŵš ļéṽéļ ~~~~]\"],\"node.ceiling.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.ceiling.panel.high30m\":[\"[Ĥîĝĥ (3.0ɱ) ~~]\"],\"node.ceiling.panel.high90\":[\"[Ĥîĝĥ (9'0\\\") ~~]\"],\"node.ceiling.panel.holes\":[\"[Ĥöļéš ~~]\"],\"node.ceiling.panel.info\":[\"[Îñƒö ~~]\"],\"node.ceiling.panel.limitedByLevel\":[\"[Ļîɱîţéð ƀý ţĥé ļéṽéļ ţö \",[\"height\"],\" — ŕáîšé ţĥé ļéṽéļ ĥéîĝĥţ ƒöŕ á ţáļļéŕ çéîļîñĝ. ~~~~~~~~~~~~~~~~~]\"],\"node.ceiling.panel.low24m\":[\"[Ļöŵ (2.4ɱ) ~~]\"],\"node.ceiling.panel.low80\":[\"[Ļöŵ (8'0\\\") ~]\"],\"node.ceiling.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.ceiling.panel.noHoles\":[\"[Ñö ĥöļéš ~~~]\"],\"node.ceiling.panel.standard25m\":[\"[Šţáñðáŕð (2.5ɱ) ~~~]\"],\"node.ceiling.panel.standard86\":[\"[Šţáñðáŕð (8'6\\\") ~~~]\"],\"node.ceiling.panel.tallerThanLevel\":[\"[Ţáļļéŕ ţĥáñ ţĥîš ļéṽéļ (\",[\"available\"],\" áṽáîļáƀļé). Ŕáîšé ţĥé ļéṽéļ ĥéîĝĥţ ƒîŕšţ. ~~~~~~~~~~~~~~~~]\"],\"node.chimney.description\":[\"[Ṽéŕţîçáļ ɱášöñŕý šţáçķ öñ á ŕööƒ šéĝɱéñţ. ~~~~~~~~~~~]\"],\"node.chimney.label\":[\"[Çĥîɱñéý ~~~]\"],\"node.chimney.panel.aboveRidge\":[\"[Åƀöṽé Ŕîðĝé ~~~]\"],\"node.chimney.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.chimney.panel.back\":[\"[Ɓáçķ ~~]\"],\"node.chimney.panel.bands\":[\"[Ɓáñðš ~~]\"],\"node.chimney.panel.cap\":[\"[Çáþ ~]\"],\"node.chimney.panel.chimney\":[\"[Çĥîɱñéý ~~~]\"],\"node.chimney.panel.chimneyType\":[\"[Çĥîɱñéý Ţýþé ~~~~]\"],\"node.chimney.panel.corbeled\":[\"[Çöŕƀéļéð ~~~]\"],\"node.chimney.panel.cornerBevel\":[\"[Çöŕñéŕ Ɓéṽéļ ~~~~]\"],\"node.chimney.panel.count\":[\"[Çöûñţ ~~]\"],\"node.chimney.panel.cricket\":[\"[Çŕîçķéţ ~~~]\"],\"node.chimney.panel.cutoutOffset\":[\"[Çûţöûţ Öƒƒšéţ ~~~~]\"],\"node.chimney.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.chimney.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.chimney.panel.diameter\":[\"[Ðîáɱéţéŕ ~~~]\"],\"node.chimney.panel.double\":[\"[Ðöûƀļé ~~]\"],\"node.chimney.panel.extent\":[\"[Éẋţéñţ ~~]\"],\"node.chimney.panel.flat\":[\"[Ƒļáţ ~~]\"],\"node.chimney.panel.flues\":[\"[Ƒļûéš ~~]\"],\"node.chimney.panel.footprint\":[\"[Ƒööţþŕîñţ ~~~]\"],\"node.chimney.panel.front\":[\"[Ƒŕöñţ ~~]\"],\"node.chimney.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.chimney.panel.hollowDepth\":[\"[Ĥöļļöŵ Ðéþţĥ ~~~~]\"],\"node.chimney.panel.length\":[\"[Ļéñĝţĥ ~~]\"],\"node.chimney.panel.none\":[\"[Ñöñé ~~]\"],\"node.chimney.panel.offset\":[\"[Öƒƒšéţ ~~]\"],\"node.chimney.panel.overhang\":[\"[Öṽéŕĥáñĝ ~~~]\"],\"node.chimney.panel.panels\":[\"[Þáñéļš ~~]\"],\"node.chimney.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.chimney.panel.rectangular\":[\"[Ŕéçţáñĝûļáŕ ~~~~]\"],\"node.chimney.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.chimney.panel.round\":[\"[Ŕöûñð ~~]\"],\"node.chimney.panel.shoulder\":[\"[Šĥöûļðéŕ ~~~]\"],\"node.chimney.panel.sideMargin\":[\"[Šîðé Ṁáŕĝîñ ~~~]\"],\"node.chimney.panel.simple\":[\"[Šîɱþļé ~~]\"],\"node.chimney.panel.single\":[\"[Šîñĝļé ~~]\"],\"node.chimney.panel.sloped\":[\"[Šļöþéð ~~]\"],\"node.chimney.panel.spacing\":[\"[Šþáçîñĝ ~~~]\"],\"node.chimney.panel.square\":[\"[Šǫûáŕé ~~]\"],\"node.chimney.panel.stepped\":[\"[Šţéþþéð ~~~]\"],\"node.chimney.panel.style\":[\"[Šţýļé ~~]\"],\"node.chimney.panel.tapered\":[\"[Ţáþéŕéð ~~~]\"],\"node.chimney.panel.thickness\":[\"[Ţĥîçķñéšš ~~~]\"],\"node.chimney.panel.topOffset\":[\"[Ţöþ Öƒƒšéţ ~~~]\"],\"node.chimney.panel.wallThickness\":[\"[Ŵáļļ Ţĥîçķñéšš ~~~~]\"],\"node.chimney.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.chimney.preset.brick\":[\"[Ɓŕîçķ ~~]\"],\"node.chimney.preset.modern\":[\"[Ṁöðéŕñ ~~]\"],\"node.chimney.preset.round\":[\"[Ŕöûñð ~~]\"],\"node.column.description\":[\"[Å þáŕáɱéţŕîç çöļûɱñ ŵîţĥ çöñƒîĝûŕáƀļé çŕöšš-šéçţîöñ, ƀášé, áñð çáþîţáļ. ~~~~~~~~~~~~~~~~~~]\"],\"node.column.label\":[\"[Çöļûɱñ ~~]\"],\"node.column.panel.aFrame\":[\"[Å-Ƒŕáɱé ~~]\"],\"node.column.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.column.panel.applyPreset\":[\"[Åþþļý þŕéšéţ... ~~~~]\"],\"node.column.panel.applyProportion\":[\"[Åþþļý þŕöþöŕţîöñ... ~~~~~]\"],\"node.column.panel.bottomDepth\":[\"[Ɓöţţöɱ Ðéþţĥ ~~~~]\"],\"node.column.panel.bottomHeight\":[\"[Ɓöţţöɱ Ĥéîĝĥţ ~~~~]\"],\"node.column.panel.bottomSpread\":[\"[Ɓöţţöɱ Šþŕéáð ~~~~]\"],\"node.column.panel.bottomStepSpread\":[\"[Ɓöţţöɱ Šţéþ Šþŕéáð ~~~~~]\"],\"node.column.panel.bottomTiers\":[\"[Ɓöţţöɱ Ţîéŕš ~~~~]\"],\"node.column.panel.bottomWidth\":[\"[Ɓöţţöɱ Ŵîðţĥ ~~~~]\"],\"node.column.panel.boxFrame\":[\"[Ɓöẋ Ƒŕáɱé ~~~]\"],\"node.column.panel.braceDepth\":[\"[Ɓŕáçé Ðéþţĥ ~~~]\"],\"node.column.panel.braceWidth\":[\"[Ɓŕáçé Ŵîðţĥ ~~~]\"],\"node.column.panel.bulge\":[\"[Ɓûļĝé ~~]\"],\"node.column.panel.bulged\":[\"[Ɓûļĝéð ~~]\"],\"node.column.panel.column\":[\"[Çöļûɱñ ~~]\"],\"node.column.panel.connectorPlates\":[\"[Çöññéçţöŕ Þļáţéš ~~~~~]\"],\"node.column.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.column.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.column.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.column.panel.edgeSoftness\":[\"[Éðĝé Šöƒţñéšš ~~~~]\"],\"node.column.panel.endWidth\":[\"[Éñð Ŵîðţĥ ~~~]\"],\"node.column.panel.ends\":[\"[Éñðš ~~]\"],\"node.column.panel.forkSpread\":[\"[Ƒöŕķ Šþŕéáð ~~~]\"],\"node.column.panel.heavy\":[\"[Ĥéáṽý ~~]\"],\"node.column.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.column.panel.heightAndFootprintAreControlledBy\":[\"[Ĥéîĝĥţ áñð ƒööţþŕîñţ áŕé çöñţŕöļļéð ƀý ţĥé ļéáñ-ţö éẋţéñšîöñ. Ŕöţáţé öŕ çĥáñĝé ţĥé šûþþöŕţ šţýļé ĥéŕé; ŕéšîžé ƒŕöɱ ţĥé þáŕéñţ ļéáñ-ţö. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.column.panel.hourglass\":[\"[Ĥöûŕĝļášš ~~~]\"],\"node.column.panel.kBrace\":[\"[Ķ Ɓŕáçé ~~]\"],\"node.column.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.column.panel.neckWidth\":[\"[Ñéçķ Ŵîðţĥ ~~~]\"],\"node.column.panel.noBottom\":[\"[Ñö Ɓöţţöɱ ~~~]\"],\"node.column.panel.noTop\":[\"[Ñö Ţöþ ~~]\"],\"node.column.panel.plinthThickness\":[\"[Þļîñţĥ Ţĥîçķñéšš ~~~~~]\"],\"node.column.panel.portalFrame\":[\"[Þöŕţáļ Ƒŕáɱé ~~~~]\"],\"node.column.panel.preset\":[\"[Þŕéšéţ ~~]\"],\"node.column.panel.rectangular\":[\"[Ŕéçţáñĝûļáŕ ~~~~]\"],\"node.column.panel.ringPairs\":[\"[Ŕîñĝ Þáîŕš ~~~]\"],\"node.column.panel.ringSpread\":[\"[Ŕîñĝ Šþŕéáð ~~~]\"],\"node.column.panel.ringThickness\":[\"[Ŕîñĝ Ţĥîçķñéšš ~~~~]\"],\"node.column.panel.round\":[\"[Ŕöûñð ~~]\"],\"node.column.panel.roundBandWidth\":[\"[Ŕöûñð Ɓáñð Ŵîðţĥ ~~~~~]\"],\"node.column.panel.roundedBottom\":[\"[Ŕöûñðéð Ɓöţţöɱ ~~~~]\"],\"node.column.panel.roundedTop\":[\"[Ŕöûñðéð Ţöþ ~~~]\"],\"node.column.panel.segmentTwist\":[\"[Šéĝɱéñţ Ţŵîšţ ~~~~]\"],\"node.column.panel.shaft\":[\"[Šĥáƒţ ~~]\"],\"node.column.panel.shaftCornerRadius\":[\"[Šĥáƒţ Çöŕñéŕ Ŕáðîûš ~~~~~~]\"],\"node.column.panel.shaftWidth\":[\"[Šĥáƒţ Ŵîðţĥ ~~~]\"],\"node.column.panel.shape\":[\"[Šĥáþé ~~]\"],\"node.column.panel.shortStout\":[\"[Šĥöŕţ / Šţöûţ ~~~]\"],\"node.column.panel.simpleBlockBottom\":[\"[Šîɱþļé Ɓļöçķ Ɓöţţöɱ ~~~~~~]\"],\"node.column.panel.simpleTop\":[\"[Šîɱþļé Ţöþ ~~~]\"],\"node.column.panel.singleStrut\":[\"[Šîñĝļé Šţŕûţ ~~~~]\"],\"node.column.panel.slender\":[\"[Šļéñðéŕ ~~~]\"],\"node.column.panel.square\":[\"[Šǫûáŕé ~~]\"],\"node.column.panel.squarePlinthBottom\":[\"[Šǫûáŕé Þļîñţĥ Ɓöţţöɱ ~~~~~~]\"],\"node.column.panel.standard\":[\"[Šţáñðáŕð ~~~]\"],\"node.column.panel.steppedBottom\":[\"[Šţéþþéð Ɓöţţöɱ ~~~~]\"],\"node.column.panel.steppedTop\":[\"[Šţéþþéð Ţöþ ~~~]\"],\"node.column.panel.straight\":[\"[Šţŕáîĝĥţ ~~~]\"],\"node.column.panel.taper\":[\"[Ţáþéŕ ~~]\"],\"node.column.panel.tapered\":[\"[Ţáþéŕéð ~~~]\"],\"node.column.panel.topDepth\":[\"[Ţöþ Ðéþţĥ ~~~]\"],\"node.column.panel.topHeight\":[\"[Ţöþ Ĥéîĝĥţ ~~~]\"],\"node.column.panel.topSpread\":[\"[Ţöþ Šþŕéáð ~~~]\"],\"node.column.panel.topStepSpread\":[\"[Ţöþ Šţéþ Šþŕéáð ~~~~]\"],\"node.column.panel.topTiers\":[\"[Ţöþ Ţîéŕš ~~~]\"],\"node.column.panel.topWidth\":[\"[Ţöþ Ŵîðţĥ ~~~]\"],\"node.column.panel.transform\":[\"[Ţŕáñšƒöŕɱ ~~~]\"],\"node.column.panel.trestle\":[\"[Ţŕéšţļé ~~~]\"],\"node.column.panel.tripod\":[\"[Ţŕîþöð ~~]\"],\"node.column.panel.twistSegments\":[\"[Ţŵîšţ Šéĝɱéñţš ~~~~]\"],\"node.column.panel.vSupport\":[\"[Ṽ Šûþþöŕţ ~~~]\"],\"node.column.panel.vertical\":[\"[Ṽéŕţîçáļ ~~~]\"],\"node.column.panel.waist\":[\"[Ŵáîšţ ~~]\"],\"node.column.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.column.panel.xBrace\":[\"[Ẋ Ɓŕáçé ~~]\"],\"node.column.panel.ySupport\":[\"[Ý Šûþþöŕţ ~~~]\"],\"node.column.panel.yaw\":[\"[Ýáŵ ~]\"],\"node.column.preset.aFrameSupport\":[\"[Å-Ƒŕáɱé Šûþþöŕţ ~~~~]\"],\"node.column.preset.basicPillar\":[\"[Šţŕáîĝĥţ Ŕöûñð ~~~~]\"],\"node.column.preset.boxFrameSupport\":[\"[Ɓöẋ Ƒŕáɱé ~~~]\"],\"node.column.preset.bulgedPillar\":[\"[Šöƒţ Ɓûļĝéð ~~~]\"],\"node.column.preset.hourglassPillar\":[\"[Ĥöûŕĝļášš ~~~]\"],\"node.column.preset.kBraceSupport\":[\"[Ķ Ɓŕáçé ~~]\"],\"node.column.preset.portalFrameSupport\":[\"[Þöŕţáļ Ƒŕáɱé ~~~~]\"],\"node.column.preset.singleStrutSupport\":[\"[Šîñĝļé Šţŕûţ ~~~~]\"],\"node.column.preset.squarePillar\":[\"[Šǫûáŕé Ɓļöçķ ~~~~]\"],\"node.column.preset.taperedPillar\":[\"[Ţáþéŕéð Ŕöûñð ~~~~]\"],\"node.column.preset.trestleSupport\":[\"[Ţŕéšţļé Ƒŕáɱé ~~~~]\"],\"node.column.preset.tripodSupport\":[\"[Ţŕîþöð Šûþþöŕţ ~~~~]\"],\"node.column.preset.vFrameSupport\":[\"[Ṽ Šûþþöŕţ ~~~]\"],\"node.column.preset.xBraceSupport\":[\"[Ẋ Ɓŕáçé ~~]\"],\"node.column.preset.yFrameSupport\":[\"[Ý Šûþþöŕţ ~~~]\"],\"node.constructionDimension.description\":[\"[Åššöçîáţîṽé ļîñéáŕ, çûŕṽéð, çîŕçûļáŕ, áñĝûļáŕ, öŕ çööŕðîñáţé þļáñ ðîɱéñšîöñ. ~~~~~~~~~~~~~~~~~~~]\"],\"node.constructionDimension.label\":[\"[Çöñšţŕûçţîöñ Ðîɱéñšîöñ ~~~~~~~]\"],\"node.cornerRadius.bottomLeft\":[\"[Ɓöţţöɱ Ļéƒţ ~~~]\"],\"node.cornerRadius.bottomRight\":[\"[Ɓöţţöɱ Ŕîĝĥţ ~~~~]\"],\"node.cornerRadius.topLeft\":[\"[Ţöþ Ļéƒţ ~~~]\"],\"node.cornerRadius.topRight\":[\"[Ţöþ Ŕîĝĥţ ~~~]\"],\"node.cupola.description\":[\"[Ļöûṽéŕéð ŕööƒ ļáñţéŕñ ŵîţĥ á ðöɱé öŕ þýŕáɱîð çáþ áñð öþţîöñáļ ƒîñîáļ. ~~~~~~~~~~~~~~~~~~]\"],\"node.cupola.label\":[\"[Çûþöļá ~~]\"],\"node.cupola.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.cupola.panel.cupola\":[\"[Çûþöļá ~~]\"],\"node.cupola.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.cupola.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.cupola.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.cupola.panel.dome\":[\"[Ðöɱé ~~]\"],\"node.cupola.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.cupola.panel.finial\":[\"[Ƒîñîáļ ~~]\"],\"node.cupola.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.cupola.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.cupola.panel.noFinial\":[\"[Ñö Ƒîñîáļ ~~~]\"],\"node.cupola.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.cupola.panel.pyramid\":[\"[Þýŕáɱîð ~~~]\"],\"node.cupola.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.cupola.panel.style\":[\"[Šţýļé ~~]\"],\"node.cupola.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.cutout.autoElevator\":[\"[Åûţö éļéṽáţöŕ çûţöûţ ~~~~~~]\"],\"node.cutout.autoStair\":[\"[Åûţö šţáîŕ çûţöûţ ~~~~~]\"],\"node.cutout.opening\":[\"[Öþéñîñĝ ~~~]\"],\"node.cutout.room\":[\"[Ŕööɱ çûţöûţ ~~~]\"],\"node.door.description\":[\"[Å ðööŕ çûţ îñţö á ŵáļļ. Åñîɱáţéð öþéñ/çļöšé šţáţé. ~~~~~~~~~~~~]\"],\"node.door.label\":[\"[Ðööŕ ~~]\"],\"node.door.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.door.panel.addSegment\":[\"[+ Åðð Šéĝɱéñţ ~~~]\"],\"node.door.panel.all\":[\"[Åļļ ~]\"],\"node.door.panel.arch\":[\"[Åŕçĥ ~~]\"],\"node.door.panel.archHeight\":[\"[Åŕçĥ Ĥéîĝĥţ ~~~]\"],\"node.door.panel.auto\":[\"[Åûţö ~~]\"],\"node.door.panel.autoFollowsTheWall\":[\"[Åûţö ƒöļļöŵš ţĥé ŵáļļ ~~~~~~]\"],\"node.door.panel.barHeight\":[\"[Ɓáŕ Ĥéîĝĥţ ~~~]\"],\"node.door.panel.columns\":[\"[Çöļûɱñš ~~~]\"],\"node.door.panel.contentPadding\":[\"[Çöñţéñţ Þáððîñĝ ~~~~~]\"],\"node.door.panel.cornerRadius\":[\"[Çöŕñéŕ Ŕáðîûš ~~~~]\"],\"node.door.panel.customTheSegmentsMatchNoStyle\":[\"[Çûšţöɱ: ţĥé šéĝɱéñţš ɱáţçĥ ñö šţýļé. ~~~~~~~~~]\"],\"node.door.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.door.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.door.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.door.panel.direction\":[\"[Ðîŕéçţîöñ ~~~]\"],\"node.door.panel.divider\":[\"[Ðîṽîðéŕ ~~~]\"],\"node.door.panel.door\":[\"[Ðööŕ ~~]\"],\"node.door.panel.doorCloser\":[\"[Ðööŕ Çļöšéŕ ~~~]\"],\"node.door.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.door.panel.empty\":[\"[Éɱþţý ~~]\"],\"node.door.panel.enableHandle\":[\"[Éñáƀļé Ĥáñðļé ~~~~]\"],\"node.door.panel.enableThreshold\":[\"[Éñáƀļé Ţĥŕéšĥöļð ~~~~~]\"],\"node.door.panel.flipSide\":[\"[Ƒļîþ Šîðé ~~~]\"],\"node.door.panel.fold\":[\"[Ƒöļð ~~]\"],\"node.door.panel.frame\":[\"[Ƒŕáɱé ~~]\"],\"node.door.panel.frameDepthAuto\":[\"[Ðéþţĥ (áûţö) ~~~]\"],\"node.door.panel.garage\":[\"[Ĝáŕáĝé ~~]\"],\"node.door.panel.glass\":[\"[Ĝļášš ~~]\"],\"node.door.panel.handle\":[\"[Ĥáñðļé ~~]\"],\"node.door.panel.handleSide\":[\"[Ĥáñðļé Šîðé ~~~]\"],\"node.door.panel.hardware\":[\"[Ĥáŕðŵáŕé ~~~]\"],\"node.door.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.door.panel.hingesSide\":[\"[Ĥîñĝéš Šîðé ~~~]\"],\"node.door.panel.horizontal\":[\"[Ĥöŕîžöñţáļ ~~~]\"],\"node.door.panel.individual\":[\"[Îñðîṽîðûáļ ~~~]\"],\"node.door.panel.inset\":[\"[Îñšéţ ~~]\"],\"node.door.panel.inward\":[\"[Îñŵáŕð ~~]\"],\"node.door.panel.left\":[\"[Ļéƒţ ~~]\"],\"node.door.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.door.panel.open\":[\"[Öþéñ ~~]\"],\"node.door.panel.opening\":[\"[Öþéñîñĝ ~~~]\"],\"node.door.panel.openingShape\":[\"[Öþéñîñĝ Šĥáþé ~~~~]\"],\"node.door.panel.outward\":[\"[Öûţŵáŕð ~~~]\"],\"node.door.panel.panel\":[\"[Þáñéļ ~~]\"],\"node.door.panel.panels\":[\"[Þáñéļš ~~]\"],\"node.door.panel.panicBar\":[\"[Þáñîç Ɓáŕ ~~~]\"],\"node.door.panel.pocket\":[\"[Þöçķéţ ~~]\"],\"node.door.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.door.panel.rail\":[\"[Ŕáîļ ~~]\"],\"node.door.panel.rect\":[\"[Ŕéçţ ~~]\"],\"node.door.panel.remove\":[\"[- Ŕéɱöṽé ~~]\"],\"node.door.panel.revealRadius\":[\"[Ŕéṽéáļ Ŕáðîûš ~~~~]\"],\"node.door.panel.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.door.panel.rounded\":[\"[Ŕöûñðéð ~~~]\"],\"node.door.panel.segments\":[\"[Šéĝɱéñţš ~~~]\"],\"node.door.panel.sizeIsLimitedToTheWall\":[\"[Šîžé îš ļîɱîţéð ţö ţĥé ŵáļļ, îñçļûðîñĝ çļéáŕáñçé ƒöŕ ţĥé öþéñîñĝ ƒŕáɱé. ~~~~~~~~~~~~~~~~~~]\"],\"node.door.panel.slide\":[\"[Šļîðé ~~]\"],\"node.door.panel.style\":[\"[Šţýļé ~~]\"],\"node.door.panel.swing\":[\"[Šŵîñĝ ~~]\"],\"node.door.panel.thickness\":[\"[Ţĥîçķñéšš ~~~]\"],\"node.door.panel.threshold\":[\"[Ţĥŕéšĥöļð ~~~]\"],\"node.door.panel.topShape\":[\"[Ţöþ Šĥáþé ~~~]\"],\"node.door.panel.type\":[\"[Ţýþé ~~]\"],\"node.door.panel.vertical\":[\"[Ṽéŕţîçáļ ~~~]\"],\"node.door.panel.wall\":[\"[ŵáļļ ~~]\"],\"node.door.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.door.style.barn\":[\"[Ɓáŕñ ~~]\"],\"node.door.style.craftsman\":[\"[Çŕáƒţšɱáñ ~~~]\"],\"node.door.style.french\":[\"[Ƒŕéñçĥ ~~]\"],\"node.door.style.glass\":[\"[Ĝļášš ~~]\"],\"node.door.style.halfLouvered\":[\"[Ĥáļƒ-ļöûṽéŕéð ~~~~]\"],\"node.door.style.modern\":[\"[Ṁöðéŕñ ~~]\"],\"node.door.style.panel\":[\"[Þáñéļ ~~]\"],\"node.door.style.paneledGlass\":[\"[Þáñéļéð ĝļášš ~~~~]\"],\"node.door.style.shaker\":[\"[Šĥáķéŕ ~~]\"],\"node.door.style.sixPanel\":[\"[Šîẋ-þáñéļ ~~~]\"],\"node.door.type.barn\":[\"[Ɓáŕñ ~~]\"],\"node.door.type.double\":[\"[Ðöûƀļé ~~]\"],\"node.door.type.folding\":[\"[Ƒöļðîñĝ ~~~]\"],\"node.door.type.french\":[\"[Ƒŕéñçĥ ~~]\"],\"node.door.type.garageRollup\":[\"[Ŕöļļ-ûþ ~~]\"],\"node.door.type.garageSectional\":[\"[Šéçţîöñáļ ~~~]\"],\"node.door.type.garageTiltup\":[\"[Ţîļţ-ûþ ~~]\"],\"node.door.type.hinged\":[\"[Ĥîñĝéð ~~]\"],\"node.door.type.pocket\":[\"[Þöçķéţ ~~]\"],\"node.door.type.sliding\":[\"[Šļîðîñĝ ~~~]\"],\"node.dormer.description\":[\"[Ĥöûšé-šĥáþéð þŕöţŕûšîöñ öñ á ŕööƒ šéĝɱéñţ. ~~~~~~~~~~~]\"],\"node.dormer.label\":[\"[Ðöŕɱéŕ ~~]\"],\"node.dormer.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.dormer.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.dormer.panel.dormer\":[\"[Ðöŕɱéŕ ~~]\"],\"node.dormer.panel.dutch\":[\"[Ðûţçĥ ~~]\"],\"node.dormer.panel.flat\":[\"[Ƒļáţ ~~]\"],\"node.dormer.panel.gable\":[\"[Ĝáƀļé ~~]\"],\"node.dormer.panel.gambrel\":[\"[Ĝáɱƀŕéļ ~~~]\"],\"node.dormer.panel.hip\":[\"[Ĥîþ ~]\"],\"node.dormer.panel.mansard\":[\"[Ṁáñšáŕð ~~~]\"],\"node.dormer.panel.pitchDirection\":[\"[Þîţçĥ Ðîŕéçţîöñ ~~~~~]\"],\"node.dormer.panel.pitchRise\":[\"[Þîţçĥ Ŕîšé ~~~]\"],\"node.dormer.panel.riseBack\":[\"[Ŕîšé Ɓáçķ ~~~]\"],\"node.dormer.panel.riseFront\":[\"[Ŕîšé Ƒŕöñţ ~~~]\"],\"node.dormer.panel.roofHeight\":[\"[Ŕööƒ Ĥéîĝĥţ ~~~]\"],\"node.dormer.panel.roofType\":[\"[Ŕööƒ Ţýþé ~~~]\"],\"node.dormer.panel.section\":[\"[Šéçţîöñ ~~~]\"],\"node.dormer.panel.shed\":[\"[Šĥéð ~~]\"],\"node.dormer.panel.wallHeight\":[\"[Ŵáļļ Ĥéîĝĥţ ~~~]\"],\"node.dormer.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.dormer.panel.windows\":[\"[Ŵîñðöŵš ~~~]\"],\"node.dormer.panelActionsSection.actions\":[\"[Åçţîöñš ~~~]\"],\"node.dormer.panelActionsSection.delete\":[\"[Ðéļéţé ~~]\"],\"node.dormer.panelActionsSection.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.dormer.panelActionsSection.move\":[\"[Ṁöṽé ~~]\"],\"node.dormer.panelPositionSection.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.dormer.panelPositionSection.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.dormer.panelWindowsSection.addWindow\":[\"[Åðð Ŵîñðöŵ ~~~]\"],\"node.dormer.panelWindowsSection.editNamed\":[\"[Éðîţ \",[\"name\"],\" ~~]\"],\"node.dormer.panelWindowsSection.editWindow\":[\"[Éðîţ ŵîñðöŵ ~~~]\"],\"node.dormer.panelWindowsSection.increaseTheDormerWidthToAdd\":[\"[Îñçŕéášé ţĥé ðöŕɱéŕ ŵîðţĥ ţö áðð áñöţĥéŕ ŵîñðöŵ. ~~~~~~~~~~~~]\"],\"node.dormer.panelWindowsSection.move\":[\"[Ṁöṽé ~~]\"],\"node.dormer.panelWindowsSection.moveNamed\":[\"[Ṁöṽé \",[\"name\"],\" ~~]\"],\"node.dormer.panelWindowsSection.moveWindow\":[\"[Ṁöṽé ŵîñðöŵ ~~~]\"],\"node.dormer.panelWindowsSection.noWindows\":[\"[Ñö ŵîñðöŵš ~~~]\"],\"node.dormer.panelWindowsSection.windowNumber\":[\"[Ŵîñðöŵ \",[\"number\"],\" ~~]\"],\"node.dormer.panelWindowsSection.windowSummary\":[\"[\",[\"face\",\"select\",{\"back\":[\"Ɓáçķ\"],\"left\":[\"Ļéƒţ\"],\"right\":[\"Ŕîĝĥţ\"],\"other\":[\"Ƒŕöñţ\"]}],\" · \",[\"width\"],\" × \",[\"height\"],\" ɱ ~~~~~~]\"],\"node.dormer.panelWindowsSection.windowsLength\":[\"[Ŵîñðöŵš (\",[\"length\"],\") ~~~]\"],\"node.downspout.description\":[\"[Ṽéŕţîçáļ ðŕöþ þîþé ƒŕöɱ á ĝûţţéŕ öûţļéţ ţö ţĥé ĝŕöûñð. ~~~~~~~~~~~~~~]\"],\"node.downspout.inspectorEditors.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.downspout.label\":[\"[Ðöŵñšþöûţ ~~~]\"],\"node.ductFitting.description\":[\"[Éļƀöŵ, ţéé, ŕéðûçéŕ, öŕ šǫûáŕé-ţö-ŕöûñð ţŕáñšîţîöñ çöññéçţîñĝ ðûçţ ŕûñš. ~~~~~~~~~~~~~~~~~~]\"],\"node.ductFitting.inspectorEditors.swapWH\":[\"[Šŵáþ Ŵ/Ĥ ~~]\"],\"node.ductFitting.inspectorEditors.swapWidthAndHeight\":[\"[Šŵáþ ŵîðţĥ áñð ĥéîĝĥţ ~~~~~~]\"],\"node.ductFitting.label\":[\"[Ðûçţ Ƒîţţîñĝ ~~~~]\"],\"node.ductFitting.tool.axis\":[\"[Åẋîš ~~]\"],\"node.ductFitting.tool.axis2\":[\"[⌥ áẋîš ~~]\"],\"node.ductFitting.tool.hoverADuctFaceThatFits\":[\"[Ĥöṽéŕ á ðûçţ ƒáçé ţĥáţ ƒîţš ţĥé ðööŕ ~~~~~~~~~]\"],\"node.ductFitting.tool.placeAccessDoor\":[\"[Þļáçé áççéšš ðööŕ ~~~~~]\"],\"node.ductFitting.tool.rTRotate\":[\"[Ŕ/Ţ ŕöţáţé ~~~]\"],\"node.ductSegment.description\":[\"[ĤṼÅÇ ðûçţ ŕûñ — þöļýļîñé öƒ ŕöûñð, ŕéçţ, öŕ ƒļáţ-öṽáļ šéçţîöñš. ~~~~~~~~~~~~~~~]\"],\"node.ductSegment.label\":[\"[Ðûçţ ~~]\"],\"node.ductTerminal.description\":[\"[Ðûçţ ţéŕɱîñáļ — šûþþļý ŕéĝîšţéŕ, çéîļîñĝ ðûšéŕ, öŕ ŕéţûŕñ ĝŕîļļé. Ðûçţ ŕûñš éñð áţ îţš çöļļáŕ. ~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.ductTerminal.label\":[\"[Ŕéĝîšţéŕ ~~~]\"],\"node.ductTerminal.tool.mSurface\":[\"[Ṁ šûŕƒáçé ~~~]\"],\"node.ductTerminal.tool.mount\":[\"[\",[\"mount\",\"select\",{\"floor\":[\"Ṁöûñţ Ƒļööŕ\"],\"ceiling\":[\"Ṁöûñţ Çéîļîñĝ\"],\"wall\":[\"Ṁöûñţ Ŵáļļ\"],\"other\":[\"Ṁöûñţ \",[\"label\"]]}],\" ~~~~~~~~~~~]\"],\"node.ductTerminal.tool.rTRotate\":[\"[Ŕ/Ţ ŕöţáţé ~~~]\"],\"node.ductTerminal.tool.snappedToDuct\":[\"[Šñáþþéð ţö ðûçţ ~~~~]\"],\"node.elevator.description\":[\"[Å ɱûļţî-ļéṽéļ éļéṽáţöŕ šĥáƒţ ŵîţĥ çöñƒîĝûŕáƀļé öþéñîñĝš þéŕ ļéṽéļ. ~~~~~~~~~~~~~~~~~]\"],\"node.elevator.label\":[\"[Éļéṽáţöŕ ~~~]\"],\"node.elevator.panel.access\":[\"[Åççéšš ~~]\"],\"node.elevator.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.elevator.panel.cab\":[\"[Çáƀ ~]\"],\"node.elevator.panel.cabHeight\":[\"[Çáƀ Ĥéîĝĥţ ~~~]\"],\"node.elevator.panel.centerOpening\":[\"[Çéñţéŕ öþéñîñĝ ~~~~]\"],\"node.elevator.panel.defaultFloor\":[\"[Ðéƒáûļţ Ƒļööŕ ~~~~]\"],\"node.elevator.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.elevator.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.elevator.panel.destination\":[\"[Ðéšţîñáţîöñ ~~~~]\"],\"node.elevator.panel.disabled\":[\"[Ðîšáƀļéð ~~~]\"],\"node.elevator.panel.doorHeight\":[\"[Ðööŕ Ĥéîĝĥţ ~~~]\"],\"node.elevator.panel.doorTime\":[\"[Ðööŕ Ţîɱé ~~~]\"],\"node.elevator.panel.doorType\":[\"[Ðööŕ Ţýþé ~~~]\"],\"node.elevator.panel.doorWidth\":[\"[Ðööŕ Ŵîðţĥ ~~~]\"],\"node.elevator.panel.doors\":[\"[Ðööŕš ~~]\"],\"node.elevator.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.elevator.panel.dwell\":[\"[Ðŵéļļ ~~]\"],\"node.elevator.panel.elevator\":[\"[Éļéṽáţöŕ ~~~]\"],\"node.elevator.panel.from\":[\"[Ƒŕöɱ ~~]\"],\"node.elevator.panel.glass\":[\"[Ĝļášš ~~]\"],\"node.elevator.panel.glassFrame\":[\"[Ĝļášš ƒŕáɱé ~~~]\"],\"node.elevator.panel.motion\":[\"[Ṁöţîöñ ~~]\"],\"node.elevator.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.elevator.panel.openingStyle\":[\"[Öþéñîñĝ Šţýļé ~~~~]\"],\"node.elevator.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.elevator.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.elevator.panel.segmentedPanel\":[\"[Šéĝɱéñţéð þáñéļ ~~~~~]\"],\"node.elevator.panel.service\":[\"[Šéŕṽîçé ~~~]\"],\"node.elevator.panel.shaft\":[\"[Šĥáƒţ ~~]\"],\"node.elevator.panel.shaftDepth\":[\"[Šĥáƒţ Ðéþţĥ ~~~]\"],\"node.elevator.panel.shaftStyle\":[\"[Šĥáƒţ Šţýļé ~~~]\"],\"node.elevator.panel.shaftWidth\":[\"[Šĥáƒţ Ŵîðţĥ ~~~]\"],\"node.elevator.panel.singleLeft\":[\"[Šîñĝļé ļéƒţ ~~~]\"],\"node.elevator.panel.singleRight\":[\"[Šîñĝļé ŕîĝĥţ ~~~~]\"],\"node.elevator.panel.solid\":[\"[Šöļîð ~~]\"],\"node.elevator.panel.solidPanel\":[\"[Šöļîð þáñéļ ~~~]\"],\"node.elevator.panel.speed\":[\"[Šþééð ~~]\"],\"node.elevator.panel.stopStoporder\":[\"[Šţöþ \",[\"stopOrder\"],\" ~~]\"],\"node.elevator.panel.to\":[\"[Ţö ~]\"],\"node.elevator.panel.wallThickness\":[\"[Ŵáļļ Ţĥîçķñéšš ~~~~]\"],\"node.elevator.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.elevator.panel.yaw\":[\"[Ýáŵ ~]\"],\"node.eyebrowVent.description\":[\"[Ļöŵ çûŕṽéð ļéñš-šĥáþéð ŕööƒ ṽéñţ ŵîţĥ á ļöûṽéŕéð ƒŕöñţ. ~~~~~~~~~~~~~~]\"],\"node.eyebrowVent.label\":[\"[Éýéƀŕöŵ Ṽéñţ ~~~~]\"],\"node.eyebrowVent.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.eyebrowVent.panel.backHeight\":[\"[Ɓáçķ ĥéîĝĥţ ~~~]\"],\"node.eyebrowVent.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.eyebrowVent.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.eyebrowVent.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.eyebrowVent.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.eyebrowVent.panel.eyebrowVent\":[\"[Éýéƀŕöŵ Ṽéñţ ~~~~]\"],\"node.eyebrowVent.panel.halfRound\":[\"[Ĥáļƒ-ŕöûñð ~~~]\"],\"node.eyebrowVent.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.eyebrowVent.panel.louvers\":[\"[Ļöûṽéŕš ~~~]\"],\"node.eyebrowVent.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.eyebrowVent.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.eyebrowVent.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.eyebrowVent.panel.scoop\":[\"[Šçööþ ~~]\"],\"node.eyebrowVent.panel.slantBox\":[\"[Šļáñţ-ƀöẋ ~~~]\"],\"node.eyebrowVent.panel.style\":[\"[Šţýļé ~~]\"],\"node.eyebrowVent.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.fence.description\":[\"[Å šţŕáîĝĥţ öŕ çûŕṽéð ƒéñçé šéĝɱéñţ ŵîţĥ çöñƒîĝûŕáƀļé þöšţš áñð îñƒîļļ. ~~~~~~~~~~~~~~~~~~]\"],\"node.fence.inspectorEditors.addPointAfter\":[\"[Åðð þöîñţ áƒţéŕ ~~~~]\"],\"node.fence.inspectorEditors.chooseASlabOrShapedSurface\":[\"[Çĥööšé á šļáƀ öŕ šĥáþéð šûŕƒáçé öñ ţĥîš ļéṽéļ. ~~~~~~~~~~~~]\"],\"node.fence.inspectorEditors.chooseASurface\":[\"[Çĥööšé á šûŕƒáçé ~~~~~]\"],\"node.fence.inspectorEditors.corner\":[\"[Çöŕñéŕ ~~]\"],\"node.fence.inspectorEditors.curve\":[\"[Çûŕṽé ~~]\"],\"node.fence.inspectorEditors.curved\":[\"[Çûŕṽéð ~~]\"],\"node.fence.inspectorEditors.distributionInfo\":[\"[\",[\"style\",\"select\",{\"picket\":[\"Ðîšţŕîƀûţîöñ çöñţŕöļš þîçķéţš îñ éáçĥ ƀáý ƀéţŵééñ þöšţš.\"],\"horizontal\":[\"Ðîšţŕîƀûţîöñ çöñţŕöļš þöšţš áļöñĝ ţĥé ƒûļļ ƒéñçé.\"],\"other\":[\"Ðîšţŕîƀûţîöñ çöñţŕöļš îñƒîļļ þîéçéš ƀéţŵééñ ţĥé ţŵö éñð þöšţš.\"]}],\" Šþáçîñĝ îš ɱéášûŕéð ƀéţŵééñ çéñţéŕš. Ţĥé áṽáîļáƀļé ŵîðţĥ ļîɱîţš ţĥé çöûñţ šö þîéçéš ðö ñöţ öṽéŕļáþ. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.fence.inspectorEditors.editPath\":[\"[Éðîţ þáţĥ ~~~]\"],\"node.fence.inspectorEditors.extendPath\":[\"[Éẋţéñð þáţĥ ~~~]\"],\"node.fence.inspectorEditors.followHighestSurface\":[\"[Ƒöļļöŵ ĥîĝĥéšţ šûŕƒáçé ~~~~~~]\"],\"node.fence.inspectorEditors.followSelectedSurface\":[\"[Ƒöļļöŵ šéļéçţéð šûŕƒáçé ~~~~~~~]\"],\"node.fence.inspectorEditors.holdStartingHeight\":[\"[Ĥöļð šţáŕţîñĝ ĥéîĝĥţ ~~~~~~]\"],\"node.fence.inspectorEditors.join\":[\"[Ĵöîñ ~~]\"],\"node.fence.inspectorEditors.length\":[\"[Ļéñĝţĥ ~~]\"],\"node.fence.inspectorEditors.pathSummary\":[\"[\",[\"count\",\"plural\",{\"one\":[[\"number\"],\" þöîñţ\"],\"other\":[[\"number\"],\" þöîñţš\"]}],\" · \",[\"length\"],\" ɱ ~~~~]\"],\"node.fence.inspectorEditors.picketRailProjection\":[\"[Þîçķéţ ŕáîļ þŕöĵéçţîöñ ~~~~~~]\"],\"node.fence.inspectorEditors.point\":[\"[Þöîñţ ~~]\"],\"node.fence.inspectorEditors.removePoint\":[\"[Ŕéɱöṽé þöîñţ ~~~~]\"],\"node.fence.inspectorEditors.setEachSpanToStraightOr\":[\"[Šéţ éáçĥ šþáñ ţö šţŕáîĝĥţ öŕ çûŕṽéð, ţĥéñ ðŕáĝ îţš þöîñţš áñð çûŕṽé ĥáñðļéš îñ éîţĥéŕ ṽîéŵ. ~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.fence.inspectorEditors.smooth\":[\"[Šɱööţĥ ~~]\"],\"node.fence.inspectorEditors.spanToPointNumber\":[\"[Šþáñ ţö þöîñţ \",[\"number\"],\" ~~~~]\"],\"node.fence.inspectorEditors.straight\":[\"[Šţŕáîĝĥţ ~~~]\"],\"node.fence.inspectorEditors.surface\":[\"[Šûŕƒáçé ~~~]\"],\"node.fence.inspectorEditors.surfaceBehavior\":[\"[Šûŕƒáçé ƀéĥáṽîöŕ ~~~~~]\"],\"node.fence.label\":[\"[Ƒéñçé ~~]\"],\"node.fence.moveEndpointTool.detachEndpoint\":[\"[Ðéţáçĥ éñðþöîñţ ~~~~~]\"],\"node.fence.moveEndpointTool.dragEndpoint\":[\"[Ðŕáĝ éñðþöîñţ ~~~~]\"],\"node.fenceFeature.actions.close\":[\"[Çļöšé ~~]\"],\"node.fenceFeature.actions.open\":[\"[Öþéñ ~~]\"],\"node.fenceFeature.inspector.boardWidth\":[\"[Ɓöáŕð ŵîðţĥ ~~~]\"],\"node.fenceFeature.inspector.bracing\":[\"[Ɓŕáçîñĝ ~~~]\"],\"node.fenceFeature.inspector.distanceFromStart\":[\"[Ðîšţáñçé ƒŕöɱ šţáŕţ ~~~~~~]\"],\"node.fenceFeature.inspector.fenceUnavailable\":[\"[Ƒéñçé ûñáṽáîļáƀļé. ~~~~~]\"],\"node.fenceFeature.inspector.frameWidth\":[\"[Ƒŕáɱé ŵîðţĥ ~~~]\"],\"node.fenceFeature.inspector.gateHeight\":[\"[Ĝáţé ĥéîĝĥţ ~~~]\"],\"node.fenceFeature.inspector.gateStyle\":[\"[Ĝáţé šţýļé ~~~]\"],\"node.fenceFeature.inspector.groundClearance\":[\"[Ĝŕöûñð çļéáŕáñçé ~~~~~]\"],\"node.fenceFeature.inspector.hingeSide\":[\"[Ĥîñĝé šîðé ~~~]\"],\"node.fenceFeature.inspector.hingesAndLatch\":[\"[Ĥîñĝéš áñð ļáţçĥ ~~~~~]\"],\"node.fenceFeature.inspector.horizontalBoards\":[\"[Ĥöŕîžöñţáļ ƀöáŕðš ~~~~~]\"],\"node.fenceFeature.inspector.infillSpacing\":[\"[Îñƒîļļ šþáçîñĝ ~~~~]\"],\"node.fenceFeature.inspector.jambPosts\":[\"[Ĵáɱƀ þöšţš ~~~]\"],\"node.fenceFeature.inspector.keepTheOpeningInsideTheFence\":[\"[Ķééþ ţĥé öþéñîñĝ îñšîðé ţĥé ƒéñçé áñð çļéáŕ öƒ öţĥéŕ ĝáţéš öŕ þáššáĝéš. ~~~~~~~~~~~~~~~~~~]\"],\"node.fenceFeature.inspector.leafThickness\":[\"[Ļéრţĥîçķñéšš ~~~~]\"],\"node.fenceFeature.inspector.leaves\":[\"[Ļéáṽéš ~~]\"],\"node.fenceFeature.inspector.leftLeafProportion\":[\"[Ļéƒţ ļéრþŕöþöŕţîöñ ~~~~~~]\"],\"node.fenceFeature.inspector.matchFenceHeight\":[\"[Ṁáţçĥ ƒéñçé ĥéîĝĥţ ~~~~~]\"],\"node.fenceFeature.inspector.matchFenceStyle\":[\"[Ṁáţçĥ ƒéñçé šţýļé ~~~~~]\"],\"node.fenceFeature.inspector.openRails\":[\"[Öþéñ ŕáîļš ~~~]\"],\"node.fenceFeature.inspector.openingAngle\":[\"[Öþéñîñĝ áñĝļé ~~~~]\"],\"node.fenceFeature.inspector.openingWidth\":[\"[Öþéñîñĝ ŵîðţĥ ~~~~]\"],\"node.fenceFeature.inspector.option.cross\":[\"[Çŕöšš ~~]\"],\"node.fenceFeature.inspector.option.diagonal\":[\"[Ðîáĝöñáļ ~~~]\"],\"node.fenceFeature.inspector.option.doubleGate\":[\"[Ðöûƀļé ĝáţé ~~~]\"],\"node.fenceFeature.inspector.option.inward\":[\"[Îñŵáŕð ~~]\"],\"node.fenceFeature.inspector.option.left\":[\"[Ļéƒţ ~~]\"],\"node.fenceFeature.inspector.option.none\":[\"[Ñöñé ~~]\"],\"node.fenceFeature.inspector.option.outward\":[\"[Öûţŵáŕð ~~~]\"],\"node.fenceFeature.inspector.option.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.fenceFeature.inspector.option.singleGate\":[\"[Šîñĝļé ĝáţé ~~~]\"],\"node.fenceFeature.inspector.picket\":[\"[Þîçķéţ ~~]\"],\"node.fenceFeature.inspector.postHeight\":[\"[Þöšţ ĥéîĝĥţ ~~~]\"],\"node.fenceFeature.inspector.removeGate\":[\"[Ŕéɱöṽé ĝáţé ~~~]\"],\"node.fenceFeature.inspector.removeOpening\":[\"[Ŕéɱöṽé öþéñîñĝ ~~~~]\"],\"node.fenceFeature.inspector.solidPrivacy\":[\"[Šöļîð þŕîṽáçý ~~~~]\"],\"node.fenceFeature.inspector.swingDirection\":[\"[Šŵîñĝ ðîŕéçţîöñ ~~~~~]\"],\"node.fenceFeature.inspector.verticalSlats\":[\"[Ṽéŕţîçáļ šļáţš ~~~~]\"],\"node.fenceGate.description\":[\"[Å ĝáţé ĥöšţéð ƀý á ƒéñçé. ~~~~~~]\"],\"node.fenceGate.label\":[\"[Ĝáţé ~~]\"],\"node.fenceOpening.description\":[\"[Åñ îñţéñţîöñáļ öþéñîñĝ îñ á ƒéñçé. ~~~~~~~~~]\"],\"node.fenceOpening.label\":[\"[Öþéñ Þáššáĝé ~~~~]\"],\"node.floorOpening.label\":[\"[Ƒļööŕ öþéñîñĝ ~~~~]\"],\"node.guide.description\":[\"[Å ɱéášûŕéɱéñţ / ŕéƒéŕéñçé áññöţáţîöñ (ļîñéáŕ, áŕéá, öŕ áŕç). ~~~~~~~~~~~~~~]\"],\"node.guide.label\":[\"[Ĝûîðé ~~]\"],\"node.gutter.description\":[\"[Ŕáîñ-ŵáţéŕ çĥáññéļ ŕûññîñĝ áļöñĝ ţĥé éáṽé öƒ á ŕööƒ šéĝɱéñţ. ~~~~~~~~~~~~~~~]\"],\"node.gutter.downspoutsPanel.addDownspout\":[\"[Åðð Ðöŵñšþöûţ ~~~~]\"],\"node.gutter.downspoutsPanel.downspoutNumber\":[\"[Ðöŵñšþöûţ \",[\"number\"],\" ~~~]\"],\"node.gutter.downspoutsPanel.downspouts\":[\"[Ðöŵñšþöûţš ~~~]\"],\"node.gutter.downspoutsPanel.removeDownspout\":[\"[Ŕéɱöṽé ðöŵñšþöûţ ~~~~~]\"],\"node.gutter.label\":[\"[Ĝûţţéŕ ~~]\"],\"node.hole.manual\":[\"[Ṁáñûáļ ~~]\"],\"node.holeEditing\":[\"[Ĥöļé \",[\"number\"],\" (Éðîţîñĝ) ~~~~]\"],\"node.holeNumber\":[\"[Ĥöļé \",[\"number\"],\" ~~]\"],\"node.holeSummary\":[\"[\",[\"area\"],\" ɱ² · \",[\"count\",\"plural\",{\"one\":[[\"points\"],\" þţ\"],\"other\":[[\"points\"],\" þţš\"]}],\" · \",[\"source\"],\" ~~]\"],\"node.hvacEquipment.description\":[\"[Ƒûŕñáçé, áîŕ ĥáñðļéŕ, öŕ çöñðéñšéŕ — ðûçţ ŕûñš çöññéçţ ţö îţš šûþþļý/ŕéţûŕñ çöļļáŕš. ~~~~~~~~~~~~~~~~~~~~~]\"],\"node.hvacEquipment.label\":[\"[ĤṼÅÇ Ûñîţ ~~~]\"],\"node.hvacEquipment.tool.rTRotate\":[\"[Ŕ/Ţ ŕöţáţé ~~~]\"],\"node.importedMesh.description\":[\"[Ĝéöɱéţŕý þŕéšéŕṽéð ƒŕöɱ áñ îɱþöŕţéð ɱöðéļ ŵĥéñ ñö ñáţîṽé Þášçáļ šĥáþé éẋîšţš. ~~~~~~~~~~~~~~~~~~~~]\"],\"node.importedMesh.label\":[\"[Îɱþöŕţéð Ṁéšĥ ~~~~]\"],\"node.item.authoredParams.couldnTRebuildWithTheseValues\":[\"[Çöûļðñ'ţ ŕéƀûîļð ŵîţĥ ţĥéšé ṽáļûéš. ~~~~~~~~~]\"],\"node.item.authoredParams.parameters\":[\"[Þáŕáɱéţéŕš ~~~]\"],\"node.item.authoredParams.rebuilding\":[\"[Ŕéƀûîļðîñĝ… ~~~]\"],\"node.item.authoredParams.rebuildingInBlender\":[\"[Ŕéƀûîļðîñĝ îñ Ɓļéñðéŕ… ~~~~~~]\"],\"node.item.authoredParams.resetParam\":[\"[Ŕéšéţ \",[\"param\"],\" ~~]\"],\"node.item.authoredParams.resetParameters\":[\"[Ŕéšéţ þáŕáɱéţéŕš ~~~~~]\"],\"node.item.authoredParams.resetToDefault\":[\"[Ŕéšéţ ţö ðéƒáûļţ ~~~~~]\"],\"node.item.description\":[\"[Å çáţáļöĝ-ƀáçķéð îţéɱ (ƒûŕñîţûŕé, ƒîẋţûŕéš, ðéçöŕáţîöñš). ~~~~~~~~~~~~~~]\"],\"node.item.label\":[\"[Îţéɱ ~~]\"],\"node.item.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.item.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.item.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.item.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.item.panel.info\":[\"[Îñƒö ~~]\"],\"node.item.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.item.panel.pos\":[\"[þöš ~]\"],\"node.item.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.item.panel.rot\":[\"[ŕöţ ~]\"],\"node.item.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.item.panel.scale\":[\"[Šçáļé ~~]\"],\"node.item.panel.scale2\":[\"[šçáļé ~~]\"],\"node.item.panel.uniformScale\":[\"[Ûñîƒöŕɱ Šçáļé ~~~~]\"],\"node.item.panel.xyz\":[\"[ẊÝŽ ~]\"],\"node.leanToExtension.description\":[\"[Åñ áţţáçĥéð ɱöñö-þîţçĥ öŕ ƒŕééšţáñðîñĝ ɱöñö, ĝáƀļé, öŕ ƀûţţéŕƒļý çáñöþý ŵîţĥ ɱáñáĝéð šţŕûçţûŕé áñð ðŕáîñáĝé. ~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.leanToExtension.label\":[\"[Çáñöþý ~~]\"],\"node.level.description\":[\"[Å šîñĝļé ƒļööŕ öƒ á ƀûîļðîñĝ, ĥöļðîñĝ ŵáļļš / šļáƀš / çéîļîñĝš / îţéɱš. ~~~~~~~~~~~~~~~~]\"],\"node.level.label\":[\"[Ļéṽéļ ~~]\"],\"node.lineset.description\":[\"[Ŕéƒŕîĝéŕáñţ ļîñéšéţ — çöþþéŕ šûçţîöñ + ļîǫûîð þáîŕ ĵöîñîñĝ á çöñðéñšéŕ ţö ţĥé îñðööŕ çöîļ. ~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.lineset.label\":[\"[Ļîñéšéţ ~~~]\"],\"node.liquidLine.description\":[\"[Šţáñðáļöñé ŕéƒŕîĝéŕáñţ ļîǫûîð ļîñé — á ţĥîñ ƀáŕé-çöþþéŕ ŕûñ; Ƒöļļöŵ ɱöðé ţŕáçéš áñ éẋîšţîñĝ ļîñéšéţ. ~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.liquidLine.label\":[\"[Ļîǫûîð Ļîñé ~~~]\"],\"node.liquidLine.tool.clickToTraceThisLinesetRun\":[\"[Çļîçķ ţö ţŕáçé ţĥîš ļîñéšéţ ŕûñ ~~~~~~~~]\"],\"node.liquidLine.tool.followHoverALineset\":[\"[Ƒöļļöŵ: ĥöṽéŕ á ļîñéšéţ ~~~~~~]\"],\"node.measurement.description\":[\"[Å þéŕšîšţéñţ ðîšţáñçé, áñĝļé, áŕéá, þéŕîɱéţéŕ, öŕ ṽöļûɱé áññöţáţîöñ. ~~~~~~~~~~~~~~~~~]\"],\"node.measurement.label\":[\"[Ṁéášûŕéɱéñţ ~~~~]\"],\"node.numberedName\":[[\"kind\"],\" \",[\"number\"]],\"node.panel.currently\":[\"[Çûŕŕéñţļý \",[\"value\"],\" ~~~]\"],\"node.pipeFitting.description\":[\"[ÐŴṼ ĵöîñţ — éļƀöŵ ƀéñð, 45° ŵýé, öŕ šáñîţáŕý ţéé. ~~~~~~~~~~]\"],\"node.pipeFitting.label\":[\"[Þîþé Ƒîţţîñĝ ~~~~]\"],\"node.pipeFitting.tool.axis\":[\"[Åẋîš ~~]\"],\"node.pipeFitting.tool.axis2\":[\"[⌥ áẋîš ~~]\"],\"node.pipeFitting.tool.rTRotate\":[\"[Ŕ/Ţ ŕöţáţé ~~~]\"],\"node.pipeSegment.description\":[\"[Ðŕáîñ / ŵášţé / ṽéñţ þîþé ŕûñ — ðŕáŵ ļéṽéļ öŕ ţöĝĝļé á ¼″ þéŕ ƒööţ ƒáļļ ŵîţĥ Š. ~~~~~~~~~~~~~~~~~]\"],\"node.pipeSegment.label\":[\"[ÐŴṼ Þîþé ~~~]\"],\"node.pipeTrap.description\":[\"[ÐŴṼ Þ-ţŕáþ — ŵáţéŕ šéáļ öñ ţĥé ŵášţé ļîñé. Ţĥé ţŕáþ áŕɱ ŕûñš ţö ţĥé ṽéñţ. ~~~~~~~~~~~~~~~~~]\"],\"node.pipeTrap.label\":[\"[Ţŕáþ ~~]\"],\"node.pipeTrap.tool.diameterTrap\":[\"[\",[\"diameter\"],\"\\\" Ţŕáþ ~~]\"],\"node.pipeTrap.tool.rTRotate\":[\"[Ŕ/Ţ ŕöţáţé ~~~]\"],\"node.proceduralItem.description\":[\"[Éẋþéŕîɱéñţáļ éðîţáƀļé ŕéçîþé ~~~~~~~~]\"],\"node.proceduralItem.label\":[\"[Þŕöçéðûŕáļ îţéɱ ~~~~~]\"],\"node.ridgeVent.description\":[\"[Ṽéñţîļáţîöñ šţŕîþ ŕûññîñĝ áļöñĝ ţĥé ŕîðĝé öƒ á ŕööƒ šéĝɱéñţ. ~~~~~~~~~~~~~~~]\"],\"node.ridgeVent.label\":[\"[Ŕîðĝé Ṽéñţ ~~~]\"],\"node.ridgeVent.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.ridgeVent.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.ridgeVent.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.ridgeVent.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.ridgeVent.panel.endCaps\":[\"[Éñð Çáþš ~~~]\"],\"node.ridgeVent.panel.flanged\":[\"[Ƒļáñĝéð ~~~]\"],\"node.ridgeVent.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.ridgeVent.panel.length\":[\"[Ļéñĝţĥ ~~]\"],\"node.ridgeVent.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.ridgeVent.panel.open\":[\"[Öþéñ ~~]\"],\"node.ridgeVent.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.ridgeVent.panel.ridgeVent\":[\"[Ŕîðĝé Ṽéñţ ~~~]\"],\"node.ridgeVent.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.ridgeVent.panel.shingled\":[\"[Šĥîñĝļéð ~~~]\"],\"node.ridgeVent.panel.standard\":[\"[Šţáñðáŕð ~~~]\"],\"node.ridgeVent.panel.style\":[\"[Šţýļé ~~]\"],\"node.ridgeVent.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.roof.barrelPanel.archBays\":[\"[Åŕçĥ ƀáýš ~~~]\"],\"node.roof.barrelPanel.barrelArch\":[\"[Ɓáŕŕéļ áŕçĥ ~~~]\"],\"node.roof.barrelPanel.flatPanesFollowACircularArch\":[\"[Ƒļáţ þáñéš ƒöļļöŵ á çîŕçûļáŕ áŕçĥ. Ŕîšé îš ɱéášûŕéð ƒŕöɱ ţĥé éáṽéš. ~~~~~~~~~~~~~~~~~]\"],\"node.roof.barrelPanel.rise\":[\"[Ŕîšé ~~]\"],\"node.roof.description\":[\"[Å þîţçĥéð / ĥîþ / ĝáƀļé ŕööƒ çöɱþöšéð öƒ öñé öŕ ɱöŕé šéĝɱéñţš. ~~~~~~~~~~~~~~~]\"],\"node.roof.glazing.face.archBay\":[\"[Åŕçĥ ƀáý \",[\"number\"],\" ~~~]\"],\"node.roof.glazing.face.back\":[\"[Ɓáçķ šļöþé ~~~]\"],\"node.roof.glazing.face.endLeft\":[\"[Ļéƒţ éñð ~~~]\"],\"node.roof.glazing.face.endRight\":[\"[Ŕîĝĥţ éñð ~~~]\"],\"node.roof.glazing.face.front\":[\"[Ƒŕöñţ šļöþé ~~~]\"],\"node.roof.glazing.face.slope\":[\"[Šĥéð šļöþé ~~~]\"],\"node.roof.glazingControls.alignment\":[\"[Åļîĝñɱéñţ ~~~]\"],\"node.roof.glazingControls.center\":[\"[Çéñţéŕ ~~]\"],\"node.roof.glazingControls.chooseALayoutToEditThe\":[\"[Çĥööšé á ļáýöûţ ţö éðîţ ţĥé ĝŕîð. ~~~~~~~~]\"],\"node.roof.glazingControls.empty\":[\"[Éɱþţý ~~]\"],\"node.roof.glazingControls.end\":[\"[Éñð ~]\"],\"node.roof.glazingControls.fixedSpacing\":[\"[Ƒîẋéð šþáçîñĝ ~~~~]\"],\"node.roof.glazingControls.glass\":[\"[Ĝļášš ~~]\"],\"node.roof.glazingControls.layout\":[\"[Ļáýöûţ ~~]\"],\"node.roof.glazingControls.maxSpacing\":[\"[Ṁáẋ šþáçîñĝ ~~~]\"],\"node.roof.glazingControls.maximumSpacing\":[\"[Ṁáẋîɱûɱ šþáçîñĝ ~~~~~]\"],\"node.roof.glazingControls.mixed\":[\"[Ṁîẋéð ~~]\"],\"node.roof.glazingControls.panelCount\":[\"[Þáñéļ çöûñţ ~~~]\"],\"node.roof.glazingControls.panels\":[\"[Þáñéļš ~~]\"],\"node.roof.glazingControls.solid\":[\"[Šöļîð ~~]\"],\"node.roof.glazingControls.spacing\":[\"[Šþáçîñĝ ~~~]\"],\"node.roof.glazingControls.start\":[\"[Šţáŕţ ~~]\"],\"node.roof.glazingControls.titleAlignment\":[\"[\",[\"title\"],\" áļîĝñɱéñţ ~~~]\"],\"node.roof.glazingPanel.changesApplyToAllLengthRoof\":[\"[Çĥáñĝéš áþþļý ţö áļļ \",[\"length\"],\" ŕööƒ šéĝɱéñţš. ~~~~~~~~~]\"],\"node.roof.glazingPanel.chooseOneRoofSystemToEdit\":[\"[Çĥööšé öñé ŕööƒ šýšţéɱ ţö éðîţ šéţţîñĝš ƒöŕ áļļ šéļéçţéð šéĝɱéñţš. ~~~~~~~~~~~~~~~~~]\"],\"node.roof.glazingPanel.closeTheRoofEnds\":[\"[Çļöšé ţĥé ŕööƒ éñðš ~~~~~]\"],\"node.roof.glazingPanel.defaultPanelInfill\":[\"[Ðéƒáûļţ þáñéļ îñƒîļļ ~~~~~~]\"],\"node.roof.glazingPanel.dividesEachRoofFaceIntoColumns\":[\"[Ðîṽîðéš éáçĥ ŕööƒ ƒáçé îñţö çöļûɱñš. ~~~~~~~~~]\"],\"node.roof.glazingPanel.dividesTheLengthOfEachArch\":[\"[Ðîṽîðéš ţĥé ļéñĝţĥ öƒ éáçĥ áŕçĥ ƀáý îñţö çöļûɱñš. ~~~~~~~~~~~~]\"],\"node.roof.glazingPanel.endInfillFillsTheSpaceAbove\":[\"[Éñð îñƒîļļ ƒîļļš ţĥé šþáçé áƀöṽé ţĥé ŵáļļš. Éðîţ ŕööɱ ŵáļļš áñð çéîļîñĝš šéþáŕáţéļý. ~~~~~~~~~~~~~~~~~~~~~]\"],\"node.roof.glazingPanel.frameColor\":[\"[Ƒŕáɱé çöļöŕ ~~~]\"],\"node.roof.glazingPanel.frameDepth\":[\"[Ƒŕáɱé ðéþţĥ ~~~]\"],\"node.roof.glazingPanel.frameWidth\":[\"[Ƒŕáɱé ŵîðţĥ ~~~]\"],\"node.roof.glazingPanel.framing\":[\"[Ƒŕáɱîñĝ ~~~]\"],\"node.roof.glazingPanel.glass\":[\"[Ĝļášš ~~]\"],\"node.roof.glazingPanel.glassTint\":[\"[Ĝļášš ţîñţ ~~~]\"],\"node.roof.glazingPanel.glazed\":[\"[Ĝļážéð ~~]\"],\"node.roof.glazingPanel.glazingIsAvailableForGableStraight\":[\"[Ĝļážîñĝ îš áṽáîļáƀļé ƒöŕ ĝáƀļé, šţŕáîĝĥţ šĥéð, áñð ƀáŕŕéļ ŕööƒš. ~~~~~~~~~~~~~~~~]\"],\"node.roof.glazingPanel.gridAcrossTheRoof\":[\"[Ĝŕîð áçŕöšš ţĥé ŕööƒ ~~~~~~]\"],\"node.roof.glazingPanel.gridAlongTheLength\":[\"[Ĝŕîð áļöñĝ ţĥé ļéñĝţĥ ~~~~~~]\"],\"node.roof.glazingPanel.gridAlongTheSlope\":[\"[Ĝŕîð áļöñĝ ţĥé šļöþé ~~~~~~]\"],\"node.roof.glazingPanel.gridWithinEachArchBay\":[\"[Ĝŕîð ŵîţĥîñ éáçĥ áŕçĥ ƀáý ~~~~~~~]\"],\"node.roof.glazingPanel.infill\":[\"[Îñƒîļļ ~~]\"],\"node.roof.glazingPanel.opacity\":[\"[Öþáçîţý ~~~]\"],\"node.roof.glazingPanel.paneThickness\":[\"[Þáñé ţĥîçķñéšš ~~~~]\"],\"node.roof.glazingPanel.roofSystem\":[\"[Ŕööƒ šýšţéɱ ~~~]\"],\"node.roof.glazingPanel.roughness\":[\"[Ŕöûĝĥñéšš ~~~]\"],\"node.roof.glazingPanel.spacingIsMeasuredOnTheSlope\":[\"[Šþáçîñĝ îš ɱéášûŕéð öñ ţĥé šļöþé, ñöţ îţš ĥöŕîžöñţáļ þŕöĵéçţîöñ. ~~~~~~~~~~~~~~~~]\"],\"node.roof.glazingPanel.standard\":[\"[Šţáñðáŕð ~~~]\"],\"node.roof.glazingPanel.subdividesEachFlatArchBayArch\":[\"[Šûƀðîṽîðéš éáçĥ ƒļáţ áŕçĥ ƀáý. Åŕçĥ ƀáýš çöñţŕöļš ţĥé ðîṽîšîöñš áŕöûñð ţĥé çûŕṽé. ~~~~~~~~~~~~~~~~~~~~~]\"],\"node.roof.glazingPanelEditor.chooseAPanelToOverrideIts\":[\"[Çĥööšé á þáñéļ ţö öṽéŕŕîðé îţš ðéƒáûļţ îñƒîļļ. ~~~~~~~~~~~~]\"],\"node.roof.glazingPanelEditor.column2\":[\"[Çöļûɱñ ~~]\"],\"node.roof.glazingPanelEditor.custom\":[\"[Çûšţöɱ ~~]\"],\"node.roof.glazingPanelEditor.default\":[\"[Ðéƒáûļţ ~~~]\"],\"node.roof.glazingPanelEditor.grid\":[\"[\",[\"columns\",\"plural\",{\"one\":[[\"columnCount\"],\" çöļûɱñ\"],\"other\":[[\"columnCount\"],\" çöļûɱñš\"]}],\" · \",[\"rows\",\"plural\",{\"one\":[[\"rowCount\"],\" ŕöŵ\"],\"other\":[[\"rowCount\"],\" ŕöŵš\"]}],\" ~~~~~~]\"],\"node.roof.glazingPanelEditor.individualPanels\":[\"[Îñðîṽîðûáļ þáñéļš ~~~~~]\"],\"node.roof.glazingPanelEditor.panelInfill\":[\"[Þáñéļ îñƒîļļ ~~~~]\"],\"node.roof.glazingPanelEditor.resetToDefault\":[\"[Ŕéšéţ ţö ðéƒáûļţ ~~~~~]\"],\"node.roof.glazingPanelEditor.roofFace\":[\"[Ŕööƒ ƒáçé ~~~]\"],\"node.roof.glazingPanelEditor.row2\":[\"[Ŕöŵ ~]\"],\"node.roof.glazingPanelEditor.selectedPanelInfill\":[\"[Šéļéçţéð þáñéļ îñƒîļļ ~~~~~~]\"],\"node.roof.label\":[\"[Ŕööƒ ~~]\"],\"node.roof.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.roof.panel.addChimney\":[\"[Åðð Çĥîɱñéý ~~~]\"],\"node.roof.panel.addCupola\":[\"[Åðð Çûþöļá ~~~]\"],\"node.roof.panel.addDormer\":[\"[Åðð Ðöŕɱéŕ ~~~]\"],\"node.roof.panel.addEyebrowVent\":[\"[Åðð Éýéƀŕöŵ Ṽéñţ ~~~~~]\"],\"node.roof.panel.addGutter\":[\"[Åðð Ĝûţţéŕ ~~~]\"],\"node.roof.panel.addSkylight\":[\"[Åðð Šķýļîĝĥţ ~~~~]\"],\"node.roof.panel.addSolarPanel\":[\"[Åðð Šöļáŕ Þáñéļ ~~~~]\"],\"node.roof.panel.addVent\":[\"[Åðð Ṽéñţ ~~~]\"],\"node.roof.panel.box\":[\"[Ɓöẋ ~]\"],\"node.roof.panel.boxVent\":[\"[ƀöẋ ṽéñţ ~~~]\"],\"node.roof.panel.chimney\":[\"[çĥîɱñéý ~~~]\"],\"node.roof.panel.custom\":[\"[Çûšţöɱ ~~]\"],\"node.roof.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.roof.panel.dormer\":[\"[ðöŕɱéŕ ~~]\"],\"node.roof.panel.drawSegment\":[\"[Ðŕáŵ Šéĝɱéñţ ~~~~]\"],\"node.roof.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.roof.panel.elements\":[\"[Éļéɱéñţš ~~~]\"],\"node.roof.panel.followsWalls\":[\"[Ƒöļļöŵš ŵáļļš ~~~~]\"],\"node.roof.panel.gutter\":[\"[ĝûţţéŕ ~~]\"],\"node.roof.panel.level\":[\"[Ļéṽéļ ~~]\"],\"node.roof.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.roof.panel.moveToLevel\":[\"[Ṁöṽé ţö \",[\"level\"],\" ~~]\"],\"node.roof.panel.moveToTheRoofLevel\":[\"[Ṁöṽé ţö ţĥé ŕööƒ ļéṽéļ ~~~~~~]\"],\"node.roof.panel.onStoreyWalls\":[\"[Öñ \",[\"storey\"],\" ŵîţĥ îţš ŵáļļš, šö îţ ĥîðéš ţĥáţ ƒļööŕ'š þļáñ îñ šöļö áñð éẋþļöðéð ṽîéŵš.\",[\"roofs\",\"plural\",{\"0\":[],\"1\":[],\"other\":[\" Ţĥé ƒļööŕ'š \",[\"roofCount\"],\" ŕööƒš ɱöṽé ţöĝéţĥéŕ.\"]}],\" ~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.roof.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.roof.panel.ridge\":[\"[Ŕîðĝé ~~]\"],\"node.roof.panel.ridgeVent\":[\"[ŕîðĝé ṽéñţ ~~~]\"],\"node.roof.panel.roof\":[\"[Ŕööƒ ~~]\"],\"node.roof.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.roof.panel.segmentType\":[\"[\",[\"roofType\",\"select\",{\"hip\":[\"Ĥîþ\"],\"gable\":[\"Ĝáƀļé\"],\"shed\":[\"Šĥéð\"],\"gambrel\":[\"Ĝáɱƀŕéļ\"],\"dutch\":[\"Ðûţçĥ\"],\"mansard\":[\"Ṁáñšáŕð\"],\"flat\":[\"Ƒļáţ\"],\"conical\":[\"Çöñîçáļ\"],\"barrel\":[\"Ɓáŕŕéļ\"],\"other\":[\"Ŕööƒ\"]}],\" ~~~~~~~~~~~~~~~~]\"],\"node.roof.panel.segments\":[\"[Šéĝɱéñţš ~~~]\"],\"node.roof.panel.skylight\":[\"[šķýļîĝĥţ ~~~]\"],\"node.roof.panel.solarPanel\":[\"[šöļáŕ þáñéļ ~~~]\"],\"node.roof.panel.turbine\":[\"[Ţûŕƀîñé ~~~]\"],\"node.roof.panel.turbineVent\":[\"[ţûŕƀîñé ṽéñţ ~~~~]\"],\"node.roofSegment.description\":[\"[Å šîñĝļé þîţçĥéð þļáñé öƒ á þáŕéñţ ŕööƒ. ~~~~~~~~~~]\"],\"node.roofSegment.label\":[\"[Ŕööƒ Šéĝɱéñţ ~~~~]\"],\"node.roofSegment.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.roofSegment.panel.angle\":[\"[Åñĝļé ~~]\"],\"node.roofSegment.panel.arc\":[\"[Åŕç ~]\"],\"node.roofSegment.panel.autoGutters\":[\"[Åûţö ĝûţţéŕš ~~~~]\"],\"node.roofSegment.panel.autoRidgeVent\":[\"[Åûţö ŕîðĝé ṽéñţ ~~~~]\"],\"node.roofSegment.panel.barrel\":[\"[Ɓáŕŕéļ ~~]\"],\"node.roofSegment.panel.clippedVersion\":[\"[Çļîþþéð ṽéŕšîöñ ~~~~~]\"],\"node.roofSegment.panel.conical\":[\"[Çöñîçáļ ~~~]\"],\"node.roofSegment.panel.conicalShape\":[\"[Çöñîçáļ Šĥáþé ~~~~]\"],\"node.roofSegment.panel.deckThick\":[\"[Ðéçķ Ţĥîçķ. ~~~]\"],\"node.roofSegment.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.roofSegment.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.roofSegment.panel.diameter\":[\"[Ðîáɱéţéŕ ~~~]\"],\"node.roofSegment.panel.doneEditing\":[\"[Ðöñé éðîţîñĝ ~~~~]\"],\"node.roofSegment.panel.drainage\":[\"[Ðŕáîñáĝé ~~~]\"],\"node.roofSegment.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.roofSegment.panel.dutch\":[\"[Ðûţçĥ ~~]\"],\"node.roofSegment.panel.eaveOverhang\":[\"[Éáṽé öṽéŕĥáñĝ ~~~~]\"],\"node.roofSegment.panel.editFootprint\":[\"[Éðîţ ƒööţþŕîñţ ~~~~]\"],\"node.roofSegment.panel.endOverhang\":[\"[Éñð öṽéŕĥáñĝ ~~~~]\"],\"node.roofSegment.panel.fascia\":[\"[Ƒášçîá ~~]\"],\"node.roofSegment.panel.fasciaHeight\":[\"[Ƒášçîá ĥéîĝĥţ ~~~~]\"],\"node.roofSegment.panel.flat\":[\"[Ƒļáţ ~~]\"],\"node.roofSegment.panel.footprint\":[\"[Ƒööţþŕîñţ ~~~]\"],\"node.roofSegment.panel.gable\":[\"[Ĝáƀļé ~~]\"],\"node.roofSegment.panel.gableOverhang\":[\"[Ĝáƀļé öṽéŕĥáñĝ ~~~~]\"],\"node.roofSegment.panel.gambrel\":[\"[Ĝáɱƀŕéļ ~~~]\"],\"node.roofSegment.panel.hip\":[\"[Ĥîþ ~]\"],\"node.roofSegment.panel.kinkDepth\":[\"[Ķîñķ Ðéþţĥ ~~~]\"],\"node.roofSegment.panel.kinkHeight\":[\"[Ķîñķ Ĥéîĝĥţ ~~~]\"],\"node.roofSegment.panel.length\":[\"[Ļéñĝţĥ ~~]\"],\"node.roofSegment.panel.mansard\":[\"[Ṁáñšáŕð ~~~]\"],\"node.roofSegment.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.roofSegment.panel.pitch\":[\"[Þîţçĥ ~~]\"],\"node.roofSegment.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.roofSegment.panel.reset\":[\"[Ŕéšéţ ~~]\"],\"node.roofSegment.panel.roofSegment\":[\"[Ŕööƒ Šéĝɱéñţ ~~~~]\"],\"node.roofSegment.panel.roofType\":[\"[Ŕööƒ Ţýþé ~~~]\"],\"node.roofSegment.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.roofSegment.panel.shape\":[\"[Šĥáþé ~~]\"],\"node.roofSegment.panel.shed\":[\"[Šĥéð ~~]\"],\"node.roofSegment.panel.shingleThick\":[\"[Šĥîñĝļé Ţĥîçķ. ~~~~]\"],\"node.roofSegment.panel.span\":[\"[Šþáñ ~~]\"],\"node.roofSegment.panel.startAngle\":[\"[Šţáŕţ Åñĝļé ~~~]\"],\"node.roofSegment.panel.structure\":[\"[Šţŕûçţûŕé ~~~]\"],\"node.roofSegment.panel.topRakeLength\":[\"[Ţöþ Ŕáķé Ļéñĝţĥ ~~~~]\"],\"node.roofSegment.panel.topRakeThick\":[\"[Ţöþ Ŕáķé Ţĥîçķ. ~~~~]\"],\"node.roofSegment.panel.trim\":[\"[Ţŕîɱ ~~]\"],\"node.roofSegment.panel.waistHeight\":[\"[Ŵáîšţ Ĥéîĝĥţ ~~~~]\"],\"node.roofSegment.panel.waistLength\":[\"[Ŵáîšţ Ļéñĝţĥ ~~~~]\"],\"node.roofSegment.panel.waistWidth\":[\"[Ŵáîšţ Ŵîðţĥ ~~~]\"],\"node.roofSegment.panel.wall\":[\"[Ŵáļļ ~~]\"],\"node.roofSegment.panel.wallHeight\":[\"[Ŵáļļ Ĥéîĝĥţ ~~~]\"],\"node.roofSegment.panel.wallThick\":[\"[Ŵáļļ Ţĥîçķ. ~~~]\"],\"node.roofSegment.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.scan.description\":[\"[Å çáþţûŕéð šéššîöñ ŵîţĥ öþţîöñáļ ɱéšĥ, ɱöţîöñ, ɱéðîá, áñð šéñšöŕ ðáţá. ~~~~~~~~~~~~~~~~~]\"],\"node.scan.label\":[\"[Çáþţûŕé ~~~]\"],\"node.segmentNumber\":[\"[Šéĝɱéñţ \",[\"number\"],\" ~~~]\"],\"node.separator.label\":[\"[Šéþáŕáţöŕ ~~~]\"],\"node.shared.itemInteractionActions.turnLightOff\":[\"[Ţûŕñ ļîĝĥţ öƒƒ ~~~~]\"],\"node.shared.itemInteractionActions.turnLightOn\":[\"[Ţûŕñ ļîĝĥţ öñ ~~~~]\"],\"node.shared.runHangerInspector.automaticSupport\":[\"[Åûţöɱáţîç šûþþöŕţ ~~~~~]\"],\"node.shared.runHangerInspector.hangerOnSegment\":[\"[Ĥáñĝéŕ \",[\"number\"],\" · šéĝɱéñţ \",[\"segment\"],\" ~~~~]\"],\"node.shared.runHangerInspector.individualHangers\":[\"[Îñðîṽîðûáļ ĥáñĝéŕš ~~~~~~]\"],\"node.shared.runHangerInspector.missingSupport\":[\"[Ṁîššîñĝ šûþþöŕţ ~~~~~]\"],\"node.shared.runHangerInspector.noSupportWithinReachMoveThe\":[\"[Ñö šûþþöŕţ ŵîţĥîñ ŕéáçĥ. Ṁöṽé ţĥé ĥáñĝéŕ öŕ çĥööšé áñöţĥéŕ ĥöšţ. ~~~~~~~~~~~~~~~~]\"],\"node.shared.runHangerInspector.positionLabel\":[\"[Ĥáñĝéŕ \",[\"number\"],\" þöšîţîöñ îñ ɱéţŕéš ~~~~~~~]\"],\"node.shared.runHangerInspector.positionM\":[\"[Þöšîţîöñ (ɱ) ~~~]\"],\"node.shared.runHangerInspector.positionsAreMeasuredAlongEachPath\":[\"[Þöšîţîöñš áŕé ɱéášûŕéð áļöñĝ éáçĥ þáţĥ šéĝɱéñţ. Çĥáñĝîñĝ šþáçîñĝ ŕéĝéñéŕáţéš ţĥé ñûɱƀéŕéð šļöţš. ~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.shared.runHangerInspector.revealSupport\":[\"[Ŕéṽéáļ šûþþöŕţ ~~~~]\"],\"node.shared.runHangerInspector.skip\":[\"[Šķîþ ~~]\"],\"node.shared.runHangerInspector.supportLabel\":[\"[Ĥáñĝéŕ \",[\"number\"],\" šûþþöŕţ ~~~~]\"],\"node.shared.systemCheckPanel.aboutTheseChecks\":[\"[Åƀöûţ ţĥéšé çĥéçķš ~~~~~]\"],\"node.shared.systemCheckPanel.allFindings\":[\"[Åļļ ƒîñðîñĝš ~~~~]\"],\"node.shared.systemCheckPanel.allSystems\":[\"[Åļļ šýšţéɱš ~~~]\"],\"node.shared.systemCheckPanel.connections\":[\"[Çöññéçţîöñš ~~~~]\"],\"node.shared.systemCheckPanel.drainage\":[\"[Ðŕáîñáĝé ~~~]\"],\"node.shared.systemCheckPanel.error\":[\"[Éŕŕöŕ ~~]\"],\"node.shared.systemCheckPanel.errors\":[\"[Éŕŕöŕš ~~]\"],\"node.shared.systemCheckPanel.filterSystemChecks\":[\"[Ƒîļţéŕ šýšţéɱ çĥéçķš ~~~~~~]\"],\"node.shared.systemCheckPanel.hangers\":[\"[Ĥáñĝéŕš ~~~]\"],\"node.shared.systemCheckPanel.intersections\":[\"[Îñţéŕšéçţîöñš ~~~~]\"],\"node.shared.systemCheckPanel.locate\":[\"[Ļöçáţé \",[\"name\"],\" (\",[\"id\"],\") ~~]\"],\"node.shared.systemCheckPanel.missingItem\":[\"[Ṁîššîñĝ îţéɱ ~~~~]\"],\"node.shared.systemCheckPanel.noFindings\":[\"[Ñö ƒîñðîñĝš ~~~]\"],\"node.shared.systemCheckPanel.noFindingsInThisCategory\":[\"[Ñö ƒîñðîñĝš îñ ţĥîš çáţéĝöŕý ~~~~~~~~]\"],\"node.shared.systemCheckPanel.openEnds\":[\"[Öþéñ éñðš ~~~]\"],\"node.shared.systemCheckPanel.openEndsAndSeparateBranchesMay\":[\"[Öþéñ éñðš áñð šéþáŕáţé ƀŕáñçĥéš ɱáý ƀé îñţéñţîöñáļ. Îñţéŕšéçţîöñ çĥéçķš ûšé ƀöûñðîñĝ ƀöẋéš; îñšþéçţ öþéñîñĝš áñð çļéáŕáñçéš. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.shared.systemCheckPanel.selectedConnectedSystem\":[\"[Šéļéçţéð çöññéçţéð šýšţéɱ ~~~~~~~]\"],\"node.shared.systemCheckPanel.selectedRuns\":[\"[Šéļéçţéð: \",[\"count\",\"plural\",{\"one\":[[\"number\"],\" ŕûñ\"],\"other\":[[\"number\"],\" ŕûñš\"]}],\" · \",[\"length\"],\" ɱ ~~~~~]\"],\"node.shared.systemCheckPanel.separateBranches\":[\"[Šéþáŕáţé ƀŕáñçĥéš ~~~~~]\"],\"node.shared.systemCheckPanel.showAllFindings\":[\"[Šĥöŵ áļļ ƒîñðîñĝš ~~~~~]\"],\"node.shared.systemCheckPanel.systemChecks\":[\"[Šýšţéɱ çĥéçķš ~~~~]\"],\"node.shared.systemCheckPanel.systemFinding\":[\"[Šýšţéɱ ƒîñðîñĝ ~~~~]\"],\"node.shared.systemCheckPanel.systemFindings\":[\"[Šýšţéɱ ƒîñðîñĝš ~~~~~]\"],\"node.shared.systemCheckPanel.warning\":[\"[Ŵáŕñîñĝ ~~~]\"],\"node.shared.systemCheckPanel.warnings\":[\"[Ŵáŕñîñĝš ~~~]\"],\"node.shelf.description\":[\"[Å çöñƒîĝûŕáƀļé šĥéļṽîñĝ ûñîţ. Îţéɱš ĥöšţ öñ éáçĥ ŕöŵ. ~~~~~~~~~~~~~]\"],\"node.shelf.label\":[\"[Šĥéļƒ ~~]\"],\"node.site.description\":[\"[Ţĥé ţöþ-ļéṽéļ çöñţáîñéŕ ĥöļðîñĝ ƀûîļðîñĝš, žöñéš, áñð ţĥé þŕöþéŕţý ƀöûñðáŕý. ~~~~~~~~~~~~~~~~~~~]\"],\"node.site.label\":[\"[Šîţé ~~]\"],\"node.site.panel.address\":[\"[Åððŕéšš ~~~]\"],\"node.site.panel.apn\":[\"[ÅÞÑ ~]\"],\"node.site.panel.autoMostNorthFacingEdge\":[\"[Åûţö — ɱöšţ ñöŕţĥ-ƒáçîñĝ éðĝé ~~~~~~~]\"],\"node.site.panel.contourIntervalSitePlanAnd3d\":[\"[Çöñţöûŕ îñţéŕṽáļ (šîţé þļáñ áñð 3Ð) ~~~~~~~~~]\"],\"node.site.panel.county\":[\"[Çöûñţý ~~]\"],\"node.site.panel.eGRs60\":[\"[é.ĝ. ŔŠ-60 ~~]\"],\"node.site.panel.eGTampaLdc27156\":[\"[é.ĝ. Ţáɱþá ĻÐÇ §27-156 ~~~]\"],\"node.site.panel.every12In\":[\"[éṽéŕý 12 îñ ~~~]\"],\"node.site.panel.every24In\":[\"[éṽéŕý 24 îñ ~~~]\"],\"node.site.panel.every6In\":[\"[éṽéŕý 6 îñ ~~~]\"],\"node.site.panel.findParcel\":[\"[Ƒîñð þáŕçéļ ~~~]\"],\"node.site.panel.finding\":[\"[Ƒîñðîñĝ… ~~~]\"],\"node.site.panel.frontStreetEdge\":[\"[Ƒŕöñţ (šţŕééţ) éðĝé ~~~~~]\"],\"node.site.panel.lookingUpTheParcel\":[\"[Ļööķîñĝ ûþ ţĥé þáŕçéļ áñð ţĥé šţŕééţš áŕöûñð îţ… ~~~~~~~~~~~~]\"],\"node.site.panel.lotArea\":[\"[Ļöţ áŕéá ~~~]\"],\"node.site.panel.n1200WCassStTampaFl\":[\"[1200 Ŵ Çášš Šţ, Ţáɱþá, ƑĻ ~~~~~]\"],\"node.site.panel.noSurveyedLinesContoursAreDrawn\":[\"[Ñö šûŕṽéýéð ļîñéš — çöñţöûŕš áŕé ðŕáŵñ ƒŕöɱ ţĥé šçûļþţéð ĝŕöûñð. ~~~~~~~~~~~~~~~~]\"],\"node.site.panel.none\":[\"[ñöñé ~~]\"],\"node.site.panel.northRotation\":[\"[Ñöŕţĥ ŕöţáţîöñ ~~~~]\"],\"node.site.panel.orientation\":[\"[Öŕîéñţáţîöñ ~~~~]\"],\"node.site.panel.parcel\":[\"[Þáŕçéļ ~~]\"],\"node.site.panel.parcelLookupFailed\":[\"[Þáŕçéļ ļööķûþ ƒáîļéð. ~~~~~~]\"],\"node.site.panel.projectLook\":[\"[Þŕöĵéçţ ļööķ ~~~~]\"],\"node.site.panel.saveCurrentLook\":[\"[Šáṽé çûŕŕéñţ ļööķ ~~~~~]\"],\"node.site.panel.saveTheCurrentLightingAndDisplay\":[\"[Šáṽé ţĥé çûŕŕéñţ ļîĝĥţîñĝ áñð ðîšþļáý áš ţĥîš þŕöĵéçţ'š ðéƒáûļţ. Þéŕšöñáļ ðîšþļáý çĥáñĝéš šţáý îñ ţĥîš ƀŕöŵšéŕ. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.site.panel.setbacks\":[\"[Šéţƀáçķš ~~~]\"],\"node.site.panel.showGround\":[\"[Šĥöŵ ĝŕöûñð ~~~]\"],\"node.site.panel.showTheContourLinesIn3d\":[\"[Šĥöŵ ţĥé çöñţöûŕ ļîñéš îñ 3Ð ~~~~~~~]\"],\"node.site.panel.side\":[\"[šîðé ~~]\"],\"node.site.panel.site\":[\"[Šîţé ~~]\"],\"node.site.panel.source\":[\"[Šöûŕçé ~~]\"],\"node.site.panel.sourceCitation\":[\"[Šöûŕçé / çîţáţîöñ ~~~~~]\"],\"node.site.panel.streetAddress\":[\"[Šţŕééţ áððŕéšš ~~~~]\"],\"node.site.panel.survey\":[\"[šûŕṽéý ~~]\"],\"node.site.panel.surveyedContours\":[\"[\",[\"count\",\"plural\",{\"one\":[[\"lineCount\"],\" šûŕṽéýéð ļîñé\"],\"other\":[[\"lineCount\"],\" šûŕṽéýéð ļîñéš\"]}],\" áţ \",[\"interval\"],\" ƒţ (\",[\"datum\"],\") — \",[\"source\"],\" ~~~~~~~~~]\"],\"node.site.panel.terrain\":[\"[Ţéŕŕáîñ ~~~]\"],\"node.site.panel.typeAnAddressFirst\":[\"[Ţýþé áñ áððŕéšš ƒîŕšţ. ~~~~~~]\"],\"node.site.panel.useProjectLook\":[\"[Ûšé þŕöĵéçţ ļööķ ~~~~~]\"],\"node.site.panel.zone\":[\"[Žöñé ~~]\"],\"node.site.setback.front\":[\"[Ƒŕöñţ ~~]\"],\"node.site.setback.leftOverride\":[\"[Ļéƒţ (öṽéŕŕîðé) ~~~~]\"],\"node.site.setback.rear\":[\"[Ŕéáŕ ~~]\"],\"node.site.setback.rightOverride\":[\"[Ŕîĝĥţ (öṽéŕŕîðé) ~~~~]\"],\"node.site.setback.side\":[\"[Šîðé ~~]\"],\"node.skylight.description\":[\"[Ƒŕáɱéð ĝļášš öþéñîñĝ öñ á ŕööƒ šéĝɱéñţ. ~~~~~~~~~~]\"],\"node.skylight.label\":[\"[Šķýļîĝĥţ ~~~]\"],\"node.skylight.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.skylight.panel.alongX\":[\"[Åļöñĝ Ẋ ~~]\"],\"node.skylight.panel.alongZ\":[\"[Åļöñĝ Ž ~~]\"],\"node.skylight.panel.bottom\":[\"[Ɓöţţöɱ ~~]\"],\"node.skylight.panel.curb\":[\"[Çûŕƀ ~~]\"],\"node.skylight.panel.cutoutOffset\":[\"[Çûţöûţ Öƒƒšéţ ~~~~]\"],\"node.skylight.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.skylight.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.skylight.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.skylight.panel.frame\":[\"[Ƒŕáɱé ~~]\"],\"node.skylight.panel.glassThickness\":[\"[Ĝļášš Ţĥîçķñéšš ~~~~~]\"],\"node.skylight.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.skylight.panel.lanternHeight\":[\"[Ļáñţéŕñ Ĥéîĝĥţ ~~~~]\"],\"node.skylight.panel.left\":[\"[Ļéƒţ ~~]\"],\"node.skylight.panel.motor\":[\"[Ṁöţöŕ ~~]\"],\"node.skylight.panel.motorHousing\":[\"[Ṁöţöŕ Ĥöûšîñĝ ~~~~]\"],\"node.skylight.panel.no\":[\"[Ñö ~]\"],\"node.skylight.panel.noMotor\":[\"[Ñö Ṁöţöŕ ~~~]\"],\"node.skylight.panel.open\":[\"[Öþéñ ~~]\"],\"node.skylight.panel.openingAngle\":[\"[Öþéñîñĝ Åñĝļé ~~~~]\"],\"node.skylight.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.skylight.panel.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.skylight.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.skylight.panel.skylight\":[\"[Šķýļîĝĥţ ~~~]\"],\"node.skylight.panel.thickness\":[\"[Ţĥîçķñéšš ~~~]\"],\"node.skylight.panel.top\":[\"[Ţöþ ~]\"],\"node.skylight.panel.topScale\":[\"[Ţöþ Šçáļé ~~~]\"],\"node.skylight.panel.trackWidth\":[\"[Ţŕáçķ Ŵîðţĥ ~~~]\"],\"node.skylight.panel.type\":[\"[Ţýþé ~~]\"],\"node.skylight.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.skylight.panel.yes\":[\"[Ýéš ~]\"],\"node.skylight.type.flat\":[\"[Ƒļáţ ŕööƒ šķýļîĝĥţ ~~~~~]\"],\"node.skylight.type.lantern\":[\"[Ŕööƒ ļáñţéŕñ ~~~~]\"],\"node.skylight.type.opening\":[\"[Öþéñîñĝ šķýļîĝĥţ ~~~~~]\"],\"node.skylight.type.sliding\":[\"[Šļîðîñĝ šķýļîĝĥţ ~~~~~]\"],\"node.skylight.type.walkOn\":[\"[Ŵáļķ-öñ ŕööƒļîĝĥţ ~~~~~]\"],\"node.slab.description\":[\"[Å þöļýĝöñ-ƀöûñðéð ƒļööŕ šûŕƒáçé ţĥáţ ĥöšţš îţéɱš öñ ţöþ. ~~~~~~~~~~~~~~]\"],\"node.slab.label\":[\"[Šļáƀ ~~]\"],\"node.slab.panel.addHole\":[\"[Åðð Ĥöļé ~~~]\"],\"node.slab.panel.area\":[\"[Åŕéá ~~]\"],\"node.slab.panel.auto\":[\"[Åûţö ~~]\"],\"node.slab.panel.base\":[\"[Ɓášé ~~]\"],\"node.slab.panel.cutHatch\":[\"[Çûţ ĥáţçĥ ~~~]\"],\"node.slab.panel.cutOpening\":[\"[Çûţ öþéñîñĝ ~~~]\"],\"node.slab.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.slab.panel.done\":[\"[Ðöñé ~~]\"],\"node.slab.panel.elevation\":[\"[Éļéṽáţîöñ ~~~]\"],\"node.slab.panel.extendsThePerimeterDownToTerrain\":[\"[Éẋţéñðš ţĥé þéŕîɱéţéŕ ðöŵñ ţö ţéŕŕáîñ. Ţĥé ƒļáţ šûŕƒáçé, ƀášé, áñð ţĥîçķñéšš šţáý ûñçĥáñĝéð. ~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.slab.panel.fixed\":[\"[Ƒîẋéð ~~]\"],\"node.slab.panel.floor\":[\"[Ƒļööŕ ~~]\"],\"node.slab.panel.followsTerrain\":[\"[Ƒöļļöŵš ţéŕŕáîñ ~~~~~]\"],\"node.slab.panel.foundation\":[\"[Ƒöûñðáţîöñ ~~~]\"],\"node.slab.panel.holes\":[\"[Ĥöļéš ~~]\"],\"node.slab.panel.info\":[\"[Îñƒö ~~]\"],\"node.slab.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.slab.panel.noHoles\":[\"[Ñö ĥöļéš ~~~]\"],\"node.slab.panel.rim\":[\"[Ŕîɱ ~]\"],\"node.slab.panel.slab\":[\"[Šļáƀ ~~]\"],\"node.slab.panel.standard2\":[\"[Šţáñðáŕð (2\\\") ~~~]\"],\"node.slab.panel.standard5cm\":[\"[Šţáñðáŕð (5çɱ) ~~~]\"],\"node.slab.panel.sunken15cm\":[\"[Šûñķéñ (15çɱ) ~~~]\"],\"node.slab.panel.sunken6\":[\"[Šûñķéñ (6\\\") ~~]\"],\"node.slab.panel.surface\":[\"[Šûŕƒáçé ~~~]\"],\"node.slab.panel.thick15cm\":[\"[Ţĥîçķ (15çɱ) ~~~]\"],\"node.slab.panel.thick6\":[\"[Ţĥîçķ (6\\\") ~~]\"],\"node.slab.panel.thickness\":[\"[Ţĥîçķñéšš ~~~]\"],\"node.slab.panel.thin1\":[\"[Ţĥîñ (1\\\") ~~]\"],\"node.slab.panel.thin2cm\":[\"[Ţĥîñ (2çɱ) ~~]\"],\"node.solarPanel.description\":[\"[Ĝŕîð öƒ þĥöţöṽöļţáîç þáñéļš ɱöûñţéð öñ á ŕööƒ šéĝɱéñţ. ~~~~~~~~~~~~~~]\"],\"node.solarPanel.label\":[\"[Šöļáŕ Þáñéļ ~~~]\"],\"node.solarPanel.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.solarPanel.panel.array\":[\"[Åŕŕáý ~~]\"],\"node.solarPanel.panel.autoFitToRoof\":[\"[Åûţö-ƒîţ ţö ŕööƒ ~~~~]\"],\"node.solarPanel.panel.columns\":[\"[Çöļûɱñš ~~~]\"],\"node.solarPanel.panel.customDimensionsDonTMatchAny\":[\"[Çûšţöɱ — ðîɱéñšîöñš ðöñ'ţ ɱáţçĥ áñý þŕéšéţ ~~~~~~~~~~~]\"],\"node.solarPanel.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.solarPanel.panel.flipOrientation\":[\"[Ƒļîþ öŕîéñţáţîöñ ~~~~~]\"],\"node.solarPanel.panel.flush\":[\"[Ƒļûšĥ ~~]\"],\"node.solarPanel.panel.frameDepth\":[\"[Ƒŕáɱé ðéþţĥ ~~~]\"],\"node.solarPanel.panel.frameThickness\":[\"[Ƒŕáɱé ţĥîçķñéšš ~~~~~]\"],\"node.solarPanel.panel.gapX\":[\"[Ĝáþ Ẋ ~~]\"],\"node.solarPanel.panel.gapY\":[\"[Ĝáþ Ý ~~]\"],\"node.solarPanel.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.solarPanel.panel.mounting\":[\"[Ṁöûñţîñĝ ~~~]\"],\"node.solarPanel.panel.panel\":[\"[Þáñéļ ~~]\"],\"node.solarPanel.panel.preset\":[\"[Þŕéšéţ ~~]\"],\"node.solarPanel.panel.rows\":[\"[Ŕöŵš ~~]\"],\"node.solarPanel.panel.setbacksTooLarge\":[\"[Šéţƀáçķš ţöö ļáŕĝé ţö ƒîţ á þáñéļ. ~~~~~~~~~]\"],\"node.solarPanel.panel.solarPanel\":[\"[Šöļáŕ Þáñéļ ~~~]\"],\"node.solarPanel.panel.standoff\":[\"[Šţáñðöƒƒ ~~~]\"],\"node.solarPanel.panel.tiltAngle\":[\"[Ţîļţ áñĝļé ~~~]\"],\"node.solarPanel.panel.tilted\":[\"[Ţîļţéð ~~]\"],\"node.solarPanel.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.solarPanel.preset.compact\":[\"[Çöɱþáçţ ~~~]\"],\"node.solarPanel.preset.frameless\":[\"[Ƒŕáɱéļéšš ~~~]\"],\"node.solarPanel.preset.residential\":[\"[Ŕéšîðéñţîáļ ~~~~]\"],\"node.solarPanel.preset.residentialLarge\":[\"[Ŕéšîðéñţîáļ Ļáŕĝé ~~~~~]\"],\"node.spawn.description\":[\"[Þļáýéŕ öŕ çáɱéŕá öŕîĝîñ ŵîţĥîñ á ļéṽéļ. Öñé þéŕ ļéṽéļ. ~~~~~~~~~~~~~]\"],\"node.spawn.label\":[\"[Šþáŵñ Þöîñţ ~~~]\"],\"node.stair.constructionControls.body\":[\"[Ɓöðý ~~]\"],\"node.stair.constructionControls.centerStringer\":[\"[Çéñţéŕ šţŕîñĝéŕ ~~~~~]\"],\"node.stair.constructionControls.closedRisers\":[\"[Çļöšéð ŕîšéŕš ~~~~]\"],\"node.stair.constructionControls.inherit\":[\"[Îñĥéŕîţ ~~~]\"],\"node.stair.constructionControls.nosing\":[\"[Ñöšîñĝ ~~]\"],\"node.stair.constructionControls.open\":[\"[Öþéñ ~~]\"],\"node.stair.constructionControls.original\":[\"[Öŕîĝîñáļ ~~~]\"],\"node.stair.constructionControls.riserThickness\":[\"[Ŕîšéŕ ţĥîçķñéšš ~~~~~]\"],\"node.stair.constructionControls.sideStringers\":[\"[Šîðé šţŕîñĝéŕš ~~~~]\"],\"node.stair.constructionControls.solid\":[\"[Šöļîð ~~]\"],\"node.stair.constructionControls.stringerDepth\":[\"[Šţŕîñĝéŕ ðéþţĥ ~~~~]\"],\"node.stair.constructionControls.stringerWidth\":[\"[Šţŕîñĝéŕ ŵîðţĥ ~~~~]\"],\"node.stair.constructionControls.treadFinish\":[\"[Ţŕéáð ƒîñîšĥ ~~~~]\"],\"node.stair.constructionControls.treadThickness\":[\"[Ţŕéáð ţĥîçķñéšš ~~~~~]\"],\"node.stair.constructionControls.waist\":[\"[Ŵáîšţ ~~]\"],\"node.stair.constructionControls.waistThickness\":[\"[Ŵáîšţ ţĥîçķñéšš ~~~~~]\"],\"node.stair.description\":[\"[Å šţáîŕ çöɱþöšéð öƒ öñé öŕ ɱöŕé ƒļîĝĥţš ŵîţĥ çöñƒîĝûŕáƀļé ţŕéáðš, ŕîšéŕš, ŕáîļîñĝš. ~~~~~~~~~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.arrivalMismatch\":[\"[Ţĥé ƒļîĝĥţ çĥáîñ ðöéš ñöţ ŕéáçĥ ţĥé ðéçļáŕéð ðéšţîñáţîöñ. ~~~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.comfortTarget\":[\"[Ţŵö ŕîšéŕš þļûš ĝöîñĝ îš öûţšîðé ţĥé 0.60–0.65 ɱ ðéšîĝñ ŕáñĝé. ~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.goingTarget\":[\"[Ĝöîñĝ îš ƀéļöŵ ţĥé ðéšîĝñ ţáŕĝéţ. ~~~~~~~~~]\"],\"node.stair.diagnostic.headroomTarget\":[\"[Öṽéŕĥéáð šûŕƒáçéš ļéáṽé ļéšš ţĥáñ ţĥé ţáŕĝéţ ĥéáðŕööɱ. ~~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.headroomUnresolved\":[\"[Ðéţáîļéð ĥéáðŕööɱ çöûļð ñöţ ƀé éṽáļûáţéð: çĥéçķ ŕîšéŕ çöûñţš áñð ţĥé šûŕƒáçé ǫûéŕý ƀûðĝéţ. ~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.invalidFlight\":[\"[Ƒļîĝĥţ ðîɱéñšîöñš áñð îñţéĝéŕ ŕîšéŕ çöûñţ ɱûšţ ƀé þöšîţîṽé. ~~~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.invalidRise\":[\"[Ţĥé ðéšţîñáţîöñ ɱûšţ ƀé áƀöṽé ţĥé šţáîŕ ƀášé. ~~~~~~~~~~~~]\"],\"node.stair.diagnostic.landingOverlap\":[\"[Ļáñðîñĝ ðéþţĥ éẋçééðš á ƒûļļ çîŕçļé áţ ţĥé ŵáļķîñĝ ļîñé; ţĥé ṽîšîƀļé ļáñðîñĝ îš ļîɱîţéð ţö öñé çîŕçļé. ~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.narrowWinderEnd\":[\"[Ţĥé ñáŕŕöŵ éñð öƒ á ŵîñðéŕ ţŕéáð îš ƀéļöŵ 0.10 ɱ; çĥéçķ ţĥé îñţéñðéð šţáîŕ ûšé. ~~~~~~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.nonuniformRisers\":[\"[Ƒļîĝĥţ ŕîšéŕ ĥéîĝĥţš ðéŕ. Ûšé ûñîƒöŕɱ-ŕîšéŕ ŕéþáîŕ öñļý îƒ ţĥîš îš á þŕöþöšéð ðéšîĝñ. ~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.raisedLanding\":[\"[Å ļáñðîñĝ ĥáš á šţöŕéð ŕîšé; îñšþéçţ îţš ţŕáñšîţîöñ ƀéƒöŕé ŕéþáîŕ. ~~~~~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.riserTarget\":[\"[Ŕîšéŕ ĥéîĝĥţ éẋçééðš ţĥé ðéšîĝñ ţáŕĝéţ. ~~~~~~~~~~]\"],\"node.stair.label\":[\"[Šţáîŕ ~~]\"],\"node.stair.layout.straight\":[\"[Šţŕáîĝĥţ ~~~]\"],\"node.stair.layout.turn\":[\"[\",[\"layout\"],\" ţûŕñ ~~]\"],\"node.stair.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.stair.panel.addFlight\":[\"[Åðð ƒļîĝĥţ ~~~]\"],\"node.stair.panel.addLanding\":[\"[Åðð ļáñðîñĝ ~~~]\"],\"node.stair.panel.applyLabelLayout\":[\"[Åþþļý \",[\"label\"],\" ļáýöûţ ~~~~]\"],\"node.stair.panel.autoCutout\":[\"[Åûţö Çûţöûţ ~~~]\"],\"node.stair.panel.balusters\":[\"[Ɓáļûšţéŕš ~~~]\"],\"node.stair.panel.boards\":[\"[Ɓöáŕðš ~~]\"],\"node.stair.panel.both\":[\"[Ɓöţĥ ~~]\"],\"node.stair.panel.cable\":[\"[Çáƀļé ~~]\"],\"node.stair.panel.centerColumn\":[\"[Çéñţéŕ Çöļûɱñ ~~~~]\"],\"node.stair.panel.clockwise\":[\"[Çļöçķŵîšé ~~~]\"],\"node.stair.panel.connectedTo\":[\"[Çöññéçţéð ţö \",[\"surface\"],\". Ṁöṽé ţĥé šţáîŕ ţö çöññéçţ ţö áñöţĥéŕ éðĝé. ~~~~~~~~~~~~~~]\"],\"node.stair.panel.connectedToSurface\":[\"[Çöññéçţéð ţö á šûŕƒáçé. Ṁöṽé ţĥé šţáîŕ ţö çöññéçţ ţö áñöţĥéŕ éðĝé. ~~~~~~~~~~~~~~~~]\"],\"node.stair.panel.construction\":[\"[Çöñšţŕûçţîöñ ~~~~]\"],\"node.stair.panel.counterclockwise\":[\"[Çöûñţéŕçļöçķŵîšé ~~~~~]\"],\"node.stair.panel.curved\":[\"[Çûŕṽéð ~~]\"],\"node.stair.panel.customRise\":[\"[Çûšţöɱ ŕîšé ~~~]\"],\"node.stair.panel.deck\":[\"[Ðéçķ ~~]\"],\"node.stair.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.stair.panel.designTargets\":[\"[Ðéšîĝñ ţáŕĝéţš ~~~~]\"],\"node.stair.panel.destination\":[\"[Ðéšţîñáţîöñ ~~~~]\"],\"node.stair.panel.dragNearADeckPatioConcrete\":[\"[Ðŕáĝ ñéáŕ á ðéçķ, þáţîö, çöñçŕéţé šļáƀ, öŕ ļáñðîñĝ éðĝé ţö ƒîţ ţĥé šţáîŕ. ~~~~~~~~~~~~~~~~~]\"],\"node.stair.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.stair.panel.equalAngle\":[\"[Éǫûáļ áñĝļé ~~~]\"],\"node.stair.panel.equalGoing\":[\"[Éǫûáļ ĝöîñĝ ~~~]\"],\"node.stair.panel.fitRisersAndGoing\":[\"[Ƒîţ ŕîšéŕš áñð ĝöîñĝ ~~~~~~]\"],\"node.stair.panel.fitToFloor\":[\"[Ƒîţ Ţö Ƒļööŕ ~~~]\"],\"node.stair.panel.fitUniformRisers\":[\"[Ƒîţ ûñîƒöŕɱ ŕîšéŕš ~~~~~]\"],\"node.stair.panel.flightMeasurements\":[\"[Ƒļîĝĥţ \",[\"number\"],\": \",[\"count\",\"plural\",{\"one\":[[\"riserCount\"],\" ŕîšéŕ\"],\"other\":[[\"riserCount\"],\" ŕîšéŕš\"]}],\" · Ŕ \",[\"riser\"],\" · Ţ \",[\"going\"],\" · \",[\"slope\"],\" ~~~~~~]\"],\"node.stair.panel.floorsCeilingsAndStairsOnly\":[\"[Ƒļööŕš, çéîļîñĝš áñð šţáîŕš öñļý. ~~~~~~~~~]\"],\"node.stair.panel.followsDeck\":[\"[Ƒöļļöŵš ðéçķ ~~~~]\"],\"node.stair.panel.followsLevel\":[\"[Ƒöļļöŵš ļéṽéļ ~~~~]\"],\"node.stair.panel.fromLevel\":[\"[Ƒŕöɱ Ļéṽéļ ~~~]\"],\"node.stair.panel.geometry\":[\"[Ĝéöɱéţŕý ~~~]\"],\"node.stair.panel.glass\":[\"[Ĝļášš ~~]\"],\"node.stair.panel.headroom\":[\"[Ĥéáðŕööɱ: ~~~]\"],\"node.stair.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.stair.panel.innerGap\":[\"[Îññéŕ ĝáþ ~~~]\"],\"node.stair.panel.innerRadius\":[\"[Îññéŕ Ŕáðîûš ~~~~]\"],\"node.stair.panel.integrated\":[\"[Îñţéĝŕáţéð ~~~]\"],\"node.stair.panel.landing\":[\"[Ļáñðîñĝ ~~~]\"],\"node.stair.panel.layout\":[\"[Ļáýöûţ ~~]\"],\"node.stair.panel.left\":[\"[Ļéƒţ ~~]\"],\"node.stair.panel.leftTurn\":[\"[Ļéƒţ ţûŕñ ~~~]\"],\"node.stair.panel.measurements\":[\"[Ṁéášûŕéɱéñţš ~~~~]\"],\"node.stair.panel.metal\":[\"[Ṁéţáļ ~~]\"],\"node.stair.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.stair.panel.movingThisStairKeepsItsCurrent\":[\"[Ṁöṽîñĝ ţĥîš šţáîŕ ķééþš îţš çûŕŕéñţ ŕîšé, šţéþš, áñð ŕûñ. ~~~~~~~~~~~~~~]\"],\"node.stair.panel.noOverheadSurface\":[\"[Ñö öṽéŕĥéáð šûŕƒáçé ~~~~~~]\"],\"node.stair.panel.none\":[\"[Ñöñé ~~]\"],\"node.stair.panel.notEvaluated\":[\"[Ñöţ éṽáļûáţéð ~~~~]\"],\"node.stair.panel.opening\":[\"[Öþéñîñĝ ~~~]\"],\"node.stair.panel.openingOffset\":[\"[Öþéñîñĝ Öƒƒšéţ ~~~~]\"],\"node.stair.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.stair.panel.postRail\":[\"[Þöšţ & ŕáîļ ~~~]\"],\"node.stair.panel.railing\":[\"[Ŕáîļîñĝ ~~~]\"],\"node.stair.panel.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.stair.panel.rightTurn\":[\"[Ŕîĝĥţ ţûŕñ ~~~]\"],\"node.stair.panel.rise\":[\"[Ŕîšé ~~]\"],\"node.stair.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.stair.panel.segmentType\":[\"[\",[\"type\",\"select\",{\"landing\":[\"Ļáñðîñĝ\"],\"other\":[\"Šţáîŕ\"]}],\" ~~~~]\"],\"node.stair.panel.segments\":[\"[Šéĝɱéñţš ~~~]\"],\"node.stair.panel.sizing\":[\"[Šîžîñĝ ~~]\"],\"node.stair.panel.snapToNearbySurfaces\":[\"[Šñáþ ţö ñéáŕƀý šûŕƒáçéš ~~~~~~]\"],\"node.stair.panel.spiral\":[\"[Šþîŕáļ ~~]\"],\"node.stair.panel.staircase\":[\"[Šţáîŕçášé ~~~]\"],\"node.stair.panel.stepSupports\":[\"[Šţéþ Šûþþöŕţš ~~~~]\"],\"node.stair.panel.steps\":[\"[Šţéþš ~~]\"],\"node.stair.panel.straight\":[\"[Šţŕáîĝĥţ ~~~]\"],\"node.stair.panel.style\":[\"[Šţýļé ~~]\"],\"node.stair.panel.surfaceConnection\":[\"[Šûŕƒáçé çöññéçţîöñ ~~~~~~]\"],\"node.stair.panel.sweep\":[\"[Šŵééþ ~~]\"],\"node.stair.panel.targetGoing\":[\"[Ţáŕĝéţ ĝöîñĝ ~~~~]\"],\"node.stair.panel.targetHeadroom\":[\"[Ţáŕĝéţ ĥéáðŕööɱ ~~~~~]\"],\"node.stair.panel.targetMaxRiser\":[\"[Ţáŕĝéţ ɱáẋ ŕîšéŕ ~~~~~]\"],\"node.stair.panel.targetMinimumGoing\":[\"[Ţáŕĝéţ ɱîñîɱûɱ ĝöîñĝ ~~~~~~]\"],\"node.stair.panel.thickness\":[\"[Ţĥîçķñéšš ~~~]\"],\"node.stair.panel.to\":[\"[Ţö ~]\"],\"node.stair.panel.topLanding\":[\"[Ţöþ Ļáñðîñĝ ~~~]\"],\"node.stair.panel.type\":[\"[Ţýþé ~~]\"],\"node.stair.panel.unavailable\":[\"[Ûñáṽáîļáƀļé ~~~~]\"],\"node.stair.panel.walkingLineOffset\":[\"[Ŵáļķîñĝ ļîñé öƒƒšéţ ~~~~~~]\"],\"node.stair.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.stair.panel.winder\":[\"[Ŵîñðéŕ ~~]\"],\"node.stair.railingControls.both\":[\"[Ɓöţĥ ~~]\"],\"node.stair.railingControls.bottomExtension\":[\"[Ɓöţţöɱ šļöþéð éẋţéñšîöñ ~~~~~~~]\"],\"node.stair.railingControls.continuous\":[\"[Çöñţîñûöûš ~~~]\"],\"node.stair.railingControls.floor\":[\"[Ƒļööŕ ~~]\"],\"node.stair.railingControls.handrailDiameter\":[\"[Ĥáñðŕáîļ ðîáɱéţéŕ ~~~~~]\"],\"node.stair.railingControls.handrailHeight\":[\"[Ĥáñðŕáîļ ĥéîĝĥţ ~~~~~]\"],\"node.stair.railingControls.handrailInset\":[\"[Ĥáñðŕáîļ îñšéţ ~~~~]\"],\"node.stair.railingControls.left\":[\"[Ļéƒţ ~~]\"],\"node.stair.railingControls.noReturn\":[\"[Ñö ŕéţûŕñ ~~~]\"],\"node.stair.railingControls.none\":[\"[Ñöñé ~~]\"],\"node.stair.railingControls.originalLayout\":[\"[Öŕîĝîñáļ ļáýöûţ ~~~~~]\"],\"node.stair.railingControls.postFacing\":[\"[Þöšţ-ƒáçîñĝ ~~~]\"],\"node.stair.railingControls.returnLength\":[\"[Ŕéţûŕñ ļéñĝţĥ ~~~~]\"],\"node.stair.railingControls.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.stair.railingControls.separateHandrail\":[\"[Šéþáŕáţé ĥáñðŕáîļ ~~~~~]\"],\"node.stair.railingControls.setTheLengthToReachThe\":[\"[Šéţ ţĥé ļéñĝţĥ ţö ŕéáçĥ ţĥé ŵáļļ öŕ þöšţ. ~~~~~~~~~~]\"],\"node.stair.railingControls.topExtension\":[\"[Ţöþ ĥöŕîžöñţáļ éẋţéñšîöñ ~~~~~~~]\"],\"node.stair.railingControls.wallFacing\":[\"[Ŵáļļ-ƒáçîñĝ ~~~]\"],\"node.stairSegment.description\":[\"[Å šîñĝļé ƒļîĝĥţ öƒ á þáŕéñţ šţáîŕ. ~~~~~~~~~]\"],\"node.stairSegment.label\":[\"[Šţáîŕ Šéĝɱéñţ ~~~~]\"],\"node.stairSegment.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.stairSegment.panel.attachment\":[\"[Åţţáçĥɱéñţ ~~~]\"],\"node.stairSegment.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.stairSegment.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.stairSegment.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.stairSegment.panel.editingSwitchesTheStairToCustom\":[\"[Éðîţîñĝ šŵîţçĥéš ţĥé šţáîŕ ţö Çûšţöɱ ŕîšé ~~~~~~~~~~~]\"],\"node.stairSegment.panel.equalAngle\":[\"[Éǫûáļ áñĝļé ~~~]\"],\"node.stairSegment.panel.equalGoing\":[\"[Éǫûáļ ĝöîñĝ ~~~]\"],\"node.stairSegment.panel.fillToFloor\":[\"[Ƒîļļ ţö ƒļööŕ ~~~~]\"],\"node.stairSegment.panel.flight\":[\"[Ƒļîĝĥţ ~~]\"],\"node.stairSegment.panel.flightShape\":[\"[Ƒļîĝĥţ šĥáþé ~~~~]\"],\"node.stairSegment.panel.front\":[\"[Ƒŕöñţ ~~]\"],\"node.stairSegment.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.stairSegment.panel.innerGap\":[\"[Îññéŕ ĝáþ ~~~]\"],\"node.stairSegment.panel.landing\":[\"[Ļáñðîñĝ ~~~]\"],\"node.stairSegment.panel.left\":[\"[Ļéƒţ ~~]\"],\"node.stairSegment.panel.leftTurn\":[\"[Ļéƒţ ţûŕñ ~~~]\"],\"node.stairSegment.panel.length\":[\"[Ļéñĝţĥ ~~]\"],\"node.stairSegment.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.stairSegment.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.stairSegment.panel.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.stairSegment.panel.rightTurn\":[\"[Ŕîĝĥţ ţûŕñ ~~~]\"],\"node.stairSegment.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.stairSegment.panel.stairSegment\":[\"[Šţáîŕ Šéĝɱéñţ ~~~~]\"],\"node.stairSegment.panel.steps\":[\"[Šţéþš ~~]\"],\"node.stairSegment.panel.straight\":[\"[Šţŕáîĝĥţ ~~~]\"],\"node.stairSegment.panel.structure\":[\"[Šţŕûçţûŕé ~~~]\"],\"node.stairSegment.panel.thickness\":[\"[Ţĥîçķñéšš ~~~]\"],\"node.stairSegment.panel.type\":[\"[Ţýþé ~~]\"],\"node.stairSegment.panel.walkingLineOffset\":[\"[Ŵáļķîñĝ ļîñé öƒƒšéţ ~~~~~~]\"],\"node.stairSegment.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.stairSegment.panel.winder\":[\"[Ŵîñðéŕ ~~]\"],\"node.structuralGrid.description\":[\"[Þéŕšîšţéñţ çöñšţŕûçţîöñ ĝŕîð áẋîš ŵîţĥ îðéñţîƒîçáţîöñ ƀûƀƀļéš. ~~~~~~~~~~~~~~~~~]\"],\"node.structuralGrid.label\":[\"[Šţŕûçţûŕáļ Ĝŕîð ~~~~~]\"],\"node.turbineVent.description\":[\"[Ŵîñð-ðŕîṽéñ šþîññîñĝ ŵĥîŕļýƀîŕð éẋĥáûšţ ṽéñţ ƒöŕ á ŕööƒ šļöþé. ~~~~~~~~~~~~~~~~]\"],\"node.turbineVent.label\":[\"[Ţûŕƀîñé Ṽéñţ ~~~~]\"],\"node.turbineVent.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.turbineVent.panel.cylinder\":[\"[Çýļîñðéŕ ~~~]\"],\"node.turbineVent.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.turbineVent.panel.diameter\":[\"[Ðîáɱéţéŕ ~~~]\"],\"node.turbineVent.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.turbineVent.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.turbineVent.panel.globe\":[\"[Ĝļöƀé ~~]\"],\"node.turbineVent.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.turbineVent.panel.motion\":[\"[Ṁöţîöñ ~~]\"],\"node.turbineVent.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.turbineVent.panel.neckHeight\":[\"[Ñéçķ Ĥéîĝĥţ ~~~]\"],\"node.turbineVent.panel.pause\":[\"[Þáûšé ~~]\"],\"node.turbineVent.panel.play\":[\"[Þļáý ~~]\"],\"node.turbineVent.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.turbineVent.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.turbineVent.panel.spinSpeed\":[\"[Šþîñ Šþééð ~~~]\"],\"node.turbineVent.panel.style\":[\"[Šţýļé ~~]\"],\"node.turbineVent.panel.turbineVent\":[\"[Ţûŕƀîñé Ṽéñţ ~~~~]\"],\"node.turbineVent.panel.vanes\":[\"[Ṽáñéš ~~]\"],\"node.unit.description\":[\"[Å ñáɱéð ĝŕöûþ öƒ žöñéš ƒöŕɱîñĝ öñé áþáŕţɱéñţ, ĥöţéļ ŕööɱ öŕ çöɱɱéŕçîáļ ļöţ. ~~~~~~~~~~~~~~~~~~~]\"],\"node.unit.kind.apartment\":[\"[Åþáŕţɱéñţ ~~~]\"],\"node.unit.kind.commercial\":[\"[Çöɱɱéŕçîáļ ~~~]\"],\"node.unit.kind.common\":[\"[Çöɱɱöñ ~~]\"],\"node.unit.kind.hotelRoom\":[\"[Ĥöţéļ ŕööɱ ~~~]\"],\"node.unit.label\":[\"[Ûñîţ ~~]\"],\"node.unit.panel.memberRoom\":[\"[Ŕööɱ ~~]\"],\"node.unit.panel.memberZone\":[\"[Žöñé ~~]\"],\"node.unit.panel.noZonesAssigned\":[\"[Ñö žöñéš áššîĝñéð ýéţ. ~~~~~~]\"],\"node.unit.panel.nonAdjacentLevels\":[\"[Ṁéɱƀéŕš šîţ öñ ļéṽéļš ţĥáţ áŕé ñöţ áðĵáçéñţ. ~~~~~~~~~~~]\"],\"node.unit.panel.removeMember\":[\"[Ŕéɱöṽé \",[\"name\"],\" ƒŕöɱ ûñîţ ~~~~~]\"],\"node.unit.panel.removeZone\":[\"[Ŕéɱöṽé žöñé ƒŕöɱ ûñîţ ~~~~~~]\"],\"node.unit.unitPanel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.unit.unitPanel.color\":[\"[Çöļöŕ ~~]\"],\"node.unit.unitPanel.delete\":[\"[Ðéļéţé ~~]\"],\"node.unit.unitPanel.focus\":[\"[Ƒöçûš ~~]\"],\"node.unit.unitPanel.grossArea\":[\"[Ĝŕöšš áŕéá ~~~]\"],\"node.unit.unitPanel.kind\":[\"[Ķîñð ~~]\"],\"node.unit.unitPanel.levels\":[\"[Ļéṽéļš ~~]\"],\"node.unit.unitPanel.members\":[\"[Ṁéɱƀéŕš ~~~]\"],\"node.unit.unitPanel.name\":[\"[Ñáɱé ~~]\"],\"node.unit.unitPanel.noRoomsYetPickThisUnit\":[\"[Ñö ŕööɱš ýéţ. Þîçķ ţĥîš ûñîţ ƒŕöɱ á ŕööɱ'š þáñéļ, öŕ ðŕáŵ žöñéš ŵĥîļé îţ îš ƒöçûšéð. ~~~~~~~~~~~~~~~~~~~~]\"],\"node.unit.unitPanel.report\":[\"[Ŕéþöŕţ ~~]\"],\"node.unit.unitPanel.unit\":[\"[Ûñîţ ~~]\"],\"node.wall.actions.mergeWalls\":[\"[Ṁéŕĝé ŵáļļš ~~~]\"],\"node.wall.actions.splitWall\":[\"[Šþļîţ ŵáļļ ~~~]\"],\"node.wall.curtain.cell\":[\"[Çöļûɱñ \",[\"column\"],\", ŕöŵ \",[\"row\"],\": \",[\"type\",\"select\",{\"glass\":[\"ĝļášš\"],\"solid\":[\"šöļîð\"],\"other\":[\"éɱþţý\"]}],\" ~~~~~~~~]\"],\"node.wall.curtain.columnSpacing\":[\"[\",[\"count\",\"plural\",{\"one\":[[\"number\"],\" çöļûɱñ\"],\"other\":[[\"number\"],\" çöļûɱñš\"]}],\" · \",[\"spacing\"],\" ĝŕîð šþáçîñĝ ~~~~~~~~]\"],\"node.wall.curtain.noPanels\":[\"[Ñö þáñéļš ~~~]\"],\"node.wall.curtain.rowSpacing\":[\"[\",[\"count\",\"plural\",{\"one\":[[\"number\"],\" ŕöŵ\"],\"other\":[[\"number\"],\" ŕöŵš\"]}],\" · \",[\"spacing\"],\" ĝŕîð šþáçîñĝ ~~~~~~]\"],\"node.wall.curtainWallPanel.applyTint\":[\"[Åþþļý ţîñţ ~~~]\"],\"node.wall.curtainWallPanel.borderOpeningFrame\":[\"[Ɓöŕðéŕ / öþéñîñĝ ƒŕáɱé ~~~~~~]\"],\"node.wall.curtainWallPanel.bottom\":[\"[Ɓöţţöɱ ~~]\"],\"node.wall.curtainWallPanel.bottomRow\":[\"[Ɓöţţöɱ ŕöŵ ~~~]\"],\"node.wall.curtainWallPanel.cancelTint\":[\"[Çáñçéļ ţîñţ ~~~]\"],\"node.wall.curtainWallPanel.center\":[\"[Çéñţéŕ ~~]\"],\"node.wall.curtainWallPanel.chooseACellOrEnterIts\":[\"[Çĥööšé á çéļļ öŕ éñţéŕ îţš çöļûɱñ áñð ŕöŵ. Ûšé áŕŕöŵ ķéýš ţö ɱöṽé ƀéţŵééñ çéļļš. Çöļûɱñš ŕûñ ƒŕöɱ ţĥé ŵáļļ šţáŕţ; ŕöŵš çöûñţ ûþŵáŕð. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.clearHiddenOverrides\":[\"[Çļéáŕ ĥîððéñ öṽéŕŕîðéš ~~~~~~]\"],\"node.wall.curtainWallPanel.column\":[\"[Çöļûɱñ ~~]\"],\"node.wall.curtainWallPanel.columnLayout\":[\"[Çöļûɱñ ļáýöûţ ~~~~]\"],\"node.wall.curtainWallPanel.columnRow\":[\"[Çöļûɱñ \",[\"column\"],\", ŕöŵ \",[\"row\"],\" ~~~]\"],\"node.wall.curtainWallPanel.construction\":[\"[Çöñšţŕûçţîöñ ~~~~]\"],\"node.wall.curtainWallPanel.continuousMullionsAndTransomsAssembledAlong\":[\"[Çöñţîñûöûš ɱûļļîöñš áñð ţŕáñšöɱš áššéɱƀļéð áļöñĝ ţĥé ŵáļļ. ~~~~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.curtainWallPanelSelection\":[\"[Çûŕţáîñ ŵáļļ þáñéļ šéļéçţîöñ ~~~~~~~~]\"],\"node.wall.curtainWallPanel.customInfill\":[\"[Çûšţöɱ îñƒîļļ ~~~~]\"],\"node.wall.curtainWallPanel.defaultPanel\":[\"[Ðéƒáûļţ þáñéļ ~~~~]\"],\"node.wall.curtainWallPanel.editIndividualPanels\":[\"[Éðîţ îñðîṽîðûáļ þáñéļš ~~~~~~]\"],\"node.wall.curtainWallPanel.effectiveThicknessLimited\":[\"[Ƀƒéçţîṽé ţĥîçķñéšš: \",[\"thickness\"],\", ļîɱîţéð ƀý ƒŕáɱé ðéþţĥ. ~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.empty\":[\"[Éɱþţý ~~]\"],\"node.wall.curtainWallPanel.enablePanelEditing\":[\"[Éñáƀļé þáñéļ éðîţîñĝ ~~~~~~]\"],\"node.wall.curtainWallPanel.end\":[\"[Éñð ~]\"],\"node.wall.curtainWallPanel.fixedSpacing\":[\"[Ƒîẋéð šþáçîñĝ ~~~~]\"],\"node.wall.curtainWallPanel.followingWallDefaults\":[\"[Ƒöļļöŵîñĝ ŵáļļ ðéƒáûļţš ~~~~~~~]\"],\"node.wall.curtainWallPanel.frameDimensions\":[\"[Ƒŕáɱé ðîɱéñšîöñš ~~~~~]\"],\"node.wall.curtainWallPanel.framing\":[\"[Ƒŕáɱîñĝ ~~~]\"],\"node.wall.curtainWallPanel.fullyCapped\":[\"[Ƒûļļý çáþþéð ~~~~]\"],\"node.wall.curtainWallPanel.glass\":[\"[Ĝļášš ~~]\"],\"node.wall.curtainWallPanel.glassAppearance\":[\"[Ĝļášš áþþéáŕáñçé ~~~~~]\"],\"node.wall.curtainWallPanel.glassAppearanceIsControlledByThe\":[\"[Ĝļášš áþþéáŕáñçé îš çöñţŕöļļéð ƀý ţĥé þáîñţ ţööļ. ~~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.glassTint\":[\"[Ĝļášš ţîñţ ~~~]\"],\"node.wall.curtainWallPanel.glazingGap\":[\"[Ĝļážîñĝ ĝáþ ~~~]\"],\"node.wall.curtainWallPanel.gridLimitedTo32PanelsPer\":[\"[Ĝŕîð ļîɱîţéð ţö 32 þáñéļš þéŕ áẋîš. Šþáçîñĝ éẋþáñðš ţö ƒîţ ţĥîš ŵáļļ. ~~~~~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.hiddenCustomPanelCount\":[\"[\",[\"length\",\"plural\",{\"one\":[[\"number\"],\" çûšţöɱ þáñéļ îš öûţšîðé ţĥîš ĝŕîð. Îţ ŕéţûŕñš îƒ ţĥé ĝŕîð éẋþáñðš.\"],\"other\":[[\"number\"],\" çûšţöɱ þáñéļš áŕé öûţšîðé ţĥîš ĝŕîð. Ţĥéý ŕéţûŕñ îƒ ţĥé ĝŕîð éẋþáñðš.\"]}],\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.horizontalCaps\":[\"[Ĥöŕîžöñţáļ çáþš ~~~~~]\"],\"node.wall.curtainWallPanel.horizontalFrameWidth\":[\"[Ĥöŕîžöñţáļ ƒŕáɱé ŵîðţĥ ~~~~~~]\"],\"node.wall.curtainWallPanel.layout\":[\"[Ļáýöûţ ~~]\"],\"node.wall.curtainWallPanel.lowRoughnessIsSmoothHighRoughness\":[\"[Ļöŵ ŕöûĝĥñéšš îš šɱööţĥ; ĥîĝĥ ŕöûĝĥñéšš ĝîṽéš á ɱáţţé šûŕƒáçé îñ ŕéñðéŕéð šĥáðîñĝ. ~~~~~~~~~~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.maximumSpacing\":[\"[Ṁáẋîɱûɱ šþáçîñĝ ~~~~~]\"],\"node.wall.curtainWallPanel.moduleJointWidth\":[\"[Ṁöðûļé ĵöîñţ ŵîðţĥ ~~~~~]\"],\"node.wall.curtainWallPanel.none\":[\"[Ñöñé ~~]\"],\"node.wall.curtainWallPanel.opacity\":[\"[Öþáçîţý ~~~]\"],\"node.wall.curtainWallPanel.opaqueBand\":[\"[Öþáǫûé ƀáñð ~~~]\"],\"node.wall.curtainWallPanel.opaqueBandsReplaceAFullRow\":[\"[Öþáǫûé ƀáñðš ŕéþļáçé á ƒûļļ ŕöŵ ŵîţĥ šöļîð þáñéļš. Åþþļý ţĥéîŕ ƒîñîšĥ ŵîţĥ ţĥé þáîñţ ţööļ. ~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.panelCount\":[\"[Þáñéļ çöûñţ ~~~]\"],\"node.wall.curtainWallPanel.panelInfill\":[\"[Þáñéļ îñƒîļļ ~~~~]\"],\"node.wall.curtainWallPanel.panelThickness\":[\"[Þáñéļ ţĥîçķñéšš ~~~~~]\"],\"node.wall.curtainWallPanel.panels\":[\"[Þáñéļš ~~]\"],\"node.wall.curtainWallPanel.resetThisPanel\":[\"[Ŕéšéţ ţĥîš þáñéļ ~~~~~]\"],\"node.wall.curtainWallPanel.row2\":[\"[Ŕöŵ ~]\"],\"node.wall.curtainWallPanel.rowLayout\":[\"[Ŕöŵ ļáýöûţ ~~~]\"],\"node.wall.curtainWallPanel.separateFramedModulesWithJointsBetween\":[\"[Šéþáŕáţé ƒŕáɱéð ɱöðûļéš ŵîţĥ ĵöîñţš ƀéţŵééñ ûñîţš. ~~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.solid\":[\"[Šöļîð ~~]\"],\"node.wall.curtainWallPanel.spacing\":[\"[Šþáçîñĝ ~~~]\"],\"node.wall.curtainWallPanel.start\":[\"[Šţáŕţ ~~]\"],\"node.wall.curtainWallPanel.stickBuilt\":[\"[Šţîçķ-ƀûîļţ ~~~]\"],\"node.wall.curtainWallPanel.structuralGlazing\":[\"[Šţŕûçţûŕáļ ĝļážîñĝ ~~~~~~]\"],\"node.wall.curtainWallPanel.surfaceRoughness\":[\"[Šûŕƒáçé ŕöûĝĥñéšš ~~~~~]\"],\"node.wall.curtainWallPanel.top\":[\"[Ţöþ ~]\"],\"node.wall.curtainWallPanel.topRow\":[\"[Ţöþ ŕöŵ ~~]\"],\"node.wall.curtainWallPanel.uncappedMembersSitBehindTheGlazing\":[\"[Ûñçáþþéð ɱéɱƀéŕš šîţ ƀéĥîñð ţĥé ĝļážîñĝ. ~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.unitized\":[\"[Ûñîţîžéð ~~~]\"],\"node.wall.curtainWallPanel.useGlassSettingsInstead\":[\"[Ûšé ĝļášš šéţţîñĝš îñšţéáð ~~~~~~~]\"],\"node.wall.curtainWallPanel.useTheDoorOrWindowTool\":[\"[Ûšé ţĥé Ðööŕ öŕ Ŵîñðöŵ ţööļ ţö áðð áñ öþéñîñĝ ţĥŕöûĝĥ ţĥé ŵáļļ. ~~~~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.verticalCaps\":[\"[Ṽéŕţîçáļ çáþš ~~~~]\"],\"node.wall.curtainWallPanel.verticalFrameWidth\":[\"[Ṽéŕţîçáļ ƒŕáɱé ŵîðţĥ ~~~~~~]\"],\"node.wall.curtainWallPanel.wallSystem\":[\"[Ŵáļļ šýšţéɱ ~~~]\"],\"node.wall.description\":[\"[Å šţŕáîĝĥţ öŕ çûŕṽéð ŵáļļ šéĝɱéñţ. Ĥöšţš ðööŕš, ŵîñðöŵš, ļéáñ-ţö éẋţéñšîöñš, áñð ŵáļļ-ɱöûñţéð îţéɱš. ~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.wall.label\":[\"[Ŵáļļ ~~]\"],\"node.wall.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.wall.panel.assembly\":[\"[Åššéɱƀļý ~~~]\"],\"node.wall.panel.auto\":[\"[Åûţö ~~]\"],\"node.wall.panel.both\":[\"[Ɓöţĥ ~~]\"],\"node.wall.panel.bottom\":[\"[Ɓöţţöɱ ~~]\"],\"node.wall.panel.brickVeneer\":[\"[Ɓŕîçķ ṽéñééŕ ~~~~]\"],\"node.wall.panel.chairRail\":[\"[Çĥáîŕ ŕáîļ ~~~]\"],\"node.wall.panel.cmu\":[\"[ÇṀÛ ~]\"],\"node.wall.panel.colonial\":[\"[Çöļöñîáļ ~~~]\"],\"node.wall.panel.cove\":[\"[Çöṽé ~~]\"],\"node.wall.panel.craft\":[\"[Çŕáƒţ ~~]\"],\"node.wall.panel.crownMolding\":[\"[Çŕöŵñ ɱöļðîñĝ ~~~~]\"],\"node.wall.panel.curtainWall\":[\"[Çûŕţáîñ ŵáļļ ~~~~]\"],\"node.wall.panel.curve\":[\"[Çûŕṽé ~~]\"],\"node.wall.panel.custom\":[\"[Çûšţöɱ ~~]\"],\"node.wall.panel.customHeight\":[\"[Çûšţöɱ ĥéîĝĥţ ~~~~]\"],\"node.wall.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.wall.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.wall.panel.drywall\":[\"[Ðŕýŵáļļ ~~~]\"],\"node.wall.panel.extendsDownwardToMeetTheTerrain\":[\"[Éẋţéñðš ðöŵñŵáŕð ţö ɱééţ ţĥé ţéŕŕáîñ. Ĥéîĝĥţ áñð ţöþ šţáý ûñçĥáñĝéð. ~~~~~~~~~~~~~~~~~]\"],\"node.wall.panel.exterior\":[\"[Éẋţéŕîöŕ ~~~]\"],\"node.wall.panel.fiberCement\":[\"[Ƒîƀéŕ çéɱéñţ ~~~~]\"],\"node.wall.panel.fillToTerrain\":[\"[Ƒîļļ ţö ţéŕŕáîñ ~~~~]\"],\"node.wall.panel.flat\":[\"[Ƒļáţ ~~]\"],\"node.wall.panel.followsLevel\":[\"[Ƒöļļöŵš ļéṽéļ ~~~~]\"],\"node.wall.panel.frameDepth\":[\"[Ƒŕáɱé ðéþţĥ ~~~]\"],\"node.wall.panel.framing\":[\"[Ƒŕáɱîñĝ ~~~]\"],\"node.wall.panel.gypsum\":[\"[Ĝýþšûɱ ~~]\"],\"node.wall.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.wall.panel.hideCode\":[\"[Ĥîðé çöðé ~~~]\"],\"node.wall.panel.icf\":[\"[ÎÇƑ ~]\"],\"node.wall.panel.interior\":[\"[Îñţéŕîöŕ ~~~]\"],\"node.wall.panel.lapSiding\":[\"[Ļáþ šîðîñĝ ~~~]\"],\"node.wall.panel.layerThicknessesFollowThe2021Irc\":[\"[Ļáýéŕ ţĥîçķñéššéš ƒöļļöŵ ţĥé 2021 ÎŔÇ áššéɱƀļý ðáţá. Ðŕáƒţîñĝ áîð, ñöţ éñĝîñééŕîñĝ — ṽéŕîƒý ŵîţĥ ţĥé áûţĥöŕîţý ĥáṽîñĝ ĵûŕîšðîçţîöñ. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.wall.panel.layered\":[\"[Ļáýéŕéð ~~~]\"],\"node.wall.panel.length\":[\"[Ļéñĝţĥ ~~]\"],\"node.wall.panel.loading\":[\"[Ļöáðîñĝ… ~~~]\"],\"node.wall.panel.modern\":[\"[Ṁöðéŕñ ~~]\"],\"node.wall.panel.none\":[\"[Ñöñé ~~]\"],\"node.wall.panel.noneSingleLayer\":[\"[Ñöñé (šîñĝļé ļáýéŕ) ~~~~~]\"],\"node.wall.panel.offset\":[\"[Öƒƒšéţ ~~]\"],\"node.wall.panel.ogee\":[\"[Öĝéé ~~]\"],\"node.wall.panel.osb\":[\"[ÖŠƁ ~]\"],\"node.wall.panel.partitionTheInteriorFinishIsApplied\":[\"[Þáŕţîţîöñ: ţĥé îñţéŕîöŕ ƒîñîšĥ îš áþþļîéð ţö ƀöţĥ ƒáçéš. ~~~~~~~~~~~~~~]\"],\"node.wall.panel.picture\":[\"[Þîçţûŕé ~~~]\"],\"node.wall.panel.plaster\":[\"[Þļášţéŕ ~~~]\"],\"node.wall.panel.plywood\":[\"[Þļýŵööð ~~~]\"],\"node.wall.panel.preset\":[\"[Þŕéšéţ ~~]\"],\"node.wall.panel.reference\":[\"[Ŕéƒéŕéñçé ~~~]\"],\"node.wall.panel.remove\":[\"[Ŕéɱöṽé ~~]\"],\"node.wall.panel.round\":[\"[Ŕöûñð ~~]\"],\"node.wall.panel.scriptedFinish\":[\"[Šçŕîþţéð ƒîñîšĥ ~~~~~]\"],\"node.wall.panel.sheathing\":[\"[Šĥéáţĥîñĝ ~~~]\"],\"node.wall.panel.shoe\":[\"[Šĥöé ~~]\"],\"node.wall.panel.sideA\":[\"[Šîðé Å ~~]\"],\"node.wall.panel.sideB\":[\"[Šîðé Ɓ ~~]\"],\"node.wall.panel.sideFace\":[\"[Šîðé \",[\"face\"],\" ~~]\"],\"node.wall.panel.skirting\":[\"[Šķîŕţîñĝ ~~~]\"],\"node.wall.panel.standard\":[\"[Šţáñðáŕð ~~~]\"],\"node.wall.panel.steelStuds\":[\"[Šţééļ šţûðš ~~~]\"],\"node.wall.panel.step\":[\"[Šţéþ ~~]\"],\"node.wall.panel.stoneVeneer\":[\"[Šţöñé ṽéñééŕ ~~~~]\"],\"node.wall.panel.stucco\":[\"[Šţûççö ~~]\"],\"node.wall.panel.thickness\":[\"[Ţĥîçķñéšš ~~~]\"],\"node.wall.panel.thicknessFromAssembly\":[\"[\",[\"thickness\"],\" · ƒŕöɱ áššéɱƀļý ~~~~]\"],\"node.wall.panel.top\":[\"[Ţöþ ~]\"],\"node.wall.panel.totalThickness\":[\"[Ţöţáļ ţĥîçķñéšš ~~~~~]\"],\"node.wall.panel.unverifiedPresetnote\":[\"[Ûñṽéŕîƒîéð: \",[\"presetNote\"],\" ~~~]\"],\"node.wall.panel.viewCode\":[\"[Ṽîéŵ çöðé ~~~]\"],\"node.wall.panel.wall\":[\"[Ŵáļļ ~~]\"],\"node.wall.panel.wallType\":[\"[Ŵáļļ ţýþé ~~~]\"],\"node.wall.panel.whichFaceIsOutsideIsUndetermined\":[\"[Ŵĥîçĥ ƒáçé îš öûţšîðé îš ûñðéţéŕɱîñéð (ñö ŕööɱ ðéţéçţéð öñ éîţĥéŕ šîðé) — ţĥé éẋţéŕîöŕ ļáýéŕš áŕé ðŕáŵñ öñ šîðé Ɓ. ~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.wall.panel.woodStuds\":[\"[Ŵööð šţûðš ~~~]\"],\"node.wall.reference.center\":[\"[Çéñţéŕ ~~]\"],\"node.wall.reference.inside\":[\"[Îñšîðé ƒáçé ~~~]\"],\"node.wall.reference.left\":[\"[Ļéƒţ ~~]\"],\"node.wall.reference.outside\":[\"[Öûţšîðé ƒáçé ~~~~]\"],\"node.wall.reference.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.wall.trim.hide\":[\"[\",[\"trim\",\"select\",{\"skirting\":[\"Ĥîðé šķîŕţîñĝ\"],\"crown\":[\"Ĥîðé çŕöŵñ ɱöļðîñĝ\"],\"other\":[\"Ĥîðé çĥáîŕ ŕáîļ\"]}],\" ~~~~~~~~~~~~~]\"],\"node.wall.trim.show\":[\"[\",[\"trim\",\"select\",{\"skirting\":[\"Šĥöŵ šķîŕţîñĝ\"],\"crown\":[\"Šĥöŵ çŕöŵñ ɱöļðîñĝ\"],\"other\":[\"Šĥöŵ çĥáîŕ ŕáîļ\"]}],\" ~~~~~~~~~~~~~]\"],\"node.window.description\":[\"[Å ŵîñðöŵ çûţ îñţö á ŵáļļ. Åñîɱáţéð öþéñ/çļöšé ƒöŕ öþéñîñĝ ŵîñðöŵš. ~~~~~~~~~~~~~~~~]\"],\"node.window.label\":[\"[Ŵîñðöŵ ~~]\"],\"node.window.operation.raise\":[\"[Ŕáîšé ~~]\"],\"node.window.operation.slats\":[\"[Šļáţš ~~]\"],\"node.window.operation.slide\":[\"[Šļîðé ~~]\"],\"node.window.operation.swing\":[\"[Šŵîñĝ ~~]\"],\"node.window.operation.tilt\":[\"[Ţîļţ ~~]\"],\"node.window.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.window.panel.all\":[\"[Åļļ ~]\"],\"node.window.panel.arch\":[\"[Åŕçĥ ~~]\"],\"node.window.panel.archHeight\":[\"[Åŕçĥ Ĥéîĝĥţ ~~~]\"],\"node.window.panel.auto\":[\"[Åûţö ~~]\"],\"node.window.panel.autoFollowsTheWall\":[\"[Åûţö ƒöļļöŵš ţĥé ŵáļļ ~~~~~~]\"],\"node.window.panel.colWidths\":[\"[Çöļ Ŵîðţĥš ~~~]\"],\"node.window.panel.columns\":[\"[Çöļûɱñš ~~~]\"],\"node.window.panel.corner\":[\"[Çöŕñéŕ ~~]\"],\"node.window.panel.cornerPost\":[\"[Çöŕñéŕ þöšţ ~~~]\"],\"node.window.panel.cornerRadius\":[\"[Çöŕñéŕ Ŕáðîûš ~~~~]\"],\"node.window.panel.customThePanesMatchNoStyle\":[\"[Çûšţöɱ: ţĥé þáñéš ɱáţçĥ ñö šţýļé. ~~~~~~~~]\"],\"node.window.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.window.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.window.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.window.panel.divider\":[\"[Ðîṽîðéŕ ~~~]\"],\"node.window.panel.down\":[\"[Ðöŵñ ~~]\"],\"node.window.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.window.panel.enableSill\":[\"[Éñáƀļé Šîļļ ~~~]\"],\"node.window.panel.flipSide\":[\"[Ƒļîþ Šîðé ~~~]\"],\"node.window.panel.frame\":[\"[Ƒŕáɱé ~~]\"],\"node.window.panel.frameDepthAuto\":[\"[Ðéþţĥ (áûţö) ~~~]\"],\"node.window.panel.french\":[\"[Ƒŕéñçĥ ~~]\"],\"node.window.panel.fusedGlass\":[\"[Ƒûšéð ĝļášš ~~~]\"],\"node.window.panel.grid\":[\"[Ĝŕîð ~~]\"],\"node.window.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.window.panel.individual\":[\"[Îñðîṽîðûáļ ~~~]\"],\"node.window.panel.left\":[\"[Ļéƒţ ~~]\"],\"node.window.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.window.panel.opening\":[\"[Öþéñîñĝ ~~~]\"],\"node.window.panel.openingShape\":[\"[Öþéñîñĝ Šĥáþé ~~~~]\"],\"node.window.panel.otherSide\":[\"[Öţĥéŕ šîðé ~~~]\"],\"node.window.panel.pos\":[\"[þöš ~]\"],\"node.window.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.window.panel.rect\":[\"[Ŕéçţ ~~]\"],\"node.window.panel.revealRadius\":[\"[Ŕéṽéáļ Ŕáðîûš ~~~~]\"],\"node.window.panel.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.window.panel.rounded\":[\"[Ŕöûñðéð ~~~]\"],\"node.window.panel.rowHeights\":[\"[Ŕöŵ Ĥéîĝĥţš ~~~]\"],\"node.window.panel.rows\":[\"[Ŕöŵš ~~]\"],\"node.window.panel.sill\":[\"[Šîļļ ~~]\"],\"node.window.panel.single\":[\"[Šîñĝļé ~~]\"],\"node.window.panel.sizeIsLimitedToTheWall\":[\"[Šîžé îš ļîɱîţéð ţö ţĥé ŵáļļ, îñçļûðîñĝ çļéáŕáñçé ƒöŕ ţĥé öþéñîñĝ ƒŕáɱé. ~~~~~~~~~~~~~~~~~~]\"],\"node.window.panel.style\":[\"[Šţýļé ~~]\"],\"node.window.panel.thickness\":[\"[Ţĥîçķñéšš ~~~]\"],\"node.window.panel.thisSide\":[\"[Ţĥîš šîðé ~~~]\"],\"node.window.panel.topShape\":[\"[Ţöþ Šĥáþé ~~~]\"],\"node.window.panel.type\":[\"[Ţýþé ~~]\"],\"node.window.panel.unwrap\":[\"[Ûñŵŕáþ ~~]\"],\"node.window.panel.up\":[\"[Ûþ ~]\"],\"node.window.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.window.panel.window\":[\"[Ŵîñðöŵ ~~]\"],\"node.window.panel.windowType\":[\"[Ŵîñðöŵ Ţýþé ~~~]\"],\"node.window.panel.wrapTheCorner\":[\"[Ŵŕáþ ţĥé çöŕñéŕ ~~~~]\"],\"node.window.panel.wrapsTheCornerWithNamed\":[\"[Ŵŕáþš ţĥé çöŕñéŕ ŵîţĥ \",[\"partner\"],\" ~~~~~~]\"],\"node.window.panel.wrapsTheCornerWithPartner\":[\"[Ŵŕáþš ţĥé çöŕñéŕ ŵîţĥ îţš þáŕţñéŕ ~~~~~~~~~]\"],\"node.window.style.casement\":[\"[Çášéɱéñţ ~~~]\"],\"node.window.style.doubleHung\":[\"[Ðöûƀļé-ĥûñĝ ~~~]\"],\"node.window.style.grid\":[\"[Ĝŕîð ~~]\"],\"node.window.style.horizontalBands\":[\"[Ĥöŕîžöñţáļ ƀáñðš ~~~~~]\"],\"node.window.style.picture\":[\"[Þîçţûŕé ~~~]\"],\"node.window.style.single\":[\"[Šîñĝļé ~~]\"],\"node.window.style.sliding\":[\"[Šļîðîñĝ ~~~]\"],\"node.window.style.tallGrid\":[\"[Ţáļļ ĝŕîð ~~~]\"],\"node.window.style.transom\":[\"[Ţŕáñšöɱ ~~~]\"],\"node.window.style.tripleHung\":[\"[Ţŕîþļé-ĥûñĝ ~~~]\"],\"node.window.style.wideGrid\":[\"[Ŵîðé ĝŕîð ~~~]\"],\"node.window.type.awning\":[\"[Åŵñîñĝ ~~]\"],\"node.window.type.bay\":[\"[Ɓáý ~]\"],\"node.window.type.bow\":[\"[Ɓöŵ ~]\"],\"node.window.type.casement\":[\"[Çášéɱéñţ ~~~]\"],\"node.window.type.doubleHung\":[\"[Ðöûƀļé Ĥûñĝ ~~~]\"],\"node.window.type.fixed\":[\"[Ƒîẋéð ~~]\"],\"node.window.type.hopper\":[\"[Ĥöþþéŕ ~~]\"],\"node.window.type.louvered\":[\"[Ļöûṽéŕéð ~~~]\"],\"node.window.type.singleHung\":[\"[Šîñĝļé Ĥûñĝ ~~~]\"],\"node.window.type.sliding\":[\"[Šļîðîñĝ ~~~]\"],\"node.zone.description\":[\"[Å þöļýĝöñáļ šîţé žöñé (ļáŵñ, ŵáţéŕ, þáṽîñĝ) ŵîţĥ á ŢŠĻ ĝŕáðîéñţ ɱáţéŕîáļ. ~~~~~~~~~~~~~~~~~~]\"],\"node.zone.label\":[\"[Žöñé ~~]\"],\"node.zone.quantitiesPanel.enclosedRoom\":[\"[Éñçļöšéð ŕööɱ ~~~~]\"],\"node.zone.quantitiesPanel.floorSurface\":[\"[Ƒļööŕ šûŕƒáçé ~~~~]\"],\"node.zone.quantitiesPanel.footprintOnly\":[\"[Ƒööţþŕîñţ öñļý ~~~~]\"],\"node.zone.quantitiesPanel.none\":[\"[Ñöñé ~~]\"],\"node.zone.quantitiesPanel.notProven\":[\"[Ñöţ þŕöṽéñ ~~~]\"],\"node.zone.quantitiesPanel.roomQuantities\":[\"[Ŕööɱ ǫûáñţîţîéš ~~~~~]\"],\"node.zone.quantitiesPanel.topViewWithZoneEdgeDimensions\":[\"[Ţöþ ṽîéŵ ŵîţĥ žöñé éðĝé ðîɱéñšîöñš ~~~~~~~~~]\"],\"node.zone.quantitiesPanel.unit\":[\"[Ûñîţ ~~]\"],\"node.zone.quantitiesPanel.volume\":[\"[Ṽöļûɱé ~~]\"],\"node.zone.quantitiesPanel.wallSurface\":[\"[Ŵáļļ šûŕƒáçé ~~~~]\"],\"node.zone.quantitiesPanel.zoneBoundaryUnavailable\":[\"[Žöñé ƀöûñðáŕý ûñáṽáîļáƀļé ~~~~~~~]\"],\"node.zone.quantitiesPanel.zoneQuantities\":[\"[Žöñé ǫûáñţîţîéš ~~~~~]\"],\"viewer.camera.orbitLeft\":[\"[Öŕƀîţ ļéƒţ ~~~]\"],\"viewer.camera.orbitRight\":[\"[Öŕƀîţ ŕîĝĥţ ~~~]\"],\"viewer.camera.topView\":[\"[Ţöþ ṽîéŵ ~~~]\"],\"viewer.common.off\":[\"[Öƒƒ ~]\"],\"viewer.common.on\":[\"[Öñ ~]\"],\"viewer.display.camera\":[\"[Çáɱéŕá ~~]\"],\"viewer.display.colored\":[\"[Çöļöŕéð ~~~]\"],\"viewer.display.colors\":[\"[Çöļöŕš ~~]\"],\"viewer.display.edges.off\":[\"[Öƒƒ ~]\"],\"viewer.display.edges.offDetail\":[\"[Ñö éðĝé ļîñéš ~~~~]\"],\"viewer.display.edges.soft\":[\"[Šöƒţ ~~]\"],\"viewer.display.edges.softDetail\":[\"[Ƒáîñţ öûţļîñé öƒ ɱáĵöŕ çŕéášéš ~~~~~~~~]\"],\"viewer.display.edges.strong\":[\"[Šţŕöñĝ ~~]\"],\"viewer.display.edges.strongDetail\":[\"[Çŕîšþ, öþáǫûé éðĝé ļîñéš ~~~~~~]\"],\"viewer.display.edges.title\":[\"[Éðĝéš ~~]\"],\"viewer.display.monochrome\":[\"[Ṁöñöçĥŕöɱé ~~~]\"],\"viewer.display.orthographic\":[\"[Öŕţĥöĝŕáþĥîç ~~~~]\"],\"viewer.display.perspective\":[\"[Þéŕšþéçţîṽé ~~~~]\"],\"viewer.display.render.rendered\":[\"[Ŕéñðéŕéð ~~~]\"],\"viewer.display.render.renderedDetail\":[\"[Ƒûļļ áɱƀîéñţ öççļûšîöñ ~~~~~~]\"],\"viewer.display.render.solid\":[\"[Šöļîð ~~]\"],\"viewer.display.render.solidDetail\":[\"[Ƒļáţ áñð ƒášţ — ñö áɱƀîéñţ öççļûšîöñ ~~~~~~~~~]\"],\"viewer.display.render.title\":[\"[Ŕéñðéŕ ~~]\"],\"viewer.display.shadows\":[\"[Šĥáðöŵš ~~~]\"],\"viewer.display.title\":[\"[Ðîšþļáý šéţţîñĝš ~~~~~]\"],\"viewer.floorplan.alignNorth\":[\"[Åļîĝñ ṽîéŵ ţö ñöŕţĥ ~~~~~]\"],\"viewer.floorplan.empty\":[\"[Ñö ƒļööŕ þļáñš áŕé áṽáîļáƀļé ƒöŕ ţĥîš šçéñé. ~~~~~~~~~~~]\"],\"viewer.floorplan.fit\":[\"[Ƒîţ ƒļööŕ þļáñ ~~~~]\"],\"viewer.floorplan.floor\":[\"[Ƒļööŕ ~~]\"],\"viewer.floorplan.floorPlan\":[\"[Ƒļööŕ þļáñ ~~~]\"],\"viewer.floorplan.viewLabel\":[\"[\",[\"floor\"],\" 2Ð ṽîéŵ ~~]\"],\"viewer.floorplan.zoomIn\":[\"[Žööɱ îñ ~~]\"],\"viewer.floorplan.zoomOut\":[\"[Žööɱ öûţ ~~~]\"],\"viewer.header.back\":[\"[Ɓáçķ ~~]\"],\"viewer.header.levels\":[\"[Ļéṽéļš ~~]\"],\"viewer.header.rooms\":[\"[Ŕööɱš ~~]\"],\"viewer.header.selection\":[\"[Šéļéçţîöñ ~~~]\"],\"viewer.header.units\":[\"[Ûñîţš ~~]\"],\"viewer.header.untitled\":[\"[Ûñţîţļéð ~~~]\"],\"viewer.header.zones\":[\"[Žöñéš ~~]\"],\"viewer.levels.exploded\":[\"[Éẋþļöðéð ~~~]\"],\"viewer.levels.label\":[\"[Ļéṽéļš: \",[\"mode\"],\" ~~]\"],\"viewer.levels.manual\":[\"[Ṁáñûáļ ~~]\"],\"viewer.levels.solo\":[\"[Šöļö ~~]\"],\"viewer.levels.stacked\":[\"[Šţáçķéð ~~~]\"],\"viewer.stage.layout\":[\"[Ṽîéŵéŕ ļáýöûţ ~~~~]\"],\"viewer.stage.split\":[\"[Šþļîţ ~~]\"],\"viewer.theme.blueprint\":[\"[Ɓļûéþŕîñţ ~~~]\"],\"viewer.theme.mediterranean\":[\"[Ṁéðîţéŕŕáñéáñ ~~~~]\"],\"viewer.theme.night\":[\"[Ñîĝĥţ ~~]\"],\"viewer.theme.overcast\":[\"[Öṽéŕçášţ ~~~]\"],\"viewer.theme.paper\":[\"[Þáþéŕ ~~]\"],\"viewer.theme.studio\":[\"[Šţûðîö ~~]\"],\"viewer.theme.sunset\":[\"[Šûñšéţ ~~]\"],\"viewer.theme.title\":[\"[Šçéñé ţĥéɱé ~~~]\"],\"viewer.theme.twilight\":[\"[Ţŵîļîĝĥţ ~~~]\"],\"viewer.theme.verdant\":[\"[Ṽéŕðáñţ ~~~]\"],\"viewer.visibility.guides\":[\"[Ĝûîðéš ~~]\"],\"viewer.visibility.scans\":[\"[Šçáñš ~~]\"],\"viewer.visibility.title\":[\"[Ṽîšîƀîļîţý ~~~]\"],\"viewer.walkthrough.label\":[\"[Ŵáļķţĥŕöûĝĥ: \",[\"state\"],\" ~~~~]\"],\"viewer.walls.cutaway\":[\"[Çûţáŵáý ~~~]\"],\"viewer.walls.fullHeight\":[\"[Ƒûļļ ĥéîĝĥţ ~~~]\"],\"viewer.walls.label\":[\"[Ŵáļļš: \",[\"mode\"],\" ~~]\"],\"viewer.walls.low\":[\"[Ļöŵ ~]\"]}")as Messages; \ No newline at end of file +/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"app.appShell.pascalHome\":[\"[Þášçáļ ĥöɱé ~~~]\"],\"app.buildTab.addGate\":[\"[Åðð Ĝáţé ~~~]\"],\"app.buildTab.addOpenPassage\":[\"[Åðð Öþéñ Þáššáĝé ~~~~~]\"],\"app.buildTab.addToRooms\":[\"[Åðð ţö ŕööɱš ~~~]\"],\"app.buildTab.allBuildTools\":[\"[← Åļļ ƀûîļð ţööļš ~~~~]\"],\"app.buildTab.chooseGateOrOpenPassageThen\":[\"[Çĥööšé Ĝáţé öŕ Öþéñ Þáššáĝé, ţĥéñ çļîçķ îţš þöšîţîöñ öñ áñý ƒéñçé. Ƒîñð þļáçéð ĝáţéš áñð öþéñîñĝš ûñðéŕ ţĥéîŕ ƒéñçé îñ ţĥé šçéñé ĝŕáþĥ. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"app.buildTab.clickALinesetToLayThe\":[\"[Çļîçķ á ļîñéšéţ ţö ļáý ţĥé ļîñé ƀéšîðé îţ. ~~~~~~~~~~]\"],\"app.buildTab.doubleGate\":[\"[Ðöûƀļé ĝáţé ~~~]\"],\"app.buildTab.featuresExtensions\":[\"[Ƒéáţûŕéš & éẋţéñšîöñš ~~~~~~]\"],\"app.buildTab.fenceFeatures\":[\"[Ƒéñçé ƒéáţûŕéš ~~~~]\"],\"app.buildTab.followLineset\":[\"[Ƒöļļöŵ ļîñéšéţ ~~~~]\"],\"app.buildTab.gate\":[\"[Ĝáţé ~~]\"],\"app.buildTab.gateStyle\":[\"[Ĝáţé šţýļé ~~~]\"],\"app.buildTab.horizontalBoards\":[\"[Ĥöŕîžöñţáļ ƀöáŕðš ~~~~~]\"],\"app.buildTab.hoverAFenceToPreviewClick\":[\"[Ĥöṽéŕ á ƒéñçé ţö þŕéṽîéŵ. Çļîçķ ţö þļáçé. Éšç çáñçéļš. Ļéáṽé ŕööɱ ƀéţŵééñ öþéñîñĝš. ~~~~~~~~~~~~~~~~~~~~]\"],\"app.buildTab.leaves\":[\"[Ļéáṽéš ~~]\"],\"app.buildTab.liquidLine\":[\"[Ļîǫûîð Ļîñé ~~~]\"],\"app.buildTab.matchFenceStyle\":[\"[Ṁáţçĥ ƒéñçé šţýļé ~~~~~]\"],\"app.buildTab.mep\":[\"[ṀÉÞ ~]\"],\"app.buildTab.off\":[\"[Öƒƒ ~]\"],\"app.buildTab.on\":[\"[Öñ ~]\"],\"app.buildTab.openRails\":[\"[Öþéñ ŕáîļš ~~~]\"],\"app.buildTab.opening\":[\"[Öþéñîñĝ ~~~]\"],\"app.buildTab.openingWidthM\":[\"[Öþéñîñĝ ŵîðţĥ (ɱ) ~~~~]\"],\"app.buildTab.outdoor\":[\"[Öûţðööŕ ~~~]\"],\"app.buildTab.picket\":[\"[Þîçķéţ ~~]\"],\"app.buildTab.roofType\":[\"[Ŕööƒ ţýþé ~~~]\"],\"app.buildTab.roomsAlreadyCreateTheirFloorAnd\":[\"[Ŕööɱš áļŕéáðý çŕéáţé ţĥéîŕ ƒļööŕ áñð çéîļîñĝ. Ûšé ţĥéšé ƒöŕ þļáţƒöŕɱš áñð öñé-öƒƒ šţŕûçţûŕé. ~~~~~~~~~~~~~~~~~~~~~~~]\"],\"app.buildTab.searchBuildToolsAndKitchenItems\":[\"[Šéáŕçĥ ƀûîļð ţööļš áñð ķîţçĥéñ îţéɱš ~~~~~~~~~~]\"],\"app.buildTab.searchToolsFridgeSink\":[\"[Šéáŕçĥ ţööļš, ƒŕîðĝé, šîñķ… ~~~~~~~]\"],\"app.buildTab.selectACurvedWallToMatch\":[\"[Šéļéçţ á çûŕṽéð ŵáļļ ţö ɱáţçĥ îţš ŕáðîûš áñð áŕç. ~~~~~~~~~~~~]\"],\"app.buildTab.singleGate\":[\"[Šîñĝļé ĝáţé ~~~]\"],\"app.buildTab.slabCeilingColumn\":[\"[Šļáƀ, çéîļîñĝ, çöļûɱñ… ~~~~~~]\"],\"app.buildTab.solidPrivacy\":[\"[Šöļîð þŕîṽáçý ~~~~]\"],\"app.buildTab.traceALineAlongsideAnExisting\":[\"[Ţŕáçé á ļîñé áļöñĝšîðé áñ éẋîšţîñĝ ļîñéšéţ (Ƒ). ~~~~~~~~~~~~]\"],\"app.buildTab.verticalSlats\":[\"[Ṽéŕţîçáļ šļáţš ~~~~]\"],\"app.editorNavbar.allProjects\":[\"[Åļļ þŕöĵéçţš ~~~~]\"],\"app.editorNavbar.preview\":[\"[Þŕéṽîéŵ ~~~]\"],\"app.editorNavbar.projectName\":[\"[Þŕöĵéçţ ñáɱé ~~~~]\"],\"app.editorNavbar.renameProject\":[\"[Ŕéñáɱé þŕöĵéçţ ~~~~]\"],\"app.editorNavbar.share\":[\"[Šĥáŕé ~~]\"],\"app.kitchenBrowser.addLabel\":[\"[Åðð \",[\"label\"],\" ~]\"],\"app.kitchenBrowser.addToKitchen\":[\"[Åðð ţö ķîţçĥéñ ~~~~]\"],\"app.kitchenBrowser.chooseAnItemThenClickTo\":[\"[Çĥööšé áñ îţéɱ, ţĥéñ çļîçķ ţö þļáçé îţ. Åþþļîáñçéš îñçļûðé ţĥéîŕ çáƀîñéţŕý. ~~~~~~~~~~~~~~~~~~~]\"],\"app.kitchenBrowser.findInThisProjectLength\":[\"[Ƒîñð îñ ţĥîš þŕöĵéçţ · \",[\"length\"],\" ~~~~~~]\"],\"app.kitchenBrowser.findName\":[\"[Ƒîñð \",[\"name\"],\" ~~]\"],\"app.kitchenBrowser.groupAdd\":[\"[Ķîţçĥéñ · Åðð ~~~]\"],\"app.kitchenBrowser.groupInThisProject\":[\"[Ķîţçĥéñ · Îñ ţĥîš þŕöĵéçţ ~~~~~~]\"],\"app.kitchenBrowser.kitchenCabinet\":[\"[Ķîţçĥéñ çáƀîñéţ ~~~~~]\"],\"app.kitchenBrowser.noMatchingKitchenItemsPlacedYet\":[\"[Ñö ɱáţçĥîñĝ ķîţçĥéñ îţéɱš þļáçéð ýéţ. ~~~~~~~~~~]\"],\"app.kitchenBrowser.selectAndShowInScene\":[\"[Šéļéçţ áñð šĥöŵ îñ šçéñé ~~~~~~]\"],\"app.lib.buildPalette.ceiling\":[\"[Çéîļîñĝ ~~~]\"],\"app.lib.buildPalette.column\":[\"[Çöļûɱñ ~~]\"],\"app.lib.buildPalette.door\":[\"[Ðööŕ ~~]\"],\"app.lib.buildPalette.duct\":[\"[Ðûçţ ~~]\"],\"app.lib.buildPalette.dwvPipe\":[\"[ÐŴṼ Þîþé ~~~]\"],\"app.lib.buildPalette.elevator\":[\"[Éļéṽáţöŕ ~~~]\"],\"app.lib.buildPalette.fence\":[\"[Ƒéñçé ~~]\"],\"app.lib.buildPalette.hvacUnit\":[\"[ĤṼÅÇ Ûñîţ ~~~]\"],\"app.lib.buildPalette.kitchen\":[\"[Ķîţçĥéñ ~~~]\"],\"app.lib.buildPalette.lineset\":[\"[Ļîñéšéţ ~~~]\"],\"app.lib.buildPalette.liquidLine\":[\"[Ļîǫûîð Ļîñé ~~~]\"],\"app.lib.buildPalette.mep\":[\"[ṀÉÞ ~]\"],\"app.lib.buildPalette.post\":[\"[Þöšţ ~~]\"],\"app.lib.buildPalette.register\":[\"[Ŕéĝîšţéŕ ~~~]\"],\"app.lib.buildPalette.roof\":[\"[Ŕööƒ ~~]\"],\"app.lib.buildPalette.shelf\":[\"[Šĥéļƒ ~~]\"],\"app.lib.buildPalette.slab\":[\"[Šļáƀ ~~]\"],\"app.lib.buildPalette.spawnPoint\":[\"[Šþáŵñ þöîñţ ~~~]\"],\"app.lib.buildPalette.stairs\":[\"[Šţáîŕš ~~]\"],\"app.lib.buildPalette.terrace\":[\"[Ţéŕŕáçé ~~~]\"],\"app.lib.buildPalette.terrain\":[\"[Ţéŕŕáîñ ~~~]\"],\"app.lib.buildPalette.wall\":[\"[Ŵáļļ ~~]\"],\"app.lib.buildPalette.window\":[\"[Ŵîñðöŵ ~~]\"],\"app.lib.buildPanelModel.addFitting\":[\"[Åðð Ƒîţţîñĝ ~~~]\"],\"app.lib.buildPanelModel.addGate\":[\"[Åðð Ĝáţé ~~~]\"],\"app.lib.buildPanelModel.addOpenPassage\":[\"[Åðð Öþéñ Þáššáĝé ~~~~~]\"],\"app.lib.buildPanelModel.addTrap\":[\"[Åðð Ţŕáþ ~~~]\"],\"app.lib.buildPanelModel.build\":[\"[Ɓûîļð ~~]\"],\"app.lib.buildPanelModel.createFrom\":[\"[Çŕéáţé ƒŕöɱ ~~~]\"],\"app.lib.buildPanelModel.drawTheRoofFootprintWithTwo\":[\"[Ðŕáŵ ţĥé ŕööƒ ƒööţþŕîñţ ŵîţĥ ţŵö çöŕñéŕ çļîçķš. ~~~~~~~~~~~~]\"],\"app.lib.buildPanelModel.duct\":[\"[Ðûçţ ~~]\"],\"app.lib.buildPanelModel.dwvPipe\":[\"[ÐŴṼ Þîþé ~~~]\"],\"app.lib.buildPanelModel.featuresExtensions\":[\"[Ƒéáţûŕéš & éẋţéñšîöñš ~~~~~~]\"],\"app.lib.buildPanelModel.fence\":[\"[Ƒéñçé ~~]\"],\"app.lib.buildPanelModel.followLineset\":[\"[Ƒöļļöŵ ļîñéšéţ ~~~~]\"],\"app.lib.buildPanelModel.gatesOpenings\":[\"[Ĝáţéš & öþéñîñĝš ~~~~]\"],\"app.lib.buildPanelModel.hoverARoomToPreviewIts\":[\"[Ĥöṽéŕ á ŕööɱ ţö þŕéṽîéŵ îţš ƀöûñðáŕý, ţĥéñ çļîçķ ţö þļáçé. ~~~~~~~~~~~~~~]\"],\"app.lib.buildPanelModel.kitchen\":[\"[Ķîţçĥéñ ~~~]\"],\"app.lib.buildPanelModel.mep\":[\"[ṀÉÞ ~]\"],\"app.lib.buildPanelModel.modularCabinet\":[\"[Ṁöðûļáŕ Çáƀîñéţ ~~~~~]\"],\"app.lib.buildPanelModel.off\":[\"[Öƒƒ ~]\"],\"app.lib.buildPanelModel.on\":[\"[Öñ ~]\"],\"app.lib.buildPanelModel.painting\":[\"[Þáîñţîñĝ ~~~]\"],\"app.lib.buildPanelModel.roof\":[\"[Ŕööƒ ~~]\"],\"app.lib.buildPanelModel.roofType\":[\"[Ŕööƒ ţýþé ~~~]\"],\"app.lib.buildPanelModel.toolCount\":[\"[\",[\"count\",\"plural\",{\"one\":[\"#\",\" ţööļ\"],\"other\":[\"#\",\" ţööļš\"]}],\" ~~~]\"],\"app.lib.buildTabState.conical\":[\"[Çöñîçáļ ~~~]\"],\"app.lib.buildTabState.draw\":[\"[Ðŕáŵ ~~]\"],\"app.lib.buildTabState.dutch\":[\"[Ðûţçĥ ~~]\"],\"app.lib.buildTabState.flat\":[\"[Ƒļáţ ~~]\"],\"app.lib.buildTabState.gable\":[\"[Ĝáƀļé ~~]\"],\"app.lib.buildTabState.gambrel\":[\"[Ĝáɱƀŕéļ ~~~]\"],\"app.lib.buildTabState.hip\":[\"[Ĥîþ ~]\"],\"app.lib.buildTabState.mansard\":[\"[Ṁáñšáŕð ~~~]\"],\"app.lib.buildTabState.room\":[\"[Ŕööɱ ~~]\"],\"app.lib.buildTabState.shed\":[\"[Šĥéð ~~]\"],\"app.lib.buildTabState.wall\":[\"[Ŵáļļ ~~]\"],\"app.sceneLoader.anotherSessionSavedFirstRefresh\":[\"[Åñöţĥéŕ šéššîöñ šáṽéð ƒîŕšţ — ŕéƒŕéšĥ? ~~~~~~~~~~]\"],\"app.sceneLoader.build\":[\"[Ɓûîļð ~~]\"],\"app.sceneLoader.dismiss\":[\"[Ðîšɱîšš ~~~]\"],\"app.sceneLoader.items\":[\"[Îţéɱš ~~]\"],\"app.sceneLoader.paint\":[\"[Þáîñţ ~~]\"],\"app.sceneLoader.reload\":[\"[Ŕéļöáð ~~]\"],\"app.sceneLoader.scene\":[\"[Šçéñé ~~]\"],\"app.sceneLoader.settings\":[\"[Šéţţîñĝš ~~~]\"],\"app.sceneLoader.yourChangesHavenTBeenSaved\":[\"[Ýöûŕ çĥáñĝéš ĥáṽéñ'ţ ƀééñ šáṽéð. Ŕéļöáð ţö þîçķ ûþ ţĥé ļáţéšţ ṽéŕšîöñ. ~~~~~~~~~~~~~~~~~]\"],\"app.sharePanel.anyoneWithTheLinkCanView\":[\"[Åñýöñé ŵîţĥ ţĥé ļîñķ çáñ ṽîéŵ ţĥîš þŕöĵéçţ. Ţĥéý çáññöţ éðîţ îţ. ~~~~~~~~~~~~~~~~]\"],\"app.sharePanel.copied\":[\"[Çöþîéð ~~]\"],\"app.sharePanel.copy\":[\"[Çöþý ~~]\"],\"app.sharePanel.couldNotReadTheSharingState\":[\"[Çöûļð ñöţ ŕéáð ţĥé šĥáŕîñĝ šţáţé. ~~~~~~~~~]\"],\"app.sharePanel.couldNotTurnOffThePublic\":[\"[Çöûļð ñöţ ţûŕñ öƒƒ ţĥé þûƀļîç ļîñķ. ~~~~~~~~~]\"],\"app.sharePanel.couldNotTurnOnThePublic\":[\"[Çöûļð ñöţ ţûŕñ öñ ţĥé þûƀļîç ļîñķ. ~~~~~~~~~]\"],\"app.sharePanel.embedCode\":[\"[Éɱƀéð çöðé ~~~]\"],\"app.sharePanel.embedLink\":[\"[Éɱƀéð ļîñķ ~~~]\"],\"app.sharePanel.hideControls\":[\"[Ĥîðé çöñţŕöļš ~~~~]\"],\"app.sharePanel.link\":[\"[Ļîñķ ~~]\"],\"app.sharePanel.onlyThe3dViewNoHeader\":[\"[Öñļý ţĥé 3Ð ṽîéŵ, ñö ĥéáðéŕ öŕ ţööļƀáŕ. ~~~~~~~~~]\"],\"app.sharePanel.open\":[\"[Öþéñ ~~]\"],\"app.sharePanel.publicLink\":[\"[Þûƀļîç ļîñķ ~~~]\"],\"app.sharePanel.shareProject\":[\"[Šĥáŕé þŕöĵéçţ ~~~~]\"],\"app.viewerToolbar.above\":[\"[Åƀöṽé ~~]\"],\"app.viewerToolbar.automaticDimensions\":[\"[Åûţöɱáţîç ðîɱéñšîöñš ~~~~~~]\"],\"app.viewerToolbar.below\":[\"[Ɓéļöŵ ~~]\"],\"app.viewerToolbar.both\":[\"[Ɓöţĥ ~~]\"],\"app.viewerToolbar.camera\":[\"[Çáɱéŕá ~~]\"],\"app.viewerToolbar.ceilings\":[\"[Çéîļîñĝš ~~~]\"],\"app.viewerToolbar.cleanPlanDimensionsAppearWithSelection\":[\"[Çļéáñ þļáñ; ðîɱéñšîöñš áþþéáŕ ŵîţĥ šéļéçţîöñ ~~~~~~~~~~~~]\"],\"app.viewerToolbar.collapseSidebar\":[\"[Çöļļáþšé šîðéƀáŕ ~~~~~]\"],\"app.viewerToolbar.crispOpaqueEdgeLines\":[\"[Çŕîšþ, öþáǫûé éðĝé ļîñéš ~~~~~~]\"],\"app.viewerToolbar.cutaway\":[\"[Çûţáŵáý ~~~]\"],\"app.viewerToolbar.default\":[\"[Ðéƒáûļţ ~~~]\"],\"app.viewerToolbar.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"app.viewerToolbar.display\":[\"[Ðîšþļáý ~~~]\"],\"app.viewerToolbar.displaySettings\":[\"[Ðîšþļáý šéţţîñĝš ~~~~~]\"],\"app.viewerToolbar.doorWindowMarks\":[\"[Ðööŕ/ŵîñðöŵ ɱáŕķš ~~~~~]\"],\"app.viewerToolbar.edges\":[\"[Éðĝéš ~~]\"],\"app.viewerToolbar.editing\":[\"[Éðîţîñĝ ~~~]\"],\"app.viewerToolbar.enterVr\":[\"[Éñţéŕ ṼŔ ~~~]\"],\"app.viewerToolbar.exitVr\":[\"[Éẋîţ ṼŔ ~~]\"],\"app.viewerToolbar.expandSidebar\":[\"[Éẋþáñð šîðéƀáŕ ~~~~]\"],\"app.viewerToolbar.expert\":[\"[Éẋþéŕţ ~~]\"],\"app.viewerToolbar.exploded\":[\"[Éẋþļöðéð ~~~]\"],\"app.viewerToolbar.faintOutlineOfMajorCreases\":[\"[Ƒáîñţ öûţļîñé öƒ ɱáĵöŕ çŕéášéš ~~~~~~~~]\"],\"app.viewerToolbar.feetInches\":[\"[Ƒééţ & îñçĥéš ~~~]\"],\"app.viewerToolbar.flatAndFastNoAmbientOcclusion\":[\"[Ƒļáţ áñð ƒášţ — ñö áɱƀîéñţ öççļûšîöñ ~~~~~~~~~]\"],\"app.viewerToolbar.floorPlanAnnotations\":[\"[Ƒļööŕ þļáñ áññöţáţîöñš ~~~~~~]\"],\"app.viewerToolbar.floorPlanMode\":[\"[Ƒļööŕ þļáñ ɱöðé ~~~~]\"],\"app.viewerToolbar.fullAmbientOcclusion\":[\"[Ƒûļļ áɱƀîéñţ öççļûšîöñ ~~~~~~]\"],\"app.viewerToolbar.fullDocumentationAndAnnotationControls\":[\"[Ƒûļļ ðöçûɱéñţáţîöñ áñð áññöţáţîöñ çöñţŕöļš ~~~~~~~~~~~~]\"],\"app.viewerToolbar.fullHeight\":[\"[Ƒûļļ ĥéîĝĥţ ~~~]\"],\"app.viewerToolbar.ghostedForReference\":[\"[Ĝĥöšţéð ƒöŕ ŕéƒéŕéñçé ~~~~~~]\"],\"app.viewerToolbar.grid\":[\"[Ĝŕîð ~~]\"],\"app.viewerToolbar.id\":[\"[ÎÐ ~]\"],\"app.viewerToolbar.idOd\":[\"[ÎÐ + ÖÐ ~~]\"],\"app.viewerToolbar.inside\":[\"[Îñšîðé ~~]\"],\"app.viewerToolbar.levelsMode\":[\"[Ļéṽéļš: \",[\"mode\"],\" ~~]\"],\"app.viewerToolbar.low\":[\"[Ļöŵ ~]\"],\"app.viewerToolbar.magneticSnap\":[\"[Ṁáĝñéţîç šñáþ ~~~~]\"],\"app.viewerToolbar.manual\":[\"[Ṁáñûáļ ~~]\"],\"app.viewerToolbar.manualDimensions\":[\"[Ṁáñûáļ ðîɱéñšîöñš ~~~~~]\"],\"app.viewerToolbar.measureWalls\":[\"[Ṁéášûŕé ŵáļļš ~~~~]\"],\"app.viewerToolbar.measurements\":[\"[Ṁéášûŕéɱéñţš ~~~~]\"],\"app.viewerToolbar.meters\":[\"[Ṁéţéŕš ~~]\"],\"app.viewerToolbar.millimeters\":[\"[Ṁîļļîɱéţéŕš ~~~~]\"],\"app.viewerToolbar.n2dOnly\":[\"[2Ð öñļý ~~]\"],\"app.viewerToolbar.n3dOnly\":[\"[3Ð öñļý ~~]\"],\"app.viewerToolbar.noEdgeLines\":[\"[Ñö éðĝé ļîñéš ~~~~]\"],\"app.viewerToolbar.od\":[\"[ÖÐ ~]\"],\"app.viewerToolbar.off\":[\"[Öƒƒ ~]\"],\"app.viewerToolbar.on\":[\"[Öñ ~]\"],\"app.viewerToolbar.orthographic\":[\"[Öŕţĥöĝŕáþĥîç ~~~~]\"],\"app.viewerToolbar.otherLevels\":[\"[Öţĥéŕ ļéṽéļš ~~~~]\"],\"app.viewerToolbar.outside\":[\"[Öûţšîðé ~~~]\"],\"app.viewerToolbar.overallSizeOutsideFaceToOutsideFace\":[\"[Öṽéŕáļļ šîžé, öûţšîðé ƒáçé ţö öûţšîðé ƒáçé ~~~~~~~~~~~]\"],\"app.viewerToolbar.perspective\":[\"[Þéŕšþéçţîṽé ~~~~]\"],\"app.viewerToolbar.plan\":[\"[Þļáñ ~~]\"],\"app.viewerToolbar.preview\":[\"[Þŕéṽîéŵ ~~~]\"],\"app.viewerToolbar.previewMode\":[\"[Þŕéṽîéŵ ɱöðé ~~~~]\"],\"app.viewerToolbar.render\":[\"[Ŕéñðéŕ ~~]\"],\"app.viewerToolbar.rendered\":[\"[Ŕéñðéŕéð ~~~]\"],\"app.viewerToolbar.roomLabels\":[\"[Ŕööɱ ļáƀéļš ~~~]\"],\"app.viewerToolbar.roomSizesInsideFaceToInsideFace\":[\"[Ŕööɱ šîžéš, îñšîðé ƒáçé ţö îñšîðé ƒáçé ~~~~~~~~~~]\"],\"app.viewerToolbar.roomSizesInsideOverallSizeOutside\":[\"[Ŕööɱ šîžéš îñšîðé, öṽéŕáļļ šîžé öûţšîðé ~~~~~~~~~~]\"],\"app.viewerToolbar.scene\":[\"[Šçéñé ~~]\"],\"app.viewerToolbar.sceneTheme\":[\"[Šçéñé ţĥéɱé ~~~]\"],\"app.viewerToolbar.shadows\":[\"[Šĥáðöŵš ~~~]\"],\"app.viewerToolbar.sharedBy2dAnd3d\":[\"[Šĥáŕéð ƀý 2Ð áñð 3Ð ~~~~]\"],\"app.viewerToolbar.show\":[\"[Šĥöŵ ~~]\"],\"app.viewerToolbar.soft\":[\"[Šöƒţ ~~]\"],\"app.viewerToolbar.solid\":[\"[Šöļîð ~~]\"],\"app.viewerToolbar.solo\":[\"[Šöļö ~~]\"],\"app.viewerToolbar.stack\":[\"[Šţáçķ ~~]\"],\"app.viewerToolbar.stairAnnotations\":[\"[Šţáîŕ áññöţáţîöñš ~~~~~]\"],\"app.viewerToolbar.strong\":[\"[Šţŕöñĝ ~~]\"],\"app.viewerToolbar.structuralGridsColumnCenters\":[\"[Šţŕûçţûŕáļ ĝŕîðš & çöļûɱñ çéñţéŕš ~~~~~~~~~]\"],\"app.viewerToolbar.translucent\":[\"[Ţŕáñšļûçéñţ ~~~~]\"],\"app.viewerToolbar.turnOnDimensionsToShowThem\":[\"[Ţûŕñ öñ Ðîɱéñšîöñš ţö šĥöŵ ţĥéɱ ~~~~~~~~]\"],\"app.viewerToolbar.units\":[\"[Ûñîţš ~~]\"],\"app.viewerToolbar.walkthrough\":[\"[Ŵáļķţĥŕöûĝĥ ~~~~]\"],\"app.viewerToolbar.wallsLabel\":[\"[Ŵáļļš: \",[\"label\"],\" ~~]\"],\"core.level.basement\":[\"[Ɓášéɱéñţ ~~~]\"],\"core.level.basementNumber\":[\"[Ɓášéɱéñţ \",[\"number\"],\" ~~~]\"],\"core.level.floorNumber\":[\"[Ƒļööŕ \",[\"number\"],\" ~~]\"],\"core.level.groundFloor\":[\"[Ĝŕöûñð ƒļööŕ ~~~~]\"],\"editor.actionMenu.cameraActions.orbitLeft\":[\"[Öŕƀîţ Ļéƒţ ~~~]\"],\"editor.actionMenu.cameraActions.orbitRight\":[\"[Öŕƀîţ Ŕîĝĥţ ~~~]\"],\"editor.actionMenu.cameraActions.topView\":[\"[Ţöþ Ṽîéŵ ~~~]\"],\"editor.actionMenu.controlModes.delete\":[\"[Ðéļéţé ~~]\"],\"editor.actionMenu.controlModes.select\":[\"[Šéļéçţ ~~]\"],\"editor.actionMenu.followPascalPill.resumeFollowing\":[\"[Ŕéšûɱé ƒöļļöŵîñĝ ~~~~~]\"],\"editor.actionMenu.followPascalToggle.off\":[\"[Ƒöļļöŵ Þášçáļ: Öƒƒ ~~~~~]\"],\"editor.actionMenu.followPascalToggle.on\":[\"[Ƒöļļöŵ Þášçáļ: Öñ ~~~~~]\"],\"editor.actionMenu.furnishTools.appliance\":[\"[Åþþļîáñçé ~~~]\"],\"editor.actionMenu.furnishTools.bathroom\":[\"[Ɓáţĥŕööɱ ~~~]\"],\"editor.actionMenu.furnishTools.furniture\":[\"[Ƒûŕñîţûŕé ~~~]\"],\"editor.actionMenu.furnishTools.kitchen\":[\"[Ķîţçĥéñ ~~~]\"],\"editor.actionMenu.furnishTools.outdoor\":[\"[Öûţðööŕ ~~~]\"],\"editor.actionMenu.measurementControl.angle\":[\"[Åñĝļé ~~]\"],\"editor.actionMenu.measurementControl.angularDimension\":[\"[Åñĝûļáŕ ðîɱéñšîöñ ~~~~~]\"],\"editor.actionMenu.measurementControl.arcLength\":[\"[Åŕç ļéñĝţĥ ~~~]\"],\"editor.actionMenu.measurementControl.area\":[\"[Åŕéá ~~]\"],\"editor.actionMenu.measurementControl.centerMark\":[\"[Çéñţéŕ ɱáŕķ ~~~]\"],\"editor.actionMenu.measurementControl.chordDimension\":[\"[Çĥöŕð ðîɱéñšîöñ ~~~~~]\"],\"editor.actionMenu.measurementControl.continuousDimension\":[\"[Çöñţîñûöûš ðîɱéñšîöñ ~~~~~~]\"],\"editor.actionMenu.measurementControl.coordinateDimensions\":[\"[Çööŕðîñáţé ðîɱéñšîöñš ~~~~~~]\"],\"editor.actionMenu.measurementControl.diameterDimension\":[\"[Ðîáɱéţéŕ ðîɱéñšîöñ ~~~~~~]\"],\"editor.actionMenu.measurementControl.distance\":[\"[Ðîšţáñçé ~~~]\"],\"editor.actionMenu.measurementControl.floorPlan\":[\"[Ƒļööŕ þļáñ ~~~]\"],\"editor.actionMenu.measurementControl.linearDimension\":[\"[Ļîñéáŕ ðîɱéñšîöñ ~~~~~]\"],\"editor.actionMenu.measurementControl.measureSelectedlabel\":[\"[Ṁéášûŕé: \",[\"selectedLabel\"],\" ~~~]\"],\"editor.actionMenu.measurementControl.measurementOptions\":[\"[Ṁéášûŕéɱéñţ öþţîöñš ~~~~~~]\"],\"editor.actionMenu.measurementControl.measurementType\":[\"[Ṁéášûŕéɱéñţ ţýþé ~~~~~]\"],\"editor.actionMenu.measurementControl.perimeter\":[\"[Þéŕîɱéţéŕ ~~~]\"],\"editor.actionMenu.measurementControl.radiusDimension\":[\"[Ŕáðîûš ðîɱéñšîöñ ~~~~~]\"],\"editor.actionMenu.measurementControl.smart\":[\"[Šɱáŕţ ~~]\"],\"editor.actionMenu.measurementControl.volume\":[\"[Ṽöļûɱé ~~]\"],\"editor.actionMenu.pointAskButton.pointAndAsk\":[\"[Þöîñţ áñð ášķ ~~~~]\"],\"editor.actionMenu.pointAskButton.pointAndAskC\":[\"[Þöîñţ áñð ášķ (Ç) ~~~~]\"],\"editor.actionMenu.pointAskButton.pointAndAskWorksInThe\":[\"[Þöîñţ áñð ášķ ŵöŕķš îñ ţĥé 3Ð ṽîéŵ ~~~~~~~~]\"],\"editor.actionMenu.structureTools.beam\":[\"[Ɓéáɱ ~~]\"],\"editor.actionMenu.structureTools.ceiling\":[\"[Çéîļîñĝ ~~~]\"],\"editor.actionMenu.structureTools.column\":[\"[Çöļûɱñ ~~]\"],\"editor.actionMenu.structureTools.door\":[\"[Ðööŕ ~~]\"],\"editor.actionMenu.structureTools.duct\":[\"[Ðûçţ ~~]\"],\"editor.actionMenu.structureTools.ductFitting\":[\"[Ðûçţ Ƒîţţîñĝ ~~~~]\"],\"editor.actionMenu.structureTools.dwvPipe\":[\"[ÐŴṼ Þîþé ~~~]\"],\"editor.actionMenu.structureTools.elevator\":[\"[Éļéṽáţöŕ ~~~]\"],\"editor.actionMenu.structureTools.fence\":[\"[Ƒéñçé ~~]\"],\"editor.actionMenu.structureTools.gableRoof\":[\"[Ĝáƀļé Ŕööƒ ~~~]\"],\"editor.actionMenu.structureTools.hvacUnit\":[\"[ĤṼÅÇ Ûñîţ ~~~]\"],\"editor.actionMenu.structureTools.lineset\":[\"[Ļîñéšéţ ~~~]\"],\"editor.actionMenu.structureTools.liquidLine\":[\"[Ļîǫûîð Ļîñé ~~~]\"],\"editor.actionMenu.structureTools.pipeFitting\":[\"[Þîþé Ƒîţţîñĝ ~~~~]\"],\"editor.actionMenu.structureTools.register\":[\"[Ŕéĝîšţéŕ ~~~]\"],\"editor.actionMenu.structureTools.shelf\":[\"[Šĥéļƒ ~~]\"],\"editor.actionMenu.structureTools.slab\":[\"[Šļáƀ ~~]\"],\"editor.actionMenu.structureTools.spawnPoint\":[\"[Šþáŵñ Þöîñţ ~~~]\"],\"editor.actionMenu.structureTools.stairs\":[\"[Šţáîŕš ~~]\"],\"editor.actionMenu.structureTools.trap\":[\"[Ţŕáþ ~~]\"],\"editor.actionMenu.structureTools.wall\":[\"[Ŵáļļ ~~]\"],\"editor.actionMenu.structureTools.window\":[\"[Ŵîñðöŵ ~~]\"],\"editor.actionMenu.structureTools.zone\":[\"[Žöñé ~~]\"],\"editor.actionMenu.viewToggles.dashedOutlinesOfTheNeighbouringLevels\":[\"[Ðášĥéð öûţļîñéš öƒ ţĥé ñéîĝĥƀöûŕîñĝ ļéṽéļš’ ŵáļļš, ţö ļîñé ŵáļļš ûþ áñð çĥéçķ á ŕööƒ áĝáîñšţ ţĥé ŵáļļš ûñðéŕ îţ. ~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.actionMenu.viewToggles.deleteGuideImage\":[\"[Ðéļéţé ĝûîðé îɱáĝé ~~~~~]\"],\"editor.actionMenu.viewToggles.deleteScan\":[\"[Ðéļéţé šçáñ ~~~]\"],\"editor.actionMenu.viewToggles.guideCount\":[\"[\",[\"count\",\"plural\",{\"one\":[\"#\",\" ĝûîðé îɱáĝé öñ ţĥîš ļéṽéļ\"],\"other\":[\"#\",\" ĝûîðé îɱáĝéš öñ ţĥîš ļéṽéļ\"]}],\" ~~~~~~~~~~~~~]\"],\"editor.actionMenu.viewToggles.guideImageNumber\":[\"[Ĝûîðé îɱáĝé \",[\"number\"],\" ~~~]\"],\"editor.actionMenu.viewToggles.guideImageSettings\":[\"[Ĝûîðé îɱáĝé šéţţîñĝš ~~~~~~]\"],\"editor.actionMenu.viewToggles.guideImages\":[\"[Ĝûîðé îɱáĝéš ~~~~]\"],\"editor.actionMenu.viewToggles.guides\":[\"[Ĝûîðéš ~~]\"],\"editor.actionMenu.viewToggles.guidesHidden\":[\"[Ĝûîðéš: Ĥîððéñ ~~~~]\"],\"editor.actionMenu.viewToggles.guidesVisible\":[\"[Ĝûîðéš: Ṽîšîƀļé ~~~~]\"],\"editor.actionMenu.viewToggles.hideGuideImages\":[\"[Ĥîðé ĝûîðé îɱáĝéš ~~~~~]\"],\"editor.actionMenu.viewToggles.hideReferenceFloor\":[\"[Ĥîðé ŕéƒéŕéñçé ƒļööŕ ~~~~~~]\"],\"editor.actionMenu.viewToggles.hideScans\":[\"[Ĥîðé šçáñš ~~~]\"],\"editor.actionMenu.viewToggles.levelsBelow\":[\"[\",[\"count\"],\" ƀéļöŵ ~~]\"],\"editor.actionMenu.viewToggles.noLevelAbove\":[\"[Ñö ļéṽéļ áƀöṽé ~~~~]\"],\"editor.actionMenu.viewToggles.noLevelBelow\":[\"[Ñö ļéṽéļ ƀéļöŵ ~~~~]\"],\"editor.actionMenu.viewToggles.noLowerFloorAvailable\":[\"[Ñö ļöŵéŕ ƒļööŕ áṽáîļáƀļé. ~~~~~~~]\"],\"editor.actionMenu.viewToggles.opacity\":[\"[Öþáçîţý ~~~]\"],\"editor.actionMenu.viewToggles.referenceFloor\":[\"[Ŕéƒéŕéñçé ƒļööŕ ~~~~~]\"],\"editor.actionMenu.viewToggles.referenceFloorSelectedlevelname\":[\"[Ŕéƒéŕéñçé ƒļööŕ: \",[\"selectedLevelName\"],\" ~~~~~]\"],\"editor.actionMenu.viewToggles.referenceFloorSettings\":[\"[Ŕéƒéŕéñçé ƒļööŕ šéţţîñĝš ~~~~~~~]\"],\"editor.actionMenu.viewToggles.referenceSettings\":[\"[Ŕéƒéŕéñçé šéţţîñĝš ~~~~~~]\"],\"editor.actionMenu.viewToggles.references\":[\"[Ŕéƒéŕéñçéš ~~~]\"],\"editor.actionMenu.viewToggles.referencesEmpty\":[\"[Ûþļöáð ĜĻƁ ɱéšĥéš áš šçáñ ŕéƒéŕéñçéš öŕ ƀļûéþŕîñţ îɱáĝéš áš ĝûîðé ŕéƒéŕéñçéš. ~~~~~~~~~~~~~~~~~~~~]\"],\"editor.actionMenu.viewToggles.referencesHidden\":[\"[Ŕéƒéŕéñçéš: Ĥîððéñ ~~~~~]\"],\"editor.actionMenu.viewToggles.referencesVisible\":[\"[Ŕéƒéŕéñçéš: Ṽîšîƀļé ~~~~~~]\"],\"editor.actionMenu.viewToggles.riserDiagram\":[\"[Ŕîšéŕ ðîáĝŕáɱ ~~~~]\"],\"editor.actionMenu.viewToggles.scanCount\":[\"[\",[\"count\",\"plural\",{\"one\":[\"#\",\" šçáñ öñ ţĥîš ļéṽéļ\"],\"other\":[\"#\",\" šçáñš öñ ţĥîš ļéṽéļ\"]}],\" ~~~~~~~~~~]\"],\"editor.actionMenu.viewToggles.scanNumber\":[\"[Šçáñ \",[\"number\"],\" ~~]\"],\"editor.actionMenu.viewToggles.scanSettings\":[\"[Šçáñ šéţţîñĝš ~~~~]\"],\"editor.actionMenu.viewToggles.scans\":[\"[Šçáñš ~~]\"],\"editor.actionMenu.viewToggles.scansHidden\":[\"[Šçáñš: Ĥîððéñ ~~~~]\"],\"editor.actionMenu.viewToggles.scansVisible\":[\"[Šçáñš: Ṽîšîƀļé ~~~~]\"],\"editor.actionMenu.viewToggles.showGuideImages\":[\"[Šĥöŵ ĝûîðé îɱáĝéš ~~~~~]\"],\"editor.actionMenu.viewToggles.showReferenceFloor\":[\"[Šĥöŵ ŕéƒéŕéñçé ƒļööŕ ~~~~~~]\"],\"editor.actionMenu.viewToggles.showScans\":[\"[Šĥöŵ šçáñš ~~~]\"],\"editor.actionMenu.viewToggles.showWallsBelowAndAbove\":[\"[Šĥöŵ ŵáļļš ƀéļöŵ áñð áƀöṽé ~~~~~~~]\"],\"editor.actionMenu.viewToggles.uploadScanOrGuideImage\":[\"[Ûþļöáð šçáñ öŕ ĝûîðé îɱáĝé ~~~~~~~]\"],\"editor.actionMenu.viewToggles.wallsAbove\":[\"[Ŵáļļš áƀöṽé ~~~]\"],\"editor.actionMenu.viewToggles.wallsBelow\":[\"[Ŵáļļš ƀéļöŵ ~~~]\"],\"editor.actionMenu.viewToggles.wallsBelowAndAbove\":[\"[Ŵáļļš ƀéļöŵ áñð áƀöṽé ~~~~~~]\"],\"editor.actionMenu.viewToggles.wallsBelowAndAboveSettings\":[\"[Ŵáļļš ƀéļöŵ áñð áƀöṽé šéţţîñĝš ~~~~~~~~]\"],\"editor.actionMenu.viewToggles.wallsBelowAndAboveShown\":[\"[Ŵáļļš ƀéļöŵ áñð áƀöṽé: šĥöŵñ ~~~~~~~]\"],\"editor.backToHome\":[\"[Ɓáçķ ţö ĥöɱé ~~~]\"],\"editor.buildPanel.advanced\":[\"[Åðṽáñçéð ~~~]\"],\"editor.buildPanel.rooms.hint\":[\"[ŵáļļš · ƒļööŕ · çéîļîñĝ ~~~~~~]\"],\"editor.buildPanel.rooms.idle\":[\"[Þîçķ á šĥáþé ţö šţáŕţ. Éṽéŕý ŕööɱ ƀŕîñĝš îţš öŵñ ŵáļļš, ƒļööŕ áñð çéîļîñĝ. ~~~~~~~~~~~~~~~~~~]\"],\"editor.buildPanel.rooms.polygon.caption\":[\"[\",[\"lead\"],\" ţĥéñ ţĥé ƒîŕšţ öñé áĝáîñ ţö çļöšé. Ƒöŕ Ļ-šĥáþéš áñð áñĝļéð ŕööɱš. ~~~~~~~~~~~~~~~~]\"],\"editor.buildPanel.rooms.polygon.label\":[\"[Þöļýĝöñ ~~~]\"],\"editor.buildPanel.rooms.polygon.lead\":[\"[Çļîçķ éáçĥ çöŕñéŕ, ~~~~~]\"],\"editor.buildPanel.rooms.polygon.title\":[\"[Þöļýĝöñ ŕööɱ ~~~~]\"],\"editor.buildPanel.rooms.rectangle.caption\":[\"[\",[\"lead\"],\" öñ ţĥé ĝŕîð. Ŵáļļš, ƒļööŕ áñð çéîļîñĝ áŕé çŕéáţéð ţöĝéţĥéŕ. ~~~~~~~~~~~~~~~]\"],\"editor.buildPanel.rooms.rectangle.label\":[\"[Ŕéçţáñĝļé ~~~]\"],\"editor.buildPanel.rooms.rectangle.lead\":[\"[Çļîçķ ţŵö çöŕñéŕš ~~~~~]\"],\"editor.buildPanel.rooms.rectangle.title\":[\"[Ŕéçţáñĝļé ŕööɱ ~~~~]\"],\"editor.buildPanel.rooms.title\":[\"[Ŕööɱš ~~]\"],\"editor.buildPanel.rooms.wallKinds.invisibleHelp\":[\"[Ðîṽîðéš á ŕööɱ öŕ çļöšéš öƒƒ á þöŕçĥ ŵîţĥöûţ ƀûîļðîñĝ á ŵáļļ; ŕööɱš çļöšé öñ îţ. Çĥáñĝé áñý ŵáļļ ļáţéŕ ƒŕöɱ îţš çöñţŕöļš. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.buildPanel.rooms.wallKinds.label\":[\"[Ŵáļļ ķîñð ~~~]\"],\"editor.buildPanel.rooms.wallKinds.railingHelp\":[\"[Å ĝûáŕð ƒöŕ šţáîŕš, ƀáļçöñîéš áñð ɱéžžáñîñéš; ŕööɱš çļöšé öñ îţ. Çĥáñĝé áñý ŵáļļ ļáţéŕ ƒŕöɱ îţš çöñţŕöļš. ~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.buildPanel.rooms.wallKinds.standardHelp\":[\"[Öñé ŵáļļ þéŕ ţŵö çļîçķš. Îţš šîðéš ƀéçöɱé éẋţéŕîöŕ öŕ îñţéŕîöŕ ƒŕöɱ ţĥé ŕööɱš îţ ƀöûñðš. Çĥáñĝé áñý ŵáļļ ļáţéŕ ƒŕöɱ îţš çöñţŕöļš. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.buildPanel.rooms.walls.label\":[\"[Ŵáļļš ~~]\"],\"editor.buildPanel.rooms.walls.title\":[\"[Ŵáļļš ~~]\"],\"editor.buildPanel.wallTypeControls.deleteFromThisProject\":[\"[Ðéļéţé ƒŕöɱ ţĥîš þŕöĵéçţ ~~~~~~~]\"],\"editor.buildPanel.wallTypeControls.duplicateAsANewType\":[\"[Ðûþļîçáţé áš á ñéŵ ţýþé… ~~~~~~]\"],\"editor.buildPanel.wallTypeControls.editLayers\":[\"[Éðîţ ļáýéŕš… ~~~]\"],\"editor.buildPanel.wallTypeControls.editOrDuplicateThisWallType\":[\"[Éðîţ öŕ ðûþļîçáţé ţĥîš ŵáļļ ţýþé ~~~~~~~~~]\"],\"editor.buildPanel.wallTypeControls.newWallType\":[\"[Ñéŵ ŵáļļ ţýþé… ~~~~]\"],\"editor.buildPanel.wallTypeControls.presetsStayAsCitedDuplicateOne\":[\"[Þŕéšéţš šţáý áš çîţéð. Ðûþļîçáţé öñé ţö çĥáñĝé îţš ļáýéŕš. ~~~~~~~~~~~~~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.aWallTypeHoldsAtMost\":[\"[Å ŵáļļ ţýþé ĥöļðš áţ ɱöšţ \",[\"limit\",\"plural\",{\"one\":[\"#\",\" ļáýéŕ\"],\"other\":[\"#\",\" ļáýéŕš\"]}],\". ~~~~~~~~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.add\":[\"[Åðð ~]\"],\"editor.buildPanel.wallTypeEditorDialog.airSpace\":[\"[Åîŕ šþáçé ~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.brickVeneer\":[\"[Ɓŕîçķ ṽéñééŕ ~~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.cancel\":[\"[Çáñçéļ ~~]\"],\"editor.buildPanel.wallTypeEditorDialog.drywall\":[\"[Ðŕýŵáļļ ~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.duplicateWallType\":[\"[Ðûþļîçáţé ŵáļļ ţýþé ~~~~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.editWallType\":[\"[Éðîţ ŵáļļ ţýþé ~~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.everyWallTypeHasOneFraming\":[\"[Éṽéŕý ŵáļļ ţýþé ĥáš öñé ƒŕáɱîñĝ çöŕé ~~~~~~~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.fiberCement\":[\"[Ƒîƀéŕ çéɱéñţ ~~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.finish\":[\"[Ƒîñîšĥ ~~]\"],\"editor.buildPanel.wallTypeEditorDialog.framingCore\":[\"[Ƒŕáɱîñĝ çöŕé ~~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.fullreasonRemoveOneToAddAnother\":[\"[\",[\"fullReason\"],\" Ŕéɱöṽé öñé ţö áðð áñöţĥéŕ. ~~~~~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.gypsumSheathing\":[\"[Ĝýþšûɱ šĥéáţĥîñĝ ~~~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.inside\":[\"[Îñšîðé ~~]\"],\"editor.buildPanel.wallTypeEditorDialog.insulation\":[\"[Îñšûļáţîöñ ~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.lapSiding\":[\"[Ļáþ šîðîñĝ ~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.layer\":[\"[Ļáýéŕ ~~]\"],\"editor.buildPanel.wallTypeEditorDialog.layerRole\":[\"[Ļáýéŕ ŕöļé ~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.lining\":[\"[Ļîñîñĝ ~~]\"],\"editor.buildPanel.wallTypeEditorDialog.material\":[\"[Ṁáţéŕîáļ ~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.mineralWoolBoard\":[\"[Ṁîñéŕáļ ŵööļ ƀöáŕð ~~~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.moveIn\":[\"[Ṁöṽé îñ ~~]\"],\"editor.buildPanel.wallTypeEditorDialog.moveOut\":[\"[Ṁöṽé öûţ ~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.name\":[\"[Ñáɱé ~~]\"],\"editor.buildPanel.wallTypeEditorDialog.newWallType\":[\"[Ñéŵ ŵáļļ ţýþé ~~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.osb\":[\"[ÖŠƁ ~]\"],\"editor.buildPanel.wallTypeEditorDialog.outside\":[\"[Öûţšîðé ~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.plaster\":[\"[Þļášţéŕ ~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.plywood\":[\"[Þļýŵööð ~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.removeLayer\":[\"[Ŕéɱöṽé ļáýéŕ ~~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.rigidFoam\":[\"[Ŕîĝîð ƒöáɱ ~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.saveWallType\":[\"[Šáṽé ŵáļļ ţýþé ~~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.sheathing\":[\"[Šĥéáţĥîñĝ ~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.stoneVeneer\":[\"[Šţöñé ṽéñééŕ ~~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.stucco\":[\"[Šţûççö ~~]\"],\"editor.buildPanel.wallTypeEditorDialog.thickness\":[\"[Ţĥîçķñéšš ~~~]\"],\"editor.buildPanel.wallTypeEditorDialog.totalThickness\":[\"[Ţöţáļ \",[\"thickness\"],\" ~~]\"],\"editor.buildPanel.wallTypeEditorDialog.wallType\":[\"[Ŵáļļ ţýþé ~~~]\"],\"editor.buildPanel.wallTypes.plainWall\":[\"[Þļáîñ ŵáļļ ~~~]\"],\"editor.cameraControlsHint\":[\"[Çáɱéŕá çöñţŕöļš ĥîñţ ~~~~~~]\"],\"editor.cameraHint.pan\":[\"[Þáñ ~]\"],\"editor.cameraHint.rotate\":[\"[Ŕöţáţé ~~]\"],\"editor.cameraHint.zoom\":[\"[Žööɱ ~~]\"],\"editor.controls.finishSwatch.ariaLabel\":[[\"label\"],\": \",[\"finish\"]],\"editor.controls.finishSwatch.default\":[\"[Ðéƒáûļţ ~~~]\"],\"editor.dismiss\":[\"[Ðîšɱîšš ~~~]\"],\"editor.dismissCameraControlsHint\":[\"[Ðîšɱîšš çáɱéŕá çöñţŕöļš ĥîñţ ~~~~~~~~]\"],\"editor.expandSidebar\":[\"[Éẋþáñð šîðéƀáŕ ~~~~]\"],\"editor.floatingActionMenu.axis\":[\"[Åẋîš ~~]\"],\"editor.floatingActionMenu.axis2\":[\"[⌥ áẋîš ~~]\"],\"editor.floatingActionMenu.noEquipment\":[\"[⚠ ñö éǫûîþɱéñţ ~~~~]\"],\"editor.floatingActionMenu.rTRotate\":[\"[Ŕ/Ţ ŕöţáţé ~~~]\"],\"editor.floatingActionMenu.registerCount\":[\"[\",[\"count\",\"plural\",{\"one\":[\"#\",\" ŕéĝîšţéŕ\"],\"other\":[\"#\",\" ŕéĝîšţéŕš\"]}],\" ~~~~~~]\"],\"editor.floatingActionMenu.runCount\":[\"[\",[\"count\",\"plural\",{\"one\":[[\"number\"],\" ŕûñ\"],\"other\":[[\"number\"],\" ŕûñš\"]}],\" ~~~]\"],\"editor.floatingActionMenu.system\":[\"[Šýšţéɱ ~~]\"],\"editor.floatingLevelSelector.addAFloorUnderTheRoof\":[\"[Åðð á ƒļööŕ ûñðéŕ ţĥé ŕööƒ ~~~~~~~]\"],\"editor.floatingLevelSelector.addLevelAbove\":[\"[Åðð ļéṽéļ áƀöṽé ~~~~]\"],\"editor.floatingLevelSelector.addLevelBelow\":[\"[Åðð ļéṽéļ ƀéļöŵ ~~~~]\"],\"editor.floatingLevelSelector.cancel\":[\"[Çáñçéļ ~~]\"],\"editor.floatingLevelSelector.delete\":[\"[Ðéļéţé ~~]\"],\"editor.floatingLevelSelector.deleteLevel\":[\"[Ðéļéţé ļéṽéļ ~~~~]\"],\"editor.floatingLevelSelector.deleteLevelConfirm\":[\"[Åŕé ýöû šûŕé ýöû ŵáñţ ţö ðéļéţé \",[\"levelName\"],\"? Åļļ ŵáļļš, ƒļööŕš, áñð öƀĵéçţš öñ ţĥîš ļéṽéļ ŵîļļ ƀé þéŕɱáñéñţļý ŕéɱöṽéð. ~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.floatingLevelSelector.dragToReorder\":[\"[Ðŕáĝ ţö ŕéöŕðéŕ ~~~~]\"],\"editor.floatingLevelSelector.duplicateLevel\":[\"[Ðûþļîçáţé ļéṽéļ ~~~~~]\"],\"editor.floatingLevelSelector.duplicateWithOptions\":[\"[Ðûþļîçáţé ŵîţĥ öþţîöñš... ~~~~~~]\"],\"editor.floatingLevelSelector.exitUnitFocus\":[\"[Éẋîţ ûñîţ ƒöçûš ~~~~]\"],\"editor.floatingLevelSelector.focusedUnitHasZonesHere\":[\"[Ƒöçûšéð ûñîţ ĥáš žöñéš ĥéŕé ~~~~~~~]\"],\"editor.floatingLevelSelector.groundFloorOverGrade\":[\"[Ţĥé ĝŕöûñð ƒļööŕ šţáñðš \",[\"distance\"],\" öṽéŕ ĝŕáðé. Šéáţ ţĥé ĝŕöûñð ƒļööŕ 8 îñ öṽéŕ ĝŕáðé ~~~~~~~~~~~~~~~~~~]\"],\"editor.floatingLevelSelector.groundFloorUnderGrade\":[\"[Ţĥé ĝŕöûñð ƒļööŕ šţáñðš \",[\"distance\"],\" ûñðéŕ ĝŕáðé. Šéáţ ţĥé ĝŕöûñð ƒļööŕ 8 îñ öṽéŕ ĝŕáðé ~~~~~~~~~~~~~~~~~~]\"],\"editor.floatingLevelSelector.groundLineTheLevelsUnderIt\":[\"[Ĝŕöûñð ļîñé: ţĥé ļéṽéļš ûñðéŕ îţ áŕé ƀéļöŵ ĝŕáðé ~~~~~~~~~~~~]\"],\"editor.floatingLevelSelector.groundOffset\":[\"[Ĝŕöûñð · \",[\"offset\"],\" ~~]\"],\"editor.floatingLevelSelector.insertLevelHere\":[\"[Îñšéŕţ ļéṽéļ ĥéŕé ~~~~~]\"],\"editor.floatingLevelSelector.levelHeight\":[\"[Ļéṽéļ ĥéîĝĥţ ~~~~]\"],\"editor.floatingLevelSelector.pasteCopiedSelection\":[\"[Þášţé çöþîéð šéļéçţîöñ ~~~~~~]\"],\"editor.floatingLevelSelector.reorderLevelname\":[\"[Ŕéöŕðéŕ \",[\"levelName\"],\" ~~~]\"],\"editor.floatingLevelSelector.seatTheBuildingSoThisFloor\":[\"[Šéáţ ţĥé ƀûîļðîñĝ šö ţĥîš ƒļööŕ šţáñðš áţ ĝŕáðé; ţĥé ƒļööŕš ûñðéŕ îţ áŕé ƀéļöŵ ĝŕáðé ~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.floatingLevelSelector.setAsGroundFloor\":[\"[Šéţ áš ĝŕöûñð ƒļööŕ ~~~~~]\"],\"editor.floatingLevelSelector.theGroundLevelCannotBeDeleted\":[\"[Ţĥé ĝŕöûñð ļéṽéļ çáññöţ ƀé ðéļéţéð ~~~~~~~~~]\"],\"editor.floatingLevelSelector.thisFloorStandsAtGrade\":[\"[Ţĥîš ƒļööŕ šţáñðš áţ ĝŕáðé ~~~~~~~]\"],\"editor.floatingLevelSelector.unit\":[\"[Ûñîţ ~~]\"],\"editor.floorFootprint.area\":[\"[Ƒļööŕ áŕéá ~~~]\"],\"editor.floorFootprint.room\":[\"[\",[\"room\"],\" ƒļööŕ ~~]\"],\"editor.floorFootprint.shared\":[\"[Šĥáŕéð ƒļööŕ ~~~~]\"],\"editor.helpers.buildingHelper.cancel\":[\"[Çáñçéļ ~~]\"],\"editor.helpers.buildingHelper.placeBuilding\":[\"[Þļáçé ƀûîļðîñĝ ~~~~]\"],\"editor.helpers.buildingHelper.rotate\":[\"[Ŕöţáţé ~~]\"],\"editor.helpers.contextualHelperPanel.cancelPlacement\":[\"[Çáñçéļ þļáçéɱéñţ ~~~~~]\"],\"editor.helpers.contextualHelperPanel.continuationClickOrPressCTo\":[\"[Çöñţîñûáţîöñ — çļîçķ öŕ þŕéšš Ç ţö çýçļé ~~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.continuationLabel\":[\"[Çöñţîñûáţîöñ: \",[\"label\"],\" ~~~~]\"],\"editor.helpers.contextualHelperPanel.dragToDrawFence\":[\"[Ðŕáĝ ţö ðŕáŵ ƒéñçé ~~~~~]\"],\"editor.helpers.contextualHelperPanel.eraseScope\":[\"[Éŕášé: \",[\"scope\"],\" ~~]\"],\"editor.helpers.contextualHelperPanel.eraseScopeClickOrPressShift\":[\"[Éŕášé šçöþé — çļîçķ öŕ þŕéšš Šĥîƒţ ţö çýçļé ~~~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.eraseScopeLabel\":[\"[Éŕášé šçöþé: \",[\"scope\"],\" ~~~]\"],\"editor.helpers.contextualHelperPanel.fenceTypeClickOrPressT\":[\"[Ƒéñçé ţýþé — çļîçķ öŕ þŕéšš Ţ ţö šŵîţçĥ ƀéţŵééñ šţŕáîĝĥţ, çûŕṽéð áñð ƒŕééĥáñð ~~~~~~~~~~~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.fewerShortcuts\":[\"[Ƒéŵéŕ šĥöŕţçûţš ~~~~~]\"],\"editor.helpers.contextualHelperPanel.finishCurveOrDoubleClick\":[\"[Ƒîñîšĥ çûŕṽé (öŕ ðöûƀļé-çļîçķ) ~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.gridLength\":[\"[Ĝŕîð: \",[\"length\"],\" ~~]\"],\"editor.helpers.contextualHelperPanel.gridStepClickOrTapCtrl\":[\"[Ĝŕîð šţéþ — çļîçķ öŕ ţáþ Çţŕļ ţö çýçļé ~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.gridStepLength\":[\"[Ĝŕîð šţéþ: \",[\"length\"],\" ~~~]\"],\"editor.helpers.contextualHelperPanel.hoverAPaintedSurfaceToErase\":[\"[Ĥöṽéŕ á þáîñţéð šûŕƒáçé ţö éŕášé ~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.hoverASurfaceToPaint\":[\"[Ĥöṽéŕ á šûŕƒáçé ţö þáîñţ ~~~~~~]\"],\"editor.helpers.contextualHelperPanel.hoverASurfaceToPickIts\":[\"[Ĥöṽéŕ á šûŕƒáçé ţö þîçķ îţš ɱáţéŕîáļ ~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.moreShortcuts\":[\"[Ṁöŕé šĥöŕţçûţš ~~~~]\"],\"editor.helpers.contextualHelperPanel.paintScope\":[\"[Þáîñţ: \",[\"scope\"],\" ~~]\"],\"editor.helpers.contextualHelperPanel.paintScopeClickOrPressShift\":[\"[Þáîñţ šçöþé — çļîçķ öŕ þŕéšš Šĥîƒţ ţö çýçļé ~~~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.paintScopeLabel\":[\"[Þáîñţ šçöþé: \",[\"scope\"],\" ~~~]\"],\"editor.helpers.contextualHelperPanel.pickScope\":[\"[Þîçķ: \",[\"scope\"],\" ~~]\"],\"editor.helpers.contextualHelperPanel.placeGateOnAFence\":[\"[Þļáçé ĝáţé öñ á ƒéñçé ~~~~~~]\"],\"editor.helpers.contextualHelperPanel.placePassageOnAFence\":[\"[Þļáçé þáššáĝé öñ á ƒéñçé ~~~~~~]\"],\"editor.helpers.contextualHelperPanel.selectAMaterialToPaint\":[\"[Šéļéçţ á ɱáţéŕîáļ ţö þáîñţ ~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.snappingAngles\":[\"[Šñáþþîñĝ: Åñĝļéš ~~~~~]\"],\"editor.helpers.contextualHelperPanel.snappingGrid\":[\"[Šñáþþîñĝ: Ĝŕîð ~~~~]\"],\"editor.helpers.contextualHelperPanel.snappingLines\":[\"[Šñáþþîñĝ: Ļîñéš ~~~~]\"],\"editor.helpers.contextualHelperPanel.snappingModeClickOrPressShift\":[\"[Šñáþþîñĝ ɱöðé — çļîçķ öŕ þŕéšš Šĥîƒţ ţö çýçļé ~~~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.snappingOff\":[\"[Šñáþþîñĝ: Öƒƒ ~~~~]\"],\"editor.helpers.contextualHelperPanel.straightContinuationIsUnavailableForCurved\":[\"[Šţŕáîĝĥţ çöñţîñûáţîöñ îš ûñáṽáîļáƀļé ƒöŕ çûŕṽéð öŕ ƒŕééĥáñð ƒéñçéš ~~~~~~~~~~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.straightContinuous\":[\"[Šţŕáîĝĥţ: Çöñţîñûöûš ~~~~~~]\"],\"editor.helpers.contextualHelperPanel.straightFenceContinuationClickOrPress\":[\"[Šţŕáîĝĥţ ƒéñçé çöñţîñûáţîöñ — çļîçķ öŕ þŕéšš Ç ţö ţöĝĝļé ~~~~~~~~~~~~~~]\"],\"editor.helpers.contextualHelperPanel.straightSingle\":[\"[Šţŕáîĝĥţ: Šîñĝļé ~~~~~]\"],\"editor.helpers.helperManager.addPoint\":[\"[Åðð þöîñţ ~~~]\"],\"editor.helpers.helperManager.addPointClickTheFirstTo\":[\"[Åðð þöîñţ · çļîçķ ţĥé ƒîŕšţ ţö çļöšé ~~~~~~~~~]\"],\"editor.helpers.helperManager.brushSize\":[\"[Ɓŕûšĥ šîžé ~~~]\"],\"editor.helpers.helperManager.cancel\":[\"[Çáñçéļ ~~]\"],\"editor.helpers.helperManager.cancelPicking\":[\"[Çáñçéļ þîçķîñĝ ~~~~]\"],\"editor.helpers.helperManager.cancelStroke\":[\"[Çáñçéļ šţŕöķé ~~~~]\"],\"editor.helpers.helperManager.done\":[\"[Ðöñé ~~]\"],\"editor.helpers.helperManager.drawTheMezzanine\":[\"[Ðŕáŵ ţĥé ɱéžžáñîñé ~~~~~]\"],\"editor.helpers.helperManager.drawTheOpening\":[\"[Ðŕáŵ ţĥé öþéñîñĝ ~~~~~]\"],\"editor.helpers.helperManager.drawTheTerrace\":[\"[Ðŕáŵ ţĥé ţéŕŕáçé ~~~~~]\"],\"editor.helpers.helperManager.exitSmartMeasure\":[\"[Éẋîţ šɱáŕţ ɱéášûŕé ~~~~~]\"],\"editor.helpers.helperManager.finish\":[\"[Ƒîñîšĥ ~~]\"],\"editor.helpers.helperManager.finishAtTheEdge\":[\"[Ƒîñîšĥ áţ ţĥé éðĝé ~~~~~]\"],\"editor.helpers.helperManager.freeMove\":[\"[Ƒŕéé ɱöṽé ~~~]\"],\"editor.helpers.helperManager.freeMoveSlideDoorsAndWindows\":[\"[Ƒŕéé ɱöṽé · šļîðé ðööŕš áñð ŵîñðöŵš ~~~~~~~~~]\"],\"editor.helpers.helperManager.holdToPickAMaterial\":[\"[Ĥöļð ţö þîçķ á ɱáţéŕîáļ ~~~~~~]\"],\"editor.helpers.helperManager.inspectSurfaceDimensions\":[\"[Îñšþéçţ šûŕƒáçé ðîɱéñšîöñš ~~~~~~~~]\"],\"editor.helpers.helperManager.paintWithThisMaterial\":[\"[Þáîñţ ŵîţĥ ţĥîš ɱáţéŕîáļ ~~~~~~~]\"],\"editor.helpers.helperManager.pickTargetHeight\":[\"[Þîçķ ţáŕĝéţ ĥéîĝĥţ ~~~~~]\"],\"editor.helpers.helperManager.pinMeasurementLens\":[\"[Þîñ ɱéášûŕéɱéñţ ļéñš ~~~~~~]\"],\"editor.helpers.helperManager.place\":[\"[Þļáçé ~~]\"],\"editor.helpers.helperManager.placeInsideTheRoom\":[\"[Þļáçé îñšîðé ţĥé ŕööɱ ~~~~~~]\"],\"editor.helpers.helperManager.pressAnywhereDragToTheOpposite\":[\"[Þŕéšš áñýŵĥéŕé, ðŕáĝ ţö ţĥé öþþöšîţé çöŕñéŕ ~~~~~~~~~~~]\"],\"editor.helpers.helperManager.raiseOrLower\":[\"[Ŕáîšé öŕ ļöŵéŕ ~~~~]\"],\"editor.helpers.helperManager.removeAPaintedPartOrReset\":[\"[Ŕéɱöṽé á þáîñţéð þáŕţ, öŕ ŕéšéţ á šûŕƒáçé ~~~~~~~~~~]\"],\"editor.helpers.helperManager.removeLastPoint\":[\"[Ŕéɱöṽé ļášţ þöîñţ ~~~~~]\"],\"editor.helpers.helperManager.resize\":[\"[Ŕéšîžé ~~]\"],\"editor.helpers.helperManager.rotate45\":[\"[Ŕöţáţé ±45° ~~]\"],\"editor.helpers.helperManager.rotateTheSelection45\":[\"[Ŕöţáţé ţĥé šéļéçţîöñ ±45° ~~~~~~]\"],\"editor.helpers.helperManager.setOneCornerThenTheOpposite\":[\"[Šéţ öñé çöŕñéŕ, ţĥéñ ţĥé öþþöšîţé ~~~~~~~~~]\"],\"editor.helpers.itemHelper.cancel\":[\"[Çáñçéļ ~~]\"],\"editor.helpers.itemHelper.forcePlace\":[\"[Ƒöŕçé þļáçé ~~~]\"],\"editor.helpers.itemHelper.place\":[\"[Þļáçé ~~]\"],\"editor.helpers.itemHelper.rotate\":[\"[Ŕöţáţé ~~]\"],\"editor.helpers.registeredToolHelper.guidedConstraintsBypassed\":[\"[Ĝûîðéð çöñšţŕáîñţš ƀýþáššéð ~~~~~~~~]\"],\"editor.inspector.field.angle.g10zaw\":[\"[Åñĝļé ~~]\"],\"editor.inspector.field.armLengthM.1jclqgw\":[\"[Åŕɱ ļéñĝţĥ ɱ ~~~]\"],\"editor.inspector.field.attachmentSide.6n9s5v\":[\"[Åţţáçĥɱéñţ šîðé ~~~~~]\"],\"editor.inspector.field.autoHangers.10554ka\":[\"[Åûţö ĥáñĝéŕš ~~~~]\"],\"editor.inspector.field.autoMiterCorners.zxr5lt\":[\"[Åûţö ɱîţéŕ çöŕñéŕš ~~~~~]\"],\"editor.inspector.field.autoSpan.1gas9r6\":[\"[Åûţö šþáñ ~~~]\"],\"editor.inspector.field.backRatio.1ughd99\":[\"[Ɓáçķ ŕáţîö ~~~]\"],\"editor.inspector.field.baseHeight.1hs4zdf\":[\"[Ɓášé ĥéîĝĥţ ~~~]\"],\"editor.inspector.field.baseStyle.24vty5\":[\"[Ɓášé šţýļé ~~~]\"],\"editor.inspector.field.beamHeight.1kq0oh1\":[\"[Ɓéáɱ ĥéîĝĥţ ~~~]\"],\"editor.inspector.field.beamWidth.1q1mzbe\":[\"[Ɓéáɱ ŵîðţĥ ~~~]\"],\"editor.inspector.field.bodyShape.arvkuw\":[\"[Ɓöðý šĥáþé ~~~]\"],\"editor.inspector.field.bracketStyle.1vvoptm\":[\"[Ɓŕáçķéţ šţýļé ~~~~]\"],\"editor.inspector.field.branchAngle.v56zme\":[\"[Ɓŕáñçĥ áñĝļé ~~~~]\"],\"editor.inspector.field.cabHeight.1yn34mk\":[\"[Çáƀ ĥéîĝĥţ ~~~]\"],\"editor.inspector.field.canopyForm.1czzggp\":[\"[Çáñöþý ƒöŕɱ ~~~]\"],\"editor.inspector.field.cap.s0thej\":[\"[Çáþ ~]\"],\"editor.inspector.field.capOverhang.kxxz9j\":[\"[Çáþ öṽéŕĥáñĝ ~~~~]\"],\"editor.inspector.field.capShape.17mbxhu\":[\"[Çáþ šĥáþé ~~~]\"],\"editor.inspector.field.capThickness.u835q9\":[\"[Çáþ ţĥîçķñéšš ~~~~]\"],\"editor.inspector.field.carcassHeight.1aks0zy\":[\"[Çáŕçášš ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.cleanoutStyle.127zz6z\":[\"[Çļéáñöûţ šţýļé ~~~~]\"],\"editor.inspector.field.collarDiameter.1d5k28r\":[\"[Çöļļáŕ ðîáɱéţéŕ ~~~~~]\"],\"editor.inspector.field.collarHeight.1dqwsrf\":[\"[Çöļļáŕ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.collarShape.1gacv11\":[\"[Çöļļáŕ šĥáþé ~~~~]\"],\"editor.inspector.field.collarWidth.qvc9ik\":[\"[Çöļļáŕ ŵîðţĥ ~~~~]\"],\"editor.inspector.field.columns.1sy73ks\":[\"[Çöļûɱñš ~~~]\"],\"editor.inspector.field.conicalFullCircle.1pgkpz5\":[\"[Çöñîçáļ ƒûļļ çîŕçļé ~~~~~~]\"],\"editor.inspector.field.connectionMode.1nty478\":[\"[Çöññéçţîöñ ɱöðé ~~~~~]\"],\"editor.inspector.field.connectionOffset.2m70s8\":[\"[Çöññéçţîöñ öƒƒšéţ ~~~~~]\"],\"editor.inspector.field.cornerBevel.16iniho\":[\"[Çöŕñéŕ ƀéṽéļ ~~~~]\"],\"editor.inspector.field.coveringType.95yd3k\":[\"[Çöṽéŕîñĝ ţýþé ~~~~]\"],\"editor.inspector.field.cricketHeight.pok31n\":[\"[Çŕîçķéţ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.cricketLength.i2aht8\":[\"[Çŕîçķéţ ļéñĝţĥ ~~~~]\"],\"editor.inspector.field.cricketSide.1xnwil7\":[\"[Çŕîçķéţ šîðé ~~~~]\"],\"editor.inspector.field.cricketStyle.10j0lat\":[\"[Çŕîçķéţ šţýļé ~~~~]\"],\"editor.inspector.field.curb.5xi2ol\":[\"[Çûŕƀ ~~]\"],\"editor.inspector.field.curbHeight.1yn97sg\":[\"[Çûŕƀ ĥéîĝĥţ ~~~]\"],\"editor.inspector.field.curveOffset.l4xhvr\":[\"[Çûŕṽé öƒƒšéţ ~~~~]\"],\"editor.inspector.field.damperAngle.h5fxn7\":[\"[Ðáɱþéŕ áñĝļé ~~~~]\"],\"editor.inspector.field.deckThickness.4jmqze\":[\"[Ðéçķ ţĥîçķñéšš ~~~~]\"],\"editor.inspector.field.defaultLevelId.xmrjzp\":[\"[Ðéƒáûļţ ļéṽéļ îð ~~~~~]\"],\"editor.inspector.field.depth.1lu11u2\":[\"[Ðéþţĥ ~~]\"],\"editor.inspector.field.diameter.s3robe\":[\"[Ðîáɱéţéŕ ~~~]\"],\"editor.inspector.field.diameter2.pm6cl4\":[\"[Ðîáɱéţéŕ2 ~~~]\"],\"editor.inspector.field.doorDurationMs.13nx909\":[\"[Ðööŕ ðûŕáţîöñ ɱš ~~~~~]\"],\"editor.inspector.field.doorHeight.92r9k4\":[\"[Ðööŕ ĥéîĝĥţ ~~~]\"],\"editor.inspector.field.doorPanelStyle.2qog4q\":[\"[Ðööŕ þáñéļ šţýļé ~~~~~]\"],\"editor.inspector.field.doorStyle.gerpos\":[\"[Ðööŕ šţýļé ~~~]\"],\"editor.inspector.field.doorWidth.sy732l\":[\"[Ðööŕ ŵîðţĥ ~~~]\"],\"editor.inspector.field.downspoutEnabled.1gn00nv\":[\"[Ðöŵñšþöûţ éñáƀļéð ~~~~~]\"],\"editor.inspector.field.downspoutPosition.fxcsop\":[\"[Ðöŵñšþöûţ þöšîţîöñ ~~~~~~]\"],\"editor.inspector.field.ductMaterial.i8eonq\":[\"[Ðûçţ ɱáţéŕîáļ ~~~~]\"],\"editor.inspector.field.dutchGabletRake.6paydp\":[\"[Ðûţçĥ ĝáƀļéţ ŕáķé ~~~~~]\"],\"editor.inspector.field.dutchHipHeightRatio.1etnwgg\":[\"[Ðûţçĥ ĥîþ ĥéîĝĥţ ŕáţîö ~~~~~~]\"],\"editor.inspector.field.dutchHipWidthRatio.1dopfvb\":[\"[Ðûţçĥ ĥîþ ŵîðţĥ ŕáţîö ~~~~~~]\"],\"editor.inspector.field.dutchTopRakeThickness.1w9khxt\":[\"[Ðûţçĥ ţöþ ŕáķé ţĥîçķñéšš ~~~~~~~]\"],\"editor.inspector.field.dutchWaistLengthRatio.agtoxw\":[\"[Ðûţçĥ ŵáîšţ ļéñĝţĥ ŕáţîö ~~~~~~~]\"],\"editor.inspector.field.dwellMs.1lkk0o5\":[\"[Ðŵéļļ ɱš ~~~]\"],\"editor.inspector.field.edgeInset.1obeimx\":[\"[Éðĝé îñšéţ ~~~]\"],\"editor.inspector.field.elevation.4jbp44\":[\"[Éļéṽáţîöñ ~~~]\"],\"editor.inspector.field.endCapLeft.19jel4v\":[\"[Éñð çáþ ļéƒţ ~~~]\"],\"editor.inspector.field.endCapRight.lhse9c\":[\"[Éñð çáþ ŕîĝĥţ ~~~~]\"],\"editor.inspector.field.endCaps.4fsb5b\":[\"[Éñð çáþš ~~~]\"],\"editor.inspector.field.endPost.1guwsk0\":[\"[Éñð þöšţ ~~~]\"],\"editor.inspector.field.equipmentType.1mc2ywt\":[\"[Éǫûîþɱéñţ ţýþé ~~~~]\"],\"editor.inspector.field.fillToFloor.1oppnkf\":[\"[Ƒîļļ ţö ƒļööŕ ~~~~]\"],\"editor.inspector.field.finial.1ertf4s\":[\"[Ƒîñîáļ ~~]\"],\"editor.inspector.field.fittingType.18mz17s\":[\"[Ƒîţţîñĝ ţýþé ~~~~]\"],\"editor.inspector.field.flashingHeight.3e8nn6\":[\"[Ƒļášĥîñĝ ĥéîĝĥţ ~~~~~]\"],\"editor.inspector.field.flashingProjection.hhf0fk\":[\"[Ƒļášĥîñĝ þŕöĵéçţîöñ ~~~~~~]\"],\"editor.inspector.field.flueCount.j3t2ci\":[\"[Ƒļûé çöûñţ ~~~]\"],\"editor.inspector.field.flueDiameter.cjhubg\":[\"[Ƒļûé ðîáɱéţéŕ ~~~~]\"],\"editor.inspector.field.flueHeight.1dhc4y4\":[\"[Ƒļûé ĥéîĝĥţ ~~~]\"],\"editor.inspector.field.flueShape.1ealiy4\":[\"[Ƒļûé šĥáþé ~~~]\"],\"editor.inspector.field.flueSpacing.exhzco\":[\"[Ƒļûé šþáçîñĝ ~~~~]\"],\"editor.inspector.field.footingStyle.e3btg6\":[\"[Ƒööţîñĝ šţýļé ~~~~]\"],\"editor.inspector.field.frameDepth.1934a5n\":[\"[Ƒŕáɱé ðéþţĥ ~~~]\"],\"editor.inspector.field.frameThickness.1agxzd8\":[\"[Ƒŕáɱé ţĥîçķñéšš ~~~~~]\"],\"editor.inspector.field.framingStrategy.3jx9qe\":[\"[Ƒŕáɱîñĝ šţŕáţéĝý ~~~~~]\"],\"editor.inspector.field.fromLevelId.15ieejs\":[\"[Ƒŕöɱ ļéṽéļ îð ~~~~]\"],\"editor.inspector.field.gableOverhang.2z0obw\":[\"[Ĝáƀļé öṽéŕĥáñĝ ~~~~]\"],\"editor.inspector.field.gambrelLowerHeightRatio.wqq7lg\":[\"[Ĝáɱƀŕéļ ļöŵéŕ ĥéîĝĥţ ŕáţîö ~~~~~~~]\"],\"editor.inspector.field.gambrelLowerWidthRatio.uvyb1v\":[\"[Ĝáɱƀŕéļ ļöŵéŕ ŵîðţĥ ŕáţîö ~~~~~~~]\"],\"editor.inspector.field.gapX.wjxa7\":[\"[Ĝáþ ẋ ~~]\"],\"editor.inspector.field.gapY.mkbl8\":[\"[Ĝáþ ý ~~]\"],\"editor.inspector.field.glassThickness.s97b0x\":[\"[Ĝļášš ţĥîçķñéšš ~~~~~]\"],\"editor.inspector.field.groundClearance.4os7f0\":[\"[Ĝŕöûñð çļéáŕáñçé ~~~~~]\"],\"editor.inspector.field.guardInfill.16heiig\":[\"[Ĝûáŕð îñƒîļļ ~~~~]\"],\"editor.inspector.field.gutterEnabled.1oxiltf\":[\"[Ĝûţţéŕ éñáƀļéð ~~~~]\"],\"editor.inspector.field.gutterProfile.1ngzqi3\":[\"[Ĝûţţéŕ þŕöƒîļé ~~~~]\"],\"editor.inspector.field.gutterSize.jgavtz\":[\"[Ĝûţţéŕ šîžé ~~~]\"],\"editor.inspector.field.hangerMaxReach.1869epv\":[\"[Ĥáñĝéŕ ɱáẋ ŕéáçĥ ~~~~~]\"],\"editor.inspector.field.hangerSpacing.i2b5d7\":[\"[Ĥáñĝéŕ šþáçîñĝ ~~~~]\"],\"editor.inspector.field.hangerStyle.l7v7gb\":[\"[Ĥáñĝéŕ šţýļé ~~~~]\"],\"editor.inspector.field.height.7puwki\":[\"[Ĥéîĝĥţ ~~]\"],\"editor.inspector.field.height2.7b3jlc\":[\"[Ĥéîĝĥţ2 ~~]\"],\"editor.inspector.field.heightAboveRidge.1k99brk\":[\"[Ĥéîĝĥţ áƀöṽé ŕîðĝé ~~~~~]\"],\"editor.inspector.field.highEdgeHeight.1s7v90t\":[\"[Ĥîĝĥ éðĝé ĥéîĝĥţ ~~~~~]\"],\"editor.inspector.field.highOverhang.67w55d\":[\"[Ĥîĝĥ öṽéŕĥáñĝ ~~~~]\"],\"editor.inspector.field.highSideMode.1rc1r5j\":[\"[Ĥîĝĥ šîðé ɱöðé ~~~~]\"],\"editor.inspector.field.hoodOverhang.1q1hcin\":[\"[Ĥööð öṽéŕĥáñĝ ~~~~]\"],\"editor.inspector.field.infillPlacement.11dxzpo\":[\"[Îñƒîļļ þļáçéɱéñţ ~~~~~]\"],\"editor.inspector.field.inletShape.ypayh2\":[\"[Îñļéţ šĥáþé ~~~]\"],\"editor.inspector.field.innerRadius.1fkmg0j\":[\"[Îññéŕ ŕáðîûš ~~~~]\"],\"editor.inspector.field.insulated.iwziey\":[\"[Îñšûļáţéð ~~~]\"],\"editor.inspector.field.insulationR.663ufx\":[\"[Îñšûļáţîöñ ŕ ~~~~]\"],\"editor.inspector.field.lanternHeight.oz7zpm\":[\"[Ļáñţéŕñ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.lanternTopScale.hkmpp2\":[\"[Ļáñţéŕñ ţöþ šçáļé ~~~~~]\"],\"editor.inspector.field.ledgerDepth.7av8k9\":[\"[Ļéðĝéŕ ðéþţĥ ~~~~]\"],\"editor.inspector.field.ledgerHeight.zo2oif\":[\"[Ļéðĝéŕ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.ledgerVerticalOffset.1athbgt\":[\"[Ļéðĝéŕ ṽéŕţîçáļ öƒƒšéţ ~~~~~~]\"],\"editor.inspector.field.leftEndCondition.1syqlaw\":[\"[Ļéƒţ éñð çöñðîţîöñ ~~~~~]\"],\"editor.inspector.field.leftOverhang.1ydl9ma\":[\"[Ļéƒţ öṽéŕĥáñĝ ~~~~]\"],\"editor.inspector.field.length.1kpdcfp\":[\"[Ļéñĝţĥ ~~]\"],\"editor.inspector.field.liquidDiameter.w3pk7c\":[\"[Ļîǫûîð ðîáɱéţéŕ ~~~~~]\"],\"editor.inspector.field.louverCount.lhw2gr\":[\"[Ļöûṽéŕ çöûñţ ~~~~]\"],\"editor.inspector.field.lowBeamInset.1g7yw5l\":[\"[Ļöŵ ƀéáɱ îñšéţ ~~~~]\"],\"editor.inspector.field.lowEdgeHeight.47mae1\":[\"[Ļöŵ éðĝé ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.lowOverhang.t4nz1h\":[\"[Ļöŵ öṽéŕĥáñĝ ~~~~]\"],\"editor.inspector.field.mansardSteepHeightRatio.1hbb8rq\":[\"[Ṁáñšáŕð šţééþ ĥéîĝĥţ ŕáţîö ~~~~~~~]\"],\"editor.inspector.field.mansardSteepWidthRatio.6xk6vd\":[\"[Ṁáñšáŕð šţééþ ŵîðţĥ ŕáţîö ~~~~~~~]\"],\"editor.inspector.field.matchHostRoofMaterial.s56zwj\":[\"[Ṁáţçĥ ĥöšţ ŕööƒ ɱáţéŕîáļ ~~~~~~~]\"],\"editor.inspector.field.matchHostRoofStructure.bojht3\":[\"[Ṁáţçĥ ĥöšţ ŕööƒ šţŕûçţûŕé ~~~~~~~]\"],\"editor.inspector.field.mount.h80tay\":[\"[Ṁöûñţ ~~]\"],\"editor.inspector.field.mountingType.1xvin1e\":[\"[Ṁöûñţîñĝ ţýþé ~~~~]\"],\"editor.inspector.field.neckHeight.19ym8n1\":[\"[Ñéçķ ĥéîĝĥţ ~~~]\"],\"editor.inspector.field.opacity.1pmpfd2\":[\"[Öþáçîţý ~~~]\"],\"editor.inspector.field.openingAngle.brhi7c\":[\"[Öþéñîñĝ áñĝļé ~~~~]\"],\"editor.inspector.field.openingOffset.wpoqt6\":[\"[Öþéñîñĝ öƒƒšéţ ~~~~]\"],\"editor.inspector.field.openingSide.18l2iwe\":[\"[Öþéñîñĝ šîðé ~~~~]\"],\"editor.inspector.field.operationState.1lwrz07\":[\"[Öþéŕáţîöñ šţáţé ~~~~~]\"],\"editor.inspector.field.outletShape.lgpqhx\":[\"[Öûţļéţ šĥáþé ~~~~]\"],\"editor.inspector.field.overhang.b5ljpv\":[\"[Öṽéŕĥáñĝ ~~~]\"],\"editor.inspector.field.panelHeight.1kf31vk\":[\"[Þáñéļ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.panelWidth.946581\":[\"[Þáñéļ ŵîðţĥ ~~~]\"],\"editor.inspector.field.patternAlignment.jd1ht0\":[\"[Þáţţéŕñ áļîĝñɱéñţ ~~~~~]\"],\"editor.inspector.field.patternCount.1r37pve\":[\"[Þáţţéŕñ çöûñţ ~~~~]\"],\"editor.inspector.field.patternDistribution.fmam51\":[\"[Þáţţéŕñ ðîšţŕîƀûţîöñ ~~~~~~]\"],\"editor.inspector.field.patternRemainder.i47p5y\":[\"[Þáţţéŕñ ŕéɱáîñðéŕ ~~~~~]\"],\"editor.inspector.field.picketProfile.1xgzuyc\":[\"[Þîçķéţ þŕöƒîļé ~~~~]\"],\"editor.inspector.field.picketRailCount.atgt6w\":[\"[Þîçķéţ ŕáîļ çöûñţ ~~~~~]\"],\"editor.inspector.field.picketSpacing.p8d98w\":[\"[Þîçķéţ šþáçîñĝ ~~~~]\"],\"editor.inspector.field.picketTop.1tskplu\":[\"[Þîçķéţ ţöþ ~~~]\"],\"editor.inspector.field.picketTopClearance.16eq1k0\":[\"[Þîçķéţ ţöþ çļéáŕáñçé ~~~~~~]\"],\"editor.inspector.field.picketVariation.f7vl1c\":[\"[Þîçķéţ ṽáŕîáţîöñ ~~~~~]\"],\"editor.inspector.field.picketWidth.3fr3rh\":[\"[Þîçķéţ ŵîðţĥ ~~~~]\"],\"editor.inspector.field.pipeMaterial.1ggc2wy\":[\"[Þîþé ɱáţéŕîáļ ~~~~]\"],\"editor.inspector.field.pitch.xe6ekx\":[\"[Þîţçĥ ~~]\"],\"editor.inspector.field.position.1quewx6\":[\"[Þöšîţîöñ ~~~]\"],\"editor.inspector.field.postBracing.crq8nn\":[\"[Þöšţ ƀŕáçîñĝ ~~~~]\"],\"editor.inspector.field.postCap.1xcvxrv\":[\"[Þöšţ çáþ ~~~]\"],\"editor.inspector.field.postCount.22r56c\":[\"[Þöšţ çöûñţ ~~~]\"],\"editor.inspector.field.postDepth.1ko6j1m\":[\"[Þöšţ ðéþţĥ ~~~]\"],\"editor.inspector.field.postInset.le36li\":[\"[Þöšţ îñšéţ ~~~]\"],\"editor.inspector.field.postLayoutMode.16jre62\":[\"[Þöšţ ļáýöûţ ɱöðé ~~~~~]\"],\"editor.inspector.field.postSize.1jodxek\":[\"[Þöšţ šîžé ~~~]\"],\"editor.inspector.field.postSpacing.voppfi\":[\"[Þöšţ šþáçîñĝ ~~~~]\"],\"editor.inspector.field.postThrough.1abgu4a\":[\"[Þöšţ ţĥŕöûĝĥ ~~~~]\"],\"editor.inspector.field.postWidth.rk26fz\":[\"[Þöšţ ŵîðţĥ ~~~]\"],\"editor.inspector.field.profile.1kwlci6\":[\"[Þŕöƒîļé ~~~]\"],\"editor.inspector.field.projection.jhtig0\":[\"[Þŕöĵéçţîöñ ~~~]\"],\"editor.inspector.field.purlinHeight.eo9cjm\":[\"[Þûŕļîñ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.purlinSpacing.4gbzb2\":[\"[Þûŕļîñ šþáçîñĝ ~~~~]\"],\"editor.inspector.field.purlinWidth.r6tu3j\":[\"[Þûŕļîñ ŵîðţĥ ~~~~]\"],\"editor.inspector.field.rafterEndInset.14c0wy5\":[\"[Ŕáƒţéŕ éñð îñšéţ ~~~~~]\"],\"editor.inspector.field.rafterHeight.1e1n99w\":[\"[Ŕáƒţéŕ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.rafterSpacing.19subc0\":[\"[Ŕáƒţéŕ šþáçîñĝ ~~~~]\"],\"editor.inspector.field.rafterWidth.eksj4t\":[\"[Ŕáƒţéŕ ŵîðţĥ ~~~~]\"],\"editor.inspector.field.railingHeight.6wf4bm\":[\"[Ŕáîļîñĝ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.railingMode.ov7xpu\":[\"[Ŕáîļîñĝ ɱöðé ~~~~]\"],\"editor.inspector.field.railingStyle.1nyd2u\":[\"[Ŕáîļîñĝ šţýļé ~~~~]\"],\"editor.inspector.field.resizeLock.b2hbr0\":[\"[Ŕéšîžé ļöçķ ~~~]\"],\"editor.inspector.field.returnDiameter.166ozhe\":[\"[Ŕéţûŕñ ðîáɱéţéŕ ~~~~~]\"],\"editor.inspector.field.returnHeight.b9sq6y\":[\"[Ŕéţûŕñ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.returnShape.1e3a27i\":[\"[Ŕéţûŕñ šĥáþé ~~~~]\"],\"editor.inspector.field.returnWidth.z9r3h3\":[\"[Ŕéţûŕñ ŵîðţĥ ~~~~]\"],\"editor.inspector.field.rightEndCondition.tjlw3l\":[\"[Ŕîĝĥţ éñð çöñðîţîöñ ~~~~~~]\"],\"editor.inspector.field.rightOverhang.yqbeft\":[\"[Ŕîĝĥţ öṽéŕĥáñĝ ~~~~]\"],\"editor.inspector.field.roofHeight.1uhy6qy\":[\"[Ŕööƒ ĥéîĝĥţ ~~~]\"],\"editor.inspector.field.roofStyle.pawqfy\":[\"[Ŕööƒ šţýļé ~~~]\"],\"editor.inspector.field.roofThickness.1xlr3rx\":[\"[Ŕööƒ ţĥîçķñéšš ~~~~]\"],\"editor.inspector.field.roofType.1m9kv5h\":[\"[Ŕööƒ ţýþé ~~~]\"],\"editor.inspector.field.rotation.ly2rj\":[\"[Ŕöţáţîöñ ~~~]\"],\"editor.inspector.field.rows.1ba1neg\":[\"[Ŕöŵš ~~]\"],\"editor.inspector.field.scale.b6rpxt\":[\"[Šçáļé ~~]\"],\"editor.inspector.field.seamDetail.197za48\":[\"[Šéáɱ ðéţáîļ ~~~]\"],\"editor.inspector.field.segmentType.l667sy\":[\"[Šéĝɱéñţ ţýþé ~~~~]\"],\"editor.inspector.field.shaftStyle.1i5ampa\":[\"[Šĥáƒţ šţýļé ~~~]\"],\"editor.inspector.field.shaftWallThickness.bduslr\":[\"[Šĥáƒţ ŵáļļ ţĥîçķñéšš ~~~~~~]\"],\"editor.inspector.field.shape.iq9t52\":[\"[Šĥáþé ~~]\"],\"editor.inspector.field.shape2.fi0nx8\":[\"[Šĥáþé2 ~~]\"],\"editor.inspector.field.shedHighSide.bzzddg\":[\"[Šĥéð ĥîĝĥ šîðé ~~~~]\"],\"editor.inspector.field.shingleThickness.1hn5wxr\":[\"[Šĥîñĝļé ţĥîçķñéšš ~~~~~]\"],\"editor.inspector.field.shoulderExtent.11j8uiv\":[\"[Šĥöûļðéŕ éẋţéñţ ~~~~~]\"],\"editor.inspector.field.shoulderHeight.xyqn6g\":[\"[Šĥöûļðéŕ ĥéîĝĥţ ~~~~~]\"],\"editor.inspector.field.shoulderStyle.1hkcv2w\":[\"[Šĥöûļðéŕ šţýļé ~~~~]\"],\"editor.inspector.field.showCenterColumn.1uggg45\":[\"[Šĥöŵ çéñţéŕ çöļûɱñ ~~~~~]\"],\"editor.inspector.field.showInfill.33rv7u\":[\"[Šĥöŵ îñƒîļļ ~~~]\"],\"editor.inspector.field.showStepSupports.1kg8h8m\":[\"[Šĥöŵ šţéþ šûþþöŕţš ~~~~~]\"],\"editor.inspector.field.sideFlashing.cv744o\":[\"[Šîðé ƒļášĥîñĝ ~~~~]\"],\"editor.inspector.field.size.1a4x3zw\":[\"[Šîžé ~~]\"],\"editor.inspector.field.skylightType.1a5vj3i\":[\"[Šķýļîĝĥţ ţýþé ~~~~]\"],\"editor.inspector.field.slabOpeningMode.g4f730\":[\"[Šļáƀ öþéñîñĝ ɱöðé ~~~~~]\"],\"editor.inspector.field.slatGap.slmk93\":[\"[Šļáţ ĝáþ ~~~]\"],\"editor.inspector.field.slideDirection.1527q13\":[\"[Šļîðé ðîŕéçţîöñ ~~~~~]\"],\"editor.inspector.field.span.1bmmuw1\":[\"[Šþáñ ~~]\"],\"editor.inspector.field.speed.2w2xwg\":[\"[Šþééð ~~]\"],\"editor.inspector.field.spinSpeed.1ozx746\":[\"[Šþîñ šþééð ~~~]\"],\"editor.inspector.field.stairType.1u05e02\":[\"[Šţáîŕ ţýþé ~~~]\"],\"editor.inspector.field.standoff.4wv2g0\":[\"[Šţáñðöƒƒ ~~~]\"],\"editor.inspector.field.standoffHeight.1qdnff\":[\"[Šţáñðöƒƒ ĥéîĝĥţ ~~~~~]\"],\"editor.inspector.field.startPost.1ood9kv\":[\"[Šţáŕţ þöšţ ~~~]\"],\"editor.inspector.field.stepCount.nzorrw\":[\"[Šţéþ çöûñţ ~~~]\"],\"editor.inspector.field.strapSpacing.1cyt3dc\":[\"[Šţŕáþ šþáçîñĝ ~~~~]\"],\"editor.inspector.field.strapStyle.fh1oy4\":[\"[Šţŕáþ šţýļé ~~~]\"],\"editor.inspector.field.style.nf3vcm\":[\"[Šţýļé ~~]\"],\"editor.inspector.field.suctionDiameter.nutxtj\":[\"[Šûçţîöñ ðîáɱéţéŕ ~~~~~]\"],\"editor.inspector.field.supplyDiameter.h5ldh5\":[\"[Šûþþļý ðîáɱéţéŕ ~~~~~]\"],\"editor.inspector.field.supplyHeight.zy6ru1\":[\"[Šûþþļý ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.supplyShape.k39wnb\":[\"[Šûþþļý šĥáþé ~~~~]\"],\"editor.inspector.field.supplyWidth.g66axi\":[\"[Šûþþļý ŵîðţĥ ~~~~]\"],\"editor.inspector.field.supportOffset.1w4cocr\":[\"[Šûþþöŕţ öƒƒšéţ ~~~~]\"],\"editor.inspector.field.sweepAngle.ucmmlw\":[\"[Šŵééþ áñĝļé ~~~]\"],\"editor.inspector.field.system.13qbhrw\":[\"[Šýšţéɱ ~~]\"],\"editor.inspector.field.terminal.1501knl\":[\"[Ţéŕɱîñáļ ~~~]\"],\"editor.inspector.field.terminalType.1ne8lgb\":[\"[Ţéŕɱîñáļ ţýþé ~~~~]\"],\"editor.inspector.field.thickness.1l8hu45\":[\"[Ţĥîçķñéšš ~~~]\"],\"editor.inspector.field.tiltAngle.1312yw1\":[\"[Ţîļţ áñĝļé ~~~]\"],\"editor.inspector.field.toLevelId.8i5qx7\":[\"[Ţö ļéṽéļ îð ~~~]\"],\"editor.inspector.field.topLandingDepth.ki7gk2\":[\"[Ţöþ ļáñðîñĝ ðéþţĥ ~~~~~]\"],\"editor.inspector.field.topLandingMode.zk0h7e\":[\"[Ţöþ ļáñðîñĝ ɱöðé ~~~~~]\"],\"editor.inspector.field.topRailHeight.fscisv\":[\"[Ţöþ ŕáîļ ĥéîĝĥţ ~~~~]\"],\"editor.inspector.field.transitionMode.f3evgt\":[\"[Ţŕáñšîţîöñ ɱöðé ~~~~~]\"],\"editor.inspector.field.transitionWidth.rtgz3m\":[\"[Ţŕáñšîţîöñ ŵîðţĥ ~~~~~]\"],\"editor.inspector.field.vaneCount.55vtye\":[\"[Ṽáñé çöûñţ ~~~]\"],\"editor.inspector.field.wallHeight.18vmh5c\":[\"[Ŵáļļ ĥéîĝĥţ ~~~]\"],\"editor.inspector.field.wallShell.vqsyhv\":[\"[Ŵáļļ šĥéļļ ~~~]\"],\"editor.inspector.field.wallSkirtHeight.1uea2ad\":[\"[Ŵáļļ šķîŕţ ĥéîĝĥţ ~~~~~]\"],\"editor.inspector.field.wallThickness.17wn4iv\":[\"[Ŵáļļ ţĥîçķñéšš ~~~~]\"],\"editor.inspector.field.width.gfxz9b\":[\"[Ŵîðţĥ ~~]\"],\"editor.inspector.field.width2.1nqawvr\":[\"[Ŵîðţĥ2 ~~]\"],\"editor.inspector.field.withBack.1ay8nus\":[\"[Ŵîţĥ ƀáçķ ~~~]\"],\"editor.inspector.field.withBottom.1x1z1vo\":[\"[Ŵîţĥ ƀöţţöɱ ~~~]\"],\"editor.inspector.field.withSides.uq066x\":[\"[Ŵîţĥ šîðéš ~~~]\"],\"editor.inspector.group.advanced.qwfkor\":[\"[Åðṽáñçéð ~~~]\"],\"editor.inspector.group.air.15jotdj\":[\"[Åîŕ ~]\"],\"editor.inspector.group.appearance.dli9wf\":[\"[Åþþéáŕáñçé ~~~]\"],\"editor.inspector.group.body.ign4wl\":[\"[Ɓöðý ~~]\"],\"editor.inspector.group.cab.o4z1ox\":[\"[Çáƀ ~]\"],\"editor.inspector.group.cabinet.rzvymr\":[\"[Çáƀîñéţ ~~~]\"],\"editor.inspector.group.cap.s0thej\":[\"[Çáþ ~]\"],\"editor.inspector.group.collar.1am2iqo\":[\"[Çöļļáŕ ~~]\"],\"editor.inspector.group.connection.2r1h4p\":[\"[Çöññéçţîöñ ~~~]\"],\"editor.inspector.group.connections.ai4w8u\":[\"[Çöññéçţîöñš ~~~~]\"],\"editor.inspector.group.construction.j6p9kc\":[\"[Çöñšţŕûçţîöñ ~~~~]\"],\"editor.inspector.group.cricket.6iwg8g\":[\"[Çŕîçķéţ ~~~]\"],\"editor.inspector.group.curb.5xi2ol\":[\"[Çûŕƀ ~~]\"],\"editor.inspector.group.curvePoints.ztdcnn\":[\"[Çûŕṽé þöîñţš ~~~~]\"],\"editor.inspector.group.dimensions.pewa8g\":[\"[Ðîɱéñšîöñš ~~~]\"],\"editor.inspector.group.doors.18w2kpa\":[\"[Ðööŕš ~~]\"],\"editor.inspector.group.dormer.1fjs5tq\":[\"[Ðöŕɱéŕ ~~]\"],\"editor.inspector.group.dormerRoof.u9uy2g\":[\"[Ðöŕɱéŕ ŕööƒ ~~~]\"],\"editor.inspector.group.drainage.7easy0\":[\"[Ðŕáîñáĝé ~~~]\"],\"editor.inspector.group.elevation.4jbp44\":[\"[Éļéṽáţîöñ ~~~]\"],\"editor.inspector.group.endCaps.4fsb5b\":[\"[Éñð çáþš ~~~]\"],\"editor.inspector.group.equipment.1xtq0ev\":[\"[Éǫûîþɱéñţ ~~~]\"],\"editor.inspector.group.face.1531fr0\":[\"[Ƒáçé ~~]\"],\"editor.inspector.group.fitting.171z1r4\":[\"[Ƒîţţîñĝ ~~~]\"],\"editor.inspector.group.flues.nq6pye\":[\"[Ƒļûéš ~~]\"],\"editor.inspector.group.footprint.g8q2pg\":[\"[Ƒööţþŕîñţ ~~~]\"],\"editor.inspector.group.frame.q7q9fq\":[\"[Ƒŕáɱé ~~]\"],\"editor.inspector.group.geometry.a21os1\":[\"[Ĝéöɱéţŕý ~~~]\"],\"editor.inspector.group.grid.d8gwxd\":[\"[Ĝŕîð ~~]\"],\"editor.inspector.group.hangers.agnfzn\":[\"[Ĥáñĝéŕš ~~~]\"],\"editor.inspector.group.hardware.1nygwm1\":[\"[Ĥáŕðŵáŕé ~~~]\"],\"editor.inspector.group.hungWall.1ftr1gz\":[\"[Ĥûñĝ ŵáļļ ~~~]\"],\"editor.inspector.group.insulation.1kyo5e7\":[\"[Îñšûļáţîöñ ~~~]\"],\"editor.inspector.group.lantern.1h7o2xb\":[\"[Ļáñţéŕñ ~~~]\"],\"editor.inspector.group.levels.1s6yaru\":[\"[Ļéṽéļš ~~]\"],\"editor.inspector.group.line.166mv5z\":[\"[Ļîñé ~~]\"],\"editor.inspector.group.lines.12bghr0\":[\"[Ļîñéš ~~]\"],\"editor.inspector.group.motion.1be7sjr\":[\"[Ṁöţîöñ ~~]\"],\"editor.inspector.group.mounting.feutd2\":[\"[Ṁöûñţîñĝ ~~~]\"],\"editor.inspector.group.opening.dfet3\":[\"[Öþéñîñĝ ~~~]\"],\"editor.inspector.group.panelDimensions.b59qe6\":[\"[Þáñéļ ðîɱéñšîöñš ~~~~~]\"],\"editor.inspector.group.patternDistribution.fmam51\":[\"[Þáţţéŕñ ðîšţŕîƀûţîöñ ~~~~~~]\"],\"editor.inspector.group.placement.13lcvts\":[\"[Þļáçéɱéñţ ~~~]\"],\"editor.inspector.group.position.1quewx6\":[\"[Þöšîţîöñ ~~~]\"],\"editor.inspector.group.profile.1kwlci6\":[\"[Þŕöƒîļé ~~~]\"],\"editor.inspector.group.railing.19a5bnr\":[\"[Ŕáîļîñĝ ~~~]\"],\"editor.inspector.group.return.1klrjrz\":[\"[Ŕéţûŕñ ~~]\"],\"editor.inspector.group.settings.ktdb8o\":[\"[Šéţţîñĝš ~~~]\"],\"editor.inspector.group.shaft.mad9cv\":[\"[Šĥáƒţ ~~]\"],\"editor.inspector.group.shape.iq9t52\":[\"[Šĥáþé ~~]\"],\"editor.inspector.group.shoulder.1nyfx25\":[\"[Šĥöûļðéŕ ~~~]\"],\"editor.inspector.group.size.1a4x3zw\":[\"[Šîžé ~~]\"],\"editor.inspector.group.structure.gezdra\":[\"[Šţŕûçţûŕé ~~~]\"],\"editor.inspector.group.style.nf3vcm\":[\"[Šţýļé ~~]\"],\"editor.inspector.group.supply.1oy2zwu\":[\"[Šûþþļý ~~]\"],\"editor.inspector.group.surface.wtamqk\":[\"[Šûŕƒáçé ~~~]\"],\"editor.inspector.group.terminal.1501knl\":[\"[Ţéŕɱîñáļ ~~~]\"],\"editor.inspector.group.topology.18t8dyc\":[\"[Ţöþöļöĝý ~~~]\"],\"editor.inspector.group.transform.1c55ayj\":[\"[Ţŕáñšƒöŕɱ ~~~]\"],\"editor.inspector.group.trap.1qc7vhe\":[\"[Ţŕáþ ~~]\"],\"editor.inspector.group.type.1m2zofh\":[\"[Ţýþé ~~]\"],\"editor.inspector.option.abs.132mz8b\":[\"[Åƀš ~]\"],\"editor.inspector.option.accessPanel.13sptb5\":[\"[Åççéšš þáñéļ ~~~~]\"],\"editor.inspector.option.airHandler.1crnyg3\":[\"[Åîŕ ĥáñðļéŕ ~~~]\"],\"editor.inspector.option.alternating.5jashi\":[\"[Åļţéŕñáţîñĝ ~~~~]\"],\"editor.inspector.option.arched.14188w0\":[\"[Åŕçĥéð ~~]\"],\"editor.inspector.option.auto.540b06\":[\"[Åûţö ~~]\"],\"editor.inspector.option.automatic.r122ro\":[\"[Åûţöɱáţîç ~~~]\"],\"editor.inspector.option.back.1hzmxtu\":[\"[Ɓáçķ ~~]\"],\"editor.inspector.option.balusters.1j3w6ng\":[\"[Ɓáļûšţéŕš ~~~]\"],\"editor.inspector.option.band.160umau\":[\"[Ɓáñð ~~]\"],\"editor.inspector.option.basePlate.17fcg8k\":[\"[Ɓášé þļáţé ~~~]\"],\"editor.inspector.option.boards.u14hig\":[\"[Ɓöáŕðš ~~]\"],\"editor.inspector.option.bookshelf.ls0zqk\":[\"[Ɓööķšĥéļƒ ~~~]\"],\"editor.inspector.option.both.mkyb42\":[\"[Ɓöţĥ ~~]\"],\"editor.inspector.option.bottom.9mpruy\":[\"[Ɓöţţöɱ ~~]\"],\"editor.inspector.option.box.1nbjcuq\":[\"[Ɓöẋ ~]\"],\"editor.inspector.option.break.17spnvc\":[\"[Ɓŕéáķ ~~]\"],\"editor.inspector.option.butterfly.pvv0g4\":[\"[Ɓûţţéŕƒļý ~~~]\"],\"editor.inspector.option.cable.fp50zq\":[\"[Çáƀļé ~~]\"],\"editor.inspector.option.castIron.1q2z4qk\":[\"[Çášţ îŕöñ ~~~]\"],\"editor.inspector.option.ceiling.1t2zaqo\":[\"[Çéîļîñĝ ~~~]\"],\"editor.inspector.option.center.kzdxno\":[\"[Çéñţéŕ ~~]\"],\"editor.inspector.option.centerOpening.bn1rvw\":[\"[Çéñţéŕ öþéñîñĝ ~~~~]\"],\"editor.inspector.option.cleanout.lww8bm\":[\"[Çļéáñöûţ ~~~]\"],\"editor.inspector.option.concretePad.m1zdij\":[\"[Çöñçŕéţé þáð ~~~~]\"],\"editor.inspector.option.condenser.a74nps\":[\"[Çöñðéñšéŕ ~~~]\"],\"editor.inspector.option.corbeled.bovs4v\":[\"[Çöŕƀéļéð ~~~]\"],\"editor.inspector.option.count.1qoi4r8\":[\"[Çöûñţ ~~]\"],\"editor.inspector.option.coupling.111aap2\":[\"[Çöûþļîñĝ ~~~]\"],\"editor.inspector.option.coveringSpecific.1h9fo8w\":[\"[Çöṽéŕîñĝ šþéçîƒîç ~~~~~]\"],\"editor.inspector.option.cross.1elubzv\":[\"[Çŕöšš ~~]\"],\"editor.inspector.option.cubby.ivq4qc\":[\"[Çûƀƀý ~~]\"],\"editor.inspector.option.curved.6noz1s\":[\"[Çûŕṽéð ~~]\"],\"editor.inspector.option.cylinder.eol6vj\":[\"[Çýļîñðéŕ ~~~]\"],\"editor.inspector.option.damper.wgri80\":[\"[Ðáɱþéŕ ~~]\"],\"editor.inspector.option.destination.gfzm1r\":[\"[Ðéšţîñáţîöñ ~~~~]\"],\"editor.inspector.option.diffuser.1igj0jh\":[\"[Ðûšéŕ ~~~]\"],\"editor.inspector.option.dogEar.xhtvjt\":[\"[Ðöĝ éáŕ ~~]\"],\"editor.inspector.option.dome.1c87e56\":[\"[Ðöɱé ~~]\"],\"editor.inspector.option.double.13h5354\":[\"[Ðöûƀļé ~~]\"],\"editor.inspector.option.ductBoard.lc3o4t\":[\"[Ðûçţ ƀöáŕð ~~~]\"],\"editor.inspector.option.dutch.1djx429\":[\"[Ðûţçĥ ~~]\"],\"editor.inspector.option.elbow.1flup74\":[\"[Éļƀöŵ ~~]\"],\"editor.inspector.option.end.1llf32i\":[\"[Éñð ~]\"],\"editor.inspector.option.endCap.1p4v4na\":[\"[Éñð çáþ ~~]\"],\"editor.inspector.option.equalFit.11vw52c\":[\"[Éǫûáļ ƒîţ ~~~]\"],\"editor.inspector.option.fixedCount.1o3dznu\":[\"[Ƒîẋéð çöûñţ ~~~]\"],\"editor.inspector.option.fixedSpacing.hl4dr4\":[\"[Ƒîẋéð šþáçîñĝ ~~~~]\"],\"editor.inspector.option.flat.ly0bei\":[\"[Ƒļáţ ~~]\"],\"editor.inspector.option.flex.ktpamq\":[\"[Ƒļéẋ ~~]\"],\"editor.inspector.option.floating.1oadpln\":[\"[Ƒļöáţîñĝ ~~~]\"],\"editor.inspector.option.floor.q9caf1\":[\"[Ƒļööŕ ~~]\"],\"editor.inspector.option.flush.olwwu5\":[\"[Ƒļûšĥ ~~]\"],\"editor.inspector.option.front.uhugl4\":[\"[Ƒŕöñţ ~~]\"],\"editor.inspector.option.furnace.w0mzpf\":[\"[Ƒûŕñáçé ~~~]\"],\"editor.inspector.option.gable.1ekyx6\":[\"[Ĝáƀļé ~~]\"],\"editor.inspector.option.gambrel.1yo90d9\":[\"[Ĝáɱƀŕéļ ~~~]\"],\"editor.inspector.option.generic.1074oey\":[\"[Ĝéñéŕîç ~~~]\"],\"editor.inspector.option.glass.163tc5n\":[\"[Ĝļášš ~~]\"],\"editor.inspector.option.glassFrame.jp9s3m\":[\"[Ĝļášš ƒŕáɱé ~~~]\"],\"editor.inspector.option.globe.1avkqoy\":[\"[Ĝļöƀé ~~]\"],\"editor.inspector.option.grounded.jwoq73\":[\"[Ĝŕöûñðéð ~~~]\"],\"editor.inspector.option.guard.1m575se\":[\"[Ĝûáŕð ~~]\"],\"editor.inspector.option.halfRound.m5hob0\":[\"[Ĥáļƒ ŕöûñð ~~~]\"],\"editor.inspector.option.hidden.gp48rd\":[\"[Ĥîððéñ ~~]\"],\"editor.inspector.option.hip.r0jnjy\":[\"[Ĥîþ ~]\"],\"editor.inspector.option.horizontal.tyapah\":[\"[Ĥöŕîžöñţáļ ~~~]\"],\"editor.inspector.option.include.1a27vnr\":[\"[Îñçļûðé ~~~]\"],\"editor.inspector.option.independentHighBeam.1tn0zvy\":[\"[Îñðéþéñðéñţ ĥîĝĥ ƀéáɱ ~~~~~~]\"],\"editor.inspector.option.industrial.8sd9u\":[\"[Îñðûšţŕîáļ ~~~]\"],\"editor.inspector.option.inline.1uh05lg\":[\"[Îñļîñé ~~]\"],\"editor.inspector.option.integrated.1xd9lv0\":[\"[Îñţéĝŕáţéð ~~~]\"],\"editor.inspector.option.joined.1x2o8ds\":[\"[Ĵöîñéð ~~]\"],\"editor.inspector.option.kStyle.m8kfwz\":[\"[Ķ šţýļé ~~]\"],\"editor.inspector.option.kickout.vt8s6p\":[\"[Ķîçķöûţ ~~~]\"],\"editor.inspector.option.knee.186hcui\":[\"[Ķñéé ~~]\"],\"editor.inspector.option.landing.tyqarg\":[\"[Ļáñðîñĝ ~~~]\"],\"editor.inspector.option.lantern.1h7o2xb\":[\"[Ļáñţéŕñ ~~~]\"],\"editor.inspector.option.leave.1xf0sbk\":[\"[Ļéáṽé ~~]\"],\"editor.inspector.option.left.14n06mo\":[\"[Ļéƒţ ~~]\"],\"editor.inspector.option.level.i4lhtp\":[\"[Ļéṽéļ ~~]\"],\"editor.inspector.option.lowProfile.1h9lgzg\":[\"[Ļöŵ þŕöƒîļé ~~~]\"],\"editor.inspector.option.mansard.dwzck9\":[\"[Ṁáñšáŕð ~~~]\"],\"editor.inspector.option.manual.1wu7r43\":[\"[Ṁáñûáļ ~~]\"],\"editor.inspector.option.maximumSpacing.n1fzl4\":[\"[Ṁáẋîɱûɱ šþáçîñĝ ~~~~~]\"],\"editor.inspector.option.metal.1az9fgc\":[\"[Ṁéţáļ ~~]\"],\"editor.inspector.option.metalPanel.1xdz476\":[\"[Ṁéţáļ þáñéļ ~~~]\"],\"editor.inspector.option.minimal.fwmiwg\":[\"[Ṁîñîɱáļ ~~~]\"],\"editor.inspector.option.mono.oszvd6\":[\"[Ṁöñö ~~]\"],\"editor.inspector.option.none.deku7v\":[\"[Ñöñé ~~]\"],\"editor.inspector.option.omit.okcs7w\":[\"[Öɱîţ ~~]\"],\"editor.inspector.option.open.n6hn1l\":[\"[Öþéñ ~~]\"],\"editor.inspector.option.openRack.mvt1x0\":[\"[Öþéñ ŕáçķ ~~~]\"],\"editor.inspector.option.opening.dfet3\":[\"[Öþéñîñĝ ~~~]\"],\"editor.inspector.option.oval.1jiqzxx\":[\"[Öṽáļ ~~]\"],\"editor.inspector.option.picket.zyeoy1\":[\"[Þîçķéţ ~~]\"],\"editor.inspector.option.pointed.effedk\":[\"[Þöîñţéð ~~~]\"],\"editor.inspector.option.postAndRail.lajk2u\":[\"[Þöšţ áñð ŕáîļ ~~~~]\"],\"editor.inspector.option.preserveHighEdge.y6ywf0\":[\"[Þŕéšéŕṽé ĥîĝĥ éðĝé ~~~~~]\"],\"editor.inspector.option.preserveLowEdge.196m5pk\":[\"[Þŕéšéŕṽé ļöŵ éðĝé ~~~~~]\"],\"editor.inspector.option.preservePitch.1uq973r\":[\"[Þŕéšéŕṽé þîţçĥ ~~~~]\"],\"editor.inspector.option.privacy.1th4hrb\":[\"[Þŕîṽáçý ~~~]\"],\"editor.inspector.option.purlins.od124c\":[\"[Þûŕļîñš ~~~]\"],\"editor.inspector.option.pvc.1oc4u2w\":[\"[Þṽç ~]\"],\"editor.inspector.option.pyramid.17ucsqv\":[\"[Þýŕáɱîð ~~~]\"],\"editor.inspector.option.rafters.16tzbby\":[\"[Ŕáƒţéŕš ~~~]\"],\"editor.inspector.option.rail.39zqc9\":[\"[Ŕáîļ ~~]\"],\"editor.inspector.option.raised.4kyx9h\":[\"[Ŕáîšéð ~~]\"],\"editor.inspector.option.rect.tpfvaf\":[\"[Ŕéçţ ~~]\"],\"editor.inspector.option.reducer.18byt67\":[\"[Ŕéðûçéŕ ~~~]\"],\"editor.inspector.option.return.1klrjrz\":[\"[Ŕéţûŕñ ~~]\"],\"editor.inspector.option.returnGrille.r28ncm\":[\"[Ŕéţûŕñ ĝŕîļļé ~~~~]\"],\"editor.inspector.option.right.8humpx\":[\"[Ŕîĝĥţ ~~]\"],\"editor.inspector.option.round.1vx0wyj\":[\"[Ŕöûñð ~~]\"],\"editor.inspector.option.rounded.199nwpm\":[\"[Ŕöûñðéð ~~~]\"],\"editor.inspector.option.sanitaryTee.oro3d4\":[\"[Šáñîţáŕý ţéé ~~~~]\"],\"editor.inspector.option.scalloped.1eltba0\":[\"[Šçáļļöþéð ~~~]\"],\"editor.inspector.option.scoop.qy5zdv\":[\"[Šçööþ ~~]\"],\"editor.inspector.option.segmentedPanel.5r3hwl\":[\"[Šéĝɱéñţéð þáñéļ ~~~~~]\"],\"editor.inspector.option.shed.6t994v\":[\"[Šĥéð ~~]\"],\"editor.inspector.option.sheetMetal.l164lv\":[\"[Šĥééţ ɱéţáļ ~~~]\"],\"editor.inspector.option.shingle.pfmynh\":[\"[Šĥîñĝļé ~~~]\"],\"editor.inspector.option.shingled.1nm9inf\":[\"[Šĥîñĝļéð ~~~]\"],\"editor.inspector.option.simple.12mfu73\":[\"[Šîɱþļé ~~]\"],\"editor.inspector.option.single.1uzxurt\":[\"[Šîñĝļé ~~]\"],\"editor.inspector.option.singleLeft.1atdh02\":[\"[Šîñĝļé ļéƒţ ~~~]\"],\"editor.inspector.option.singleRight.1axbu67\":[\"[Šîñĝļé ŕîĝĥţ ~~~~]\"],\"editor.inspector.option.slantBox.1ta99vy\":[\"[Šļáñţ ƀöẋ ~~~]\"],\"editor.inspector.option.slat.1p9njbz\":[\"[Šļáţ ~~]\"],\"editor.inspector.option.sliding.cd0jox\":[\"[Šļîðîñĝ ~~~]\"],\"editor.inspector.option.slope.1bn2qw\":[\"[Šļöþé ~~]\"],\"editor.inspector.option.sloped.lo4sh0\":[\"[Šļöþéð ~~]\"],\"editor.inspector.option.solid.o4uy6s\":[\"[Šöļîð ~~]\"],\"editor.inspector.option.solidPanel.2yaw62\":[\"[Šöļîð þáñéļ ~~~]\"],\"editor.inspector.option.spiral.91hcl4\":[\"[Šþîŕáļ ~~]\"],\"editor.inspector.option.splash.1uke4cm\":[\"[Šþļášĥ ~~]\"],\"editor.inspector.option.spread.1g1zysu\":[\"[Šþŕéáð ~~]\"],\"editor.inspector.option.square.1xl1lk6\":[\"[Šǫûáŕé ~~]\"],\"editor.inspector.option.stair.1xf86e\":[\"[Šţáîŕ ~~]\"],\"editor.inspector.option.standard.vuco\":[\"[Šţáñðáŕð ~~~]\"],\"editor.inspector.option.start.30xvgf\":[\"[Šţáŕţ ~~]\"],\"editor.inspector.option.step.jtn9kf\":[\"[Šţéþ ~~]\"],\"editor.inspector.option.stepped.naxzh0\":[\"[Šţéþþéð ~~~]\"],\"editor.inspector.option.straight.lxqbfr\":[\"[Šţŕáîĝĥţ ~~~]\"],\"editor.inspector.option.strap.14q0ps9\":[\"[Šţŕáþ ~~]\"],\"editor.inspector.option.supply.1oy2zwu\":[\"[Šûþþļý ~~]\"],\"editor.inspector.option.supplyRegister.1lzdbbn\":[\"[Šûþþļý ŕéĝîšţéŕ ~~~~~]\"],\"editor.inspector.option.tapered.3y5blo\":[\"[Ţáþéŕéð ~~~]\"],\"editor.inspector.option.targetSpacing.14uibc9\":[\"[Ţáŕĝéţ šþáçîñĝ ~~~~]\"],\"editor.inspector.option.tee.7d6tjp\":[\"[Ţéé ~]\"],\"editor.inspector.option.tilted.6n0u5j\":[\"[Ţîļţéð ~~]\"],\"editor.inspector.option.top.2nypcs\":[\"[Ţöþ ~]\"],\"editor.inspector.option.transition.1rziz9e\":[\"[Ţŕáñšîţîöñ ~~~]\"],\"editor.inspector.option.vent.xda5j2\":[\"[Ṽéñţ ~~]\"],\"editor.inspector.option.walkOn.1n5sg9l\":[\"[Ŵáļķ öñ ~~]\"],\"editor.inspector.option.wall.blj585\":[\"[Ŵáļļ ~~]\"],\"editor.inspector.option.wallAbutment.lza941\":[\"[Ŵáļļ áƀûţɱéñţ ~~~~]\"],\"editor.inspector.option.wallLedger.5m8ana\":[\"[Ŵáļļ ļéðĝéŕ ~~~]\"],\"editor.inspector.option.wallShelf.yiozfl\":[\"[Ŵáļļ šĥéļƒ ~~~]\"],\"editor.inspector.option.waste.3xrp79\":[\"[Ŵášţé ~~]\"],\"editor.inspector.option.wye.14vupc8\":[\"[Ŵýé ~]\"],\"editor.layers.collapse\":[\"[Çöļļáþšé ~~~]\"],\"editor.layers.defaultName.ceiling\":[\"[Çéîļîñĝ (\",[\"area\"],\") ~~~]\"],\"editor.layers.defaultName.collection\":[\"[Çöļļéçţîöñ ~~~]\"],\"editor.layers.defaultName.flight\":[\"[Ƒļîĝĥţ (\",[\"width\"],\"×\",[\"length\"],\"ɱ) ~~~]\"],\"editor.layers.defaultName.landing\":[\"[Ļáñðîñĝ (\",[\"width\"],\"×\",[\"length\"],\"ɱ) ~~~]\"],\"editor.layers.defaultName.node\":[\"[Ñöðé ~~]\"],\"editor.layers.defaultName.roof\":[\"[Ŕööƒ (\",[\"count\",\"plural\",{\"one\":[\"#\",\" šéĝɱéñţ\"],\"other\":[\"#\",\" šéĝɱéñţš\"]}],\") ~~~~~~]\"],\"editor.layers.defaultName.roofSegment\":[\"[\",[\"roofType\",\"select\",{\"hip\":[\"Ĥîþ\"],\"gable\":[\"Ĝáƀļé\"],\"shed\":[\"Šĥéð\"],\"gambrel\":[\"Ĝáɱƀŕéļ\"],\"dutch\":[\"Ðûţçĥ\"],\"mansard\":[\"Ṁáñšáŕð\"],\"flat\":[\"Ƒļáţ\"],\"conical\":[\"Çöñîçáļ\"],\"barrel\":[\"Ɓáŕŕéļ\"],\"other\":[\"Ŕööƒ\"]}],\" (\",[\"width\"],\"×\",[\"depth\"],\"ɱ) ~~~~~~~~~~~~~~~~]\"],\"editor.layers.defaultName.room\":[\"[Ŕööɱ (\",[\"area\"],\") ~~]\"],\"editor.layers.defaultName.slab\":[\"[Šļáƀ (\",[\"area\"],\") ~~]\"],\"editor.layers.defaultName.staircase\":[\"[Šţáîŕçášé (\",[\"count\",\"plural\",{\"one\":[\"#\",\" šéĝɱéñţ\"],\"other\":[\"#\",\" šéĝɱéñţš\"]}],\") ~~~~~~~~]\"],\"editor.layers.defaultName.zone\":[\"[Žöñé (\",[\"area\"],\") ~~]\"],\"editor.layers.expand\":[\"[Éẋþáñð ~~]\"],\"editor.layers.levelOptions\":[\"[\",[\"levelName\"],\" öþţîöñš ~~~]\"],\"editor.layers.rename\":[\"[Ŕéñáɱé ~~]\"],\"editor.layers.spaceColour\":[\"[\",[\"role\",\"select\",{\"room\":[\"Ŕööɱ çöļöûŕ\"],\"other\":[\"Žöñé çöļöûŕ\"]}],\" ~~~~~~]\"],\"editor.layers.unitColour\":[\"[Ûñîţ çöļöûŕ ~~~]\"],\"editor.levelDuplicateDialog.cancel\":[\"[Çáñçéļ ~~]\"],\"editor.levelDuplicateDialog.chooseWhatToCopyFromLevel\":[\"[Çĥööšé ŵĥáţ ţö çöþý ƒŕöɱ \",[\"levelName\"],\". ~~~~~~]\"],\"editor.levelDuplicateDialog.chooseWhatToCopyFromThisLevel\":[\"[Çĥööšé ŵĥáţ ţö çöþý ƒŕöɱ ţĥîš ļéṽéļ. ~~~~~~~~~]\"],\"editor.levelDuplicateDialog.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"editor.levelDuplicateDialog.duplicateLevel\":[\"[Ðûþļîçáţé Ļéṽéļ ~~~~~]\"],\"editor.levelDuplicateDialog.everything\":[\"[Éṽéŕýţĥîñĝ ~~~]\"],\"editor.levelDuplicateDialog.structureFinishesAndPlacedItemsWithout\":[\"[Šţŕûçţûŕé, ƒîñîšĥéš, áñð þļáçéð îţéɱš, ŵîţĥöûţ ĝûîðé ŕéƒéŕéñçéš. ~~~~~~~~~~~~~~~~]\"],\"editor.levelDuplicateDialog.structureFurniture\":[\"[Šţŕûçţûŕé + ƒûŕñîţûŕé ~~~~~~]\"],\"editor.levelDuplicateDialog.structureMaterials\":[\"[Šţŕûçţûŕé + ɱáţéŕîáļš ~~~~~~]\"],\"editor.levelDuplicateDialog.structureMaterialsFurnitureAndReferences\":[\"[Šţŕûçţûŕé, ɱáţéŕîáļš, ƒûŕñîţûŕé, áñð ŕéƒéŕéñçéš. ~~~~~~~~~~~~]\"],\"editor.levelDuplicateDialog.structureOnly\":[\"[Šţŕûçţûŕé öñļý ~~~~]\"],\"editor.levelDuplicateDialog.structureWithTheCurrentMaterialAnd\":[\"[Šţŕûçţûŕé ŵîţĥ ţĥé çûŕŕéñţ ɱáţéŕîáļ áñð ƒîñîšĥ áššîĝñɱéñţš. ~~~~~~~~~~~~~~~~]\"],\"editor.levelDuplicateDialog.wallsSlabsRoofsStairsWindowsAnd\":[\"[Ŵáļļš, šļáƀš, ŕööƒš, šţáîŕš, ŵîñðöŵš, áñð ðööŕš ŵîţĥöûţ ƒîñîšĥéš. ~~~~~~~~~~~~~~~~]\"],\"editor.levelWallCopyPrompt.copy\":[\"[Çöþý ~~]\"],\"editor.levelWallCopyPrompt.copyExteriorWallsFromTheLevel\":[\"[Çöþý éẋţéŕîöŕ ŵáļļš ƒŕöɱ ţĥé ļéṽéļ \",[\"direction\"],\"? ~~~~~~~~~]\"],\"editor.levelWallCopyPrompt.noThanks\":[\"[Ñö ţĥáñķš ~~~]\"],\"editor.levelWallCopyPrompt.sourcenameSOutsideWallsInPlace\":[\"[\",[\"sourceName\"],\"’š öûţšîðé ŵáļļš, îñ þļáçé, šö ţĥîš ļéṽéļ ļîñéš ûþ ŵîţĥ îţ. ~~~~~~~~~~~~~~]\"],\"editor.lib.contextualHelp.addOrRemoveObjectsFromThe\":[\"[Åðð öŕ ŕéɱöṽé öƀĵéçţš ƒŕöɱ ţĥé šéļéçţîöñ ~~~~~~~~~~~]\"],\"editor.lib.contextualHelp.adjustOneSideSCornerRadius\":[\"[Åðĵûšţ öñé šîðé’š çöŕñéŕ ŕáðîûš ~~~~~~~~]\"],\"editor.lib.contextualHelp.clearTheSelectionOrClickOutside\":[\"[Çļéáŕ ţĥé šéļéçţîöñ (öŕ çļîçķ öûţšîðé) ~~~~~~~~~~]\"],\"editor.lib.contextualHelp.clickAHandleDotToShow\":[\"[Çļîçķ á ĥáñðļé ðöţ ţö šĥöŵ ɱöṽé áŕŕöŵš ~~~~~~~~~~]\"],\"editor.lib.contextualHelp.clickOrDragTheSelectionTo\":[\"[Çļîçķ öŕ ðŕáĝ ţĥé šéļéçţîöñ ţö ɱöṽé îţ áš öñé ~~~~~~~~~~~]\"],\"editor.lib.contextualHelp.clickTheHandleDotToShow\":[\"[Çļîçķ ţĥé ĥáñðļé ðöţ ţö šĥöŵ ɱöṽé + ŕöţáţé ĥáñðļéš ~~~~~~~~~~~~]\"],\"editor.lib.contextualHelp.detachTheJointWhileDraggingAn\":[\"[Ðéţáçĥ ţĥé ĵöîñţ ŵĥîļé ðŕáĝĝîñĝ áñ áŕŕöŵ ~~~~~~~~~~~]\"],\"editor.lib.contextualHelp.dragLeftOrRightToRotate\":[\"[Ðŕáĝ ļéƒţ öŕ ŕîĝĥţ ţö ŕöţáţé šéļéçţéð öƀĵéçţ ~~~~~~~~~~~~]\"],\"editor.lib.contextualHelp.dragSelectedMovableObject\":[\"[Ðŕáĝ šéļéçţéð ɱöṽáƀļé öƀĵéçţ ~~~~~~~~]\"],\"editor.lib.contextualHelp.groupSelectionSessionOnly\":[\"[Ĝŕöûþ šéļéçţîöñ (šéššîöñ öñļý) ~~~~~~~~]\"],\"editor.lib.contextualHelp.holdToRotateFreely\":[\"[Ĥöļð ţö ŕöţáţé ƒŕééļý ~~~~~~]\"],\"editor.lib.contextualHelp.rotate45\":[\"[Ŕöţáţé ±45° ~~]\"],\"editor.lib.contextualHelp.rotateTheSelection45\":[\"[Ŕöţáţé ţĥé šéļéçţîöñ ±45° ~~~~~~]\"],\"editor.lib.contextualHelp.rotatingFreely\":[\"[Ŕöţáţîñĝ ƒŕééļý (ñö áñĝļé šţéþ) ~~~~~~~~]\"],\"editor.lib.contextualHelp.switchTheRotationAxisYX\":[\"[Šŵîţçĥ ţĥé ŕöţáţîöñ áẋîš (Ý → Ẋ → Ž) ~~~~~~~~]\"],\"editor.lib.contextualHelp.ungroupSessionSelection\":[\"[Ûñĝŕöûþ šéššîöñ šéļéçţîöñ ~~~~~~~]\"],\"editor.lib.continuation.continuous\":[\"[Çöñţîñûöûš ~~~]\"],\"editor.lib.continuation.continuousCanopy\":[\"[Çöñţîñûöûš çáñöþý ~~~~~]\"],\"editor.lib.continuation.continuousRun\":[\"[Çöñţîñûöûš ŕûñ ~~~~]\"],\"editor.lib.continuation.curvedFence\":[\"[Çûŕṽéð ƒéñçé ~~~~]\"],\"editor.lib.continuation.freehandFence\":[\"[Ƒŕééĥáñð ƒéñçé ~~~~]\"],\"editor.lib.continuation.placeMultiple\":[\"[Þļáçé ɱûļţîþļé ~~~~]\"],\"editor.lib.continuation.placeOnce\":[\"[Þļáçé öñçé ~~~]\"],\"editor.lib.continuation.polygonRoom\":[\"[Þöļýĝöñ ŕööɱ ~~~~]\"],\"editor.lib.continuation.rectangleRoom\":[\"[Ŕéçţáñĝļé ŕööɱ ~~~~]\"],\"editor.lib.continuation.singleCabinet\":[\"[Šîñĝļé çáƀîñéţ ~~~~]\"],\"editor.lib.continuation.singleCanopy\":[\"[Šîñĝļé çáñöþý ~~~~]\"],\"editor.lib.continuation.singleFence\":[\"[Šîñĝļé ƒéñçé ~~~~]\"],\"editor.lib.continuation.walls\":[\"[Ŵáļļš ~~]\"],\"editor.lib.hudTitle.cutOpening\":[\"[Çûţ öþéñîñĝ ~~~]\"],\"editor.lib.hudTitle.divideRoom\":[\"[Ðîṽîðé ŕööɱ ~~~]\"],\"editor.lib.hudTitle.editKind\":[\"[Éðîţ \",[\"kind\"],\" ~~]\"],\"editor.lib.hudTitle.erase\":[\"[Éŕášé ~~]\"],\"editor.lib.hudTitle.levelTerrain\":[\"[Ļéṽéļ ţéŕŕáîñ ~~~~]\"],\"editor.lib.hudTitle.lowerTerrain\":[\"[Ļöŵéŕ ţéŕŕáîñ ~~~~]\"],\"editor.lib.hudTitle.mezzanine\":[\"[Ṁéžžáñîñé ~~~]\"],\"editor.lib.hudTitle.moveKind\":[\"[Ṁöṽé \",[\"kind\"],\" ~~]\"],\"editor.lib.hudTitle.moveRoom\":[\"[Ṁöṽé ŕööɱ ~~~]\"],\"editor.lib.hudTitle.moveSelection\":[\"[Ṁöṽé šéļéçţîöñ ~~~~]\"],\"editor.lib.hudTitle.paint\":[\"[Þáîñţ ~~]\"],\"editor.lib.hudTitle.paintARectangle\":[\"[Þáîñţ á ŕéçţáñĝļé ~~~~~]\"],\"editor.lib.hudTitle.paintAShape\":[\"[Þáîñţ á šĥáþé ~~~~]\"],\"editor.lib.hudTitle.pickMaterial\":[\"[Þîçķ ɱáţéŕîáļ ~~~~]\"],\"editor.lib.hudTitle.raiseTerrain\":[\"[Ŕáîšé ţéŕŕáîñ ~~~~]\"],\"editor.lib.hudTitle.resize\":[\"[Ŕéšîžé ~~]\"],\"editor.lib.hudTitle.rotate\":[\"[Ŕöţáţé ~~]\"],\"editor.lib.hudTitle.select\":[\"[Šéļéçţ ~~]\"],\"editor.lib.hudTitle.smartMeasure\":[\"[Šɱáŕţ ɱéášûŕé ~~~~]\"],\"editor.lib.hudTitle.smoothTerrain\":[\"[Šɱööţĥ ţéŕŕáîñ ~~~~]\"],\"editor.lib.hudTitle.splitKind\":[\"[Šþļîţ \",[\"kind\"],\" ~~]\"],\"editor.lib.hudTitle.terrace\":[\"[Ţéŕŕáçé ~~~]\"],\"editor.lib.wallDrawVariant.kind.invisible\":[\"[Îñṽîšîƀļé ~~~]\"],\"editor.lib.wallDrawVariant.kind.railing\":[\"[Ŕáîļîñĝ ~~~]\"],\"editor.lib.wallDrawVariant.kind.standard\":[\"[Šţáñðáŕð ~~~]\"],\"editor.lib.wallDrawVariant.polygonRoom\":[\"[Þöļýĝöñ ŕööɱ ~~~~]\"],\"editor.lib.wallDrawVariant.rectangleRoom\":[\"[Ŕéçţáñĝļé ŕööɱ ~~~~]\"],\"editor.lib.wallDrawVariant.walls\":[\"[Ŵáļļš ~~]\"],\"editor.mechanismAction\":[\"[\",[\"action\",\"select\",{\"close\":[\"Çļöšé\"],\"open\":[\"Öþéñ\"],\"stop\":[\"Šţöþ\"],\"other\":[\"Þļáý\"]}],\" ~~~~~~]\"],\"editor.nodeActionMenu.curve\":[\"[Çûŕṽé ~~]\"],\"editor.nodeActionMenu.cutOut\":[\"[Çûţ öûţ ~~]\"],\"editor.nodeActionMenu.delete\":[\"[Ðéļéţé ~~]\"],\"editor.nodeActionMenu.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"editor.nodeActionMenu.editMesh\":[\"[Éðîţ ɱéšĥ ~~~]\"],\"editor.nodeActionMenu.findInCatalog\":[\"[Ƒîñð îñ çáţáļöĝ ~~~~]\"],\"editor.nodeActionMenu.groupSelection\":[\"[Ĝŕöûþ šéļéçţîöñ ~~~~~]\"],\"editor.nodeActionMenu.move\":[\"[Ṁöṽé ~~]\"],\"editor.nodeActionMenu.rotateLeft\":[\"[Ŕöţáţé ļéƒţ ~~~]\"],\"editor.nodeActionMenu.rotateRight\":[\"[Ŕöţáţé ŕîĝĥţ ~~~~]\"],\"editor.nodeActionMenu.ungroupSelection\":[\"[Ûñĝŕöûþ šéļéçţîöñ ~~~~~]\"],\"editor.nodeDisplay.ceiling\":[\"[Çéîļîñĝ ~~~]\"],\"editor.nodeDisplay.column\":[\"[Çöļûɱñ ~~]\"],\"editor.nodeDisplay.door\":[\"[Ðööŕ ~~]\"],\"editor.nodeDisplay.elevator\":[\"[Éļéṽáţöŕ ~~~]\"],\"editor.nodeDisplay.fence\":[\"[Ƒéñçé ~~]\"],\"editor.nodeDisplay.guide\":[\"[Ĝûîðé îɱáĝé ~~~]\"],\"editor.nodeDisplay.item\":[\"[Îţéɱ ~~]\"],\"editor.nodeDisplay.roof\":[\"[Ŕööƒ ~~]\"],\"editor.nodeDisplay.roofSegment\":[\"[Ŕööƒ šéĝɱéñţ ~~~~]\"],\"editor.nodeDisplay.room\":[\"[Ŕööɱ ~~]\"],\"editor.nodeDisplay.scan\":[\"[3Ð Šçáñ ~~]\"],\"editor.nodeDisplay.selection\":[\"[Šéļéçţîöñ ~~~]\"],\"editor.nodeDisplay.slab\":[\"[Šļáƀ ~~]\"],\"editor.nodeDisplay.stair\":[\"[Šţáîŕ ~~]\"],\"editor.nodeDisplay.stairSegment\":[\"[Šţáîŕ šéĝɱéñţ ~~~~]\"],\"editor.nodeDisplay.wall\":[\"[Ŵáļļ ~~]\"],\"editor.nodeDisplay.window\":[\"[Ŵîñðöŵ ~~]\"],\"editor.nodeDisplay.zone\":[\"[Žöñé ~~]\"],\"editor.panels.collections.collectionsPopover.cancel\":[\"[Çáñçéļ ~~]\"],\"editor.panels.collections.collectionsPopover.collectionName\":[\"[Çöļļéçţîöñ ñáɱé… ~~~~~]\"],\"editor.panels.collections.collectionsPopover.collections\":[\"[Çöļļéçţîöñš ~~~~]\"],\"editor.panels.collections.collectionsPopover.delete\":[\"[Ðéļéţé ~~]\"],\"editor.panels.collections.collectionsPopover.deleteName\":[\"[Ðéļéţé \\\"\",[\"name\"],\"\\\"? ~~]\"],\"editor.panels.collections.collectionsPopover.new\":[\"[Ñéŵ ~]\"],\"editor.panels.collections.collectionsPopover.noCollectionsYetCreateOneTo\":[\"[Ñö çöļļéçţîöñš ýéţ. Çŕéáţé öñé ţö ĝŕöûþ éļéɱéñţš ţöĝéţĥéŕ. ~~~~~~~~~~~~~~~]\"],\"editor.panels.collections.collectionsPopover.rename\":[\"[Ŕéñáɱé ~~]\"],\"editor.panels.deckBoardsFields.alongHouse\":[\"[Åļöñĝ ĥöûšé ~~~]\"],\"editor.panels.deckBoardsFields.boards\":[\"[Ɓöáŕðš ~~]\"],\"editor.panels.deckBoardsFields.boardsSummary\":[\"[\",[\"label\"],\" ƀöáŕðš \",[\"thickness\"],\" × \",[\"width\"],\" îñ, \",[\"gap\"],\" îñ áþáŕţ, \",[\"direction\",\"select\",{\"parallel\":[\"áļöñĝ ţĥé ĥöûšé, öñ ĵöîšţš šǫûáŕé ţö îţ\"],\"diagonal\":[\"áţ 45° ţö ţĥé ĥöûšé\"],\"other\":[\"öûţ ƒŕöɱ ţĥé ĥöûšé, öñ ĵöîšţš áļöñĝ îţ, çáŕŕîéð ƀý ƀéáɱš šǫûáŕé ţö ţĥé ĥöûšé\"]}],\"; ĵöîšţš \",[\"spacing\"],\" îñ öñ çéñţŕé. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.deckBoardsFields.deckBoards\":[\"[Ðéçķ ƀöáŕðš ~~~]\"],\"editor.panels.deckBoardsFields.diagonal\":[\"[Ðîáĝöñáļ ~~~]\"],\"editor.panels.deckBoardsFields.gap\":[\"[Ĝáþ ~]\"],\"editor.panels.deckBoardsFields.outFromHouse\":[\"[Öûţ ƒŕöɱ ĥöûšé ~~~~]\"],\"editor.panels.deckBoardsFields.run\":[\"[Ŕûñ ~]\"],\"editor.panels.floorFoundationPanel.aThickerFloorGrowsUpwardThe\":[\"[Å ţĥîçķéŕ ƒļööŕ ĝŕöŵš ûþŵáŕð: ţĥé ŕööɱš ƀéļöŵ ķééþ ţĥéîŕ ĥéîĝĥţ. ~~~~~~~~~~~~~~~~]\"],\"editor.panels.floorFoundationPanel.edgeFinish\":[\"[Éðĝé ƒîñîšĥ ~~~]\"],\"editor.panels.floorFoundationPanel.floorPlate\":[\"[Ƒļööŕ þļáţé ~~~]\"],\"editor.panels.floorFoundationPanel.floorPlateThicknesslabelThickRestingOn\":[\"[Ƒļööŕ þļáţé \",[\"thicknessLabel\"],\" ţĥîçķ, ŕéšţîñĝ öñ ţĥé ŵáļļš ƀéļöŵ ~~~~~~~~~~~~]\"],\"editor.panels.floorFoundationPanel.floorThickness\":[\"[Ƒļööŕ ţĥîçķñéšš ~~~~~]\"],\"editor.panels.floorFoundationPanel.floorTopAbove\":[\"[Ƒļööŕ ţöþ +\",[\"height\"],\" ~~~]\"],\"editor.panels.floorFoundationPanel.floorTopValue\":[\"[Ƒļööŕ ţöþ \",[\"height\"],\" ~~~]\"],\"editor.panels.floorFoundationPanel.foundationFinish\":[\"[Ƒöûñðáţîöñ ƒîñîšĥ ~~~~~]\"],\"editor.panels.floorFoundationPanel.foundationHeight\":[\"[Ƒöûñðáţîöñ ĥéîĝĥţ ~~~~~]\"],\"editor.panels.floorFoundationPanel.kicker\":[\"[Ƒļööŕ þļáţé ~~~]\"],\"editor.panels.floorFoundationPanel.kickerLevel\":[\"[Ƒļööŕ þļáţé · \",[\"level\"],\" ~~~]\"],\"editor.panels.floorFoundationPanel.kickerRestsOn\":[\"[Ƒļööŕ þļáţé · \",[\"level\"],\" · ŕéšţš öñ \",[\"below\"],\" ~~~~~~]\"],\"editor.panels.floorFoundationPanel.lowerTogether\":[\"[\",[\"count\",\"plural\",{\"2\":[\"Ļöŵéŕ ƀöţĥ\"],\"other\":[\"Ļöŵéŕ áļļ \",[\"number\"]]}],\" ~~~~~~]\"],\"editor.panels.floorFoundationPanel.notToScale\":[\"[Ñöţ ţö šçáļé ~~~]\"],\"editor.panels.floorFoundationPanel.onTheGround\":[\"[Öñ ţĥé ĝŕöûñð ~~~~]\"],\"editor.panels.floorFoundationPanel.raiseTogether\":[\"[\",[\"count\",\"plural\",{\"2\":[\"Ŕáîšé ƀöţĥ\"],\"other\":[\"Ŕáîšé áļļ \",[\"number\"]]}],\" ~~~~~~]\"],\"editor.panels.floorFoundationPanel.raisedOnAFoundation\":[\"[Ŕáîšéð öñ á ƒöûñðáţîöñ ~~~~~~]\"],\"editor.panels.floorFoundationPanel.section.floorPlate\":[\"[Ƒļööŕ þļáţé · \",[\"thickness\"],\" ~~~]\"],\"editor.panels.floorFoundationPanel.section.floorTop\":[\"[Ƒļööŕ ţöþ ~~~]\"],\"editor.panels.floorFoundationPanel.section.foundation\":[\"[Ƒöûñðáţîöñ ~~~]\"],\"editor.panels.floorFoundationPanel.section.foundationKind\":[\"[Ƒöûñðáţîöñ · \",[\"foundation\"],\" ~~~]\"],\"editor.panels.floorFoundationPanel.section.ground\":[\"[Ĝŕöûñð ~~]\"],\"editor.panels.floorFoundationPanel.section.slab\":[\"[Šļáƀ · \",[\"thickness\"],\" ~~]\"],\"editor.panels.floorFoundationPanel.section.wallsBelow\":[\"[Ŵáļļš ƀéļöŵ ~~~]\"],\"editor.panels.floorFoundationPanel.sectionOnGround\":[\"[Šļáƀ \",[\"thickness\"],\" ţĥîçķ öñ ţĥé ĝŕöûñð, ƒļööŕ ţöþ \",[\"top\"],\" áƀöṽé ţĥé ĝŕöûñð ~~~~~~~~~~~~~]\"],\"editor.panels.floorFoundationPanel.sectionRaised\":[\"[Šļáƀ \",[\"thickness\"],\" ţĥîçķ öñ á \",[\"foundation\"],\" ƒöûñðáţîöñ, ƒļööŕ ţöþ \",[\"top\"],\" áƀöṽé ţĥé ĝŕöûñð ~~~~~~~~~~~~~~]\"],\"editor.panels.floorFoundationPanel.slab\":[\"[Šļáƀ ~~]\"],\"editor.panels.floorFoundationPanel.slabThickness\":[\"[Šļáƀ ţĥîçķñéšš ~~~~]\"],\"editor.panels.floorFoundationPanel.theFloorSOutsideEdgeAll\":[\"[Ţĥé ƒļööŕ'š öûţšîðé éðĝé, áļļ áŕöûñð ţĥé ƒööţþŕîñţ. ~~~~~~~~~~~~~]\"],\"editor.panels.floorFoundationPanel.theFoundationStandsOnTheGround\":[\"[Ţĥé ƒöûñðáţîöñ šţáñðš öñ ţĥé ĝŕöûñð; ţĥé šļáƀ šîţš öñ îţ. ~~~~~~~~~~~~~~]\"],\"editor.panels.floorFoundationPanel.theSlabSitsOnTheFoundation\":[\"[Ţĥé šļáƀ šîţš öñ ţĥé ƒöûñðáţîöñ (öŕ ţĥé ĝŕöûñð): á ţĥîçķéŕ šļáƀ ŕáîšéš ţĥé ƒļööŕ ţöþ áñð éṽéŕýţĥîñĝ öñ îţ. ~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.floorFoundationPanel.underTheFloor\":[\"[Ûñðéŕ ţĥé ƒļööŕ ~~~~]\"],\"editor.panels.floorOpeningPanel.aHatchInTheMezzanineIt\":[\"[Å ĥáţçĥ îñ ţĥé ɱéžžáñîñé: îţ çûţš öñļý ţĥé ɱéžžáñîñé’š ƒļööŕ. ~~~~~~~~~~~~~~~]\"],\"editor.panels.floorOpeningPanel.alsoCutTheCeilingBelow\":[\"[Åļšö çûţ ţĥé çéîļîñĝ ƀéļöŵ ~~~~~~~]\"],\"editor.panels.floorOpeningPanel.alsoCutTheFloorAbove\":[\"[Åļšö çûţ ţĥé ƒļööŕ áƀöṽé ~~~~~~]\"],\"editor.panels.floorOpeningPanel.areaDragCorners\":[\"[\",[\"area\"],\" · Ðŕáĝ îţš çöŕñéŕš ţö çĥáñĝé ţĥé šĥáþé. ~~~~~~~~~]\"],\"editor.panels.floorOpeningPanel.areaOwned\":[\"[\",[\"area\"],\" · Šĥáþé ƒöļļöŵš îţš öŵñéŕ. ~~~~~~]\"],\"editor.panels.floorOpeningPanel.areaStairResize\":[\"[\",[\"area\"],\" · Ðŕáĝ îţš šîðéš öŕ çöŕñéŕš ţö ŕéšîžé îţ; îţ ɱöṽéš ŵîţĥ ţĥé šţáîŕ. ~~~~~~~~~~~~~~~]\"],\"editor.panels.floorOpeningPanel.delete\":[\"[Ðéļéţé ~~]\"],\"editor.panels.floorOpeningPanel.done\":[\"[Ðöñé ~~]\"],\"editor.panels.floorOpeningPanel.kicker\":[\"[Öþéñîñĝ ~~~]\"],\"editor.panels.floorOpeningPanel.kickerLevel\":[\"[Öþéñîñĝ · \",[\"level\"],\" ~~~]\"],\"editor.panels.floorOpeningPanel.kickerRoom\":[\"[Öþéñîñĝ · îñ \",[\"room\"],\" ~~~]\"],\"editor.panels.floorOpeningPanel.kickerRoomLevel\":[\"[Öþéñîñĝ · îñ \",[\"room\"],\" · \",[\"level\"],\" ~~~]\"],\"editor.panels.floorOpeningPanel.oneVoidWith\":[\"[Öñ \",[\"level\"],\", áš öñé ṽöîð ŵîţĥ ţĥîš öþéñîñĝ. ~~~~~~~~]\"],\"editor.panels.floorOpeningPanel.ownedByElevator\":[\"[Öŵñéð ƀý Éļéṽáţöŕ ~~~~~]\"],\"editor.panels.floorOpeningPanel.ownedByStaircase\":[\"[Öŵñéð ƀý Šţáîŕçášé ~~~~~]\"],\"editor.panels.floorOpeningPanel.room\":[\"[Ŕööɱ ~~]\"],\"editor.panels.floorOpeningPanel.thereIsNoFloorAboveThis\":[\"[Ţĥéŕé îš ñö ƒļööŕ áƀöṽé ţĥîš šţöŕéý. ~~~~~~~~~]\"],\"editor.panels.floorOpeningPanel.thereIsNoStoreyBelow\":[\"[Ţĥéŕé îš ñö šţöŕéý ƀéļöŵ. ~~~~~~]\"],\"editor.panels.floorOpeningPanel.title\":[\"[\",[\"source\",\"select\",{\"stair\":[\"Šţáîŕ öþéñîñĝ\"],\"elevator\":[\"Éļéṽáţöŕ öþéñîñĝ\"],\"ceiling\":[\"Çéîļîñĝ öþéñîñĝ\"],\"other\":[\"Ƒļööŕ öþéñîñĝ\"]}],\" ~~~~~~~~~~~~~~~~]\"],\"editor.panels.mergeRefusal.alreadyJoined\":[\"[Öñé öƒ ţĥéɱ áļŕéáðý ŵŕáþš áñöţĥéŕ çöŕñéŕ. Ûñŵŕáþ îţ ƒîŕšţ. ~~~~~~~~~~~~~~~]\"],\"editor.panels.mergeRefusal.between\":[\"[\",[\"kind\",\"select\",{\"item\":[\"Ţĥéŕé îš áñ îţéɱ ƀéţŵééñ ţĥéɱ.\"],\"door\":[\"Ţĥéŕé îš á ðööŕ ƀéţŵééñ ţĥéɱ.\"],\"window\":[\"Ţĥéŕé îš á ŵîñðöŵ ƀéţŵééñ ţĥéɱ.\"],\"shelf\":[\"Ţĥéŕé îš á šĥéļƒ ƀéţŵééñ ţĥéɱ.\"],\"other\":[\"Ţĥéŕé îš šöɱéţĥîñĝ ƀéţŵééñ ţĥéɱ.\"]}],\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.mergeRefusal.cannotMerge\":[\"[Ţĥéšé ŵîñðöŵš çáññöţ ƀé ɱéŕĝéð. ~~~~~~~~]\"],\"editor.panels.mergeRefusal.cornerAngle\":[\"[Ţĥéîŕ ŵáļļš ɱééţ áţ ţöö šĥáŕþ öŕ ţöö ƒļáţ áñ áñĝļé ƒöŕ á çöŕñéŕ ŵîñðöŵ. ~~~~~~~~~~~~~~~~~]\"],\"editor.panels.mergeRefusal.heightExceedsWall\":[\"[Ţĥé ŵîñðöŵ šéļéçţéð ƒîŕšţ îš ţáļļéŕ ţĥáñ ţĥé öţĥéŕ ŵáļļ. Šéļéçţ ţĥé öţĥéŕ öñé ƒîŕšţ. ~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.mergeRefusal.notAdjacent\":[\"[Ţĥéý áŕé ţöö ƒáŕ áþáŕţ. Ŵîñðöŵš ɱéŕĝé ŵîţĥ áţ ɱöšţ \",[\"reach\"],\" ƀéţŵééñ ţĥéɱ. ~~~~~~~~~~~~~~~~]\"],\"editor.panels.mergeRefusal.notAtCorner\":[\"[Öñé öƒ ţĥéɱ îš ţöö ƒáŕ ƒŕöɱ ţĥé çöŕñéŕ. Å ŵîñðöŵ ĵöîñš öñé ŵîţĥîñ \",[\"reach\"],\" öƒ îţ. ~~~~~~~~~~~~~~~~~]\"],\"editor.panels.mergeRefusal.notOnWall\":[\"[Å ŕööƒ öŕ ðöŕɱéŕ ŵîñðöŵ çáññöţ ĵöîñ áñöţĥéŕ ŵîñðöŵ. ~~~~~~~~~~~~~]\"],\"editor.panels.mergeRefusal.overlap\":[\"[\",[\"kind\",\"select\",{\"item\":[\"Šļîðîñĝ ţĥéɱ ţö ţĥé çöŕñéŕ ŵöûļð öṽéŕļáþ áñ îţéɱ.\"],\"door\":[\"Šļîðîñĝ ţĥéɱ ţö ţĥé çöŕñéŕ ŵöûļð öṽéŕļáþ á ðööŕ.\"],\"window\":[\"Šļîðîñĝ ţĥéɱ ţö ţĥé çöŕñéŕ ŵöûļð öṽéŕļáþ á ŵîñðöŵ.\"],\"shelf\":[\"Šļîðîñĝ ţĥéɱ ţö ţĥé çöŕñéŕ ŵöûļð öṽéŕļáþ á šĥéļƒ.\"],\"other\":[\"Šļîðîñĝ ţĥéɱ ţö ţĥé çöŕñéŕ ŵöûļð öṽéŕļáþ šöɱéţĥîñĝ.\"]}],\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.mergeRefusal.wallsNotMeeting\":[\"[Ţĥéîŕ ŵáļļš ðö ñöţ ɱééţ áţ á çöŕñéŕ. ~~~~~~~~~]\"],\"editor.panels.mixed\":[\"[Ṁîẋéð ~~]\"],\"editor.panels.mobilePanelSheet.close\":[\"[Çļöšé ~~]\"],\"editor.panels.mobileSelectionBar.delete\":[\"[Ðéļéţé ~~]\"],\"editor.panels.mobileSelectionBar.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"editor.panels.mobileSelectionBar.editProperties\":[\"[Éðîţ þŕöþéŕţîéš ~~~~~]\"],\"editor.panels.mobileSelectionBar.editResolvedlabel\":[\"[Éðîţ \",[\"resolvedLabel\"],\" ~~]\"],\"editor.panels.mobileSelectionBar.move\":[\"[Ṁöṽé ~~]\"],\"editor.panels.multiHeightMode.currentlyCurrentlabel\":[\"[Çûŕŕéñţļý \",[\"currentLabel\"],\" ~~~]\"],\"editor.panels.multiHeightMode.customHeight\":[\"[Çûšţöɱ ĥéîĝĥţ ~~~~]\"],\"editor.panels.multiHeightMode.followsLevel\":[\"[Ƒöļļöŵš ļéṽéļ ~~~~]\"],\"editor.panels.multiHeightMode.height\":[\"[Ĥéîĝĥţ ~~]\"],\"editor.panels.multiHeightMode.top\":[\"[Ţöþ ~]\"],\"editor.panels.multiParametricInspector.labelSessionOnlyPlainClickReselects\":[\"[\",[\"label\"],\" (šéššîöñ öñļý). Þļáîñ çļîçķ ŕéšéļéçţš áļļ ɱéɱƀéŕš. Ñöţ šáṽéð ŵîţĥ ţĥé þŕöĵéçţ. ~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.multiSelectionPanel.delete\":[\"[Ðéļéţé ~~]\"],\"editor.panels.multiSelectionPanel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"editor.panels.multiSelectionPanel.group\":[\"[Ĝŕöûþ ~~]\"],\"editor.panels.multiSelectionPanel.groupCtrlCmdG\":[\"[Ĝŕöûþ (Çţŕļ/Çɱð+Ĝ) ~~~~]\"],\"editor.panels.multiSelectionPanel.labelSessionOnlyPlainClickReselects\":[\"[\",[\"label\"],\" (šéššîöñ öñļý). Þļáîñ çļîçķ ŕéšéļéçţš áļļ ɱéɱƀéŕš. Ñöţ šáṽéð ŵîţĥ ţĥé þŕöĵéçţ. ~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.multiSelectionPanel.lengthSelected\":[\"[\",[\"length\"],\" šéļéçţéð ~~~]\"],\"editor.panels.multiSelectionPanel.mergeWindows\":[\"[Ṁéŕĝé ŵîñðöŵš ~~~~]\"],\"editor.panels.multiSelectionPanel.mergeWindowsIntoACornerWindow\":[\"[Ṁéŕĝé ŵîñðöŵš îñţö á çöŕñéŕ ŵîñðöŵ: ƀöţĥ ţáķé ţĥé ĥéîĝĥţ, šîļļ áñð ţýþé öƒ ţĥé öñé ýöû šéļéçţéð ƒîŕšţ ~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.multiSelectionPanel.mergeWindowsIntoOneAcrossBoth\":[\"[Ṁéŕĝé ŵîñðöŵš îñţö öñé áçŕöšš ƀöţĥ: îţ ķééþš ţĥé ţýþé áñð šţýļé öƒ ţĥé öñé ýöû šéļéçţéð ƒîŕšţ ~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.multiSelectionPanel.selectBuilding\":[\"[Šéļéçţ ƀûîļðîñĝ ~~~~~]\"],\"editor.panels.multiSelectionPanel.selectTheWholeBuildingToMove\":[\"[Šéļéçţ ţĥé ŵĥöļé ƀûîļðîñĝ ţö ɱöṽé áļļ îţš ļéṽéļš ~~~~~~~~~~~~]\"],\"editor.panels.multiSelectionPanel.ungroup\":[\"[Ûñĝŕöûþ ~~~]\"],\"editor.panels.multiSelectionPanel.ungroupCtrlCmdShiftG\":[\"[Ûñĝŕöûþ (Çţŕļ/Çɱð+Šĥîƒţ+Ĝ) ~~~~~~]\"],\"editor.panels.multiSelectionPanel.unwrapTheCorner\":[\"[Ûñŵŕáþ ţĥé çöŕñéŕ ~~~~~]\"],\"editor.panels.multiSelectionPanel.unwrapTheCornerBothWindowsStay\":[\"[Ûñŵŕáþ ţĥé çöŕñéŕ: ƀöţĥ ŵîñðöŵš šţáý, éáçĥ ƒŕáɱéð áţ ţĥé çöŕñéŕ ~~~~~~~~~~~~~~~~]\"],\"editor.panels.panelManager.selection\":[\"[Šéļéçţîöñ ~~~]\"],\"editor.panels.panelWrapper.back\":[\"[Ɓáçķ ~~]\"],\"editor.panels.panelWrapper.close\":[\"[Çļöšé ~~]\"],\"editor.panels.panelWrapper.collapsePanel\":[\"[Çöļļáþšé þáñéļ ~~~~]\"],\"editor.panels.panelWrapper.collections\":[\"[Çöļļéçţîöñš ~~~~]\"],\"editor.panels.panelWrapper.expandPanel\":[\"[Éẋþáñð þáñéļ ~~~~]\"],\"editor.panels.panelWrapper.manageCollections\":[\"[Ṁáñáĝé çöļļéçţîöñš… ~~~~~~]\"],\"editor.panels.panelWrapper.reset\":[\"[Ŕéšéţ ~~]\"],\"editor.panels.panelWrapper.titleHitAnErrorAndWas\":[\"[“\",[\"title\"],\"” ĥîţ áñ éŕŕöŕ áñð ŵáš ûñļöáðéð ƒöŕ ţĥîš šéššîöñ. ~~~~~~~~~~~~]\"],\"editor.panels.parametricFieldControl.mixed\":[\"[Ṁîẋéð ~~]\"],\"editor.panels.parametricInspector.actions\":[\"[Åçţîöñš ~~~]\"],\"editor.panels.parametricInspector.delete\":[\"[Ðéļéţé ~~]\"],\"editor.panels.parametricInspector.deleteWithContents\":[\"[Ðéļéţé ŵîţĥ çöñţéñţš ~~~~~~]\"],\"editor.panels.parametricInspector.move\":[\"[Ṁöṽé ~~]\"],\"editor.panels.referencePanel.cancel\":[\"[Çáñçéļ ~~]\"],\"editor.panels.referencePanel.capture\":[\"[Çáþţûŕé ~~~]\"],\"editor.panels.referencePanel.center\":[\"[Çéñţéŕ ~~]\"],\"editor.panels.referencePanel.clearScale\":[\"[Çļéáŕ Šçáļé ~~~]\"],\"editor.panels.referencePanel.clickBothEndsOfAKnown\":[\"[Çļîçķ ƀöţĥ éñðš öƒ á ķñöŵñ ðîšţáñçé öñ ţĥé þļáñ, ţĥéñ ţýþé îţš ŕéáļ ļéñĝţĥ. ~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.referencePanel.delete\":[\"[Ðéļéţé ~~]\"],\"editor.panels.referencePanel.drawALineOverAKnown\":[\"[Ðŕáŵ á ļîñé öṽéŕ á ķñöŵñ ðîɱéñšîöñ öñ ţĥé þļáñ, ţĥéñ ţýþé îţš ŕéáļ ļéñĝţĥ ţö šçáļé ţĥé îɱáĝé éẋáçţļý. ~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.referencePanel.editScale\":[\"[Éðîţ Šçáļé ~~~]\"],\"editor.panels.referencePanel.guideImage\":[\"[Ĝûîðé Îɱáĝé ~~~]\"],\"editor.panels.referencePanel.hide\":[\"[Ĥîðé ~~]\"],\"editor.panels.referencePanel.hideScale\":[\"[Ĥîðé Šçáļé ~~~]\"],\"editor.panels.referencePanel.image\":[\"[Îɱáĝé ~~]\"],\"editor.panels.referencePanel.lock\":[\"[Ļöçķ ~~]\"],\"editor.panels.referencePanel.move\":[\"[Ṁöṽé ~~]\"],\"editor.panels.referencePanel.opacity\":[\"[Öþáçîţý ~~~]\"],\"editor.panels.referencePanel.overlayImageUnavailableReplaceTheImage\":[\"[Öṽéŕļáý îɱáĝé ûñáṽáîļáƀļé. Ŕéþļáçé ţĥé îɱáĝé ţö ŕéšţöŕé îţ. ~~~~~~~~~~~~~~~]\"],\"editor.panels.referencePanel.pos\":[\"[þöš ~]\"],\"editor.panels.referencePanel.position\":[\"[Þöšîţîöñ ~~~]\"],\"editor.panels.referencePanel.quickActions\":[\"[Ǫûîçķ Åçţîöñš ~~~~]\"],\"editor.panels.referencePanel.referenceScale\":[\"[Ŕéƒéŕéñçé Šçáļé ~~~~~]\"],\"editor.panels.referencePanel.replace\":[\"[Ŕéþļáçé ~~~]\"],\"editor.panels.referencePanel.replacing\":[\"[Ŕéþļáçîñĝ... ~~~]\"],\"editor.panels.referencePanel.resetImageScale\":[\"[Ŕéšéţ Îɱáĝé Šçáļé ~~~~~]\"],\"editor.panels.referencePanel.resetRotation\":[\"[Ŕéšéţ Ŕöţáţîöñ ~~~~]\"],\"editor.panels.referencePanel.rot\":[\"[ŕöţ ~]\"],\"editor.panels.referencePanel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"editor.panels.referencePanel.scale\":[\"[šçáļé ~~]\"],\"editor.panels.referencePanel.scaleOpacity\":[\"[Šçáļé & Öþáçîţý ~~~~]\"],\"editor.panels.referencePanel.scaled\":[\"[Šçáļéð · \",[\"scale\"],\" ~~]\"],\"editor.panels.referencePanel.scaledHidden\":[\"[Šçáļéð (ĥîððéñ) · \",[\"scale\"],\" ~~~~]\"],\"editor.panels.referencePanel.setScale\":[\"[Šéţ Šçáļé ~~~]\"],\"editor.panels.referencePanel.show\":[\"[Šĥöŵ ~~]\"],\"editor.panels.referencePanel.showScale\":[\"[Šĥöŵ Šçáļé ~~~]\"],\"editor.panels.referencePanel.uncalibrated\":[\"[Ûñçáļîƀŕáţéð ~~~~]\"],\"editor.panels.referencePanel.unlock\":[\"[Ûñļöçķ ~~]\"],\"editor.panels.referencePanel.xyz\":[\"[ẊÝŽ ~]\"],\"editor.panels.roomConstructionRows.aDrawnSlabSetItsThickness\":[\"[Å ðŕáŵñ šļáƀ: šéţ îţš ţĥîçķñéšš áñð ƒîñîšĥéš ĥéŕé. Îţ ĥáš ñö ƒööţþŕîñţ ĥéîĝĥţ öŕ ƒöûñðáţîöñ. ~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.roomConstructionRows.addMezzanine\":[\"[+ Åðð ɱéžžáñîñé ~~~~]\"],\"editor.panels.roomConstructionRows.atFloorLevel\":[\"[Åţ ƒļööŕ ļéṽéļ ~~~~]\"],\"editor.panels.roomConstructionRows.beam\":[\"[Ɓéáɱ ~~]\"],\"editor.panels.roomConstructionRows.beamSize\":[\"[Ɓéáɱ šîžé ~~~]\"],\"editor.panels.roomConstructionRows.builtOn\":[\"[Ɓûîļţ öñ ~~~]\"],\"editor.panels.roomConstructionRows.builtWith\":[\"[Ɓûîļţ ŵîţĥ ~~~]\"],\"editor.panels.roomConstructionRows.ceiling\":[\"[Çéîļîñĝ ~~~]\"],\"editor.panels.roomConstructionRows.ceilingAt\":[\"[Åţ \",[\"height\"],\" ~]\"],\"editor.panels.roomConstructionRows.closeWithWalls\":[\"[Çļöšé ŵîţĥ ŵáļļš ~~~~~]\"],\"editor.panels.roomConstructionRows.drawnFloor\":[\"[\",[\"ambiguous\",\"select\",{\"yes\":[\"Ƒļööŕ îš šéṽéŕáļ ðŕáŵñ šļáƀš, ɱöšţļý \",[\"name\"]],\"other\":[\"Ƒļööŕ îš á ðŕáŵñ šļáƀ: \",[\"name\"]]}],[\"shared\",\"plural\",{\"0\":[],\"one\":[\" (šĥáŕéð ŵîţĥ \",[\"sharedCount\"],\" ŕööɱ)\"],\"other\":[\" (šĥáŕéð ŵîţĥ \",[\"sharedCount\"],\" ŕööɱš)\"]}],\" ~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.roomConstructionRows.drawnFloorSwitchHint\":[\"[Ţĥîš ƒļööŕ îš á ðŕáŵñ šļáƀ: šéļéçţ îţ ţö éðîţ öŕ ðéļéţé îţ. ~~~~~~~~~~~~~~]\"],\"editor.panels.roomConstructionRows.drawnSlab\":[\"[Ðŕáŵñ šļáƀ ~~~]\"],\"editor.panels.roomConstructionRows.drawnSlabAt\":[\"[Ðŕáŵñ šļáƀ áţ \",[\"height\"],\" ~~~~]\"],\"editor.panels.roomConstructionRows.editShape\":[\"[Éðîţ šĥáþé ~~~]\"],\"editor.panels.roomConstructionRows.flatAtWallHeight\":[\"[Ƒļáţ, áţ ŵáļļ ĥéîĝĥţ ~~~~~]\"],\"editor.panels.roomConstructionRows.floor\":[\"[Ƒļööŕ ~~]\"],\"editor.panels.roomConstructionRows.floorDown\":[\"[\",[\"distance\"],\" ðöŵñ ~~]\"],\"editor.panels.roomConstructionRows.floorThickness\":[\"[Ƒļööŕ ţĥîçķñéšš ~~~~~]\"],\"editor.panels.roomConstructionRows.floorUp\":[\"[\",[\"distance\"],\" ûþ ~]\"],\"editor.panels.roomConstructionRows.framingAutoHint\":[\"[\",[\"posts\",\"plural\",{\"one\":[[\"postCount\"],\" þöšţ\"],\"other\":[[\"postCount\"],\" þöšţš\"]}],\" áñð \",[\"beams\",\"plural\",{\"one\":[[\"beamCount\"],\" ƀéáɱ\"],\"other\":[[\"beamCount\"],\" ƀéáɱš\"]}],\", á þöšţ öñ éáçĥ öûţšîðé çöŕñéŕ, ķéþţ ŵîţĥ \",[\"room\",\"select\",{\"deck\":[\"ţĥé ðéçķ\"],\"patio\":[\"ţĥé þáţîö\"],\"other\":[\"ţĥé þöŕçĥ\"]}],\". ~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.roomConstructionRows.framingAutomatic\":[\"[Åûţöɱáţîç ~~~]\"],\"editor.panels.roomConstructionRows.framingManual\":[\"[Ṁáñûáļ ~~]\"],\"editor.panels.roomConstructionRows.framingManualHint\":[\"[Ķéþţ áš ýöû éðîţéð ţĥéɱ. Åûţöɱáţîç ŕéƀûîļðš ţĥéɱ ƒŕöɱ ţĥéšé šéţţîñĝš. ~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.roomConstructionRows.framingOff\":[\"[Öƒƒ ~]\"],\"editor.panels.roomConstructionRows.framingOffHint\":[\"[Ñöñé. Åûţöɱáţîç þûţš á þöšţ öñ éáçĥ öûţšîðé çöŕñéŕ áñð á ƀéáɱ öñ ţĥéɱ, ţö çáŕŕý á ŕööƒ öṽéŕ \",[\"room\",\"select\",{\"deck\":[\"ţĥé ðéçķ\"],\"patio\":[\"ţĥé þáţîö\"],\"other\":[\"ţĥé þöŕçĥ\"]}],\". ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.roomConstructionRows.handDrawnCeiling\":[\"[Ĥáñð-ðŕáŵñ çéîļîñĝ ~~~~~]\"],\"editor.panels.roomConstructionRows.height\":[\"[Ĥéîĝĥţ ~~]\"],\"editor.panels.roomConstructionRows.includeFloor\":[\"[Îñçļûðé ƒļööŕ ~~~~]\"],\"editor.panels.roomConstructionRows.includePart\":[\"[\",[\"part\",\"select\",{\"floor\":[\"Îñçļûðé ƒļööŕ\"],\"walls\":[\"Îñçļûðé ŵáļļš\"],\"other\":[\"Îñçļûðé çéîļîñĝ\"]}],\" ~~~~~~~~~~~~]\"],\"editor.panels.roomConstructionRows.includeWalls\":[\"[Îñçļûðé ŵáļļš ~~~~]\"],\"editor.panels.roomConstructionRows.keepOutsideDimensions\":[\"[Ķééþ öûţšîðé ðîɱéñšîöñš ~~~~~~~]\"],\"editor.panels.roomConstructionRows.lowered\":[\"[Ļöŵéŕéð \",[\"lift\"],\" ~~~]\"],\"editor.panels.roomConstructionRows.newFloor\":[\"[+ Ñéŵ ƒļööŕ ~~~]\"],\"editor.panels.roomConstructionRows.noFloor\":[\"[Ñö ƒļööŕ ~~~]\"],\"editor.panels.roomConstructionRows.notIncluded\":[\"[Ñöţ îñçļûðéð ~~~~]\"],\"editor.panels.roomConstructionRows.nothingToChange\":[\"[Ñöţĥîñĝ ţö çĥáñĝé. ~~~~~]\"],\"editor.panels.roomConstructionRows.onTheGround\":[\"[Öñ ţĥé ĝŕöûñð ~~~~]\"],\"editor.panels.roomConstructionRows.onTheWallsBelow\":[\"[Öñ ţĥé ŵáļļš ƀéļöŵ ~~~~~]\"],\"editor.panels.roomConstructionRows.openSides\":[\"[\",[\"openSides\",\"plural\",{\"one\":[[\"openSideCount\"],\" öþéñ šîðé\"],\"other\":[[\"openSideCount\"],\" öþéñ šîðéš\"]}],\" ~~~~~~]\"],\"editor.panels.roomConstructionRows.partialCovered\":[\"[Þáŕţîáļ · \",[\"coverage\",\"number\",\"percent\"],\" çöṽéŕéð ~~~~~]\"],\"editor.panels.roomConstructionRows.partialWalls\":[\"[Þáŕţîáļ · \",[\"walls\",\"plural\",{\"one\":[[\"wallCount\"],\" ŵáļļ\"],\"other\":[[\"wallCount\"],\" ŵáļļš\"]}],\", \",[\"openSides\",\"plural\",{\"one\":[[\"openSideCount\"],\" öþéñ šîðé\"],\"other\":[[\"openSideCount\"],\" öþéñ šîðéš\"]}],\" ~~~~~~~~~~]\"],\"editor.panels.roomConstructionRows.postSize\":[\"[Þöšţ šîžé ~~~]\"],\"editor.panels.roomConstructionRows.postSpacingMax\":[\"[Þöšţ šþáçîñĝ (ɱáẋ) ~~~~~]\"],\"editor.panels.roomConstructionRows.postsAndBeam\":[\"[Þöšţš áñð ƀéáɱ ~~~~]\"],\"editor.panels.roomConstructionRows.raised\":[\"[Ŕáîšéð \",[\"lift\"],\" ~~]\"],\"editor.panels.roomConstructionRows.replace\":[\"[Ŕéþļáçé ~~~]\"],\"editor.panels.roomConstructionRows.roomType\":[\"[Ŕööɱ ţýþé ~~~]\"],\"editor.panels.roomConstructionRows.roomTypeDeck\":[\"[Ðéçķ ~~]\"],\"editor.panels.roomConstructionRows.roomTypeDeckHint\":[\"[Öûţðööŕš: ðéçķ ƀöáŕðš öñ á ŵööð ƒŕáɱé áñð þöšţš, 1 îñ ðöŵñ ƒŕöɱ ţĥé ĥöûšé; ñö çéîļîñĝ. ~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.roomConstructionRows.roomTypePatio\":[\"[Þáţîö ~~]\"],\"editor.panels.roomConstructionRows.roomTypePatioHint\":[\"[Öûţðööŕš áñð öþéñ: á çöñçŕéţé šļáƀ 1½ îñ ðöŵñ ƒŕöɱ ţĥé ĥöûšé, ñö çéîļîñĝ. ~~~~~~~~~~~~~~~~~]\"],\"editor.panels.roomConstructionRows.roomTypePorch\":[\"[Þöŕçĥ ~~]\"],\"editor.panels.roomConstructionRows.roomTypePorchHint\":[\"[Öûţðööŕš ûñðéŕ á çéîļîñĝ: á çöñçŕéţé šļáƀ 1½ îñ ðöŵñ ƒŕöɱ ţĥé ĥöûšé, çéîļîñĝ áţ ţĥé ĥöûšé’š. ~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.panels.roomConstructionRows.roomTypeRoom\":[\"[Ŕööɱ ~~]\"],\"editor.panels.roomConstructionRows.roomTypeRoomHint\":[\"[Åñ öŕðîñáŕý ŕööɱ îñšîðé ţĥé ĥöûšé. ~~~~~~~~~]\"],\"editor.panels.roomConstructionRows.select\":[\"[Šéļéçţ ~~]\"],\"editor.panels.roomConstructionRows.shape\":[\"[Šĥáþé ~~]\"],\"editor.panels.roomConstructionRows.sharedWallsNote\":[\"[Ţûŕñîñĝ ŵáļļš öƒƒ ķééþš ţĥé öñéš šĥáŕéð ŵîţĥ \",[\"rooms\"],\". ~~~~~~~~~~~~]\"],\"editor.panels.roomConstructionRows.sitsOnPreset\":[\"[Šîţš öñ: \",[\"name\"],\" · \",[\"preset\"],\" ~~]\"],\"editor.panels.roomConstructionRows.theNextRoom\":[\"[ţĥé ñéẋţ ŕööɱ ~~~~]\"],\"editor.panels.roomConstructionRows.useExisting\":[\"[Ûšé éẋîšţîñĝ ~~~~]\"],\"editor.panels.roomConstructionRows.wallCount\":[\"[\",[\"walls\",\"plural\",{\"one\":[[\"wallCount\"],\" ŵáļļ\"],\"other\":[[\"wallCount\"],\" ŵáļļš\"]}],\" ~~~]\"],\"editor.panels.roomConstructionRows.walls\":[\"[Ŵáļļš ~~]\"],\"editor.panels.roomConstructionRows.wallsThickenInwardSoTheBuilding\":[\"[Ŵáļļš ţĥîçķéñ îñŵáŕð, šö ţĥé ƀûîļðîñĝ'š öûţéŕ šîžé šţáýš ţĥé šáɱé. ~~~~~~~~~~~~~~~~]\"],\"editor.panels.roomOpeningsField.cutOpening\":[\"[Çûţ öþéñîñĝ ~~~]\"],\"editor.panels.roomOpeningsField.done\":[\"[Ðöñé ~~]\"],\"editor.panels.roomOpeningsField.editFloor\":[\"[Éðîţ ƒļööŕ ~~~]\"],\"editor.panels.roomOpeningsField.elevatorOpening\":[\"[Éļéṽáţöŕ öþéñîñĝ ~~~~~]\"],\"editor.panels.roomOpeningsField.noOpeningsYetCutOneFor\":[\"[Ñö öþéñîñĝš ýéţ. Çûţ öñé ƒöŕ á šţáîŕ ṽöîð öŕ á ĥáţçĥ. ~~~~~~~~~~~~]\"],\"editor.panels.roomOpeningsField.openingNumber\":[\"[Öþéñîñĝ \",[\"number\"],\" ~~~]\"],\"editor.panels.roomOpeningsField.openings\":[\"[\",[\"count\",\"plural\",{\"0\":[\"Ñö öþéñîñĝš\"],\"one\":[[\"number\"],\" öþéñîñĝ\"],\"other\":[[\"number\"],\" öþéñîñĝš\"]}],\" ~~~~~~~~]\"],\"editor.panels.roomOpeningsField.stairOpening\":[\"[Šţáîŕ öþéñîñĝ ~~~~]\"],\"editor.panels.roomPanel.addStairs\":[\"[Åðð šţáîŕš ~~~]\"],\"editor.panels.roomPanel.addToAUnit\":[\"[Åðð ţö á ûñîţ ~~~]\"],\"editor.panels.roomPanel.area\":[\"[Åŕéá ~~]\"],\"editor.panels.roomPanel.browse\":[\"[Ɓŕöŵšé ~~]\"],\"editor.panels.roomPanel.builtWith\":[\"[Ɓûîļţ ŵîţĥ ~~~]\"],\"editor.panels.roomPanel.ceiling\":[\"[Çéîļîñĝ ~~~]\"],\"editor.panels.roomPanel.deleteRoom\":[\"[Ðéļéţé ŕööɱ ~~~]\"],\"editor.panels.roomPanel.editShape\":[\"[Éðîţ šĥáþé ~~~]\"],\"editor.panels.roomPanel.floor\":[\"[Ƒļööŕ ~~]\"],\"editor.panels.roomPanel.headroom\":[\"[\",[\"height\"],\" ĥéáðŕööɱ ~~~]\"],\"editor.panels.roomPanel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"editor.panels.roomPanel.hideCode\":[\"[Ĥîðé çöðé ~~~]\"],\"editor.panels.roomPanel.kickerLevel\":[\"[Ŕööɱ · \",[\"level\"],\" ~~]\"],\"editor.panels.roomPanel.kickerMezzanineIn\":[\"[Ṁéžžáñîñé · îñ \",[\"room\"],\" ~~~~]\"],\"editor.panels.roomPanel.kickerNotEnclosed\":[\"[Ŕööɱ · ñöţ éñçļöšéð ~~~~~]\"],\"editor.panels.roomPanel.loading\":[\"[Ļöáðîñĝ… ~~~]\"],\"editor.panels.roomPanel.mezzanine\":[\"[Ṁéžžáñîñé ~~~]\"],\"editor.panels.roomPanel.mezzanineName\":[\"[Ṁéžžáñîñé ñáɱé ~~~~]\"],\"editor.panels.roomPanel.mezzanineNames\":[\"[Ṁéžžáñîñé ñáɱéš ~~~~~]\"],\"editor.panels.roomPanel.newUnit\":[\"[Ñéŵ ûñîţ ~~~]\"],\"editor.panels.roomPanel.none\":[\"[Ñöñé ~~]\"],\"editor.panels.roomPanel.notEnoughHeadroom\":[\"[Ñöţ éñöûĝĥ ĥéáðŕööɱ ~~~~~~]\"],\"editor.panels.roomPanel.openRoomArea\":[\"[\",[\"area\"],\" · Çļöšé îţš ŵáļļš ţö ƀûîļð îţš ƒļööŕ áñð çéîļîñĝ. ~~~~~~~~~~~~]\"],\"editor.panels.roomPanel.openingCounts\":[\"[\",[\"doors\",\"plural\",{\"one\":[[\"doorCount\"],\" ðööŕ\"],\"other\":[[\"doorCount\"],\" ðööŕš\"]}],\" · \",[\"windows\",\"plural\",{\"one\":[[\"windowCount\"],\" ŵîñðöŵ\"],\"other\":[[\"windowCount\"],\" ŵîñðöŵš\"]}],\" ~~~~~~~]\"],\"editor.panels.roomPanel.overTheMezzanine\":[\"[Öṽéŕ ţĥé ɱéžžáñîñé ~~~~~]\"],\"editor.panels.roomPanel.perimeter\":[\"[Þéŕîɱéţéŕ ~~~]\"],\"editor.panels.roomPanel.pick\":[\"[Þîçķ ~~]\"],\"editor.panels.roomPanel.pickingItAddsANumber\":[\"[Þîçķîñĝ îţ áððš á ñûɱƀéŕ ~~~~~~]\"],\"editor.panels.roomPanel.remove\":[\"[Ŕéɱöṽé ~~]\"],\"editor.panels.roomPanel.removeFromUnit\":[\"[Ŕéɱöṽé ƒŕöɱ ûñîţ ~~~~~]\"],\"editor.panels.roomPanel.removeFromUnitNamed\":[\"[Ŕéɱöṽé ƒŕöɱ \",[\"unit\"],\" ~~~]\"],\"editor.panels.roomPanel.rename\":[\"[Ŕéñáɱé ~~]\"],\"editor.panels.roomPanel.renameNamed\":[\"[\",[\"name\"],\" · Ŕéñáɱé ~~]\"],\"editor.panels.roomPanel.revert\":[\"[Ŕéṽéŕţ ~~]\"],\"editor.panels.roomPanel.room\":[\"[Ŕööɱ ~~]\"],\"editor.panels.roomPanel.roomColourUsedInThePlan\":[\"[Ŕööɱ çöļöûŕ — ûšéð îñ ţĥé þļáñ áñð ļáƀéļš ~~~~~~~~~~]\"],\"editor.panels.roomPanel.roomName\":[\"[Ŕööɱ ñáɱé ~~~]\"],\"editor.panels.roomPanel.roomNames\":[\"[Ŕööɱ ñáɱéš ~~~]\"],\"editor.panels.roomPanel.scriptedFinish\":[\"[Šçŕîþţéð ƒîñîšĥ ~~~~~]\"],\"editor.panels.roomPanel.shape\":[\"[Šĥáþé ~~]\"],\"editor.panels.roomPanel.showMezzanineNames\":[\"[Šĥöŵ ɱéžžáñîñé ñáɱéš ~~~~~~]\"],\"editor.panels.roomPanel.showRoomNames\":[\"[Šĥöŵ ŕööɱ ñáɱéš ~~~~]\"],\"editor.panels.roomPanel.stairs\":[\"[Šţáîŕš ~~]\"],\"editor.panels.roomPanel.unit\":[\"[Ûñîţ ~~]\"],\"editor.panels.roomPanel.use\":[\"[Ûšé ~]\"],\"editor.panels.roomPanel.useTyped\":[[\"use\"],\" “\",[\"name\"],\"”\"],\"editor.panels.roomPanel.usedOnThisLevel\":[\"[\",[\"used\"],\" öñ ţĥîš ļéṽéļ ~~~~]\"],\"editor.panels.roomPanel.viewCode\":[\"[Ṽîéŵ çöðé ~~~]\"],\"editor.panels.scriptUnreadable\":[\"[Ţĥé šçŕîþţ çöûļð ñöţ ƀé ŕéáð. ~~~~~~~]\"],\"editor.panels.shapeChoice.polygon\":[\"[Þöļýĝöñ ~~~]\"],\"editor.panels.shapeChoice.rectangle\":[\"[Ŕéçţáñĝļé ~~~]\"],\"editor.panels.wallRegionList.deleteRegion\":[\"[Ðéļéţé ŕéĝîöñ ~~~~]\"],\"editor.panels.wallRegionList.paintRegions\":[\"[Þáîñţ ŕéĝîöñš ~~~~]\"],\"editor.proceduralItems.inspector.adjustDesign\":[\"[Åðĵûšţ ðéšîĝñ ~~~~]\"],\"editor.proceduralItems.inspector.back\":[\"[Ɓáçķ ~~]\"],\"editor.proceduralItems.inspector.editParts\":[\"[Éðîţ þáŕţš ~~~]\"],\"editor.proceduralItems.inspector.invalidAttachment\":[\"[Îñṽáļîð áţţáçĥɱéñţ ~~~~~~]\"],\"editor.proceduralItems.inspector.invalidEdit\":[\"[Îñṽáļîð éðîţ ~~~~]\"],\"editor.proceduralItems.inspector.invalidPlacement\":[\"[Îñṽáļîð þļáçéɱéñţ ~~~~~]\"],\"editor.proceduralItems.inspector.invalidPosition\":[\"[Îñṽáļîð þöšîţîöñ ~~~~~]\"],\"editor.proceduralItems.inspector.invalidReset\":[\"[Îñṽáļîð ŕéšéţ ~~~~]\"],\"editor.proceduralItems.inspector.pos\":[\"[þöš ~]\"],\"editor.proceduralItems.inspector.position\":[\"[Þöšîţîöñ ~~~]\"],\"editor.proceduralItems.inspector.resetThisPart\":[\"[Ŕéšéţ ţĥîš þáŕţ ~~~~]\"],\"editor.reloadEditor\":[\"[Ŕéļöáð éðîţöŕ ~~~~]\"],\"editor.riserDiagramPanel.close\":[\"[Çļöšé ŕîšéŕ ðîáĝŕáɱ ~~~~~~]\"],\"editor.riserDiagramPanel.dwvPlumbingIsometric\":[\"[ÐŴṼ þļûɱƀîñĝ îšöɱéţŕîç ~~~~~~]\"],\"editor.riserDiagramPanel.dwvRiserDiagram\":[\"[ÐŴṼ ŕîšéŕ ðîáĝŕáɱ ~~~~~]\"],\"editor.riserDiagramPanel.noDrainWasteOrVentPipes\":[\"[Ñö ðŕáîñ, ŵášţé, öŕ ṽéñţ þîþéš ýéţ. Ðŕáŵ þļûɱƀîñĝ ţö šéé ţĥé ŕîšéŕ ðîáĝŕáɱ. ~~~~~~~~~~~~~~~~~~]\"],\"editor.riserDiagramPanel.riserDiagram\":[\"[Ŕîšéŕ Ðîáĝŕáɱ ~~~~]\"],\"editor.riserDiagramPanel.trap\":[\"[\",[\"diameter\"],\"\\\" Þ-ţŕáþ ~~]\"],\"editor.riserDiagramPanel.vent\":[\"[Ṽéñţ ~~]\"],\"editor.riserDiagramPanel.ventTermination\":[\"[\",[\"diameter\"],\"\\\" ṼŢŔ ~]\"],\"editor.riserDiagramPanel.waste\":[\"[Ŵášţé ~~]\"],\"editor.room.builtOn.above\":[\"[\",[\"current\"],\" · \",[\"distance\"],\" áƀöṽé \",[\"shared\"],\" ~~]\"],\"editor.room.builtOn.below\":[\"[\",[\"current\"],\" · \",[\"distance\"],\" ƀéļöŵ \",[\"shared\"],\" ~~]\"],\"editor.room.builtOn.levelWith\":[\"[\",[\"current\"],\" · ļéṽéļ ŵîţĥ \",[\"shared\"],\" ~~~]\"],\"editor.roomHandles.cannotReadInput\":[\"[Çáññöţ ŕéáð \\\"\",[\"input\"],\"\\\" ~~~]\"],\"editor.roomHandles.dimensionValue\":[\"[Ðîɱéñšîöñ ṽáļûé ~~~~~]\"],\"editor.roomHandles.floor\":[\"[Ƒļööŕ ~~]\"],\"editor.roomHandles.typeASizeToMoveThe\":[\"[Ţýþé á šîžé ţö ɱöṽé ţĥé ŵáļļ ~~~~~~~]\"],\"editor.roomLabel.room\":[\"[Ŕööɱ ~~]\"],\"editor.roomLabel.zone\":[\"[Žöñé ~~]\"],\"editor.roomName.attic\":[\"[Åţţîç ~~]\"],\"editor.roomName.balcony\":[\"[Ɓáļçöñý ~~~]\"],\"editor.roomName.basement\":[\"[Ɓášéɱéñţ ~~~]\"],\"editor.roomName.bathroom\":[\"[Ɓáţĥŕööɱ ~~~]\"],\"editor.roomName.bedroom\":[\"[Ɓéðŕööɱ ~~~]\"],\"editor.roomName.boilerRoom\":[\"[Ɓöîļéŕ ŕööɱ ~~~]\"],\"editor.roomName.carport\":[\"[Çáŕþöŕţ ~~~]\"],\"editor.roomName.cellar\":[\"[Çéļļáŕ ~~]\"],\"editor.roomName.closet\":[\"[Çļöšéţ ~~]\"],\"editor.roomName.corridor\":[\"[Çöŕŕîðöŕ ~~~]\"],\"editor.roomName.courtyard\":[\"[Çöûŕţýáŕð ~~~]\"],\"editor.roomName.deck\":[\"[Ðéçķ ~~]\"],\"editor.roomName.den\":[\"[Ðéñ ~]\"],\"editor.roomName.diningRoom\":[\"[Ðîñîñĝ ŕööɱ ~~~]\"],\"editor.roomName.dressingRoom\":[\"[Ðŕéššîñĝ ŕööɱ ~~~~]\"],\"editor.roomName.enSuite\":[\"[Éñ-šûîţé ~~~]\"],\"editor.roomName.entrance\":[\"[Éñţŕáñçé ~~~]\"],\"editor.roomName.familyRoom\":[\"[Ƒáɱîļý ŕööɱ ~~~]\"],\"editor.roomName.gallery\":[\"[Ĝáļļéŕý ~~~]\"],\"editor.roomName.gamesRoom\":[\"[Ĝáɱéš ŕööɱ ~~~]\"],\"editor.roomName.garage\":[\"[Ĝáŕáĝé ~~]\"],\"editor.roomName.garden\":[\"[Ĝáŕðéñ ~~]\"],\"editor.roomName.gardenShed\":[\"[Ĝáŕðéñ šĥéð ~~~]\"],\"editor.roomName.guestRoom\":[\"[Ĝûéšţ ŕööɱ ~~~]\"],\"editor.roomName.gym\":[\"[Ĝýɱ ~]\"],\"editor.roomName.hallway\":[\"[Ĥáļļŵáý ~~~]\"],\"editor.roomName.homeCinema\":[\"[Ĥöɱé çîñéɱá ~~~]\"],\"editor.roomName.kidsRoom\":[\"[Ķîðš' ŕööɱ ~~~]\"],\"editor.roomName.kitchen\":[\"[Ķîţçĥéñ ~~~]\"],\"editor.roomName.kitchenette\":[\"[Ķîţçĥéñéţţé ~~~~]\"],\"editor.roomName.landing\":[\"[Ļáñðîñĝ ~~~]\"],\"editor.roomName.laundry\":[\"[Ļáûñðŕý ~~~]\"],\"editor.roomName.library\":[\"[Ļîƀŕáŕý ~~~]\"],\"editor.roomName.livingRoom\":[\"[Ļîṽîñĝ ŕööɱ ~~~]\"],\"editor.roomName.loft\":[\"[Ļöƒţ ~~]\"],\"editor.roomName.lounge\":[\"[Ļöûñĝé ~~]\"],\"editor.roomName.mezzanine\":[\"[Ṁéžžáñîñé ~~~]\"],\"editor.roomName.mudroom\":[\"[Ṁûðŕööɱ ~~~]\"],\"editor.roomName.nursery\":[\"[Ñûŕšéŕý ~~~]\"],\"editor.roomName.office\":[\"[Öƒƒîçé ~~]\"],\"editor.roomName.pantry\":[\"[Þáñţŕý ~~]\"],\"editor.roomName.patio\":[\"[Þáţîö ~~]\"],\"editor.roomName.playroom\":[\"[Þļáýŕööɱ ~~~]\"],\"editor.roomName.poolArea\":[\"[Þööļ áŕéá ~~~]\"],\"editor.roomName.porch\":[\"[Þöŕçĥ ~~]\"],\"editor.roomName.powderRoom\":[\"[Þöŵðéŕ ŕööɱ ~~~]\"],\"editor.roomName.primaryBedroom\":[\"[Þŕîɱáŕý ƀéðŕööɱ ~~~~~]\"],\"editor.roomName.readingNook\":[\"[Ŕéáðîñĝ ñööķ ~~~~]\"],\"editor.roomName.section.bathrooms\":[\"[Ɓáţĥŕööɱš ~~~]\"],\"editor.roomName.section.circulation\":[\"[Çîŕçûļáţîöñ ~~~~]\"],\"editor.roomName.section.living\":[\"[Ļîṽîñĝ ~~]\"],\"editor.roomName.section.mezzanine\":[\"[Ṁéžžáñîñé ~~~]\"],\"editor.roomName.section.outdoor\":[\"[Öûţðööŕ ~~~]\"],\"editor.roomName.section.sleeping\":[\"[Šļééþîñĝ ~~~]\"],\"editor.roomName.section.utility\":[\"[Ûţîļîţý & šţöŕáĝé ~~~~~]\"],\"editor.roomName.section.work\":[\"[Ŵöŕķ & ĥöƀƀîéš ~~~~]\"],\"editor.roomName.showerRoom\":[\"[Šĥöŵéŕ ŕööɱ ~~~]\"],\"editor.roomName.stairwell\":[\"[Šţáîŕŵéļļ ~~~]\"],\"editor.roomName.storage\":[\"[Šţöŕáĝé ~~~]\"],\"editor.roomName.studio\":[\"[Šţûðîö ~~]\"],\"editor.roomName.study\":[\"[Šţûðý ~~]\"],\"editor.roomName.sunroom\":[\"[Šûñŕööɱ ~~~]\"],\"editor.roomName.terrace\":[\"[Ţéŕŕáçé ~~~]\"],\"editor.roomName.toilet\":[\"[Ţöîļéţ ~~]\"],\"editor.roomName.utilityRoom\":[\"[Ûţîļîţý ŕööɱ ~~~~]\"],\"editor.roomName.veranda\":[\"[Ṽéŕáñðá ~~~]\"],\"editor.roomName.walkInCloset\":[\"[Ŵáļķ-îñ çļöšéţ ~~~~]\"],\"editor.roomName.workshop\":[\"[Ŵöŕķšĥöþ ~~~]\"],\"editor.sidebar.iconRail.settings\":[\"[Šéţţîñĝš ~~~]\"],\"editor.sidebar.iconRail.site\":[\"[Šîţé ~~]\"],\"editor.sidebar.panels.itemsPanel.all\":[\"[Åļļ ~]\"],\"editor.sidebar.panels.itemsPanel.community\":[\"[Çöɱɱûñîţý ~~~]\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.all\":[\"[Åļļ ~]\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.community\":[\"[Çöɱɱûñîţý ~~~]\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.library\":[\"[Ļîƀŕáŕý ~~~]\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.mine\":[\"[Ṁîñé ~~]\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.noResultsForSearch\":[\"[Ñö ŕéšûļţš ƒöŕ “\",[\"search\"],\"” ~~~~]\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.search\":[\"[Šéáŕçĥ... ~~]\"],\"editor.sidebar.panels.itemsPanel.library\":[\"[Ļîƀŕáŕý ~~~]\"],\"editor.sidebar.panels.itemsPanel.mine\":[\"[Ṁîñé ~~]\"],\"editor.sidebar.panels.itemsPanel.noResultsForSearch\":[\"[Ñö ŕéšûļţš ƒöŕ “\",[\"search\"],\"” ~~~~]\"],\"editor.sidebar.panels.itemsPanel.search\":[\"[Šéáŕçĥ... ~~]\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.buildTools\":[\"[Ɓûîļð Ţööļš ~~~]\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.camera\":[\"[Çáɱéŕá ~~]\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.directManipulation\":[\"[Ðîŕéçţ Ṁáñîþûļáţîöñ ~~~~~~]\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.drawingTools\":[\"[Ðŕáŵîñĝ Ţööļš ~~~~]\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.editorNavigation\":[\"[Éðîţöŕ Ñáṽîĝáţîöñ ~~~~~]\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.itemPlacement\":[\"[Îţéɱ Þļáçéɱéñţ ~~~~]\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.keyboardShortcuts\":[\"[Ķéýƀöáŕð šĥöŕţçûţš ~~~~~~]\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.modesHistory\":[\"[Ṁöðéš & Ĥîšţöŕý ~~~~]\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.selection\":[\"[Šéļéçţîöñ ~~~]\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.shortcutsAreContextAwareGuidedConstraints\":[\"[Šĥöŕţçûţš áŕé çöñţéẋţ-áŵáŕé. Šñáþþîñĝ îš á ṽîšîƀļé ɱöðé: ţáþ Šĥîƒţ ţö çýçļé îţ, ĥöļð Åļţ ðûŕîñĝ á ĝéšţûŕé ţö þļáçé ƒŕééļý. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.sidebar.panels.sitePanel.addLevel\":[\"[Åðð ļéṽéļ ~~~]\"],\"editor.sidebar.panels.sitePanel.addPoint\":[\"[Åðð þöîñţ ~~~]\"],\"editor.sidebar.panels.sitePanel.area\":[\"[Åŕéá: ~~]\"],\"editor.sidebar.panels.sitePanel.baseElevation\":[\"[Ɓášé éļéṽáţîöñ ~~~~]\"],\"editor.sidebar.panels.sitePanel.building\":[\"[Ɓûîļðîñĝ ~~~]\"],\"editor.sidebar.panels.sitePanel.buildingTreeNode.addNewLevel\":[\"[Åðð ñéŵ ļéṽéļ ~~~~]\"],\"editor.sidebar.panels.sitePanel.buildingTreeNode.building\":[\"[Ɓûîļðîñĝ ~~~]\"],\"editor.sidebar.panels.sitePanel.cameraSnapshot\":[\"[Çáɱéŕá šñáþšĥöţ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.capture\":[\"[Çáþţûŕé ~~~]\"],\"editor.sidebar.panels.sitePanel.clearSelection\":[\"[Çļéáŕ šéļéçţîöñ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.clearSnapshot\":[\"[Çļéáŕ šñáþšĥöţ ~~~~]\"],\"editor.sidebar.panels.sitePanel.closeWallsAroundASpaceTo\":[\"[Çļöšé ŵáļļš áŕöûñð á šþáçé ţö ɱáķé á ŕööɱ. ~~~~~~~~~~]\"],\"editor.sidebar.panels.sitePanel.collectionTreeNode.collectionColour\":[\"[Çöļļéçţîöñ çöļöûŕ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.collectionTreeNode.collections\":[\"[Çöļļéçţîöñš ~~~~]\"],\"editor.sidebar.panels.sitePanel.collectionTreeNode.deleteCollection\":[\"[Ðéļéţé çöļļéçţîöñ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.delete\":[\"[Ðéļéţé ~~]\"],\"editor.sidebar.panels.sitePanel.deleteLevel\":[\"[Ðéļéţé ļéṽéļ ~~~~]\"],\"editor.sidebar.panels.sitePanel.drawAZone\":[\"[Ðŕáŵ á žöñé ~~~]\"],\"editor.sidebar.panels.sitePanel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"editor.sidebar.panels.sitePanel.duplicateLevel\":[\"[Ðûþļîçáţé ļéṽéļ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.duplicateLevelWithOptions\":[\"[Ðûþļîçáţé ļéṽéļ ŵîţĥ öþţîöñš ~~~~~~~~]\"],\"editor.sidebar.panels.sitePanel.duplicateWithOptions\":[\"[Ðûþļîçáţé ŵîţĥ öþţîöñš... ~~~~~~]\"],\"editor.sidebar.panels.sitePanel.elements\":[\"[Éļéɱéñţš ~~~]\"],\"editor.sidebar.panels.sitePanel.guide\":[\"[Ĝûîðé ~~]\"],\"editor.sidebar.panels.sitePanel.hide\":[\"[Ĥîðé ~~]\"],\"editor.sidebar.panels.sitePanel.level\":[\"[Ļéṽéļ ~~]\"],\"editor.sidebar.panels.sitePanel.newUnit\":[\"[Ñéŵ ûñîţ ~~~]\"],\"editor.sidebar.panels.sitePanel.noBuildingsYet\":[\"[Ñö ƀûîļðîñĝš ýéţ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.noElementsOnThisLevel\":[\"[Ñö éļéɱéñţš öñ ţĥîš ļéṽéļ ~~~~~~~]\"],\"editor.sidebar.panels.sitePanel.noLevelsYet\":[\"[Ñö ļéṽéļš ýéţ ~~~~]\"],\"editor.sidebar.panels.sitePanel.objectsSelected\":[\"[\",[\"count\",\"plural\",{\"one\":[\"#\",\" öƀĵéçţ šéļéçţéð\"],\"other\":[\"#\",\" öƀĵéçţš šéļéçţéð\"]}],\" ~~~~~~~~~]\"],\"editor.sidebar.panels.sitePanel.otherZones\":[\"[Öţĥéŕ žöñéš ~~~]\"],\"editor.sidebar.panels.sitePanel.perimeter\":[\"[Þéŕîɱéţéŕ: ~~~]\"],\"editor.sidebar.panels.sitePanel.propertyLine\":[\"[Þŕöþéŕţý Ļîñé ~~~~]\"],\"editor.sidebar.panels.sitePanel.rooms\":[\"[Ŕööɱš ~~]\"],\"editor.sidebar.panels.sitePanel.selectALevelToViewContent\":[\"[Šéļéçţ á ļéṽéļ ţö ṽîéŵ çöñţéñţ ~~~~~~~~]\"],\"editor.sidebar.panels.sitePanel.show\":[\"[Šĥöŵ ~~]\"],\"editor.sidebar.panels.sitePanel.site\":[\"[Šîţé ~~]\"],\"editor.sidebar.panels.sitePanel.takeSnapshot\":[\"[Ţáķé šñáþšĥöţ ~~~~]\"],\"editor.sidebar.panels.sitePanel.theGroundLevelCannotBeDeleted\":[\"[Ţĥé ĝŕöûñð ļéṽéļ çáññöţ ƀé ðéļéţéð ~~~~~~~~~]\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.cameraSnapshot\":[\"[Çáɱéŕá šñáþšĥöţ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.clearSnapshot\":[\"[Çļéáŕ šñáþšĥöţ ~~~~]\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.hide\":[\"[Ĥîðé ~~]\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.show\":[\"[Šĥöŵ ~~]\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.takeSnapshot\":[\"[Ţáķé šñáþšĥöţ ~~~~]\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.updateSnapshot\":[\"[Ûþðáţé šñáþšĥöţ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.viewSnapshot\":[\"[Ṽîéŵ šñáþšĥöţ ~~~~]\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.deleteUnit\":[\"[Ðéļéţé ûñîţ ~~~]\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.focused\":[\"[Ƒöçûšéð ~~~]\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.removeFromUnit\":[\"[Ŕéɱöṽé ƒŕöɱ ûñîţ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.room\":[\"[Ŕööɱ ~~]\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.zone\":[\"[Žöñé ~~]\"],\"editor.sidebar.panels.sitePanel.units\":[\"[Ûñîţš ~~]\"],\"editor.sidebar.panels.sitePanel.updateSnapshot\":[\"[Ûþðáţé šñáþšĥöţ ~~~~~]\"],\"editor.sidebar.panels.sitePanel.uploadScanFloorplan\":[\"[Ûþļöáð šçáñ/ƒļööŕþļáñ ~~~~~~]\"],\"editor.sidebar.panels.sitePanel.uploadingProgress\":[\"[\",[\"assetType\",\"select\",{\"guide\":[\"Ûþļöáðîñĝ ĝûîðé... \",[\"progress\"],\"%\"],\"other\":[\"Ûþļöáðîñĝ šçáñ... \",[\"progress\"],\"%\"]}],\" ~~~~~~~~~]\"],\"editor.sidebar.panels.sitePanel.viewSnapshot\":[\"[Ṽîéŵ šñáþšĥöţ ~~~~]\"],\"editor.sidebar.panels.sitePanel.zoneMembershipCheckbox.inUnitname\":[\"[Îñ \",[\"unitName\"],\" ~]\"],\"editor.sidebar.panels.zonePanel.actions\":[\"[Åçţîöñš ~~~]\"],\"editor.sidebar.panels.zonePanel.addOne\":[\"[Åðð öñé ~~]\"],\"editor.sidebar.panels.zonePanel.cameraSnapshot\":[\"[Çáɱéŕá šñáþšĥöţ ~~~~~]\"],\"editor.sidebar.panels.zonePanel.clearSnapshot\":[\"[Çļéáŕ šñáþšĥöţ ~~~~]\"],\"editor.sidebar.panels.zonePanel.delete\":[\"[Ðéļéţé ~~]\"],\"editor.sidebar.panels.zonePanel.deleteWithContents\":[\"[Ðéļéţé ŵîţĥ çöñţéñţš ~~~~~~]\"],\"editor.sidebar.panels.zonePanel.noZonesOnThisLevel\":[\"[Ñö žöñéš öñ ţĥîš ļéṽéļ. ~~~~~~]\"],\"editor.sidebar.panels.zonePanel.saveToCatalog\":[\"[Šáṽé ţö çáţáļöĝ ~~~~]\"],\"editor.sidebar.panels.zonePanel.selectALevelToViewAnd\":[\"[Šéļéçţ á ļéṽéļ ţö ṽîéŵ áñð çŕéáţé žöñéš ~~~~~~~~~~]\"],\"editor.sidebar.panels.zonePanel.takeSnapshot\":[\"[Ţáķé šñáþšĥöţ ~~~~]\"],\"editor.sidebar.panels.zonePanel.updateSnapshot\":[\"[Ûþðáţé šñáþšĥöţ ~~~~~]\"],\"editor.sidebar.panels.zonePanel.viewSnapshot\":[\"[Ṽîéŵ šñáþšĥöţ ~~~~]\"],\"editor.sidebar.usePluginPanels.labelPluginCrashed\":[\"[\\\"\",[\"label\"],\"\\\" þļûĝîñ çŕášĥéð ~~~~]\"],\"editor.sidebar.usePluginPanels.loading\":[\"[Ļöáðîñĝ… ~~~]\"],\"editor.sidebar.usePluginPanels.plugins\":[\"[Þļûĝîñš ~~~]\"],\"editor.sidebar.usePluginPanels.thisPanelHitAnErrorAnd\":[\"[Ţĥîš þáñéļ ĥîţ áñ éŕŕöŕ áñð ŵáš ûñļöáðéð ƒöŕ ţĥîš šéššîöñ. Ţĥé ŕéšţ öƒ ţĥé éðîţöŕ îš ûñჃéçţéð — ŕéļöáð ţö ţŕý áĝáîñ. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.snapTarget.ceiling\":[\"[Çéîļîñĝ áţţáçĥɱéñţ ~~~~~~]\"],\"editor.snapTarget.roof\":[\"[Ŕööƒ áţţáçĥɱéñţ ~~~~~]\"],\"editor.snapTarget.wall\":[\"[Ŵáļļ áţţáçĥɱéñţ ~~~~~]\"],\"editor.theEditorSceneFailedToRender\":[\"[Ţĥé éðîţöŕ šçéñé ƒáîļéð ţö ŕéñðéŕ ~~~~~~~~~]\"],\"editor.toolHint.aCurtainWallTakesNoCorner.1qxjv5i\":[\"[Å çûŕţáîñ ŵáļļ ţáķéš ñö çöŕñéŕ ŵîñðöŵ ~~~~~~~~~~]\"],\"editor.toolHint.aCurvedWallTakesNoCorner.1vdnaw5\":[\"[Å çûŕṽéð ŵáļļ ţáķéš ñö çöŕñéŕ ŵîñðöŵ ~~~~~~~~~]\"],\"editor.toolHint.addACornerClickTheFirst.o4r67t\":[\"[Åðð á çöŕñéŕ · çļîçķ ţĥé ƒîŕšţ ţö çļöšé ~~~~~~~~~]\"],\"editor.toolHint.anotherOpeningIsInTheWay.11l9dd0\":[\"[Åñöţĥéŕ öþéñîñĝ îš îñ ţĥé ŵáý áţ ţĥé çöŕñéŕ ~~~~~~~~~~~]\"],\"editor.toolHint.autoHangers.10554ka\":[\"[Åûţö ĥáñĝéŕš ~~~~]\"],\"editor.toolHint.autoHangersClickOrPressH.rwa3ka\":[\"[Åûţö ĥáñĝéŕš - çļîçķ öŕ þŕéšš Ĥ ţö ţöĝĝļé ~~~~~~~~~~]\"],\"editor.toolHint.autoHangersOff.7yx01x\":[\"[Åûţö ĥáñĝéŕš: Öƒƒ ~~~~~]\"],\"editor.toolHint.autoHangersOn.10b1umh\":[\"[Åûţö ĥáñĝéŕš: Öñ ~~~~]\"],\"editor.toolHint.bypassSnapping.w5lmdv\":[\"[Ɓýþášš šñáþþîñĝ ~~~~~]\"],\"editor.toolHint.cancel.ew9em3\":[\"[Çáñçéļ ~~]\"],\"editor.toolHint.cancelMove.lvp31c\":[\"[Çáñçéļ ɱöṽé ~~~]\"],\"editor.toolHint.cancelRunExit.zqjf3h\":[\"[Çáñçéļ ŕûñ / éẋîţ ~~~~]\"],\"editor.toolHint.cancelStartPoint.1xbq2lh\":[\"[Çáñçéļ šţáŕţ þöîñţ ~~~~~]\"],\"editor.toolHint.cornerWindow.1avkzpo\":[\"[Çöŕñéŕ ŵîñðöŵ ~~~~]\"],\"editor.toolHint.cuts.1y0axps\":[\"[Çûţš ~~]\"],\"editor.toolHint.cutsValue.ouzhvb\":[\"[Çûţš: \",[\"value\"],\" ~~]\"],\"editor.toolHint.cutsValueEven.1ngsz3\":[\"[Çûţš: \",[\"value\"],\", éṽéñ ~~~]\"],\"editor.toolHint.cycleMonoGableButterfly.1poga3m\":[\"[Çýçļé ɱöñö / ĝáƀļé / ƀûţţéŕƒļý ~~~~~~~]\"],\"editor.toolHint.cycleSnappingMode.1ct0gn6\":[\"[Çýçļé šñáþþîñĝ ɱöðé ~~~~~~]\"],\"editor.toolHint.doorStyleClickOrPressL.33pe65\":[\"[Ðööŕ šţýļé — çļîçķ öŕ þŕéšš Ļ ţö çýçļé ~~~~~~~~~]\"],\"editor.toolHint.doorTypeClickOrPressO.1hhh8gt\":[\"[Ðööŕ ţýþé — çļîçķ öŕ þŕéšš Ö ţö çýçļé ~~~~~~~~~]\"],\"editor.toolHint.dropDownspoutFromOutlet.1k4h1m4\":[\"[Ðŕöþ ðöŵñšþöûţ ƒŕöɱ öûţļéţ ~~~~~~~]\"],\"editor.toolHint.ductDiameterDownUp.1wdz5vq\":[\"[Ðûçţ ðîáɱéţéŕ ðöŵñ / ûþ ~~~~~~]\"],\"editor.toolHint.endRunCancel.59dh2w\":[\"[Éñð ŕûñ / çáñçéļ ~~~~]\"],\"editor.toolHint.endTheRun.1c1raig\":[\"[Éñð ţĥé ŕûñ ~~~]\"],\"editor.toolHint.exit.engmg5\":[\"[Éẋîţ ~~]\"],\"editor.toolHint.exitDrawing.9noxyb\":[\"[Éẋîţ ðŕáŵîñĝ ~~~~]\"],\"editor.toolHint.finishAndContinue.1gpfsks\":[\"[Ƒîñîšĥ áñð çöñţîñûé ~~~~~~]\"],\"editor.toolHint.finishCeiling.1c1lfel\":[\"[Ƒîñîšĥ çéîļîñĝ ~~~~]\"],\"editor.toolHint.finishGridAxis.1wvrfhr\":[\"[Ƒîñîšĥ ĝŕîð áẋîš ~~~~~]\"],\"editor.toolHint.finishMeasurement.1e4gv16\":[\"[Ƒîñîšĥ ɱéášûŕéɱéñţ ~~~~~~]\"],\"editor.toolHint.finishMultiPointWitnesses.8wzskz\":[\"[Ƒîñîšĥ ɱûļţî-þöîñţ ŵîţñéššéš ~~~~~~~~]\"],\"editor.toolHint.finishSlab.xmnm8e\":[\"[Ƒîñîšĥ šļáƀ ~~~]\"],\"editor.toolHint.flipSide.172xku9\":[\"[Ƒļîþ šîðé ~~~]\"],\"editor.toolHint.followTraceALineset.mgquwe\":[\"[Ƒöļļöŵ: ţŕáçé á ļîñéšéţ ~~~~~~]\"],\"editor.toolHint.forcePlace.1hq1nr\":[\"[Ƒöŕçé þļáçé ~~~]\"],\"editor.toolHint.freeAngle.1ptblho\":[\"[Ƒŕéé áñĝļé ~~~]\"],\"editor.toolHint.freePlace.1s1uusw\":[\"[Ƒŕéé þļáçé ~~~]\"],\"editor.toolHint.freePlacement.1nztdac\":[\"[Ƒŕéé þļáçéɱéñţ ~~~~]\"],\"editor.toolHint.goVerticalClickToPlace.dg8g6m\":[\"[Ĝö ṽéŕţîçáļ ↕, çļîçķ ţö þļáçé ~~~~~~~]\"],\"editor.toolHint.highlightOutlet.65hoq8\":[\"[Ĥîĝĥļîĝĥţ öûţļéţ ~~~~~]\"],\"editor.toolHint.joinAsACornerWindow.jvdp4j\":[\"[Ĵöîñ áš á çöŕñéŕ ŵîñðöŵ ~~~~~~]\"],\"editor.toolHint.key.altDrag.ai3wn9\":[\"[Åļţ + ðŕáĝ ~~~]\"],\"editor.toolHint.key.backspace.qy6qx8\":[\"[Ɓáçķšþáçé ~~~]\"],\"editor.toolHint.key.click.m8sun\":[\"[Çļîçķ ~~]\"],\"editor.toolHint.key.clickAgain.190ws9j\":[\"[Çļîçķ áĝáîñ ~~~]\"],\"editor.toolHint.key.command.1j2mkia\":[\"[Çöɱɱáñð ~~~]\"],\"editor.toolHint.key.control.10fbl8e\":[\"[Çöñţŕöļ ~~~]\"],\"editor.toolHint.key.delete.oay2cq\":[\"[Ðéļéţé ~~]\"],\"editor.toolHint.key.doubleClick.vlma6o\":[\"[Ðöûƀļé çļîçķ ~~~~]\"],\"editor.toolHint.key.drag.8pwtpf\":[\"[Ðŕáĝ ~~]\"],\"editor.toolHint.key.enter.1ctpui5\":[\"[Éñţéŕ ~~]\"],\"editor.toolHint.key.hover.6xw79p\":[\"[Ĥöṽéŕ ~~]\"],\"editor.toolHint.key.hoverADuctEnd.19axr3b\":[\"[Ĥöṽéŕ á ðûçţ éñð ~~~~]\"],\"editor.toolHint.key.hoverAPipeEnd.1jbum5f\":[\"[Ĥöṽéŕ á þîþé éñð ~~~~]\"],\"editor.toolHint.key.hoverGutter.1dwcsno\":[\"[Ĥöṽéŕ ĝûţţéŕ ~~~~]\"],\"editor.toolHint.key.leftClick.s4gwfc\":[\"[Ļéƒţ çļîçķ ~~~]\"],\"editor.toolHint.key.middleClick.1jbaan4\":[\"[Ṁîððļé çļîçķ ~~~~]\"],\"editor.toolHint.key.rShiftR.13bnobh\":[\"[Ŕ / Šĥîƒţ+Ŕ ~~~]\"],\"editor.toolHint.key.rightClick.1ovld0h\":[\"[Ŕîĝĥţ çļîçķ ~~~]\"],\"editor.toolHint.key.room.1f3jkpm\":[\"[Ŕööɱ ~~]\"],\"editor.toolHint.key.scroll.ai6wr0\":[\"[Šçŕöļļ ~~]\"],\"editor.toolHint.key.scrollWheel.18j0ix7\":[\"[Šçŕöļļ ŵĥééļ ~~~~]\"],\"editor.toolHint.key.space.1hrh82t\":[\"[Šþáçé ~~]\"],\"editor.toolHint.key.tab.1xsal0s\":[\"[Ţáƀ ~]\"],\"editor.toolHint.mountFloorCeilingWall.32dxpv\":[\"[Ṁöûñţ: ƒļööŕ / çéîļîñĝ / ŵáļļ ~~~~~~~]\"],\"editor.toolHint.noRoomForTheMatchingWindow.1755948\":[\"[Ñö ŕööɱ ƒöŕ ţĥé ɱáţçĥîñĝ ŵîñðöŵ öñ ţĥé öţĥéŕ ŵáļļ ~~~~~~~~~~~~]\"],\"editor.toolHint.noWallMeetsHere.19n99yc\":[\"[Ñö ŵáļļ ɱééţš ĥéŕé ~~~~~]\"],\"editor.toolHint.notARectangleDrawThisRoof.100pa5g\":[\"[Ñöţ á ŕéçţáñĝļé: ðŕáŵ ţĥîš ŕööƒ îñšţéáð ~~~~~~~~~~]\"],\"editor.toolHint.numberOfCutsScrollOrClick.1kqe84b\":[\"[Ñûɱƀéŕ öƒ çûţš — šçŕöļļ öŕ çļîçķ ţö çĥáñĝé ~~~~~~~~~~]\"],\"editor.toolHint.pickWitnessPoint.k3hgh1\":[\"[Þîçķ ŵîţñéšš þöîñţ ~~~~~]\"],\"editor.toolHint.pipeSizeDownUp.wp04og\":[\"[Þîþé šîžé ðöŵñ / ûþ ~~~~~]\"],\"editor.toolHint.placeAndContinue.qfwkrq\":[\"[Þļáçé áñð çöñţîñûé ~~~~~]\"],\"editor.toolHint.placeBlock.1aylwrx\":[\"[Þļáçé ƀļöçķ ~~~]\"],\"editor.toolHint.placeBoxVentOnRoof.kf88e5\":[\"[Þļáçé ƀöẋ ṽéñţ öñ ŕööƒ ~~~~~~]\"],\"editor.toolHint.placeCabinet.b0ouyk\":[\"[Þļáçé çáƀîñéţ ~~~~]\"],\"editor.toolHint.placeCanopyOrSetTheNext.12l7zf8\":[\"[Þļáçé çáñöþý öŕ šéţ ţĥé ñéẋţ ŕûñ þöîñţ ~~~~~~~~~~]\"],\"editor.toolHint.placeChimneyOnRoof.19dbqu\":[\"[Þļáçé çĥîɱñéý öñ ŕööƒ ~~~~~~]\"],\"editor.toolHint.placeColumn.1w2vq86\":[\"[Þļáçé çöļûɱñ ~~~~]\"],\"editor.toolHint.placeCupolaOnRoof.ofx3bn\":[\"[Þļáçé çûþöļá öñ ŕööƒ ~~~~~~]\"],\"editor.toolHint.placeDimensionLineWhenNeeded.bjw2cj\":[\"[Þļáçé ðîɱéñšîöñ ļîñé ŵĥéñ ñééðéð ~~~~~~~~~]\"],\"editor.toolHint.placeDoorOnWall.1jwadf\":[\"[Þļáçé ðööŕ öñ ŵáļļ ~~~~~]\"],\"editor.toolHint.placeDormerOnRoof.1w518a6\":[\"[Þļáçé ðöŕɱéŕ öñ ŕööƒ ~~~~~~]\"],\"editor.toolHint.placeElevator.1f65zva\":[\"[Þļáçé éļéṽáţöŕ ~~~~]\"],\"editor.toolHint.placeEyebrowVentOnRoof.1h1tqxn\":[\"[Þļáçé éýéƀŕöŵ ṽéñţ öñ ŕööƒ ~~~~~~~]\"],\"editor.toolHint.placeFitting.1pmx3vn\":[\"[Þļáçé ƒîţţîñĝ ~~~~]\"],\"editor.toolHint.placeGutterOnRoofEave.llwzf9\":[\"[Þļáçé ĝûţţéŕ öñ ŕööƒ éáṽé ~~~~~~~]\"],\"editor.toolHint.placeItLockedTo45.16e4csk\":[\"[Þļáçé îţ (ļöçķéð ţö 45°) ~~~~~]\"],\"editor.toolHint.placeItem.teynf\":[\"[Þļáçé îţéɱ ~~~]\"],\"editor.toolHint.placeMeasurementPoint.bsatli\":[\"[Þļáçé ɱéášûŕéɱéñţ þöîñţ ~~~~~~~]\"],\"editor.toolHint.placeOnAFence.1dptstr\":[\"[Þļáçé öñ á ƒéñçé ~~~~]\"],\"editor.toolHint.placeRegister.1uebycd\":[\"[Þļáçé ŕéĝîšţéŕ ~~~~]\"],\"editor.toolHint.placeRidgeVentOnRoof.2tpd8r\":[\"[Þļáçé ŕîðĝé ṽéñţ öñ ŕööƒ ~~~~~~]\"],\"editor.toolHint.placeShelf.y4l3iw\":[\"[Þļáçé šĥéļƒ ~~~]\"],\"editor.toolHint.placeSkylightOnRoof.e215pe\":[\"[Þļáçé šķýļîĝĥţ öñ ŕööƒ ~~~~~~]\"],\"editor.toolHint.placeSolarPanelArrayOnRoof.kk11fn\":[\"[Þļáçé šöļáŕ þáñéļ áŕŕáý öñ ŕööƒ ~~~~~~~~]\"],\"editor.toolHint.placeSpawnPoint.205o25\":[\"[Þļáçé šþáŵñ þöîñţ ~~~~~]\"],\"editor.toolHint.placeStairs.zwxxu2\":[\"[Þļáçé šţáîŕš ~~~~]\"],\"editor.toolHint.placeTrap.1gxemn3\":[\"[Þļáçé ţŕáþ ~~~]\"],\"editor.toolHint.placeTurbineVentOnRoof.1iqeluf\":[\"[Þļáçé ţûŕƀîñé ṽéñţ öñ ŕööƒ ~~~~~~~]\"],\"editor.toolHint.placeUnit.8zkx4q\":[\"[Þļáçé ûñîţ ~~~]\"],\"editor.toolHint.placeWindowOnWall.1k3qnfb\":[\"[Þļáçé ŵîñðöŵ öñ ŵáļļ ~~~~~~]\"],\"editor.toolHint.placeWithoutTheCornerSnap.1nifqew\":[\"[Þļáçé ŵîţĥöûţ ţĥé çöŕñéŕ šñáþ ~~~~~~~~]\"],\"editor.toolHint.placement.13lcvts\":[\"[Þļáçéɱéñţ ~~~]\"],\"editor.toolHint.placementAuto.1caa52d\":[\"[Þļáçéɱéñţ: Åûţö ~~~~]\"],\"editor.toolHint.placementGround.1ruz145\":[\"[Þļáçéɱéñţ: Ĝŕöûñð ~~~~~]\"],\"editor.toolHint.placementRoof.renkw8\":[\"[Þļáçéɱéñţ: Ŕööƒ ~~~~]\"],\"editor.toolHint.placementSurfaceClickOrPressP.w56h19\":[\"[Þļáçéɱéñţ šûŕƒáçé - çļîçķ öŕ þŕéšš Þ ţö çýçļé ~~~~~~~~~~~]\"],\"editor.toolHint.placementType.1mdpl60\":[\"[Þļáçéɱéñţ ţýþé ~~~~]\"],\"editor.toolHint.placementTypeClickOrPressI.10cgxh2\":[\"[Þļáçéɱéñţ ţýþé — çļîçķ öŕ þŕéšš Î ţö ţöĝĝļé ~~~~~~~~~~~]\"],\"editor.toolHint.pointInsideARoomPorchOr.58w64l\":[\"[Þöîñţ îñšîðé á ŕööɱ, þöŕçĥ öŕ ðéçķ ~~~~~~~~~]\"],\"editor.toolHint.removeLastPoint.2dmdcx\":[\"[Ŕéɱöṽé ļášţ þöîñţ ~~~~~]\"],\"editor.toolHint.removeLastWitness.1b6vvzw\":[\"[Ŕéɱöṽé ļášţ ŵîţñéšš ~~~~~~]\"],\"editor.toolHint.ridgeDirection.5m1369\":[\"[Ŕîðĝé ðîŕéçţîöñ ~~~~~]\"],\"editor.toolHint.ridgeDirectionClickOrPressR.1t14dyk\":[\"[Ŕîðĝé ðîŕéçţîöñ - çļîçķ öŕ þŕéšš Ŕ ţö ţûŕñ îţ 90° ~~~~~~~~~~~]\"],\"editor.toolHint.ridgeLongSide.ew0euv\":[\"[Ŕîðĝé: Ļöñĝ šîðé ~~~~]\"],\"editor.toolHint.ridgeShortSide.gye8pb\":[\"[Ŕîðĝé: Šĥöŕţ šîðé ~~~~~]\"],\"editor.toolHint.rotate.1thqa0a\":[\"[Ŕöţáţé ~~]\"],\"editor.toolHint.rotate45.9zq68u\":[\"[Ŕöţáţé ±45° ~~]\"],\"editor.toolHint.rotate45FloorCeiling.m9t57d\":[\"[Ŕöţáţé ±45° (ƒļööŕ / çéîļîñĝ) ~~~~~~]\"],\"editor.toolHint.rotateGhost15.rsa52c\":[\"[Ŕöţáţé ĝĥöšţ ±15° ~~~~]\"],\"editor.toolHint.rotateOrFlipTheRunSide.t5ior7\":[\"[Ŕöţáţé öŕ ƒļîþ ţĥé ŕûñ šîðé ~~~~~~~]\"],\"editor.toolHint.rotateSpawnPoint.1opcuu7\":[\"[Ŕöţáţé šþáŵñ þöîñţ ~~~~~]\"],\"editor.toolHint.roundRectangularOval.e4nh6x\":[\"[Ŕöûñð / ŕéçţáñĝûļáŕ / öṽáļ ~~~~~~]\"],\"editor.toolHint.setBeamStartEndTheNext.di3bzj\":[\"[Šéţ ƀéáɱ šţáŕţ / éñð; ţĥé ñéẋţ ƀéáɱ šţáŕţš ţĥéŕé ~~~~~~~~~~~~]\"],\"editor.toolHint.setFenceStartEnd.1phbwsq\":[\"[Šéţ ƒéñçé šţáŕţ / éñð ~~~~~]\"],\"editor.toolHint.setOneCornerThenTheOpposite.8tsl49\":[\"[Šéţ öñé çöŕñéŕ, ţĥéñ ţĥé öþþöšîţé ~~~~~~~~~]\"],\"editor.toolHint.setRoofFootprint.p50n0o\":[\"[Šéţ ŕööƒ ƒööţþŕîñţ ~~~~~]\"],\"editor.toolHint.setWallStartEnd.1r8ubcx\":[\"[Šéţ ŵáļļ šţáŕţ / éñð ~~~~~]\"],\"editor.toolHint.slopeLevel.ftqp67\":[\"[Šļöþé / ļéṽéļ ~~~]\"],\"editor.toolHint.snapOntoTheRun.86yhmp\":[\"[Šñáþ öñţö ţĥé ŕûñ ~~~~~]\"],\"editor.toolHint.splitAtTheMarks.x5tpdd\":[\"[Šþļîţ áţ ţĥé ɱáŕķš ~~~~~]\"],\"editor.toolHint.startGridAxis.k92yza\":[\"[Šţáŕţ ĝŕîð áẋîš ~~~~]\"],\"editor.toolHint.startLineset.23q8dh\":[\"[Šţáŕţ ļîñéšéţ ~~~~]\"],\"editor.toolHint.startLiquidLine.1rlxsgd\":[\"[Šţáŕţ ļîǫûîð ļîñé ~~~~~]\"],\"editor.toolHint.startRun.r6fc5u\":[\"[Šţáŕţ ŕûñ ~~~]\"],\"editor.toolHint.startSegment.rolym6\":[\"[Šţáŕţ šéĝɱéñţ ~~~~]\"],\"editor.toolHint.stepBackOrCancel.zbfdkn\":[\"[Šţéþ ƀáçķ öŕ çáñçéļ ~~~~~]\"],\"editor.toolHint.style.nf3vcm\":[\"[Šţýļé ~~]\"],\"editor.toolHint.styleBarn.k9n1x\":[\"[Šţýļé: Ɓáŕñ ~~~]\"],\"editor.toolHint.styleCasement.ziklec\":[\"[Šţýļé: Çášéɱéñţ ~~~~]\"],\"editor.toolHint.styleCraftsman.52e6a9\":[\"[Šţýļé: Çŕáƒţšɱáñ ~~~~~]\"],\"editor.toolHint.styleDoubleHung.1lg8pkg\":[\"[Šţýļé: Ðöûƀļé-ĥûñĝ ~~~~~]\"],\"editor.toolHint.styleFrench.1ue3j64\":[\"[Šţýļé: Ƒŕéñçĥ ~~~~]\"],\"editor.toolHint.styleGlass.qudnb4\":[\"[Šţýļé: Ĝļášš ~~~]\"],\"editor.toolHint.styleGrid.1vuq4po\":[\"[Šţýļé: Ĝŕîð ~~~]\"],\"editor.toolHint.styleHalfLouvered.13b1few\":[\"[Šţýļé: Ĥáļƒ-ļöûṽéŕéð ~~~~~~]\"],\"editor.toolHint.styleHorizontalBands.12ethxk\":[\"[Šţýļé: Ĥöŕîžöñţáļ ƀáñðš ~~~~~~]\"],\"editor.toolHint.styleModern.1fh8hhn\":[\"[Šţýļé: Ṁöðéŕñ ~~~~]\"],\"editor.toolHint.stylePanel.922jze\":[\"[Šţýļé: Þáñéļ ~~~]\"],\"editor.toolHint.stylePaneledGlass.17a17en\":[\"[Šţýļé: Þáñéļéð ĝļášš ~~~~~~]\"],\"editor.toolHint.styleShaker.49z17k\":[\"[Šţýļé: Šĥáķéŕ ~~~~]\"],\"editor.toolHint.styleSingle.6f3cm0\":[\"[Šţýļé: Šîñĝļé ~~~~]\"],\"editor.toolHint.styleSixPanel.u49laj\":[\"[Šţýļé: Šîẋ-þáñéļ ~~~~]\"],\"editor.toolHint.styleSliding.q81s0i\":[\"[Šţýļé: Šļîðîñĝ ~~~~]\"],\"editor.toolHint.styleTallGrid.1eotg3x\":[\"[Šţýļé: Ţáļļ ĝŕîð ~~~~]\"],\"editor.toolHint.styleTransom.kb9bh6\":[\"[Šţýļé: Ţŕáñšöɱ ~~~~]\"],\"editor.toolHint.styleTripleHung.pxnqi3\":[\"[Šţýļé: Ţŕîþļé-ĥûñĝ ~~~~~]\"],\"editor.toolHint.styleWideGrid.12n27et\":[\"[Šţýļé: Ŵîðé ĝŕîð ~~~~]\"],\"editor.toolHint.switchRotationAxisYXZ.15lohm6\":[\"[Šŵîţçĥ ŕöţáţîöñ áẋîš (Ý → Ẋ → Ž) ~~~~~~~]\"],\"editor.toolHint.theWallsMeetAtTooSharp.kh3wi3\":[\"[Ţĥé ŵáļļš ɱééţ áţ ţöö šĥáŕþ öŕ ţöö ƒļáţ áñ áñĝļé ~~~~~~~~~~~~]\"],\"editor.toolHint.theWindowWaitingThereIsTaller.1tqwez4\":[\"[Ţĥé ŵîñðöŵ ŵáîţîñĝ ţĥéŕé îš ţáļļéŕ ţĥáñ ţĥîš ŵáļļ ~~~~~~~~~~~~~]\"],\"editor.toolHint.threeOrMoreWallsMeetHere.rgifif\":[\"[Ţĥŕéé öŕ ɱöŕé ŵáļļš ɱééţ ĥéŕé ~~~~~~~~]\"],\"editor.toolHint.traceCeilingOutline.1b639wv\":[\"[Ţŕáçé çéîļîñĝ öûţļîñé ~~~~~~]\"],\"editor.toolHint.traceSlabOutline.z0j2lc\":[\"[Ţŕáçé šļáƀ öûţļîñé ~~~~~]\"],\"editor.toolHint.type.1m2zofh\":[\"[Ţýþé ~~]\"],\"editor.toolHint.typeAwning.1cj59al\":[\"[Ţýþé: Åŵñîñĝ ~~~]\"],\"editor.toolHint.typeBarn.sbnygq\":[\"[Ţýþé: Ɓáŕñ ~~~]\"],\"editor.toolHint.typeBay.1200hc1\":[\"[Ţýþé: Ɓáý ~~~]\"],\"editor.toolHint.typeBow.14s2t9p\":[\"[Ţýþé: Ɓöŵ ~~~]\"],\"editor.toolHint.typeCabinet.1r68je5\":[\"[Ţýþé: Çáƀîñéţ ~~~~]\"],\"editor.toolHint.typeCasement.176uo9j\":[\"[Ţýþé: Çášéɱéñţ ~~~~]\"],\"editor.toolHint.typeDouble.af7w4i\":[\"[Ţýþé: Ðöûƀļé ~~~]\"],\"editor.toolHint.typeDoubleHung.t482fu\":[\"[Ţýþé: Ðöûƀļé Ĥûñĝ ~~~~~]\"],\"editor.toolHint.typeFixed.v1cjez\":[\"[Ţýþé: Ƒîẋéð ~~~]\"],\"editor.toolHint.typeFolding.sxxyng\":[\"[Ţýþé: Ƒöļðîñĝ ~~~~]\"],\"editor.toolHint.typeFrench.1y57z1b\":[\"[Ţýþé: Ƒŕéñçĥ ~~~]\"],\"editor.toolHint.typeHinged.1xrcfju\":[\"[Ţýþé: Ĥîñĝéð ~~~]\"],\"editor.toolHint.typeIsland.ufr3ce\":[\"[Ţýþé: Κļáñð ~~~]\"],\"editor.toolHint.typeLouvered.oxl1cz\":[\"[Ţýþé: Ļöûṽéŕéð ~~~~]\"],\"editor.toolHint.typePocket.hc65x9\":[\"[Ţýþé: Þöçķéţ ~~~]\"],\"editor.toolHint.typeSingleHung.p53pyl\":[\"[Ţýþé: Šîñĝļé Ĥûñĝ ~~~~~]\"],\"editor.toolHint.typeSliding.nwmr3f\":[\"[Ţýþé: Šļîðîñĝ ~~~~]\"],\"editor.toolHint.verticalStackClickToPlace.ijcn4q\":[\"[Ṽéŕţîçáļ šţáçķ ↕, çļîçķ ţö þļáçé ~~~~~~~~]\"],\"editor.toolHint.wasteVent.1hvi3vj\":[\"[Ŵášţé / ṽéñţ ~~~]\"],\"editor.toolHint.windowStyleClickOrPressL.ah7qm9\":[\"[Ŵîñðöŵ šţýļé — çļîçķ öŕ þŕéšš Ļ ţö çýçļé ~~~~~~~~~~]\"],\"editor.toolHint.windowTypeClickOrPressO.wv4x35\":[\"[Ŵîñðöŵ ţýþé — çļîçķ öŕ þŕéšš Ö ţö çýçļé ~~~~~~~~~]\"],\"editor.tools.distribution.distributionRunTool.lengthField\":[\"[Ļéñĝţĥ: \",[\"field\"],\" ɱ ~~~]\"],\"editor.tools.distribution.distributionRunTool.tabDirection\":[\"[Ţáƀ: ðîŕéçţîöñ ~~~~]\"],\"editor.tools.distribution.distributionRunTool.typeALength\":[\"[ţýþé á ļéñĝţĥ ~~~~]\"],\"editor.views.plugins\":[\"[Þļûĝîñš ~~~]\"],\"editor.views.view2d\":[\"[2Ð ~]\"],\"editor.views.view3d\":[\"[3Ð ~]\"],\"editor.views.viewBar.auto\":[\"[Åûţö ~~]\"],\"editor.views.viewBar.browsePlugins\":[\"[Ɓŕöŵšé þļûĝîñš ~~~~]\"],\"editor.views.viewBar.closeLabel\":[\"[Çļöšé \",[\"label\"],\" ~~]\"],\"editor.views.viewBar.closeSplit\":[\"[Çļöšé šþļîţ (\\\\) ~~~]\"],\"editor.views.viewBar.ground\":[\"[Ĝŕöûñð ~~]\"],\"editor.views.viewBar.groundSolid\":[\"[\",[\"standing\",\"select\",{\"partly\":[\"Þáŕţļý ƀéļöŵ ĝŕáðé · ĝŕöûñð šöļîð\"],\"below\":[\"Ɓéļöŵ ĝŕáðé · ĝŕöûñð šöļîð\"],\"other\":[\"Ĝŕöûñð šöļîð\"]}],\" ~~~~~~~~~~~~~~~~~~]\"],\"editor.views.viewBar.groundVeiled\":[\"[\",[\"standing\",\"select\",{\"partly\":[\"Þáŕţļý ƀéļöŵ ĝŕáðé · ĝŕöûñð ṽéîļéð\"],\"below\":[\"Ɓéļöŵ ĝŕáðé · ĝŕöûñð ṽéîļéð\"],\"other\":[\"Ĝŕöûñð ṽéîļéð\"]}],\" ~~~~~~~~~~~~~~~~~~~]\"],\"editor.views.viewBar.keepTheGroundSolid\":[\"[Ķééþ ţĥé ĝŕöûñð šöļîð ~~~~~~]\"],\"editor.views.viewBar.moreViews\":[\"[Ṁöŕé ṽîéŵš ~~~]\"],\"editor.views.viewBar.paneViews\":[\"[Þáñé \",[\"pane\"],\" ṽîéŵš ~~~]\"],\"editor.views.viewBar.pinLabel\":[\"[Þîñ \",[\"label\"],\" ~]\"],\"editor.views.viewBar.pinToTheViewBar\":[\"[Þîñ ţö ţĥé ṽîéŵ ƀáŕ ~~~~~]\"],\"editor.views.viewBar.solid\":[\"[Šöļîð ~~]\"],\"editor.views.viewBar.split\":[\"[Šþļîţ (\\\\) ~~]\"],\"editor.views.viewBar.split2\":[\"[Šþļîţ ~~]\"],\"editor.views.viewBar.swapPanes\":[\"[Šŵáþ þáñéš ~~~]\"],\"editor.views.viewBar.unpinFromTheViewBar\":[\"[Ûñþîñ ƒŕöɱ ţĥé ṽîéŵ ƀáŕ ~~~~~~]\"],\"editor.views.viewBar.unpinLabel\":[\"[Ûñþîñ \",[\"label\"],\" ~~]\"],\"editor.views.viewBar.veilTheGroundOverALevel\":[\"[Ṽéîļ ţĥé ĝŕöûñð öṽéŕ á ļéṽéļ ƀéļöŵ ĝŕáðé ~~~~~~~~~~]\"],\"editor.views.viewBar.views\":[\"[Ṽîéŵš ~~]\"],\"editor.wallTypeEditorDialog.listTheLayersAppliedToThisWall\":[\"[Ļîšţ ţĥé ļáýéŕš ƒŕöɱ ţĥé öûţšîðé îñ, áŕöûñð öñé ƒŕáɱîñĝ çöŕé. Ţĥé ţýþé îš šáṽéð ŵîţĥ ţĥé þŕöĵéçţ áñð áþþļîéð ţö ţĥîš ŵáļļ; öţĥéŕ ŵáļļš ķééþ ţĥéîŕ ļáýéŕš. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"editor.wallTypeMenu.custom\":[\"[Çûšţöɱ ~~]\"],\"editor.wallTypeMenu.wallTypesOf\":[\"[Ŵáļļ ţýþéš: ñéŵ, éðîţ öŕ ðûþļîçáţé \",[\"label\"],\" ~~~~~~~~~]\"],\"editor.youCanRetryTheSceneOr\":[\"[Ýöû çáñ ŕéţŕý ţĥé šçéñé öŕ ŕéţûŕñ ĥöɱé ŵîţĥöûţ ŕéļöáðîñĝ ţĥé ŵĥöļé áþþ šĥéļļ. ~~~~~~~~~~~~~~~~~~~]\"],\"node.beam.description\":[\"[Å ƒŕáɱîñĝ ƀéáɱ ðŕáŵñ éñð ţö éñð: á þöŕçĥ ĥéáðéŕ, á ðéçķ ƀéáɱ, á ĝîŕðéŕ. ~~~~~~~~~~~~~~~~]\"],\"node.beam.label\":[\"[Ɓéáɱ ~~]\"],\"node.beam.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.beam.panel.addPosts\":[\"[Åðð þöšţš ~~~]\"],\"node.beam.panel.beam\":[\"[Ɓéáɱ ~~]\"],\"node.beam.panel.beamSize\":[\"[Ɓéáɱ \",[\"size\"],\" ~~]\"],\"node.beam.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.beam.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.beam.panel.dropped\":[\"[Ðŕöþþéð ~~~]\"],\"node.beam.panel.flush\":[\"[Ƒļûšĥ ~~]\"],\"node.beam.panel.followTheCeilingPlane\":[\"[Ƒöļļöŵ ţĥé çéîļîñĝ þļáñé ~~~~~~~]\"],\"node.beam.panel.lengthLongItsUnderside\":[\"[\",[\"length\"],\" ļöñĝ; îţš ûñðéŕšîðé \",[\"underside\"],\" öṽéŕ ţĥé ƒļööŕ, ţĥé çéîļîñĝ þļáñé \",[\"plane\"],\". ~~~~~~~~~~~~~]\"],\"node.beam.panel.material\":[\"[Ṁáţéŕîáļ ~~~]\"],\"node.beam.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.beam.panel.n1Ply\":[\"[1 þļý ~]\"],\"node.beam.panel.placement\":[\"[Þļáçéɱéñţ ~~~]\"],\"node.beam.panel.pliesPlies\":[\"[\",[\"plies\"],\" þļîéš ~~]\"],\"node.beam.panel.size\":[\"[Šîžé ~~]\"],\"node.beam.panel.top\":[\"[Ţöþ ~]\"],\"node.beam.panel.topElevation\":[\"[Ţöþ éļéṽáţîöñ ~~~~]\"],\"node.beam.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.block.description\":[\"[Å ţöþöļöĝý-ƀáçķéð šöļîð éðîţéð ðîŕéçţļý îñ ţĥé çáñṽáš. ~~~~~~~~~~~~~~]\"],\"node.block.label\":[\"[Ɓļöçķ ~~]\"],\"node.boxVent.description\":[\"[Šɱáļļ ļöûṽéŕéð éẋĥáûšţ ṽéñţ ţĥáţ šîţš öñ á ŕööƒ šļöþé. ~~~~~~~~~~~~~~]\"],\"node.boxVent.label\":[\"[Ɓöẋ Ṽéñţ ~~~]\"],\"node.boxVent.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.boxVent.panel.baseFlange\":[\"[Ɓášé Ƒļáñĝé ~~~]\"],\"node.boxVent.panel.baseHeight\":[\"[Ɓášé Ĥéîĝĥţ ~~~]\"],\"node.boxVent.panel.baseInset\":[\"[Ɓášé Îñšéţ ~~~]\"],\"node.boxVent.panel.box\":[\"[Ɓöẋ ~]\"],\"node.boxVent.panel.boxVent\":[\"[Ɓöẋ Ṽéñţ ~~~]\"],\"node.boxVent.panel.cap\":[\"[Çáþ ~]\"],\"node.boxVent.panel.capHeight\":[\"[Çáþ Ĥéîĝĥţ ~~~]\"],\"node.boxVent.panel.cornerBevel\":[\"[Çöŕñéŕ Ɓéṽéļ ~~~~]\"],\"node.boxVent.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.boxVent.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.boxVent.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.boxVent.panel.dome\":[\"[Ðöɱé ~~]\"],\"node.boxVent.panel.domeCurvature\":[\"[Ðöɱé Çûŕṽáţûŕé ~~~~]\"],\"node.boxVent.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.boxVent.panel.gapHeight\":[\"[Ĝáþ Ĥéîĝĥţ ~~~]\"],\"node.boxVent.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.boxVent.panel.hoodOverhang\":[\"[Ĥööð Öṽéŕĥáñĝ ~~~~]\"],\"node.boxVent.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.boxVent.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.boxVent.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.boxVent.panel.style\":[\"[Šţýļé ~~]\"],\"node.boxVent.panel.topTaper\":[\"[Ţöþ Ţáþéŕ ~~~]\"],\"node.boxVent.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.building.description\":[\"[Å ƀûîļðîñĝ çöñţáîñéŕ ĥöļðîñĝ öñé öŕ ɱöŕé ļéṽéļš. ~~~~~~~~~~~~]\"],\"node.building.label\":[\"[Ɓûîļðîñĝ ~~~]\"],\"node.cabinet.compartmentCard.baskets\":[\"[Ɓášķéţš ~~~]\"],\"node.cabinet.compartmentCard.bottom\":[\"[Ɓöţţöɱ ~~]\"],\"node.cabinet.compartmentCard.bottomFreezer\":[\"[Ɓöţţöɱ Ƒŕééžéŕ ~~~~]\"],\"node.cabinet.compartmentCard.bowls\":[\"[Ɓöŵļš ~~]\"],\"node.cabinet.compartmentCard.burnersOn\":[\"[Ɓûŕñéŕš öñ ~~~]\"],\"node.cabinet.compartmentCard.chimney\":[\"[Çĥîɱñéý ~~~]\"],\"node.cabinet.compartmentCard.decrease\":[\"[Ðéçŕéášé \",[\"label\"],\" ~~~]\"],\"node.cabinet.compartmentCard.door\":[\"[Ðööŕ ~~]\"],\"node.cabinet.compartmentCard.double\":[\"[Ðöûƀļé ~~]\"],\"node.cabinet.compartmentCard.drawer\":[\"[Ðŕáŵéŕ ~~]\"],\"node.cabinet.compartmentCard.drawers\":[\"[Ðŕáŵéŕš ~~~]\"],\"node.cabinet.compartmentCard.flipHinge\":[\"[Ƒļîþ ĥîñĝé ~~~]\"],\"node.cabinet.compartmentCard.flipTheDoorHingeToThe\":[\"[Ƒļîþ ţĥé ðööŕ ĥîñĝé ţö ţĥé öþþöšîţé šîðé ~~~~~~~~~~]\"],\"node.cabinet.compartmentCard.fridge\":[\"[Ƒŕîðĝé ~~]\"],\"node.cabinet.compartmentCard.gas\":[\"[Ĝáš ~]\"],\"node.cabinet.compartmentCard.glass\":[\"[Ĝļášš ~~]\"],\"node.cabinet.compartmentCard.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.cabinet.compartmentCard.hob\":[\"[Ĥöƀ ~]\"],\"node.cabinet.compartmentCard.increase\":[\"[Îñçŕéášé \",[\"label\"],\" ~~~]\"],\"node.cabinet.compartmentCard.induction\":[\"[Îñðûçţîöñ ~~~]\"],\"node.cabinet.compartmentCard.layout\":[\"[Ļáýöûţ ~~]\"],\"node.cabinet.compartmentCard.left\":[\"[Ļéƒţ ~~]\"],\"node.cabinet.compartmentCard.micro\":[\"[Ṁîçŕö ~~]\"],\"node.cabinet.compartmentCard.moveDown\":[\"[Ṁöṽé ðöŵñ ~~~]\"],\"node.cabinet.compartmentCard.moveUp\":[\"[Ṁöṽé ûþ ~~]\"],\"node.cabinet.compartmentCard.oven\":[\"[Öṽéñ ~~]\"],\"node.cabinet.compartmentCard.pullout\":[\"[Þûļļöûţ ~~~]\"],\"node.cabinet.compartmentCard.rack\":[\"[Ŕáçķ ~~]\"],\"node.cabinet.compartmentCard.removeCompartment\":[\"[Ŕéɱöṽé çöɱþáŕţɱéñţ ~~~~~~]\"],\"node.cabinet.compartmentCard.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.cabinet.compartmentCard.shelf\":[\"[Šĥéļƒ ~~]\"],\"node.cabinet.compartmentCard.shelves\":[\"[Šĥéļṽéš ~~~]\"],\"node.cabinet.compartmentCard.shelvesInside\":[\"[Šĥéļṽéš îñšîðé ~~~~]\"],\"node.cabinet.compartmentCard.single\":[\"[Šîñĝļé ~~]\"],\"node.cabinet.compartmentCard.sink\":[\"[Šîñķ ~~]\"],\"node.cabinet.compartmentCard.style\":[\"[Šţýļé ~~]\"],\"node.cabinet.compartmentCard.surface\":[\"[Šûŕƒáçé ~~~]\"],\"node.cabinet.compartmentCard.top\":[\"[Ţöþ ~]\"],\"node.cabinet.compartmentCard.topFreezer\":[\"[Ţöþ Ƒŕééžéŕ ~~~]\"],\"node.cabinet.compartmentCard.topGrate\":[\"[Ţöþ ĝŕáţé ~~~]\"],\"node.cabinet.compartmentCard.tray\":[\"[Ţŕáý ~~]\"],\"node.cabinet.compartmentCard.type\":[\"[Ţýþé ~~]\"],\"node.cabinet.compartmentCard.washer\":[\"[Ŵášĥéŕ ~~]\"],\"node.cabinet.compartmentCard.wire\":[\"[Ŵîŕé ~~]\"],\"node.cabinet.description\":[\"[Å çöñƒîĝûŕáƀļé þáŕáɱéţŕîç ƀášé çáƀîñéţ. ~~~~~~~~~~~]\"],\"node.cabinet.essentialControls.bottomFreezer\":[\"[Ɓöţţöɱ ƒŕééžéŕ ~~~~]\"],\"node.cabinet.essentialControls.cooktopType\":[\"[Çööķţöþ ţýþé ~~~~]\"],\"node.cabinet.essentialControls.doorDirection\":[\"[Ðööŕ ðîŕéçţîöñ ~~~~]\"],\"node.cabinet.essentialControls.double\":[\"[Ðöûƀļé ~~]\"],\"node.cabinet.essentialControls.fridgeType\":[\"[Ƒŕîðĝé ţýþé ~~~]\"],\"node.cabinet.essentialControls.gas\":[\"[Ĝáš ~]\"],\"node.cabinet.essentialControls.glass\":[\"[Ĝļášš ~~]\"],\"node.cabinet.essentialControls.induction\":[\"[Îñðûçţîöñ ~~~]\"],\"node.cabinet.essentialControls.itemOptions\":[\"[Îţéɱ öþţîöñš ~~~~]\"],\"node.cabinet.essentialControls.leftHinge\":[\"[Ļéƒţ ĥîñĝé ~~~]\"],\"node.cabinet.essentialControls.rightHinge\":[\"[Ŕîĝĥţ ĥîñĝé ~~~]\"],\"node.cabinet.essentialControls.single\":[\"[Šîñĝļé ~~]\"],\"node.cabinet.essentialControls.sinkLayout\":[\"[Šîñķ ļáýöûţ ~~~]\"],\"node.cabinet.essentialControls.topFreezer\":[\"[Ţöþ ƒŕééžéŕ ~~~]\"],\"node.cabinet.kitchenCollection.chooseLabel\":[\"[Çĥööšé \",[\"label\"],\" ~~]\"],\"node.cabinet.kitchenCollection.noKitchenItemsMatchTryFridge\":[\"[Ñö ķîţçĥéñ îţéɱš ɱáţçĥ. Ţŕý “ƒŕîðĝé”, “šîñķ”, öŕ “çáƀîñéţ”. ~~~~~~~~~~~~~]\"],\"node.cabinet.kitchenCollection.searchFridgeSinkCabinets\":[\"[Šéáŕçĥ ƒŕîðĝé, šîñķ, çáƀîñéţš… ~~~~~~~~]\"],\"node.cabinet.kitchenCollection.searchKitchenItems\":[\"[Šéáŕçĥ ķîţçĥéñ îţéɱš ~~~~~~]\"],\"node.cabinet.kitchenGroup.appliances\":[\"[Åþþļîáñçéš & ƒîẋţûŕéš ~~~~~~]\"],\"node.cabinet.kitchenGroup.cabinets\":[\"[Çáƀîñéţš ~~~]\"],\"node.cabinet.kitchenModuleActions.addBeside\":[\"[Åðð ƀéšîðé ~~~]\"],\"node.cabinet.kitchenModuleActions.addBesideSelectedItem\":[\"[Åðð ƀéšîðé šéļéçţéð îţéɱ ~~~~~~~]\"],\"node.cabinet.kitchenModuleActions.addLabel\":[\"[Åðð \",[\"label\"],\" ~]\"],\"node.cabinet.kitchenModuleActions.anUpperCabinetAttachedToThis\":[\"[Åñ ûþþéŕ çáƀîñéţ áţţáçĥéð ţö ţĥîš îţéɱ ŵîļļ ƀé ŕéɱöṽéð ţö ɱáķé ŕööɱ. ~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.kitchenModuleActions.cabinet\":[\"[Çáƀîñéţ ~~~]\"],\"node.cabinet.kitchenModuleActions.cancel\":[\"[Çáñçéļ ~~]\"],\"node.cabinet.kitchenModuleActions.cannotFit\":[\"[Ţĥîš \",[\"width\"],\" îţéɱ çáññöţ ƒîţ ŵîţĥîñ ţĥé çûŕŕéñţ ŕûñ áñð îţš ŵáļļ öŕ çöŕñéŕ ļîɱîţš. Ṁöṽé áñ éñð çáƀîñéţ öŕ ƒŕéé šþáçé, ţĥéñ ţŕý áĝáîñ. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.kitchenModuleActions.insertsBeside\":[\"[\",[\"side\",\"select\",{\"left\":[\"Îñšéŕţš öñ ţĥé ļéƒţ öƒ ţĥé šéļéçţéð îţéɱ.\"],\"other\":[\"Îñšéŕţš öñ ţĥé ŕîĝĥţ öƒ ţĥé šéļéçţéð îţéɱ.\"]}],\" ~~~~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.kitchenModuleActions.kitchenChanged\":[\"[Ţĥé ķîţçĥéñ çĥáñĝéð. Šéļéçţ áñ îţéɱ áĝáîñ ţö ŕéƒŕéšĥ ţĥé þŕéṽîéŵ. ~~~~~~~~~~~~~~~~]\"],\"node.cabinet.kitchenModuleActions.kitchenRunPreviewHighlightedItemIs\":[\"[Ķîţçĥéñ ŕûñ þŕéṽîéŵ, ĥîĝĥļîĝĥţéð îţéɱ îš ţĥé þŕöþöšéð çĥáñĝé ~~~~~~~~~~~~~~~~]\"],\"node.cabinet.kitchenModuleActions.leftSide\":[\"[Ļéƒţ šîðé ~~~]\"],\"node.cabinet.kitchenModuleActions.moved\":[\"[\",[\"name\"],\": ɱöṽéš \",[\"distance\"],\" ~~]\"],\"node.cabinet.kitchenModuleActions.previewItem\":[[\"name\"],\": \",[\"width\"]],\"node.cabinet.kitchenModuleActions.replaceSelectedItem\":[\"[Ŕéþļáçé šéļéçţéð îţéɱ ~~~~~~]\"],\"node.cabinet.kitchenModuleActions.replaceWith\":[\"[Ŕéþļáçé ŵîţĥ… ~~~~]\"],\"node.cabinet.kitchenModuleActions.replaceWithLabel\":[\"[Ŕéþļáçé ŵîţĥ \",[\"label\"],\" ~~~~]\"],\"node.cabinet.kitchenModuleActions.replacesOnlyTheSelectedItem\":[\"[Ŕéþļáçéš öñļý ţĥé šéļéçţéð îţéɱ. ~~~~~~~~~]\"],\"node.cabinet.kitchenModuleActions.resized\":[[\"name\"],\": \",[\"before\"],\" → \",[\"after\"]],\"node.cabinet.kitchenModuleActions.rightSide\":[\"[Ŕîĝĥţ šîðé ~~~]\"],\"node.cabinet.kitchenModuleActions.unableToUpdateThisKitchen\":[\"[Ûñáƀļé ţö ûþðáţé ţĥîš ķîţçĥéñ. ~~~~~~~~]\"],\"node.cabinet.label\":[\"[Ṁöðûļáŕ Çáƀîñéţ ~~~~~]\"],\"node.cabinet.panel.aboveCeiling\":[\"[Ƒîñîšĥéð ĥéîĝĥţ éẋţéñðš \",[\"overflow\"],\" ɱɱ áƀöṽé ţĥé çéîļîñĝ. ~~~~~~~~~~~~]\"],\"node.cabinet.panel.addChimney\":[\"[Åðð çĥîɱñéý ~~~]\"],\"node.cabinet.panel.addCompartment\":[\"[Åðð çöɱþáŕţɱéñţ ~~~~~]\"],\"node.cabinet.panel.addWallCabinet\":[\"[Åðð ŵáļļ çáƀîñéţ ~~~~~]\"],\"node.cabinet.panel.advanced\":[\"[Åðṽáñçéð ~~~]\"],\"node.cabinet.panel.appliance\":[\"[Åþþļîáñçé ~~~]\"],\"node.cabinet.panel.applianceFront\":[\"[Åþþļîáñçé ƒŕöñţ ~~~~~]\"],\"node.cabinet.panel.auto\":[\"[Åûţö ~~]\"],\"node.cabinet.panel.bar\":[\"[Ɓáŕ ~]\"],\"node.cabinet.panel.baseCabinet\":[\"[Ɓášé Çáƀîñéţ ~~~~]\"],\"node.cabinet.panel.cabinetConstructionCompartmentsAndOpeningPreview\":[\"[Çáƀîñéţ çöñšţŕûçţîöñ, çöɱþáŕţɱéñţš, áñð öþéñîñĝ þŕéṽîéŵ. ~~~~~~~~~~~~~~~]\"],\"node.cabinet.panel.cabinetPanel\":[\"[Çáƀîñéţ þáñéļ ~~~~]\"],\"node.cabinet.panel.cabinetType\":[\"[Çáƀîñéţ Ţýþé ~~~~]\"],\"node.cabinet.panel.center\":[\"[Çéñţéŕ ~~]\"],\"node.cabinet.panel.close\":[\"[Çļöšé ~~]\"],\"node.cabinet.panel.closeCabinet\":[\"[Çļöšé çáƀîñéţ ~~~~]\"],\"node.cabinet.panel.commonWallCabinetHeightsUseThe\":[\"[Çöɱɱöñ ŵáļļ-çáƀîñéţ ĥéîĝĥţš. Ûšé ţĥé šļîðéŕ ƀéļöŵ ƒöŕ á çûšţöɱ ĥéîĝĥţ. ~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.panel.compartments\":[\"[Çöɱþáŕţɱéñţš ~~~~]\"],\"node.cabinet.panel.cutout\":[\"[Çûţöûţ ~~]\"],\"node.cabinet.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.cabinet.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.cabinet.panel.editKitchenRun\":[\"[Éðîţ ķîţçĥéñ ŕûñ ~~~~~]\"],\"node.cabinet.panel.fillToCeiling\":[\"[Ƒîļļ ţö çéîļîñĝ ~~~~]\"],\"node.cabinet.panel.finish\":[\"[Ƒîñîšĥ ~~]\"],\"node.cabinet.panel.frontConstruction\":[\"[Ƒŕöñţ çöñšţŕûçţîöñ ~~~~~~]\"],\"node.cabinet.panel.handles\":[\"[Ĥáñðļéš ~~~]\"],\"node.cabinet.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.cabinet.panel.heightPreset\":[\"[Ĥéîĝĥţ þŕéšéţ ~~~~]\"],\"node.cabinet.panel.hole\":[\"[Ĥöļé ~~]\"],\"node.cabinet.panel.inset\":[\"[Îñšéţ ~~]\"],\"node.cabinet.panel.kitchen\":[\"[Ķîţçĥéñ ~~~]\"],\"node.cabinet.panel.kitchenRun\":[\"[Ķîţçĥéñ ŕûñ ~~~]\"],\"node.cabinet.panel.knob\":[\"[Ķñöƀ ~~]\"],\"node.cabinet.panel.mounting\":[\"[Ṁöûñţîñĝ ~~~]\"],\"node.cabinet.panel.none\":[\"[Ñöñé ~~]\"],\"node.cabinet.panel.open\":[\"[Öþéñ ~~]\"],\"node.cabinet.panel.openAnimation\":[\"[Öþéñ Åñîɱáţîöñ ~~~~]\"],\"node.cabinet.panel.openCabinet\":[\"[Öþéñ çáƀîñéţ ~~~~]\"],\"node.cabinet.panel.overlay\":[\"[Öṽéŕļáý ~~~]\"],\"node.cabinet.panel.panelReady\":[\"[Þáñéļ-ŕéáðý ~~~]\"],\"node.cabinet.panel.planningChecks\":[\"[Þļáññîñĝ çĥéçķš ~~~~~]\"],\"node.cabinet.panel.play\":[\"[Þļáý ~~]\"],\"node.cabinet.panel.playAnimation\":[\"[Þļáý áñîɱáţîöñ ~~~~]\"],\"node.cabinet.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.cabinet.panel.raisedArch\":[\"[Ŕáîšéð Åŕçĥ ~~~]\"],\"node.cabinet.panel.removeWallCabinet\":[\"[Ŕéɱöṽé ŵáļļ çáƀîñéţ ~~~~~~]\"],\"node.cabinet.panel.replaceWith\":[\"[Ŕéþļáçé ŵîţĥ… ~~~~]\"],\"node.cabinet.panel.revealGap\":[\"[Ŕéṽéáļ ĝáþ ~~~]\"],\"node.cabinet.panel.shaker\":[\"[Šĥáķéŕ ~~]\"],\"node.cabinet.panel.sharedCountertopPlinthAndFinishes\":[\"[Šĥáŕéð çöûñţéŕţöþ, þļîñţĥ, áñð ƒîñîšĥéš ~~~~~~~~~~]\"],\"node.cabinet.panel.slab\":[\"[Šļáƀ ~~]\"],\"node.cabinet.panel.solidMatchingFrontBetweenTheCabinet\":[\"[Šöļîð ɱáţçĥîñĝ ƒŕöñţ ƀéţŵééñ ţĥé çáƀîñéţ áñð ŵáļļ. Çöûñţéŕţöþ áñð ţöé-ķîçķ çöñţîñûé áçŕöšš ţĥîš ƒîļļéŕ. ~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.panel.standardWidth\":[\"[Šţáñðáŕð ŵîðţĥ ~~~~]\"],\"node.cabinet.panel.stop\":[\"[Šţöþ ~~]\"],\"node.cabinet.panel.stopAnimation\":[\"[Šţöþ áñîɱáţîöñ ~~~~]\"],\"node.cabinet.panel.style\":[\"[Šţýļé ~~]\"],\"node.cabinet.panel.tallCabinet\":[\"[Ţáļļ Çáƀîñéţ ~~~~]\"],\"node.cabinet.panel.top\":[\"[Ţöþ ~]\"],\"node.cabinet.panel.topCabinet\":[\"[Ţöþ Çáƀîñéţ ~~~]\"],\"node.cabinet.panel.topCeiling\":[\"[Ţöþ / Çéîļîñĝ ~~~]\"],\"node.cabinet.panel.topDepth\":[\"[Ţöþ ðéþţĥ ~~~]\"],\"node.cabinet.panel.topHeight\":[\"[Ţöþ ĥéîĝĥţ ~~~]\"],\"node.cabinet.panel.trimSoffit\":[\"[Ţŕîɱ / Šöƒƒîţ ~~~]\"],\"node.cabinet.panel.usesTheCabinetFrontStyleReveal\":[\"[Ûšéš ţĥé çáƀîñéţ ƒŕöñţ šţýļé, ŕéṽéáļ, ĥáñðļé, áñð ƒŕöñţ ɱáţéŕîáļ šéţţîñĝš ƀéļöŵ. ~~~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.panel.wallFiller\":[\"[Ŵáļļ ƒîļļéŕ ~~~]\"],\"node.cabinet.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.cabinet.preset.baseCabinet\":[\"[Ɓášé çáƀîñéţ ~~~~]\"],\"node.cabinet.preset.dishwasher\":[\"[Ðîšĥŵášĥéŕ ~~~]\"],\"node.cabinet.preset.drawerCabinet\":[\"[Ðŕáŵéŕ çáƀîñéţ ~~~~]\"],\"node.cabinet.preset.fridge\":[\"[Ƒŕîðĝé ~~]\"],\"node.cabinet.preset.gasCooktop\":[\"[Ĝáš çööķţöþ ~~~]\"],\"node.cabinet.preset.inductionCooktop\":[\"[Îñðûçţîöñ çööķţöþ ~~~~~]\"],\"node.cabinet.preset.ovenTower\":[\"[Öṽéñ Ţöŵéŕ ~~~]\"],\"node.cabinet.preset.sinkCabinet\":[\"[Šîñķ çáƀîñéţ ~~~~]\"],\"node.cabinet.preset.tallPantry\":[\"[Ţáļļ Þáñţŕý ~~~]\"],\"node.cabinet.preset.wallCabinet\":[\"[Ŵáļļ çáƀîñéţ ~~~~]\"],\"node.cabinet.runPanel.addLeft\":[\"[Åðð ļéƒţ ~~~]\"],\"node.cabinet.runPanel.addRight\":[\"[Åðð ŕîĝĥţ ~~~]\"],\"node.cabinet.runPanel.alignCabinetsHandles\":[\"[Åļîĝñ çáƀîñéţš & ĥáñðļéš ~~~~~~]\"],\"node.cabinet.runPanel.appliesDepthCarcassPlinthAndCountertop\":[\"[Åþþļîéš ðéþţĥ, çáŕçášš, þļîñţĥ, áñð çöûñţéŕţöþ ţĥîçķñéšš ţö ţĥîš ŕûñ. ~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.arrayCreate\":[\"[\",[\"count\",\"plural\",{\"one\":[\"Çŕéáţé \",[\"number\"],\" ɱöðûļé çöþý\"],\"other\":[\"Çŕéáţé \",[\"number\"],\" ɱöðûļé çöþîéš\"]}],\" ~~~~~~~~~~~]\"],\"node.cabinet.runPanel.arrayCreateNamed\":[\"[\",[\"count\",\"plural\",{\"one\":[\"Çŕéáţé \",[\"number\"],\" \",[\"name\"],\" çöþý\"],\"other\":[\"Çŕéáţé \",[\"number\"],\" \",[\"name\"],\" çöþîéš\"]}],\" ~~~~~~~]\"],\"node.cabinet.runPanel.arrayInvalidOptions\":[\"[Çĥööšé á çöþý çöûñţ ƒŕöɱ 1 ţö 20 áñð šþáçîñĝ ƒŕöɱ 0 ţö 2 ɱ ~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.arrayNoRoom\":[\"[Ţĥéŕé îš ñöţ éñöûĝĥ ŕööɱ îñ ţĥîš ŕûñ ƒöŕ ţĥé ŕéǫûéšţéð áŕŕáý ~~~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.arrayNoSource\":[\"[Çĥööšé á šţáñðáŕð öŕ áþþļîáñçé ɱöðûļé áš ţĥé šöûŕçé ~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.auto\":[\"[Åûţö ~~]\"],\"node.cabinet.runPanel.back\":[\"[Ɓáçķ ~~]\"],\"node.cabinet.runPanel.balancesStandardBaseCabinetsWhileKeeping\":[\"[Ɓáļáñçéš šţáñðáŕð ƀášé çáƀîñéţš ŵĥîļé ķééþîñĝ áþþļîáñçé áñð çöŕñéŕ-ƒîļļéŕ ŵîðţĥš ƒîẋéð. ~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.bar\":[\"[Ɓáŕ ~]\"],\"node.cabinet.runPanel.barCounter\":[\"[Ɓáŕ çöûñţéŕ ~~~]\"],\"node.cabinet.runPanel.barDepth\":[\"[Ɓáŕ ðéþţĥ ~~~]\"],\"node.cabinet.runPanel.barHeight\":[\"[Ɓáŕ ĥéîĝĥţ ~~~]\"],\"node.cabinet.runPanel.carcassHeight\":[\"[Çáŕçášš ĥéîĝĥţ ~~~~]\"],\"node.cabinet.runPanel.center\":[\"[Çéñţéŕ ~~]\"],\"node.cabinet.runPanel.commonWallCabinetHeightsUseThe\":[\"[Çöɱɱöñ ŵáļļ-çáƀîñéţ ĥéîĝĥţš. Ûšé ţĥé šļîðéŕ ƀéļöŵ ƒöŕ á çûšţöɱ ĥéîĝĥţ. ~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.copies\":[\"[Çöþîéš ~~]\"],\"node.cabinet.runPanel.copiesIncludeTheSourceCabinetStructure\":[\"[Çöþîéš îñçļûðé ţĥé šöûŕçé çáƀîñéţ šţŕûçţûŕé áñð áñý áţţáçĥéð ŵáļļ çáƀîñéţ. Éẋîšţîñĝ ɱöðûļéš šţáý ƒîẋéð; ţĥé ŕéǫûéšţéð áŕŕáý ɱûšţ ƒîţ îñ ţĥé áṽáîļáƀļé ŕûñ šþáçé. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.cornerFillersCannotBeUsedAs\":[\"[Çöŕñéŕ ƒîļļéŕš çáññöţ ƀé ûšéð áš áŕŕáý šöûŕçéš ~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.countertopDepth\":[\"[Çöûñţéŕţöþ ðéþţĥ ~~~~~]\"],\"node.cabinet.runPanel.countertopHeight\":[\"[Çöûñţéŕţöþ ĥéîĝĥţ ~~~~~]\"],\"node.cabinet.runPanel.createArray\":[\"[Çŕéáţé áŕŕáý ~~~~]\"],\"node.cabinet.runPanel.cutout\":[\"[Çûţöûţ ~~]\"],\"node.cabinet.runPanel.deleteModule\":[\"[Ðéļéţé \",[\"name\"],\" ~~]\"],\"node.cabinet.runPanel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.cabinet.runPanel.direction\":[\"[Ðîŕéçţîöñ ~~~]\"],\"node.cabinet.runPanel.duplicateAlongRun\":[\"[Ðûþļîçáţé áļöñĝ ŕûñ ~~~~~~]\"],\"node.cabinet.runPanel.equalizeAll\":[\"[Éǫûáļîžé áļļ ŕéšîžéáƀļé šţáñðáŕð ƀášé çáƀîñéţš îñ ţĥîš ŕûñ ~~~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.equalizeAlreadyEqual\":[\"[Ţĥé ŕéšîžéáƀļé çáƀîñéţ ŵîðţĥš áŕé áļŕéáðý éǫûáļ ~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.equalizeNeedsTwo\":[\"[Åţ ļéášţ ţŵö šţáñðáŕð ƀášé çáƀîñéţš áŕé ŕéǫûîŕéð ~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.equalizeNoFit\":[\"[Ţĥé áṽáîļáƀļé ŕûñ ŵîðţĥ çáññöţ šáţý ţĥé çáƀîñéţ ŵîðţĥ ļîɱîţš ~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.equalizeWidths\":[\"[Éǫûáļîžé ŵîðţĥš ~~~~~]\"],\"node.cabinet.runPanel.fillerPlanSide\":[\"[\",[\"side\",\"select\",{\"left\":[\"Ļéƒţ: \",[\"width\"],\" ɱɱ\"],\"other\":[\"Ŕîĝĥţ: \",[\"width\"],\" ɱɱ\"]}],\" ~~~~]\"],\"node.cabinet.runPanel.finishAlign\":[\"[Ƒîñîšĥ & áļîĝñ ~~~~]\"],\"node.cabinet.runPanel.finishedBack\":[\"[Ƒîñîšĥéð ƀáçķ ~~~~]\"],\"node.cabinet.runPanel.finishedExposedEnds\":[\"[Ƒîñîšĥéð éẋþöšéð éñðš ~~~~~~]\"],\"node.cabinet.runPanel.fitWallFillers\":[\"[Ƒîţ ŵáļļ ƒîļļéŕš ~~~~~]\"],\"node.cabinet.runPanel.fits50150MmGapsAt\":[\"[Ƒîţš 50–150 ɱɱ ĝáþš áţ ŕûñ éñðš ƀéšîðé þéŕþéñðîçûļáŕ ŵáļļš. ~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.fronts\":[\"[Ƒŕöñţš ~~]\"],\"node.cabinet.runPanel.handles\":[\"[Ĥáñðļéš ~~~]\"],\"node.cabinet.runPanel.heightPreset\":[\"[Ĥéîĝĥţ þŕéšéţ ~~~~]\"],\"node.cabinet.runPanel.hole\":[\"[Ĥöļé ~~]\"],\"node.cabinet.runPanel.inset\":[\"[Îñšéţ ~~]\"],\"node.cabinet.runPanel.islandBar\":[\"[Κļáñð & Ɓáŕ ~~~]\"],\"node.cabinet.runPanel.kitchenRun\":[\"[Ķîţçĥéñ ŕûñ ~~~]\"],\"node.cabinet.runPanel.knob\":[\"[Ķñöƀ ~~]\"],\"node.cabinet.runPanel.left\":[\"[Ļéƒţ ~~]\"],\"node.cabinet.runPanel.matchBaseHeightsBacksRevealsAnd\":[\"[Ṁáţçĥ ƀášé ĥéîĝĥţš, ƀáçķš, ŕéṽéáļš áñð ĥáñðļéš. Åļîĝñ ûþþéŕ çáƀîñéţš; þŕéšéŕṽé ţáļļ áþþļîáñçéš áñð çûšţöɱ çöɱþáŕţɱéñţš. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.metricProfile\":[\"[Ṁéţŕîç · 600 ɱɱ ~~~]\"],\"node.cabinet.runPanel.moduleNumber\":[\"[Ṁöðûļé \",[\"number\"],\" ~~]\"],\"node.cabinet.runPanel.modules\":[\"[Ṁöðûļéš ~~~]\"],\"node.cabinet.runPanel.mounting\":[\"[Ṁöûñţîñĝ ~~~]\"],\"node.cabinet.runPanel.noEligibleModule\":[\"[Ñö éļîĝîƀļé ɱöðûļé ~~~~~]\"],\"node.cabinet.runPanel.none\":[\"[Ñöñé ~~]\"],\"node.cabinet.runPanel.overlay\":[\"[Öṽéŕļáý ~~~]\"],\"node.cabinet.runPanel.plinthHeight\":[\"[Þļîñţĥ ĥéîĝĥţ ~~~~]\"],\"node.cabinet.runPanel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.cabinet.runPanel.raisedArch\":[\"[Ŕáîšéð Åŕçĥ ~~~]\"],\"node.cabinet.runPanel.revealGap\":[\"[Ŕéṽéáļ ĝáþ ~~~]\"],\"node.cabinet.runPanel.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.cabinet.runPanel.seatingOverhang\":[\"[Šéáţîñĝ öṽéŕĥáñĝ ~~~~~]\"],\"node.cabinet.runPanel.shaker\":[\"[Šĥáķéŕ ~~]\"],\"node.cabinet.runPanel.sharedPlinthCountertop\":[\"[Šĥáŕéð Þļîñţĥ & Çöûñţéŕţöþ ~~~~~~~]\"],\"node.cabinet.runPanel.showCountertop\":[\"[Šĥöŵ çöûñţéŕţöþ ~~~~~]\"],\"node.cabinet.runPanel.showPlinth\":[\"[Šĥöŵ þļîñţĥ ~~~]\"],\"node.cabinet.runPanel.slab\":[\"[Šļáƀ ~~]\"],\"node.cabinet.runPanel.sourceModule\":[\"[Šöûŕçé ɱöðûļé ~~~~]\"],\"node.cabinet.runPanel.spacing\":[\"[Šþáçîñĝ ~~~]\"],\"node.cabinet.runPanel.standardDimensions\":[\"[Šţáñðáŕð ðîɱéñšîöñš ~~~~~~]\"],\"node.cabinet.runPanel.style\":[\"[Šţýļé ~~]\"],\"node.cabinet.runPanel.summaryCompartment\":[\"[\",[\"type\",\"select\",{\"shelf\":[\"Šĥéļƒ\"],\"drawer\":[\"Ðŕáŵéŕ\"],\"door\":[\"Ðööŕ\"],\"oven\":[\"Öṽéñ\"],\"microwave\":[\"Ṁîçŕöŵáṽé\"],\"dishwasher\":[\"Ðîšĥŵášĥéŕ\"],\"sink\":[\"Šîñķ\"],\"cooktop_gas\":[\"Ĝáš çööķţöþ\"],\"cooktop_induction\":[\"Îñðûçţîöñ çööķţöþ\"],\"pull_out_pantry\":[\"Þûļļ-öûţ þáñţŕý\"],\"fridge_single\":[\"Ƒŕîðĝé\"],\"fridge_double\":[\"Ðöûƀļé ƒŕîðĝé\"],\"fridge_top_freezer\":[\"Ţöþ-ƒŕééžéŕ ƒŕîðĝé\"],\"fridge_bottom_freezer\":[\"Ɓöţţöɱ-ƒŕééžéŕ ƒŕîðĝé\"],\"hood_pyramid\":[\"Þýŕáɱîð ĥööð\"],\"hood_curved_glass\":[\"Çûŕṽéð ĝļášš ĥööð\"],\"other\":[[\"raw\"]]}],\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.cabinet.runPanel.summaryCompartments\":[\"[\",[\"count\",\"plural\",{\"one\":[[\"number\"],\" çöɱþáŕţɱéñţ\"],\"other\":[[\"number\"],\" çöɱþáŕţɱéñţš\"]}],\" ~~~~~~~]\"],\"node.cabinet.runPanel.summaryEmpty\":[\"[Éɱþţý ~~]\"],\"node.cabinet.runPanel.summaryTall\":[\"[Ţáļļ çáƀîñéţ ~~~~]\"],\"node.cabinet.runPanel.top\":[\"[Ţöþ ~]\"],\"node.cabinet.runPanel.unableToFinish\":[\"[Ûñáƀļé ţö ƒîñîšĥ ţĥîš ķîţçĥéñ ŕûñ. ~~~~~~~~~]\"],\"node.cabinet.runPanel.usProfile\":[\"[ÛŠ · 24 îñ ~~]\"],\"node.cabinet.runPanel.useAsArraySource\":[\"[Ûšé \",[\"name\"],\" áš áŕŕáý šöûŕçé ~~~~~]\"],\"node.cabinet.runPanel.useThisModuleAsTheArray\":[\"[Ûšé ţĥîš ɱöðûļé áš ţĥé áŕŕáý šöûŕçé ~~~~~~~~~]\"],\"node.cabinet.runPanel.waterfallEnds\":[\"[Ŵáţéŕƒáļļ éñðš ~~~~]\"],\"node.cabinetModule.description\":[\"[Åñ éðîţáƀļé ɱöðûļé îñšîðé á ɱöðûļáŕ çáƀîñéţ ŕûñ. ~~~~~~~~~~~~]\"],\"node.cabinetModule.label\":[\"[Çáƀîñéţ Ṁöðûļé ~~~~]\"],\"node.ceiling.buildUpSection.bottomChord\":[\"[Ɓöţţöɱ çĥöŕð ~~~~]\"],\"node.ceiling.buildUpSection.ceilingJoists\":[\"[Çéîļîñĝ ĵöîšţš ~~~~]\"],\"node.ceiling.buildUpSection.decking\":[\"[Ðéçķîñĝ ~~~]\"],\"node.ceiling.buildUpSection.finish\":[\"[Ƒîñîšĥ ~~]\"],\"node.ceiling.buildUpSection.framing\":[\"[Ƒŕáɱîñĝ ~~~]\"],\"node.ceiling.buildUpSection.joists\":[\"[Ĵöîšţš ~~]\"],\"node.ceiling.buildUpSection.layers\":[\"[Ļáýéŕš ~~]\"],\"node.ceiling.buildUpSection.none\":[\"[Ñöñé ~~]\"],\"node.ceiling.buildUpSection.preset\":[\"[Þŕéšéţ ~~]\"],\"node.ceiling.buildUpSection.theHeightIsTheFinishedUnderside\":[\"[Ţĥé ĥéîĝĥţ îš ţĥé ƒîñîšĥéð ûñðéŕšîðé; ţĥé ļáýéŕš ŕîšé ƒŕöɱ îţ. ~~~~~~~~~~~~~~~]\"],\"node.ceiling.buildUpSection.thickness\":[\"[Ţĥîçķñéšš ~~~]\"],\"node.ceiling.buildUpSection.trussBottomChords\":[\"[Ţŕûšš ƀöţţöɱ çĥöŕðš ~~~~~~]\"],\"node.ceiling.description\":[\"[Å þöļýĝöñ-ƀöûñðéð çéîļîñĝ šûŕƒáçé ţĥáţ ĥöšţš çéîļîñĝ-ɱöûñţéð îţéɱš. ~~~~~~~~~~~~~~~~~~]\"],\"node.ceiling.label\":[\"[Çéîļîñĝ ~~~]\"],\"node.ceiling.panel.addHole\":[\"[Åðð Ĥöļé ~~~]\"],\"node.ceiling.panel.area\":[\"[Åŕéá ~~]\"],\"node.ceiling.panel.auto\":[\"[Åûţö ~~]\"],\"node.ceiling.panel.ceiling\":[\"[Çéîļîñĝ ~~~]\"],\"node.ceiling.panel.customHeight\":[\"[Çûšţöɱ ĥéîĝĥţ ~~~~]\"],\"node.ceiling.panel.cutOpening\":[\"[Çûţ öþéñîñĝ ~~~]\"],\"node.ceiling.panel.done\":[\"[Ðöñé ~~]\"],\"node.ceiling.panel.followsLevel\":[\"[Ƒöļļöŵš ļéṽéļ ~~~~]\"],\"node.ceiling.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.ceiling.panel.high30m\":[\"[Ĥîĝĥ (3.0ɱ) ~~]\"],\"node.ceiling.panel.high90\":[\"[Ĥîĝĥ (9'0\\\") ~~]\"],\"node.ceiling.panel.holes\":[\"[Ĥöļéš ~~]\"],\"node.ceiling.panel.info\":[\"[Îñƒö ~~]\"],\"node.ceiling.panel.limitedByLevel\":[\"[Ļîɱîţéð ƀý ţĥé ļéṽéļ ţö \",[\"height\"],\" — ŕáîšé ţĥé ļéṽéļ ĥéîĝĥţ ƒöŕ á ţáļļéŕ çéîļîñĝ. ~~~~~~~~~~~~~~~~~]\"],\"node.ceiling.panel.low24m\":[\"[Ļöŵ (2.4ɱ) ~~]\"],\"node.ceiling.panel.low80\":[\"[Ļöŵ (8'0\\\") ~]\"],\"node.ceiling.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.ceiling.panel.noHoles\":[\"[Ñö ĥöļéš ~~~]\"],\"node.ceiling.panel.standard25m\":[\"[Šţáñðáŕð (2.5ɱ) ~~~]\"],\"node.ceiling.panel.standard86\":[\"[Šţáñðáŕð (8'6\\\") ~~~]\"],\"node.ceiling.panel.tallerThanLevel\":[\"[Ţáļļéŕ ţĥáñ ţĥîš ļéṽéļ (\",[\"available\"],\" áṽáîļáƀļé). Ŕáîšé ţĥé ļéṽéļ ĥéîĝĥţ ƒîŕšţ. ~~~~~~~~~~~~~~~~]\"],\"node.chimney.description\":[\"[Ṽéŕţîçáļ ɱášöñŕý šţáçķ öñ á ŕööƒ šéĝɱéñţ. ~~~~~~~~~~~]\"],\"node.chimney.label\":[\"[Çĥîɱñéý ~~~]\"],\"node.chimney.panel.aboveRidge\":[\"[Åƀöṽé Ŕîðĝé ~~~]\"],\"node.chimney.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.chimney.panel.back\":[\"[Ɓáçķ ~~]\"],\"node.chimney.panel.bands\":[\"[Ɓáñðš ~~]\"],\"node.chimney.panel.cap\":[\"[Çáþ ~]\"],\"node.chimney.panel.chimney\":[\"[Çĥîɱñéý ~~~]\"],\"node.chimney.panel.chimneyType\":[\"[Çĥîɱñéý Ţýþé ~~~~]\"],\"node.chimney.panel.corbeled\":[\"[Çöŕƀéļéð ~~~]\"],\"node.chimney.panel.cornerBevel\":[\"[Çöŕñéŕ Ɓéṽéļ ~~~~]\"],\"node.chimney.panel.count\":[\"[Çöûñţ ~~]\"],\"node.chimney.panel.cricket\":[\"[Çŕîçķéţ ~~~]\"],\"node.chimney.panel.cutoutOffset\":[\"[Çûţöûţ Öƒƒšéţ ~~~~]\"],\"node.chimney.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.chimney.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.chimney.panel.diameter\":[\"[Ðîáɱéţéŕ ~~~]\"],\"node.chimney.panel.double\":[\"[Ðöûƀļé ~~]\"],\"node.chimney.panel.extent\":[\"[Éẋţéñţ ~~]\"],\"node.chimney.panel.flat\":[\"[Ƒļáţ ~~]\"],\"node.chimney.panel.flues\":[\"[Ƒļûéš ~~]\"],\"node.chimney.panel.footprint\":[\"[Ƒööţþŕîñţ ~~~]\"],\"node.chimney.panel.front\":[\"[Ƒŕöñţ ~~]\"],\"node.chimney.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.chimney.panel.hollowDepth\":[\"[Ĥöļļöŵ Ðéþţĥ ~~~~]\"],\"node.chimney.panel.length\":[\"[Ļéñĝţĥ ~~]\"],\"node.chimney.panel.none\":[\"[Ñöñé ~~]\"],\"node.chimney.panel.offset\":[\"[Öƒƒšéţ ~~]\"],\"node.chimney.panel.overhang\":[\"[Öṽéŕĥáñĝ ~~~]\"],\"node.chimney.panel.panels\":[\"[Þáñéļš ~~]\"],\"node.chimney.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.chimney.panel.rectangular\":[\"[Ŕéçţáñĝûļáŕ ~~~~]\"],\"node.chimney.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.chimney.panel.round\":[\"[Ŕöûñð ~~]\"],\"node.chimney.panel.shoulder\":[\"[Šĥöûļðéŕ ~~~]\"],\"node.chimney.panel.sideMargin\":[\"[Šîðé Ṁáŕĝîñ ~~~]\"],\"node.chimney.panel.simple\":[\"[Šîɱþļé ~~]\"],\"node.chimney.panel.single\":[\"[Šîñĝļé ~~]\"],\"node.chimney.panel.sloped\":[\"[Šļöþéð ~~]\"],\"node.chimney.panel.spacing\":[\"[Šþáçîñĝ ~~~]\"],\"node.chimney.panel.square\":[\"[Šǫûáŕé ~~]\"],\"node.chimney.panel.stepped\":[\"[Šţéþþéð ~~~]\"],\"node.chimney.panel.style\":[\"[Šţýļé ~~]\"],\"node.chimney.panel.tapered\":[\"[Ţáþéŕéð ~~~]\"],\"node.chimney.panel.thickness\":[\"[Ţĥîçķñéšš ~~~]\"],\"node.chimney.panel.topOffset\":[\"[Ţöþ Öƒƒšéţ ~~~]\"],\"node.chimney.panel.wallThickness\":[\"[Ŵáļļ Ţĥîçķñéšš ~~~~]\"],\"node.chimney.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.chimney.preset.brick\":[\"[Ɓŕîçķ ~~]\"],\"node.chimney.preset.modern\":[\"[Ṁöðéŕñ ~~]\"],\"node.chimney.preset.round\":[\"[Ŕöûñð ~~]\"],\"node.column.description\":[\"[Å þáŕáɱéţŕîç çöļûɱñ ŵîţĥ çöñƒîĝûŕáƀļé çŕöšš-šéçţîöñ, ƀášé, áñð çáþîţáļ. ~~~~~~~~~~~~~~~~~~]\"],\"node.column.label\":[\"[Çöļûɱñ ~~]\"],\"node.column.panel.aFrame\":[\"[Å-Ƒŕáɱé ~~]\"],\"node.column.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.column.panel.applyPreset\":[\"[Åþþļý þŕéšéţ... ~~~~]\"],\"node.column.panel.applyProportion\":[\"[Åþþļý þŕöþöŕţîöñ... ~~~~~]\"],\"node.column.panel.bottomDepth\":[\"[Ɓöţţöɱ Ðéþţĥ ~~~~]\"],\"node.column.panel.bottomHeight\":[\"[Ɓöţţöɱ Ĥéîĝĥţ ~~~~]\"],\"node.column.panel.bottomSpread\":[\"[Ɓöţţöɱ Šþŕéáð ~~~~]\"],\"node.column.panel.bottomStepSpread\":[\"[Ɓöţţöɱ Šţéþ Šþŕéáð ~~~~~]\"],\"node.column.panel.bottomTiers\":[\"[Ɓöţţöɱ Ţîéŕš ~~~~]\"],\"node.column.panel.bottomWidth\":[\"[Ɓöţţöɱ Ŵîðţĥ ~~~~]\"],\"node.column.panel.boxFrame\":[\"[Ɓöẋ Ƒŕáɱé ~~~]\"],\"node.column.panel.braceDepth\":[\"[Ɓŕáçé Ðéþţĥ ~~~]\"],\"node.column.panel.braceWidth\":[\"[Ɓŕáçé Ŵîðţĥ ~~~]\"],\"node.column.panel.bulge\":[\"[Ɓûļĝé ~~]\"],\"node.column.panel.bulged\":[\"[Ɓûļĝéð ~~]\"],\"node.column.panel.column\":[\"[Çöļûɱñ ~~]\"],\"node.column.panel.connectorPlates\":[\"[Çöññéçţöŕ Þļáţéš ~~~~~]\"],\"node.column.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.column.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.column.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.column.panel.edgeSoftness\":[\"[Éðĝé Šöƒţñéšš ~~~~]\"],\"node.column.panel.endWidth\":[\"[Éñð Ŵîðţĥ ~~~]\"],\"node.column.panel.ends\":[\"[Éñðš ~~]\"],\"node.column.panel.forkSpread\":[\"[Ƒöŕķ Šþŕéáð ~~~]\"],\"node.column.panel.heavy\":[\"[Ĥéáṽý ~~]\"],\"node.column.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.column.panel.heightAndFootprintAreControlledBy\":[\"[Ĥéîĝĥţ áñð ƒööţþŕîñţ áŕé çöñţŕöļļéð ƀý ţĥé ļéáñ-ţö éẋţéñšîöñ. Ŕöţáţé öŕ çĥáñĝé ţĥé šûþþöŕţ šţýļé ĥéŕé; ŕéšîžé ƒŕöɱ ţĥé þáŕéñţ ļéáñ-ţö. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.column.panel.hourglass\":[\"[Ĥöûŕĝļášš ~~~]\"],\"node.column.panel.kBrace\":[\"[Ķ Ɓŕáçé ~~]\"],\"node.column.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.column.panel.neckWidth\":[\"[Ñéçķ Ŵîðţĥ ~~~]\"],\"node.column.panel.noBottom\":[\"[Ñö Ɓöţţöɱ ~~~]\"],\"node.column.panel.noTop\":[\"[Ñö Ţöþ ~~]\"],\"node.column.panel.plinthThickness\":[\"[Þļîñţĥ Ţĥîçķñéšš ~~~~~]\"],\"node.column.panel.portalFrame\":[\"[Þöŕţáļ Ƒŕáɱé ~~~~]\"],\"node.column.panel.preset\":[\"[Þŕéšéţ ~~]\"],\"node.column.panel.rectangular\":[\"[Ŕéçţáñĝûļáŕ ~~~~]\"],\"node.column.panel.ringPairs\":[\"[Ŕîñĝ Þáîŕš ~~~]\"],\"node.column.panel.ringSpread\":[\"[Ŕîñĝ Šþŕéáð ~~~]\"],\"node.column.panel.ringThickness\":[\"[Ŕîñĝ Ţĥîçķñéšš ~~~~]\"],\"node.column.panel.round\":[\"[Ŕöûñð ~~]\"],\"node.column.panel.roundBandWidth\":[\"[Ŕöûñð Ɓáñð Ŵîðţĥ ~~~~~]\"],\"node.column.panel.roundedBottom\":[\"[Ŕöûñðéð Ɓöţţöɱ ~~~~]\"],\"node.column.panel.roundedTop\":[\"[Ŕöûñðéð Ţöþ ~~~]\"],\"node.column.panel.segmentTwist\":[\"[Šéĝɱéñţ Ţŵîšţ ~~~~]\"],\"node.column.panel.shaft\":[\"[Šĥáƒţ ~~]\"],\"node.column.panel.shaftCornerRadius\":[\"[Šĥáƒţ Çöŕñéŕ Ŕáðîûš ~~~~~~]\"],\"node.column.panel.shaftWidth\":[\"[Šĥáƒţ Ŵîðţĥ ~~~]\"],\"node.column.panel.shape\":[\"[Šĥáþé ~~]\"],\"node.column.panel.shortStout\":[\"[Šĥöŕţ / Šţöûţ ~~~]\"],\"node.column.panel.simpleBlockBottom\":[\"[Šîɱþļé Ɓļöçķ Ɓöţţöɱ ~~~~~~]\"],\"node.column.panel.simpleTop\":[\"[Šîɱþļé Ţöþ ~~~]\"],\"node.column.panel.singleStrut\":[\"[Šîñĝļé Šţŕûţ ~~~~]\"],\"node.column.panel.slender\":[\"[Šļéñðéŕ ~~~]\"],\"node.column.panel.square\":[\"[Šǫûáŕé ~~]\"],\"node.column.panel.squarePlinthBottom\":[\"[Šǫûáŕé Þļîñţĥ Ɓöţţöɱ ~~~~~~]\"],\"node.column.panel.standard\":[\"[Šţáñðáŕð ~~~]\"],\"node.column.panel.steppedBottom\":[\"[Šţéþþéð Ɓöţţöɱ ~~~~]\"],\"node.column.panel.steppedTop\":[\"[Šţéþþéð Ţöþ ~~~]\"],\"node.column.panel.straight\":[\"[Šţŕáîĝĥţ ~~~]\"],\"node.column.panel.taper\":[\"[Ţáþéŕ ~~]\"],\"node.column.panel.tapered\":[\"[Ţáþéŕéð ~~~]\"],\"node.column.panel.topDepth\":[\"[Ţöþ Ðéþţĥ ~~~]\"],\"node.column.panel.topHeight\":[\"[Ţöþ Ĥéîĝĥţ ~~~]\"],\"node.column.panel.topSpread\":[\"[Ţöþ Šþŕéáð ~~~]\"],\"node.column.panel.topStepSpread\":[\"[Ţöþ Šţéþ Šþŕéáð ~~~~]\"],\"node.column.panel.topTiers\":[\"[Ţöþ Ţîéŕš ~~~]\"],\"node.column.panel.topWidth\":[\"[Ţöþ Ŵîðţĥ ~~~]\"],\"node.column.panel.transform\":[\"[Ţŕáñšƒöŕɱ ~~~]\"],\"node.column.panel.trestle\":[\"[Ţŕéšţļé ~~~]\"],\"node.column.panel.tripod\":[\"[Ţŕîþöð ~~]\"],\"node.column.panel.twistSegments\":[\"[Ţŵîšţ Šéĝɱéñţš ~~~~]\"],\"node.column.panel.vSupport\":[\"[Ṽ Šûþþöŕţ ~~~]\"],\"node.column.panel.vertical\":[\"[Ṽéŕţîçáļ ~~~]\"],\"node.column.panel.waist\":[\"[Ŵáîšţ ~~]\"],\"node.column.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.column.panel.xBrace\":[\"[Ẋ Ɓŕáçé ~~]\"],\"node.column.panel.ySupport\":[\"[Ý Šûþþöŕţ ~~~]\"],\"node.column.panel.yaw\":[\"[Ýáŵ ~]\"],\"node.column.postSection.aSizeDeckPostStandsNo\":[\"[Å \",[\"size\"],\" ðéçķ þöšţ šţáñðš ñö ţáļļéŕ ţĥáñ \",[\"limit\"],\" (ÎŔÇ Ţáƀļé Ŕ507.4, ƀý šþéçîéš áñð ţĥé áŕéá îţ çáŕŕîéš): çĥéçķ îţ, öŕ ûšé ţĥé ñéẋţ šîžé ûþ. ~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.column.postSection.custom\":[\"[Çûšţöɱ ~~]\"],\"node.column.postSection.fitToTheBeamOverIt\":[\"[Ƒîţ ţö ţĥé ƀéáɱ öṽéŕ îţ (\",[\"height\"],\") ~~~~~~]\"],\"node.column.postSection.fitToTheCeilingPlane\":[\"[Ƒîţ ţö ţĥé çéîļîñĝ þļáñé (\",[\"height\"],\") ~~~~~~]\"],\"node.column.postSection.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.column.postSection.keepItsShapeAndStyleIt\":[\"[Ķééþ îţš šĥáþé áñð šţýļé îţ áš á çöļûɱñ ~~~~~~~~~~]\"],\"node.column.postSection.makeItAColumn\":[\"[Ṁáķé îţ á çöļûɱñ ~~~~]\"],\"node.column.postSection.post\":[\"[Þöšţ ~~]\"],\"node.column.postSection.treated\":[\"[Ţŕéáţéð ~~~]\"],\"node.column.postSection.untreated\":[\"[Ûñţŕéáţéð ~~~]\"],\"node.column.preset.aFrameSupport\":[\"[Å-Ƒŕáɱé Šûþþöŕţ ~~~~]\"],\"node.column.preset.basicPillar\":[\"[Šţŕáîĝĥţ Ŕöûñð ~~~~]\"],\"node.column.preset.boxFrameSupport\":[\"[Ɓöẋ Ƒŕáɱé ~~~]\"],\"node.column.preset.bulgedPillar\":[\"[Šöƒţ Ɓûļĝéð ~~~]\"],\"node.column.preset.hourglassPillar\":[\"[Ĥöûŕĝļášš ~~~]\"],\"node.column.preset.kBraceSupport\":[\"[Ķ Ɓŕáçé ~~]\"],\"node.column.preset.portalFrameSupport\":[\"[Þöŕţáļ Ƒŕáɱé ~~~~]\"],\"node.column.preset.singleStrutSupport\":[\"[Šîñĝļé Šţŕûţ ~~~~]\"],\"node.column.preset.squarePillar\":[\"[Šǫûáŕé Ɓļöçķ ~~~~]\"],\"node.column.preset.taperedPillar\":[\"[Ţáþéŕéð Ŕöûñð ~~~~]\"],\"node.column.preset.trestleSupport\":[\"[Ţŕéšţļé Ƒŕáɱé ~~~~]\"],\"node.column.preset.tripodSupport\":[\"[Ţŕîþöð Šûþþöŕţ ~~~~]\"],\"node.column.preset.vFrameSupport\":[\"[Ṽ Šûþþöŕţ ~~~]\"],\"node.column.preset.xBraceSupport\":[\"[Ẋ Ɓŕáçé ~~]\"],\"node.column.preset.yFrameSupport\":[\"[Ý Šûþþöŕţ ~~~]\"],\"node.constructionDimension.description\":[\"[Åššöçîáţîṽé ļîñéáŕ, çûŕṽéð, çîŕçûļáŕ, áñĝûļáŕ, öŕ çööŕðîñáţé þļáñ ðîɱéñšîöñ. ~~~~~~~~~~~~~~~~~~~]\"],\"node.constructionDimension.label\":[\"[Çöñšţŕûçţîöñ Ðîɱéñšîöñ ~~~~~~~]\"],\"node.cornerRadius.bottomLeft\":[\"[Ɓöţţöɱ Ļéƒţ ~~~]\"],\"node.cornerRadius.bottomRight\":[\"[Ɓöţţöɱ Ŕîĝĥţ ~~~~]\"],\"node.cornerRadius.topLeft\":[\"[Ţöþ Ļéƒţ ~~~]\"],\"node.cornerRadius.topRight\":[\"[Ţöþ Ŕîĝĥţ ~~~]\"],\"node.cupola.description\":[\"[Ļöûṽéŕéð ŕööƒ ļáñţéŕñ ŵîţĥ á ðöɱé öŕ þýŕáɱîð çáþ áñð öþţîöñáļ ƒîñîáļ. ~~~~~~~~~~~~~~~~~~]\"],\"node.cupola.label\":[\"[Çûþöļá ~~]\"],\"node.cupola.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.cupola.panel.cupola\":[\"[Çûþöļá ~~]\"],\"node.cupola.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.cupola.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.cupola.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.cupola.panel.dome\":[\"[Ðöɱé ~~]\"],\"node.cupola.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.cupola.panel.finial\":[\"[Ƒîñîáļ ~~]\"],\"node.cupola.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.cupola.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.cupola.panel.noFinial\":[\"[Ñö Ƒîñîáļ ~~~]\"],\"node.cupola.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.cupola.panel.pyramid\":[\"[Þýŕáɱîð ~~~]\"],\"node.cupola.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.cupola.panel.style\":[\"[Šţýļé ~~]\"],\"node.cupola.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.cutout.autoElevator\":[\"[Åûţö éļéṽáţöŕ çûţöûţ ~~~~~~]\"],\"node.cutout.autoStair\":[\"[Åûţö šţáîŕ çûţöûţ ~~~~~]\"],\"node.cutout.opening\":[\"[Öþéñîñĝ ~~~]\"],\"node.cutout.room\":[\"[Ŕööɱ çûţöûţ ~~~]\"],\"node.door.actions.swapHingeSide\":[\"[Šŵáþ ĥîñĝé šîðé ~~~~]\"],\"node.door.actions.swapSwingSide\":[\"[Šŵáþ šŵîñĝ šîðé ~~~~]\"],\"node.door.description\":[\"[Å ðööŕ çûţ îñţö á ŵáļļ. Åñîɱáţéð öþéñ/çļöšé šţáţé. ~~~~~~~~~~~~]\"],\"node.door.label\":[\"[Ðööŕ ~~]\"],\"node.door.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.door.panel.addSegment\":[\"[+ Åðð Šéĝɱéñţ ~~~]\"],\"node.door.panel.all\":[\"[Åļļ ~]\"],\"node.door.panel.arch\":[\"[Åŕçĥ ~~]\"],\"node.door.panel.archHeight\":[\"[Åŕçĥ Ĥéîĝĥţ ~~~]\"],\"node.door.panel.auto\":[\"[Åûţö ~~]\"],\"node.door.panel.autoFollowsTheWall\":[\"[Åûţö ƒöļļöŵš ţĥé ŵáļļ ~~~~~~]\"],\"node.door.panel.barHeight\":[\"[Ɓáŕ Ĥéîĝĥţ ~~~]\"],\"node.door.panel.columns\":[\"[Çöļûɱñš ~~~]\"],\"node.door.panel.contentPadding\":[\"[Çöñţéñţ Þáððîñĝ ~~~~~]\"],\"node.door.panel.cornerRadius\":[\"[Çöŕñéŕ Ŕáðîûš ~~~~]\"],\"node.door.panel.customTheSegmentsMatchNoStyle\":[\"[Çûšţöɱ: ţĥé šéĝɱéñţš ɱáţçĥ ñö šţýļé. ~~~~~~~~~]\"],\"node.door.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.door.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.door.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.door.panel.direction\":[\"[Ðîŕéçţîöñ ~~~]\"],\"node.door.panel.divider\":[\"[Ðîṽîðéŕ ~~~]\"],\"node.door.panel.door\":[\"[Ðööŕ ~~]\"],\"node.door.panel.doorCloser\":[\"[Ðööŕ Çļöšéŕ ~~~]\"],\"node.door.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.door.panel.empty\":[\"[Éɱþţý ~~]\"],\"node.door.panel.enableHandle\":[\"[Éñáƀļé Ĥáñðļé ~~~~]\"],\"node.door.panel.enableThreshold\":[\"[Éñáƀļé Ţĥŕéšĥöļð ~~~~~]\"],\"node.door.panel.flipSide\":[\"[Ƒļîþ Šîðé ~~~]\"],\"node.door.panel.fold\":[\"[Ƒöļð ~~]\"],\"node.door.panel.frame\":[\"[Ƒŕáɱé ~~]\"],\"node.door.panel.frameDepthAuto\":[\"[Ðéþţĥ (áûţö) ~~~]\"],\"node.door.panel.garage\":[\"[Ĝáŕáĝé ~~]\"],\"node.door.panel.glass\":[\"[Ĝļášš ~~]\"],\"node.door.panel.handle\":[\"[Ĥáñðļé ~~]\"],\"node.door.panel.handleSide\":[\"[Ĥáñðļé Šîðé ~~~]\"],\"node.door.panel.hardware\":[\"[Ĥáŕðŵáŕé ~~~]\"],\"node.door.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.door.panel.hingesSide\":[\"[Ĥîñĝéš Šîðé ~~~]\"],\"node.door.panel.horizontal\":[\"[Ĥöŕîžöñţáļ ~~~]\"],\"node.door.panel.individual\":[\"[Îñðîṽîðûáļ ~~~]\"],\"node.door.panel.inset\":[\"[Îñšéţ ~~]\"],\"node.door.panel.inward\":[\"[Îñŵáŕð ~~]\"],\"node.door.panel.left\":[\"[Ļéƒţ ~~]\"],\"node.door.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.door.panel.open\":[\"[Öþéñ ~~]\"],\"node.door.panel.opening\":[\"[Öþéñîñĝ ~~~]\"],\"node.door.panel.openingShape\":[\"[Öþéñîñĝ Šĥáþé ~~~~]\"],\"node.door.panel.outward\":[\"[Öûţŵáŕð ~~~]\"],\"node.door.panel.panel\":[\"[Þáñéļ ~~]\"],\"node.door.panel.panels\":[\"[Þáñéļš ~~]\"],\"node.door.panel.panicBar\":[\"[Þáñîç Ɓáŕ ~~~]\"],\"node.door.panel.pocket\":[\"[Þöçķéţ ~~]\"],\"node.door.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.door.panel.rail\":[\"[Ŕáîļ ~~]\"],\"node.door.panel.rect\":[\"[Ŕéçţ ~~]\"],\"node.door.panel.remove\":[\"[- Ŕéɱöṽé ~~]\"],\"node.door.panel.revealRadius\":[\"[Ŕéṽéáļ Ŕáðîûš ~~~~]\"],\"node.door.panel.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.door.panel.rounded\":[\"[Ŕöûñðéð ~~~]\"],\"node.door.panel.segments\":[\"[Šéĝɱéñţš ~~~]\"],\"node.door.panel.sizeIsLimitedToTheWall\":[\"[Šîžé îš ļîɱîţéð ţö ţĥé ŵáļļ, îñçļûðîñĝ çļéáŕáñçé ƒöŕ ţĥé öþéñîñĝ ƒŕáɱé. ~~~~~~~~~~~~~~~~~~]\"],\"node.door.panel.slide\":[\"[Šļîðé ~~]\"],\"node.door.panel.style\":[\"[Šţýļé ~~]\"],\"node.door.panel.swing\":[\"[Šŵîñĝ ~~]\"],\"node.door.panel.thickness\":[\"[Ţĥîçķñéšš ~~~]\"],\"node.door.panel.threshold\":[\"[Ţĥŕéšĥöļð ~~~]\"],\"node.door.panel.topShape\":[\"[Ţöþ Šĥáþé ~~~]\"],\"node.door.panel.type\":[\"[Ţýþé ~~]\"],\"node.door.panel.vertical\":[\"[Ṽéŕţîçáļ ~~~]\"],\"node.door.panel.wall\":[\"[ŵáļļ ~~]\"],\"node.door.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.door.style.barn\":[\"[Ɓáŕñ ~~]\"],\"node.door.style.craftsman\":[\"[Çŕáƒţšɱáñ ~~~]\"],\"node.door.style.french\":[\"[Ƒŕéñçĥ ~~]\"],\"node.door.style.glass\":[\"[Ĝļášš ~~]\"],\"node.door.style.halfLouvered\":[\"[Ĥáļƒ-ļöûṽéŕéð ~~~~]\"],\"node.door.style.modern\":[\"[Ṁöðéŕñ ~~]\"],\"node.door.style.panel\":[\"[Þáñéļ ~~]\"],\"node.door.style.paneledGlass\":[\"[Þáñéļéð ĝļášš ~~~~]\"],\"node.door.style.shaker\":[\"[Šĥáķéŕ ~~]\"],\"node.door.style.sixPanel\":[\"[Šîẋ-þáñéļ ~~~]\"],\"node.door.type.barn\":[\"[Ɓáŕñ ~~]\"],\"node.door.type.double\":[\"[Ðöûƀļé ~~]\"],\"node.door.type.folding\":[\"[Ƒöļðîñĝ ~~~]\"],\"node.door.type.french\":[\"[Ƒŕéñçĥ ~~]\"],\"node.door.type.garageRollup\":[\"[Ŕöļļ-ûþ ~~]\"],\"node.door.type.garageSectional\":[\"[Šéçţîöñáļ ~~~]\"],\"node.door.type.garageTiltup\":[\"[Ţîļţ-ûþ ~~]\"],\"node.door.type.hinged\":[\"[Ĥîñĝéð ~~]\"],\"node.door.type.pocket\":[\"[Þöçķéţ ~~]\"],\"node.door.type.sliding\":[\"[Šļîðîñĝ ~~~]\"],\"node.dormer.description\":[\"[Ĥöûšé-šĥáþéð þŕöţŕûšîöñ öñ á ŕööƒ šéĝɱéñţ. ~~~~~~~~~~~]\"],\"node.dormer.label\":[\"[Ðöŕɱéŕ ~~]\"],\"node.dormer.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.dormer.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.dormer.panel.dormer\":[\"[Ðöŕɱéŕ ~~]\"],\"node.dormer.panel.dutch\":[\"[Ðûţçĥ ~~]\"],\"node.dormer.panel.flat\":[\"[Ƒļáţ ~~]\"],\"node.dormer.panel.gable\":[\"[Ĝáƀļé ~~]\"],\"node.dormer.panel.gambrel\":[\"[Ĝáɱƀŕéļ ~~~]\"],\"node.dormer.panel.hip\":[\"[Ĥîþ ~]\"],\"node.dormer.panel.mansard\":[\"[Ṁáñšáŕð ~~~]\"],\"node.dormer.panel.pitchDirection\":[\"[Þîţçĥ Ðîŕéçţîöñ ~~~~~]\"],\"node.dormer.panel.pitchRise\":[\"[Þîţçĥ Ŕîšé ~~~]\"],\"node.dormer.panel.riseBack\":[\"[Ŕîšé Ɓáçķ ~~~]\"],\"node.dormer.panel.riseFront\":[\"[Ŕîšé Ƒŕöñţ ~~~]\"],\"node.dormer.panel.roofHeight\":[\"[Ŕööƒ Ĥéîĝĥţ ~~~]\"],\"node.dormer.panel.roofType\":[\"[Ŕööƒ Ţýþé ~~~]\"],\"node.dormer.panel.section\":[\"[Šéçţîöñ ~~~]\"],\"node.dormer.panel.shed\":[\"[Šĥéð ~~]\"],\"node.dormer.panel.wallHeight\":[\"[Ŵáļļ Ĥéîĝĥţ ~~~]\"],\"node.dormer.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.dormer.panel.windows\":[\"[Ŵîñðöŵš ~~~]\"],\"node.dormer.panelActionsSection.actions\":[\"[Åçţîöñš ~~~]\"],\"node.dormer.panelActionsSection.delete\":[\"[Ðéļéţé ~~]\"],\"node.dormer.panelActionsSection.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.dormer.panelActionsSection.move\":[\"[Ṁöṽé ~~]\"],\"node.dormer.panelPositionSection.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.dormer.panelPositionSection.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.dormer.panelWindowsSection.addWindow\":[\"[Åðð Ŵîñðöŵ ~~~]\"],\"node.dormer.panelWindowsSection.editNamed\":[\"[Éðîţ \",[\"name\"],\" ~~]\"],\"node.dormer.panelWindowsSection.editWindow\":[\"[Éðîţ ŵîñðöŵ ~~~]\"],\"node.dormer.panelWindowsSection.increaseTheDormerWidthToAdd\":[\"[Îñçŕéášé ţĥé ðöŕɱéŕ ŵîðţĥ ţö áðð áñöţĥéŕ ŵîñðöŵ. ~~~~~~~~~~~~]\"],\"node.dormer.panelWindowsSection.move\":[\"[Ṁöṽé ~~]\"],\"node.dormer.panelWindowsSection.moveNamed\":[\"[Ṁöṽé \",[\"name\"],\" ~~]\"],\"node.dormer.panelWindowsSection.moveWindow\":[\"[Ṁöṽé ŵîñðöŵ ~~~]\"],\"node.dormer.panelWindowsSection.noWindows\":[\"[Ñö ŵîñðöŵš ~~~]\"],\"node.dormer.panelWindowsSection.windowNumber\":[\"[Ŵîñðöŵ \",[\"number\"],\" ~~]\"],\"node.dormer.panelWindowsSection.windowSummary\":[\"[\",[\"face\",\"select\",{\"back\":[\"Ɓáçķ\"],\"left\":[\"Ļéƒţ\"],\"right\":[\"Ŕîĝĥţ\"],\"other\":[\"Ƒŕöñţ\"]}],\" · \",[\"width\"],\" × \",[\"height\"],\" ɱ ~~~~~~]\"],\"node.dormer.panelWindowsSection.windowsLength\":[\"[Ŵîñðöŵš (\",[\"length\"],\") ~~~]\"],\"node.downspout.description\":[\"[Ṽéŕţîçáļ ðŕöþ þîþé ƒŕöɱ á ĝûţţéŕ öûţļéţ ţö ţĥé ĝŕöûñð. ~~~~~~~~~~~~~~]\"],\"node.downspout.inspectorEditors.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.downspout.label\":[\"[Ðöŵñšþöûţ ~~~]\"],\"node.ductFitting.description\":[\"[Éļƀöŵ, ţéé, ŕéðûçéŕ, öŕ šǫûáŕé-ţö-ŕöûñð ţŕáñšîţîöñ çöññéçţîñĝ ðûçţ ŕûñš. ~~~~~~~~~~~~~~~~~~]\"],\"node.ductFitting.inspectorEditors.swapWH\":[\"[Šŵáþ Ŵ/Ĥ ~~]\"],\"node.ductFitting.inspectorEditors.swapWidthAndHeight\":[\"[Šŵáþ ŵîðţĥ áñð ĥéîĝĥţ ~~~~~~]\"],\"node.ductFitting.label\":[\"[Ðûçţ Ƒîţţîñĝ ~~~~]\"],\"node.ductFitting.tool.axis\":[\"[Åẋîš ~~]\"],\"node.ductFitting.tool.axis2\":[\"[⌥ áẋîš ~~]\"],\"node.ductFitting.tool.hoverADuctFaceThatFits\":[\"[Ĥöṽéŕ á ðûçţ ƒáçé ţĥáţ ƒîţš ţĥé ðööŕ ~~~~~~~~~]\"],\"node.ductFitting.tool.placeAccessDoor\":[\"[Þļáçé áççéšš ðööŕ ~~~~~]\"],\"node.ductFitting.tool.rTRotate\":[\"[Ŕ/Ţ ŕöţáţé ~~~]\"],\"node.ductSegment.description\":[\"[ĤṼÅÇ ðûçţ ŕûñ — þöļýļîñé öƒ ŕöûñð, ŕéçţ, öŕ ƒļáţ-öṽáļ šéçţîöñš. ~~~~~~~~~~~~~~~]\"],\"node.ductSegment.label\":[\"[Ðûçţ ~~]\"],\"node.ductTerminal.description\":[\"[Ðûçţ ţéŕɱîñáļ — šûþþļý ŕéĝîšţéŕ, çéîļîñĝ ðûšéŕ, öŕ ŕéţûŕñ ĝŕîļļé. Ðûçţ ŕûñš éñð áţ îţš çöļļáŕ. ~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.ductTerminal.label\":[\"[Ŕéĝîšţéŕ ~~~]\"],\"node.ductTerminal.tool.mSurface\":[\"[Ṁ šûŕƒáçé ~~~]\"],\"node.ductTerminal.tool.mount\":[\"[\",[\"mount\",\"select\",{\"floor\":[\"Ṁöûñţ Ƒļööŕ\"],\"ceiling\":[\"Ṁöûñţ Çéîļîñĝ\"],\"wall\":[\"Ṁöûñţ Ŵáļļ\"],\"other\":[\"Ṁöûñţ \",[\"label\"]]}],\" ~~~~~~~~~~~]\"],\"node.ductTerminal.tool.rTRotate\":[\"[Ŕ/Ţ ŕöţáţé ~~~]\"],\"node.ductTerminal.tool.snappedToDuct\":[\"[Šñáþþéð ţö ðûçţ ~~~~]\"],\"node.elevator.description\":[\"[Å ɱûļţî-ļéṽéļ éļéṽáţöŕ šĥáƒţ ŵîţĥ çöñƒîĝûŕáƀļé öþéñîñĝš þéŕ ļéṽéļ. ~~~~~~~~~~~~~~~~~]\"],\"node.elevator.label\":[\"[Éļéṽáţöŕ ~~~]\"],\"node.elevator.panel.access\":[\"[Åççéšš ~~]\"],\"node.elevator.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.elevator.panel.cab\":[\"[Çáƀ ~]\"],\"node.elevator.panel.cabHeight\":[\"[Çáƀ Ĥéîĝĥţ ~~~]\"],\"node.elevator.panel.centerOpening\":[\"[Çéñţéŕ öþéñîñĝ ~~~~]\"],\"node.elevator.panel.defaultFloor\":[\"[Ðéƒáûļţ Ƒļööŕ ~~~~]\"],\"node.elevator.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.elevator.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.elevator.panel.destination\":[\"[Ðéšţîñáţîöñ ~~~~]\"],\"node.elevator.panel.disabled\":[\"[Ðîšáƀļéð ~~~]\"],\"node.elevator.panel.doorHeight\":[\"[Ðööŕ Ĥéîĝĥţ ~~~]\"],\"node.elevator.panel.doorTime\":[\"[Ðööŕ Ţîɱé ~~~]\"],\"node.elevator.panel.doorType\":[\"[Ðööŕ Ţýþé ~~~]\"],\"node.elevator.panel.doorWidth\":[\"[Ðööŕ Ŵîðţĥ ~~~]\"],\"node.elevator.panel.doors\":[\"[Ðööŕš ~~]\"],\"node.elevator.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.elevator.panel.dwell\":[\"[Ðŵéļļ ~~]\"],\"node.elevator.panel.elevator\":[\"[Éļéṽáţöŕ ~~~]\"],\"node.elevator.panel.from\":[\"[Ƒŕöɱ ~~]\"],\"node.elevator.panel.glass\":[\"[Ĝļášš ~~]\"],\"node.elevator.panel.glassFrame\":[\"[Ĝļášš ƒŕáɱé ~~~]\"],\"node.elevator.panel.motion\":[\"[Ṁöţîöñ ~~]\"],\"node.elevator.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.elevator.panel.openingStyle\":[\"[Öþéñîñĝ Šţýļé ~~~~]\"],\"node.elevator.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.elevator.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.elevator.panel.segmentedPanel\":[\"[Šéĝɱéñţéð þáñéļ ~~~~~]\"],\"node.elevator.panel.service\":[\"[Šéŕṽîçé ~~~]\"],\"node.elevator.panel.shaft\":[\"[Šĥáƒţ ~~]\"],\"node.elevator.panel.shaftDepth\":[\"[Šĥáƒţ Ðéþţĥ ~~~]\"],\"node.elevator.panel.shaftStyle\":[\"[Šĥáƒţ Šţýļé ~~~]\"],\"node.elevator.panel.shaftWidth\":[\"[Šĥáƒţ Ŵîðţĥ ~~~]\"],\"node.elevator.panel.singleLeft\":[\"[Šîñĝļé ļéƒţ ~~~]\"],\"node.elevator.panel.singleRight\":[\"[Šîñĝļé ŕîĝĥţ ~~~~]\"],\"node.elevator.panel.solid\":[\"[Šöļîð ~~]\"],\"node.elevator.panel.solidPanel\":[\"[Šöļîð þáñéļ ~~~]\"],\"node.elevator.panel.speed\":[\"[Šþééð ~~]\"],\"node.elevator.panel.stopStoporder\":[\"[Šţöþ \",[\"stopOrder\"],\" ~~]\"],\"node.elevator.panel.to\":[\"[Ţö ~]\"],\"node.elevator.panel.wallThickness\":[\"[Ŵáļļ Ţĥîçķñéšš ~~~~]\"],\"node.elevator.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.elevator.panel.yaw\":[\"[Ýáŵ ~]\"],\"node.eyebrowVent.description\":[\"[Ļöŵ çûŕṽéð ļéñš-šĥáþéð ŕööƒ ṽéñţ ŵîţĥ á ļöûṽéŕéð ƒŕöñţ. ~~~~~~~~~~~~~~]\"],\"node.eyebrowVent.label\":[\"[Éýéƀŕöŵ Ṽéñţ ~~~~]\"],\"node.eyebrowVent.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.eyebrowVent.panel.backHeight\":[\"[Ɓáçķ ĥéîĝĥţ ~~~]\"],\"node.eyebrowVent.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.eyebrowVent.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.eyebrowVent.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.eyebrowVent.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.eyebrowVent.panel.eyebrowVent\":[\"[Éýéƀŕöŵ Ṽéñţ ~~~~]\"],\"node.eyebrowVent.panel.halfRound\":[\"[Ĥáļƒ-ŕöûñð ~~~]\"],\"node.eyebrowVent.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.eyebrowVent.panel.louvers\":[\"[Ļöûṽéŕš ~~~]\"],\"node.eyebrowVent.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.eyebrowVent.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.eyebrowVent.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.eyebrowVent.panel.scoop\":[\"[Šçööþ ~~]\"],\"node.eyebrowVent.panel.slantBox\":[\"[Šļáñţ-ƀöẋ ~~~]\"],\"node.eyebrowVent.panel.style\":[\"[Šţýļé ~~]\"],\"node.eyebrowVent.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.fence.description\":[\"[Å šţŕáîĝĥţ öŕ çûŕṽéð ƒéñçé šéĝɱéñţ ŵîţĥ çöñƒîĝûŕáƀļé þöšţš áñð îñƒîļļ. ~~~~~~~~~~~~~~~~~~]\"],\"node.fence.inspectorEditors.addPointAfter\":[\"[Åðð þöîñţ áƒţéŕ ~~~~]\"],\"node.fence.inspectorEditors.chooseASlabOrShapedSurface\":[\"[Çĥööšé á šļáƀ öŕ šĥáþéð šûŕƒáçé öñ ţĥîš ļéṽéļ. ~~~~~~~~~~~~]\"],\"node.fence.inspectorEditors.chooseASurface\":[\"[Çĥööšé á šûŕƒáçé ~~~~~]\"],\"node.fence.inspectorEditors.corner\":[\"[Çöŕñéŕ ~~]\"],\"node.fence.inspectorEditors.curve\":[\"[Çûŕṽé ~~]\"],\"node.fence.inspectorEditors.curved\":[\"[Çûŕṽéð ~~]\"],\"node.fence.inspectorEditors.distributionInfo\":[\"[\",[\"style\",\"select\",{\"picket\":[\"Ðîšţŕîƀûţîöñ çöñţŕöļš þîçķéţš îñ éáçĥ ƀáý ƀéţŵééñ þöšţš.\"],\"horizontal\":[\"Ðîšţŕîƀûţîöñ çöñţŕöļš þöšţš áļöñĝ ţĥé ƒûļļ ƒéñçé.\"],\"other\":[\"Ðîšţŕîƀûţîöñ çöñţŕöļš îñƒîļļ þîéçéš ƀéţŵééñ ţĥé ţŵö éñð þöšţš.\"]}],\" Šþáçîñĝ îš ɱéášûŕéð ƀéţŵééñ çéñţéŕš. Ţĥé áṽáîļáƀļé ŵîðţĥ ļîɱîţš ţĥé çöûñţ šö þîéçéš ðö ñöţ öṽéŕļáþ. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.fence.inspectorEditors.editPath\":[\"[Éðîţ þáţĥ ~~~]\"],\"node.fence.inspectorEditors.extendPath\":[\"[Éẋţéñð þáţĥ ~~~]\"],\"node.fence.inspectorEditors.followHighestSurface\":[\"[Ƒöļļöŵ ĥîĝĥéšţ šûŕƒáçé ~~~~~~]\"],\"node.fence.inspectorEditors.followSelectedSurface\":[\"[Ƒöļļöŵ šéļéçţéð šûŕƒáçé ~~~~~~~]\"],\"node.fence.inspectorEditors.holdStartingHeight\":[\"[Ĥöļð šţáŕţîñĝ ĥéîĝĥţ ~~~~~~]\"],\"node.fence.inspectorEditors.join\":[\"[Ĵöîñ ~~]\"],\"node.fence.inspectorEditors.length\":[\"[Ļéñĝţĥ ~~]\"],\"node.fence.inspectorEditors.pathSummary\":[\"[\",[\"count\",\"plural\",{\"one\":[[\"number\"],\" þöîñţ\"],\"other\":[[\"number\"],\" þöîñţš\"]}],\" · \",[\"length\"],\" ɱ ~~~~]\"],\"node.fence.inspectorEditors.picketRailProjection\":[\"[Þîçķéţ ŕáîļ þŕöĵéçţîöñ ~~~~~~]\"],\"node.fence.inspectorEditors.point\":[\"[Þöîñţ ~~]\"],\"node.fence.inspectorEditors.removePoint\":[\"[Ŕéɱöṽé þöîñţ ~~~~]\"],\"node.fence.inspectorEditors.setEachSpanToStraightOr\":[\"[Šéţ éáçĥ šþáñ ţö šţŕáîĝĥţ öŕ çûŕṽéð, ţĥéñ ðŕáĝ îţš þöîñţš áñð çûŕṽé ĥáñðļéš îñ éîţĥéŕ ṽîéŵ. ~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.fence.inspectorEditors.smooth\":[\"[Šɱööţĥ ~~]\"],\"node.fence.inspectorEditors.spanToPointNumber\":[\"[Šþáñ ţö þöîñţ \",[\"number\"],\" ~~~~]\"],\"node.fence.inspectorEditors.straight\":[\"[Šţŕáîĝĥţ ~~~]\"],\"node.fence.inspectorEditors.surface\":[\"[Šûŕƒáçé ~~~]\"],\"node.fence.inspectorEditors.surfaceBehavior\":[\"[Šûŕƒáçé ƀéĥáṽîöŕ ~~~~~]\"],\"node.fence.label\":[\"[Ƒéñçé ~~]\"],\"node.fence.moveEndpointTool.detachEndpoint\":[\"[Ðéţáçĥ éñðþöîñţ ~~~~~]\"],\"node.fence.moveEndpointTool.dragEndpoint\":[\"[Ðŕáĝ éñðþöîñţ ~~~~]\"],\"node.fenceFeature.actions.close\":[\"[Çļöšé ~~]\"],\"node.fenceFeature.actions.open\":[\"[Öþéñ ~~]\"],\"node.fenceFeature.inspector.boardWidth\":[\"[Ɓöáŕð ŵîðţĥ ~~~]\"],\"node.fenceFeature.inspector.bracing\":[\"[Ɓŕáçîñĝ ~~~]\"],\"node.fenceFeature.inspector.distanceFromStart\":[\"[Ðîšţáñçé ƒŕöɱ šţáŕţ ~~~~~~]\"],\"node.fenceFeature.inspector.fenceUnavailable\":[\"[Ƒéñçé ûñáṽáîļáƀļé. ~~~~~]\"],\"node.fenceFeature.inspector.frameWidth\":[\"[Ƒŕáɱé ŵîðţĥ ~~~]\"],\"node.fenceFeature.inspector.gateHeight\":[\"[Ĝáţé ĥéîĝĥţ ~~~]\"],\"node.fenceFeature.inspector.gateStyle\":[\"[Ĝáţé šţýļé ~~~]\"],\"node.fenceFeature.inspector.groundClearance\":[\"[Ĝŕöûñð çļéáŕáñçé ~~~~~]\"],\"node.fenceFeature.inspector.hingeSide\":[\"[Ĥîñĝé šîðé ~~~]\"],\"node.fenceFeature.inspector.hingesAndLatch\":[\"[Ĥîñĝéš áñð ļáţçĥ ~~~~~]\"],\"node.fenceFeature.inspector.horizontalBoards\":[\"[Ĥöŕîžöñţáļ ƀöáŕðš ~~~~~]\"],\"node.fenceFeature.inspector.infillSpacing\":[\"[Îñƒîļļ šþáçîñĝ ~~~~]\"],\"node.fenceFeature.inspector.jambPosts\":[\"[Ĵáɱƀ þöšţš ~~~]\"],\"node.fenceFeature.inspector.keepTheOpeningInsideTheFence\":[\"[Ķééþ ţĥé öþéñîñĝ îñšîðé ţĥé ƒéñçé áñð çļéáŕ öƒ öţĥéŕ ĝáţéš öŕ þáššáĝéš. ~~~~~~~~~~~~~~~~~~]\"],\"node.fenceFeature.inspector.leafThickness\":[\"[Ļéრţĥîçķñéšš ~~~~]\"],\"node.fenceFeature.inspector.leaves\":[\"[Ļéáṽéš ~~]\"],\"node.fenceFeature.inspector.leftLeafProportion\":[\"[Ļéƒţ ļéრþŕöþöŕţîöñ ~~~~~~]\"],\"node.fenceFeature.inspector.matchFenceHeight\":[\"[Ṁáţçĥ ƒéñçé ĥéîĝĥţ ~~~~~]\"],\"node.fenceFeature.inspector.matchFenceStyle\":[\"[Ṁáţçĥ ƒéñçé šţýļé ~~~~~]\"],\"node.fenceFeature.inspector.openRails\":[\"[Öþéñ ŕáîļš ~~~]\"],\"node.fenceFeature.inspector.openingAngle\":[\"[Öþéñîñĝ áñĝļé ~~~~]\"],\"node.fenceFeature.inspector.openingWidth\":[\"[Öþéñîñĝ ŵîðţĥ ~~~~]\"],\"node.fenceFeature.inspector.option.cross\":[\"[Çŕöšš ~~]\"],\"node.fenceFeature.inspector.option.diagonal\":[\"[Ðîáĝöñáļ ~~~]\"],\"node.fenceFeature.inspector.option.doubleGate\":[\"[Ðöûƀļé ĝáţé ~~~]\"],\"node.fenceFeature.inspector.option.inward\":[\"[Îñŵáŕð ~~]\"],\"node.fenceFeature.inspector.option.left\":[\"[Ļéƒţ ~~]\"],\"node.fenceFeature.inspector.option.none\":[\"[Ñöñé ~~]\"],\"node.fenceFeature.inspector.option.outward\":[\"[Öûţŵáŕð ~~~]\"],\"node.fenceFeature.inspector.option.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.fenceFeature.inspector.option.singleGate\":[\"[Šîñĝļé ĝáţé ~~~]\"],\"node.fenceFeature.inspector.picket\":[\"[Þîçķéţ ~~]\"],\"node.fenceFeature.inspector.postHeight\":[\"[Þöšţ ĥéîĝĥţ ~~~]\"],\"node.fenceFeature.inspector.removeGate\":[\"[Ŕéɱöṽé ĝáţé ~~~]\"],\"node.fenceFeature.inspector.removeOpening\":[\"[Ŕéɱöṽé öþéñîñĝ ~~~~]\"],\"node.fenceFeature.inspector.solidPrivacy\":[\"[Šöļîð þŕîṽáçý ~~~~]\"],\"node.fenceFeature.inspector.swingDirection\":[\"[Šŵîñĝ ðîŕéçţîöñ ~~~~~]\"],\"node.fenceFeature.inspector.verticalSlats\":[\"[Ṽéŕţîçáļ šļáţš ~~~~]\"],\"node.fenceGate.description\":[\"[Å ĝáţé ĥöšţéð ƀý á ƒéñçé. ~~~~~~]\"],\"node.fenceGate.label\":[\"[Ĝáţé ~~]\"],\"node.fenceOpening.description\":[\"[Åñ îñţéñţîöñáļ öþéñîñĝ îñ á ƒéñçé. ~~~~~~~~~]\"],\"node.fenceOpening.label\":[\"[Öþéñ Þáššáĝé ~~~~]\"],\"node.floorOpening.label\":[\"[Ƒļööŕ öþéñîñĝ ~~~~]\"],\"node.guide.description\":[\"[Å ɱéášûŕéɱéñţ / ŕéƒéŕéñçé áññöţáţîöñ (ļîñéáŕ, áŕéá, öŕ áŕç). ~~~~~~~~~~~~~~]\"],\"node.guide.label\":[\"[Ĝûîðé ~~]\"],\"node.gutter.description\":[\"[Ŕáîñ-ŵáţéŕ çĥáññéļ ŕûññîñĝ áļöñĝ ţĥé éáṽé öƒ á ŕööƒ šéĝɱéñţ. ~~~~~~~~~~~~~~~]\"],\"node.gutter.downspoutsPanel.addDownspout\":[\"[Åðð Ðöŵñšþöûţ ~~~~]\"],\"node.gutter.downspoutsPanel.downspoutNumber\":[\"[Ðöŵñšþöûţ \",[\"number\"],\" ~~~]\"],\"node.gutter.downspoutsPanel.downspouts\":[\"[Ðöŵñšþöûţš ~~~]\"],\"node.gutter.downspoutsPanel.removeDownspout\":[\"[Ŕéɱöṽé ðöŵñšþöûţ ~~~~~]\"],\"node.gutter.label\":[\"[Ĝûţţéŕ ~~]\"],\"node.hole.manual\":[\"[Ṁáñûáļ ~~]\"],\"node.holeEditing\":[\"[Ĥöļé \",[\"number\"],\" (Éðîţîñĝ) ~~~~]\"],\"node.holeNumber\":[\"[Ĥöļé \",[\"number\"],\" ~~]\"],\"node.holeSummary\":[\"[\",[\"area\"],\" \",[\"unit\"],\" · \",[\"count\",\"plural\",{\"one\":[[\"points\"],\" þţ\"],\"other\":[[\"points\"],\" þţš\"]}],\" · \",[\"source\"],\" ~~]\"],\"node.hvacEquipment.description\":[\"[Ƒûŕñáçé, áîŕ ĥáñðļéŕ, öŕ çöñðéñšéŕ — ðûçţ ŕûñš çöññéçţ ţö îţš šûþþļý/ŕéţûŕñ çöļļáŕš. ~~~~~~~~~~~~~~~~~~~~~]\"],\"node.hvacEquipment.label\":[\"[ĤṼÅÇ Ûñîţ ~~~]\"],\"node.hvacEquipment.tool.rTRotate\":[\"[Ŕ/Ţ ŕöţáţé ~~~]\"],\"node.importedMesh.description\":[\"[Ĝéöɱéţŕý þŕéšéŕṽéð ƒŕöɱ áñ îɱþöŕţéð ɱöðéļ ŵĥéñ ñö ñáţîṽé Þášçáļ šĥáþé éẋîšţš. ~~~~~~~~~~~~~~~~~~~~]\"],\"node.importedMesh.label\":[\"[Îɱþöŕţéð Ṁéšĥ ~~~~]\"],\"node.item.authoredParams.couldnTRebuildWithTheseValues\":[\"[Çöûļðñ'ţ ŕéƀûîļð ŵîţĥ ţĥéšé ṽáļûéš. ~~~~~~~~~]\"],\"node.item.authoredParams.parameters\":[\"[Þáŕáɱéţéŕš ~~~]\"],\"node.item.authoredParams.rebuilding\":[\"[Ŕéƀûîļðîñĝ… ~~~]\"],\"node.item.authoredParams.rebuildingInBlender\":[\"[Ŕéƀûîļðîñĝ îñ Ɓļéñðéŕ… ~~~~~~]\"],\"node.item.authoredParams.resetParam\":[\"[Ŕéšéţ \",[\"param\"],\" ~~]\"],\"node.item.authoredParams.resetParameters\":[\"[Ŕéšéţ þáŕáɱéţéŕš ~~~~~]\"],\"node.item.authoredParams.resetToDefault\":[\"[Ŕéšéţ ţö ðéƒáûļţ ~~~~~]\"],\"node.item.description\":[\"[Å çáţáļöĝ-ƀáçķéð îţéɱ (ƒûŕñîţûŕé, ƒîẋţûŕéš, ðéçöŕáţîöñš). ~~~~~~~~~~~~~~]\"],\"node.item.label\":[\"[Îţéɱ ~~]\"],\"node.item.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.item.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.item.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.item.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.item.panel.info\":[\"[Îñƒö ~~]\"],\"node.item.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.item.panel.pos\":[\"[þöš ~]\"],\"node.item.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.item.panel.rot\":[\"[ŕöţ ~]\"],\"node.item.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.item.panel.scale\":[\"[Šçáļé ~~]\"],\"node.item.panel.scale2\":[\"[šçáļé ~~]\"],\"node.item.panel.uniformScale\":[\"[Ûñîƒöŕɱ Šçáļé ~~~~]\"],\"node.item.panel.xyz\":[\"[ẊÝŽ ~]\"],\"node.leanToExtension.description\":[\"[Åñ áţţáçĥéð ɱöñö-þîţçĥ öŕ ƒŕééšţáñðîñĝ ɱöñö, ĝáƀļé, öŕ ƀûţţéŕƒļý çáñöþý ŵîţĥ ɱáñáĝéð šţŕûçţûŕé áñð ðŕáîñáĝé. ~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.leanToExtension.label\":[\"[Çáñöþý ~~]\"],\"node.level.description\":[\"[Å šîñĝļé ƒļööŕ öƒ á ƀûîļðîñĝ, ĥöļðîñĝ ŵáļļš / šļáƀš / çéîļîñĝš / îţéɱš. ~~~~~~~~~~~~~~~~]\"],\"node.level.label\":[\"[Ļéṽéļ ~~]\"],\"node.lineset.description\":[\"[Ŕéƒŕîĝéŕáñţ ļîñéšéţ — çöþþéŕ šûçţîöñ + ļîǫûîð þáîŕ ĵöîñîñĝ á çöñðéñšéŕ ţö ţĥé îñðööŕ çöîļ. ~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.lineset.label\":[\"[Ļîñéšéţ ~~~]\"],\"node.liquidLine.description\":[\"[Šţáñðáļöñé ŕéƒŕîĝéŕáñţ ļîǫûîð ļîñé — á ţĥîñ ƀáŕé-çöþþéŕ ŕûñ; Ƒöļļöŵ ɱöðé ţŕáçéš áñ éẋîšţîñĝ ļîñéšéţ. ~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.liquidLine.label\":[\"[Ļîǫûîð Ļîñé ~~~]\"],\"node.liquidLine.tool.clickToTraceThisLinesetRun\":[\"[Çļîçķ ţö ţŕáçé ţĥîš ļîñéšéţ ŕûñ ~~~~~~~~]\"],\"node.liquidLine.tool.followHoverALineset\":[\"[Ƒöļļöŵ: ĥöṽéŕ á ļîñéšéţ ~~~~~~]\"],\"node.measurement.description\":[\"[Å þéŕšîšţéñţ ðîšţáñçé, áñĝļé, áŕéá, þéŕîɱéţéŕ, öŕ ṽöļûɱé áññöţáţîöñ. ~~~~~~~~~~~~~~~~~]\"],\"node.measurement.label\":[\"[Ṁéášûŕéɱéñţ ~~~~]\"],\"node.numberedName\":[[\"kind\"],\" \",[\"number\"]],\"node.panel.currently\":[\"[Çûŕŕéñţļý \",[\"value\"],\" ~~~]\"],\"node.pipeFitting.description\":[\"[ÐŴṼ ĵöîñţ — éļƀöŵ ƀéñð, 45° ŵýé, öŕ šáñîţáŕý ţéé. ~~~~~~~~~~]\"],\"node.pipeFitting.label\":[\"[Þîþé Ƒîţţîñĝ ~~~~]\"],\"node.pipeFitting.tool.axis\":[\"[Åẋîš ~~]\"],\"node.pipeFitting.tool.axis2\":[\"[⌥ áẋîš ~~]\"],\"node.pipeFitting.tool.rTRotate\":[\"[Ŕ/Ţ ŕöţáţé ~~~]\"],\"node.pipeSegment.description\":[\"[Ðŕáîñ / ŵášţé / ṽéñţ þîþé ŕûñ — ðŕáŵ ļéṽéļ öŕ ţöĝĝļé á ¼″ þéŕ ƒööţ ƒáļļ ŵîţĥ Š. ~~~~~~~~~~~~~~~~~]\"],\"node.pipeSegment.label\":[\"[ÐŴṼ Þîþé ~~~]\"],\"node.pipeTrap.description\":[\"[ÐŴṼ Þ-ţŕáþ — ŵáţéŕ šéáļ öñ ţĥé ŵášţé ļîñé. Ţĥé ţŕáþ áŕɱ ŕûñš ţö ţĥé ṽéñţ. ~~~~~~~~~~~~~~~~~]\"],\"node.pipeTrap.label\":[\"[Ţŕáþ ~~]\"],\"node.pipeTrap.tool.diameterTrap\":[\"[\",[\"diameter\"],\"\\\" Ţŕáþ ~~]\"],\"node.pipeTrap.tool.rTRotate\":[\"[Ŕ/Ţ ŕöţáţé ~~~]\"],\"node.proceduralItem.description\":[\"[Éẋþéŕîɱéñţáļ éðîţáƀļé ŕéçîþé ~~~~~~~~]\"],\"node.proceduralItem.label\":[\"[Þŕöçéðûŕáļ îţéɱ ~~~~~]\"],\"node.ridgeVent.description\":[\"[Ṽéñţîļáţîöñ šţŕîþ ŕûññîñĝ áļöñĝ ţĥé ŕîðĝé öƒ á ŕööƒ šéĝɱéñţ. ~~~~~~~~~~~~~~~]\"],\"node.ridgeVent.label\":[\"[Ŕîðĝé Ṽéñţ ~~~]\"],\"node.ridgeVent.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.ridgeVent.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.ridgeVent.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.ridgeVent.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.ridgeVent.panel.endCaps\":[\"[Éñð Çáþš ~~~]\"],\"node.ridgeVent.panel.flanged\":[\"[Ƒļáñĝéð ~~~]\"],\"node.ridgeVent.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.ridgeVent.panel.length\":[\"[Ļéñĝţĥ ~~]\"],\"node.ridgeVent.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.ridgeVent.panel.open\":[\"[Öþéñ ~~]\"],\"node.ridgeVent.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.ridgeVent.panel.ridgeVent\":[\"[Ŕîðĝé Ṽéñţ ~~~]\"],\"node.ridgeVent.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.ridgeVent.panel.shingled\":[\"[Šĥîñĝļéð ~~~]\"],\"node.ridgeVent.panel.standard\":[\"[Šţáñðáŕð ~~~]\"],\"node.ridgeVent.panel.style\":[\"[Šţýļé ~~]\"],\"node.ridgeVent.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.roof.barrelPanel.archBays\":[\"[Åŕçĥ ƀáýš ~~~]\"],\"node.roof.barrelPanel.barrelArch\":[\"[Ɓáŕŕéļ áŕçĥ ~~~]\"],\"node.roof.barrelPanel.flatPanesFollowACircularArch\":[\"[Ƒļáţ þáñéš ƒöļļöŵ á çîŕçûļáŕ áŕçĥ. Ŕîšé îš ɱéášûŕéð ƒŕöɱ ţĥé éáṽéš. ~~~~~~~~~~~~~~~~~]\"],\"node.roof.barrelPanel.rise\":[\"[Ŕîšé ~~]\"],\"node.roof.description\":[\"[Å þîţçĥéð / ĥîþ / ĝáƀļé ŕööƒ çöɱþöšéð öƒ öñé öŕ ɱöŕé šéĝɱéñţš. ~~~~~~~~~~~~~~~]\"],\"node.roof.glazing.face.archBay\":[\"[Åŕçĥ ƀáý \",[\"number\"],\" ~~~]\"],\"node.roof.glazing.face.back\":[\"[Ɓáçķ šļöþé ~~~]\"],\"node.roof.glazing.face.endLeft\":[\"[Ļéƒţ éñð ~~~]\"],\"node.roof.glazing.face.endRight\":[\"[Ŕîĝĥţ éñð ~~~]\"],\"node.roof.glazing.face.front\":[\"[Ƒŕöñţ šļöþé ~~~]\"],\"node.roof.glazing.face.slope\":[\"[Šĥéð šļöþé ~~~]\"],\"node.roof.glazingControls.alignment\":[\"[Åļîĝñɱéñţ ~~~]\"],\"node.roof.glazingControls.center\":[\"[Çéñţéŕ ~~]\"],\"node.roof.glazingControls.chooseALayoutToEditThe\":[\"[Çĥööšé á ļáýöûţ ţö éðîţ ţĥé ĝŕîð. ~~~~~~~~]\"],\"node.roof.glazingControls.empty\":[\"[Éɱþţý ~~]\"],\"node.roof.glazingControls.end\":[\"[Éñð ~]\"],\"node.roof.glazingControls.fixedSpacing\":[\"[Ƒîẋéð šþáçîñĝ ~~~~]\"],\"node.roof.glazingControls.glass\":[\"[Ĝļášš ~~]\"],\"node.roof.glazingControls.layout\":[\"[Ļáýöûţ ~~]\"],\"node.roof.glazingControls.maxSpacing\":[\"[Ṁáẋ šþáçîñĝ ~~~]\"],\"node.roof.glazingControls.maximumSpacing\":[\"[Ṁáẋîɱûɱ šþáçîñĝ ~~~~~]\"],\"node.roof.glazingControls.mixed\":[\"[Ṁîẋéð ~~]\"],\"node.roof.glazingControls.panelCount\":[\"[Þáñéļ çöûñţ ~~~]\"],\"node.roof.glazingControls.panels\":[\"[Þáñéļš ~~]\"],\"node.roof.glazingControls.solid\":[\"[Šöļîð ~~]\"],\"node.roof.glazingControls.spacing\":[\"[Šþáçîñĝ ~~~]\"],\"node.roof.glazingControls.start\":[\"[Šţáŕţ ~~]\"],\"node.roof.glazingControls.titleAlignment\":[\"[\",[\"title\"],\" áļîĝñɱéñţ ~~~]\"],\"node.roof.glazingPanel.changesApplyToAllLengthRoof\":[\"[Çĥáñĝéš áþþļý ţö áļļ \",[\"length\"],\" ŕööƒ šéĝɱéñţš. ~~~~~~~~~]\"],\"node.roof.glazingPanel.chooseOneRoofSystemToEdit\":[\"[Çĥööšé öñé ŕööƒ šýšţéɱ ţö éðîţ šéţţîñĝš ƒöŕ áļļ šéļéçţéð šéĝɱéñţš. ~~~~~~~~~~~~~~~~~]\"],\"node.roof.glazingPanel.closeTheRoofEnds\":[\"[Çļöšé ţĥé ŕööƒ éñðš ~~~~~]\"],\"node.roof.glazingPanel.defaultPanelInfill\":[\"[Ðéƒáûļţ þáñéļ îñƒîļļ ~~~~~~]\"],\"node.roof.glazingPanel.dividesEachRoofFaceIntoColumns\":[\"[Ðîṽîðéš éáçĥ ŕööƒ ƒáçé îñţö çöļûɱñš. ~~~~~~~~~]\"],\"node.roof.glazingPanel.dividesTheLengthOfEachArch\":[\"[Ðîṽîðéš ţĥé ļéñĝţĥ öƒ éáçĥ áŕçĥ ƀáý îñţö çöļûɱñš. ~~~~~~~~~~~~]\"],\"node.roof.glazingPanel.endInfillFillsTheSpaceAbove\":[\"[Éñð îñƒîļļ ƒîļļš ţĥé šþáçé áƀöṽé ţĥé ŵáļļš. Éðîţ ŕööɱ ŵáļļš áñð çéîļîñĝš šéþáŕáţéļý. ~~~~~~~~~~~~~~~~~~~~~]\"],\"node.roof.glazingPanel.frameColor\":[\"[Ƒŕáɱé çöļöŕ ~~~]\"],\"node.roof.glazingPanel.frameDepth\":[\"[Ƒŕáɱé ðéþţĥ ~~~]\"],\"node.roof.glazingPanel.frameWidth\":[\"[Ƒŕáɱé ŵîðţĥ ~~~]\"],\"node.roof.glazingPanel.framing\":[\"[Ƒŕáɱîñĝ ~~~]\"],\"node.roof.glazingPanel.glass\":[\"[Ĝļášš ~~]\"],\"node.roof.glazingPanel.glassTint\":[\"[Ĝļášš ţîñţ ~~~]\"],\"node.roof.glazingPanel.glazed\":[\"[Ĝļážéð ~~]\"],\"node.roof.glazingPanel.glazingIsAvailableForGableStraight\":[\"[Ĝļážîñĝ îš áṽáîļáƀļé ƒöŕ ĝáƀļé, šţŕáîĝĥţ šĥéð, áñð ƀáŕŕéļ ŕööƒš. ~~~~~~~~~~~~~~~~]\"],\"node.roof.glazingPanel.gridAcrossTheRoof\":[\"[Ĝŕîð áçŕöšš ţĥé ŕööƒ ~~~~~~]\"],\"node.roof.glazingPanel.gridAlongTheLength\":[\"[Ĝŕîð áļöñĝ ţĥé ļéñĝţĥ ~~~~~~]\"],\"node.roof.glazingPanel.gridAlongTheSlope\":[\"[Ĝŕîð áļöñĝ ţĥé šļöþé ~~~~~~]\"],\"node.roof.glazingPanel.gridWithinEachArchBay\":[\"[Ĝŕîð ŵîţĥîñ éáçĥ áŕçĥ ƀáý ~~~~~~~]\"],\"node.roof.glazingPanel.infill\":[\"[Îñƒîļļ ~~]\"],\"node.roof.glazingPanel.opacity\":[\"[Öþáçîţý ~~~]\"],\"node.roof.glazingPanel.paneThickness\":[\"[Þáñé ţĥîçķñéšš ~~~~]\"],\"node.roof.glazingPanel.roofSystem\":[\"[Ŕööƒ šýšţéɱ ~~~]\"],\"node.roof.glazingPanel.roughness\":[\"[Ŕöûĝĥñéšš ~~~]\"],\"node.roof.glazingPanel.spacingIsMeasuredOnTheSlope\":[\"[Šþáçîñĝ îš ɱéášûŕéð öñ ţĥé šļöþé, ñöţ îţš ĥöŕîžöñţáļ þŕöĵéçţîöñ. ~~~~~~~~~~~~~~~~]\"],\"node.roof.glazingPanel.standard\":[\"[Šţáñðáŕð ~~~]\"],\"node.roof.glazingPanel.subdividesEachFlatArchBayArch\":[\"[Šûƀðîṽîðéš éáçĥ ƒļáţ áŕçĥ ƀáý. Åŕçĥ ƀáýš çöñţŕöļš ţĥé ðîṽîšîöñš áŕöûñð ţĥé çûŕṽé. ~~~~~~~~~~~~~~~~~~~~~]\"],\"node.roof.glazingPanelEditor.chooseAPanelToOverrideIts\":[\"[Çĥööšé á þáñéļ ţö öṽéŕŕîðé îţš ðéƒáûļţ îñƒîļļ. ~~~~~~~~~~~~]\"],\"node.roof.glazingPanelEditor.column2\":[\"[Çöļûɱñ ~~]\"],\"node.roof.glazingPanelEditor.custom\":[\"[Çûšţöɱ ~~]\"],\"node.roof.glazingPanelEditor.default\":[\"[Ðéƒáûļţ ~~~]\"],\"node.roof.glazingPanelEditor.grid\":[\"[\",[\"columns\",\"plural\",{\"one\":[[\"columnCount\"],\" çöļûɱñ\"],\"other\":[[\"columnCount\"],\" çöļûɱñš\"]}],\" · \",[\"rows\",\"plural\",{\"one\":[[\"rowCount\"],\" ŕöŵ\"],\"other\":[[\"rowCount\"],\" ŕöŵš\"]}],\" ~~~~~~]\"],\"node.roof.glazingPanelEditor.individualPanels\":[\"[Îñðîṽîðûáļ þáñéļš ~~~~~]\"],\"node.roof.glazingPanelEditor.panelInfill\":[\"[Þáñéļ îñƒîļļ ~~~~]\"],\"node.roof.glazingPanelEditor.resetToDefault\":[\"[Ŕéšéţ ţö ðéƒáûļţ ~~~~~]\"],\"node.roof.glazingPanelEditor.roofFace\":[\"[Ŕööƒ ƒáçé ~~~]\"],\"node.roof.glazingPanelEditor.row2\":[\"[Ŕöŵ ~]\"],\"node.roof.glazingPanelEditor.selectedPanelInfill\":[\"[Šéļéçţéð þáñéļ îñƒîļļ ~~~~~~]\"],\"node.roof.label\":[\"[Ŕööƒ ~~]\"],\"node.roof.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.roof.panel.addChimney\":[\"[Åðð Çĥîɱñéý ~~~]\"],\"node.roof.panel.addCupola\":[\"[Åðð Çûþöļá ~~~]\"],\"node.roof.panel.addDormer\":[\"[Åðð Ðöŕɱéŕ ~~~]\"],\"node.roof.panel.addEyebrowVent\":[\"[Åðð Éýéƀŕöŵ Ṽéñţ ~~~~~]\"],\"node.roof.panel.addGutter\":[\"[Åðð Ĝûţţéŕ ~~~]\"],\"node.roof.panel.addSkylight\":[\"[Åðð Šķýļîĝĥţ ~~~~]\"],\"node.roof.panel.addSolarPanel\":[\"[Åðð Šöļáŕ Þáñéļ ~~~~]\"],\"node.roof.panel.addVent\":[\"[Åðð Ṽéñţ ~~~]\"],\"node.roof.panel.box\":[\"[Ɓöẋ ~]\"],\"node.roof.panel.boxVent\":[\"[ƀöẋ ṽéñţ ~~~]\"],\"node.roof.panel.chimney\":[\"[çĥîɱñéý ~~~]\"],\"node.roof.panel.custom\":[\"[Çûšţöɱ ~~]\"],\"node.roof.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.roof.panel.dormer\":[\"[ðöŕɱéŕ ~~]\"],\"node.roof.panel.drawSegment\":[\"[Ðŕáŵ Šéĝɱéñţ ~~~~]\"],\"node.roof.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.roof.panel.eaveOverhang\":[\"[Éáṽé öṽéŕĥáñĝ ~~~~]\"],\"node.roof.panel.eaves\":[\"[Éáṽéš ~~]\"],\"node.roof.panel.elements\":[\"[Éļéɱéñţš ~~~]\"],\"node.roof.panel.followsWalls\":[\"[Ƒöļļöŵš ŵáļļš ~~~~]\"],\"node.roof.panel.gableOverhang\":[\"[Ĝáƀļé öṽéŕĥáñĝ ~~~~]\"],\"node.roof.panel.gutter\":[\"[ĝûţţéŕ ~~]\"],\"node.roof.panel.level\":[\"[Ļéṽéļ ~~]\"],\"node.roof.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.roof.panel.moveToLevel\":[\"[Ṁöṽé ţö \",[\"level\"],\" ~~]\"],\"node.roof.panel.moveToTheRoofLevel\":[\"[Ṁöṽé ţö ţĥé ŕööƒ ļéṽéļ ~~~~~~]\"],\"node.roof.panel.onStoreyWalls\":[\"[Öñ \",[\"storey\"],\" ŵîţĥ îţš ŵáļļš, šö îţ ĥîðéš ţĥáţ ƒļööŕ'š þļáñ îñ šöļö áñð éẋþļöðéð ṽîéŵš.\",[\"roofs\",\"plural\",{\"0\":[],\"1\":[],\"other\":[\" Ţĥé ƒļööŕ'š \",[\"roofCount\"],\" ŕööƒš ɱöṽé ţöĝéţĥéŕ.\"]}],\" ~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.roof.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.roof.panel.ridge\":[\"[Ŕîðĝé ~~]\"],\"node.roof.panel.ridgeVent\":[\"[ŕîðĝé ṽéñţ ~~~]\"],\"node.roof.panel.roof\":[\"[Ŕööƒ ~~]\"],\"node.roof.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.roof.panel.segmentType\":[\"[\",[\"roofType\",\"select\",{\"hip\":[\"Ĥîþ\"],\"gable\":[\"Ĝáƀļé\"],\"shed\":[\"Šĥéð\"],\"gambrel\":[\"Ĝáɱƀŕéļ\"],\"dutch\":[\"Ðûţçĥ\"],\"mansard\":[\"Ṁáñšáŕð\"],\"flat\":[\"Ƒļáţ\"],\"conical\":[\"Çöñîçáļ\"],\"barrel\":[\"Ɓáŕŕéļ\"],\"other\":[\"Ŕööƒ\"]}],\" ~~~~~~~~~~~~~~~~]\"],\"node.roof.panel.segments\":[\"[Šéĝɱéñţš ~~~]\"],\"node.roof.panel.skylight\":[\"[šķýļîĝĥţ ~~~]\"],\"node.roof.panel.solarPanel\":[\"[šöļáŕ þáñéļ ~~~]\"],\"node.roof.panel.turbine\":[\"[Ţûŕƀîñé ~~~]\"],\"node.roof.panel.turbineVent\":[\"[ţûŕƀîñé ṽéñţ ~~~~]\"],\"node.roofSegment.buildUpSection.applyToAllPlanesOfThis\":[\"[Åþþļý ţö áļļ þļáñéš öƒ ţĥîš ŕööƒ ~~~~~~~~]\"],\"node.roofSegment.buildUpSection.architecturalShingle\":[\"[Åŕçĥîţéçţûŕáļ šĥîñĝļé ~~~~~~]\"],\"node.roofSegment.buildUpSection.asphalt3Tab\":[\"[Åšþĥáļţ 3-ţáƀ ~~~]\"],\"node.roofSegment.buildUpSection.clayTile\":[\"[Çļáý ţîļé ~~~]\"],\"node.roofSegment.buildUpSection.concreteTile\":[\"[Çöñçŕéţé ţîļé ~~~~]\"],\"node.roofSegment.buildUpSection.covering\":[\"[Çöṽéŕîñĝ ~~~]\"],\"node.roofSegment.buildUpSection.deck\":[\"[Ðéçķ ~~]\"],\"node.roofSegment.buildUpSection.editLayers\":[\"[Éðîţ ļáýéŕš ~~~]\"],\"node.roofSegment.buildUpSection.finishName\":[\"[Ƒîñîšĥ ñáɱé ~~~]\"],\"node.roofSegment.buildUpSection.iceAndWaterShield\":[\"[Îçé áñð ŵáţéŕ šĥîéļð ~~~~~~]\"],\"node.roofSegment.buildUpSection.insulationName\":[\"[Îñšûļáţîöñ ñáɱé ~~~~~]\"],\"node.roofSegment.buildUpSection.interiorFinish\":[\"[Îñţéŕîöŕ ƒîñîšĥ ~~~~~]\"],\"node.roofSegment.buildUpSection.layers\":[\"[Ļáýéŕš ~~]\"],\"node.roofSegment.buildUpSection.n15Felt\":[\"[#15 ƒéļţ ~~]\"],\"node.roofSegment.buildUpSection.n30Felt\":[\"[#30 ƒéļţ ~~]\"],\"node.roofSegment.buildUpSection.none\":[\"[Ñöñé ~~]\"],\"node.roofSegment.buildUpSection.preset\":[\"[Þŕéšéţ ~~]\"],\"node.roofSegment.buildUpSection.rafters\":[\"[Ŕáƒţéŕš ~~~]\"],\"node.roofSegment.buildUpSection.roofing\":[\"[Ŕööƒîñĝ ~~~]\"],\"node.roofSegment.buildUpSection.roofingName\":[\"[Ŕööƒîñĝ ñáɱé ~~~~]\"],\"node.roofSegment.buildUpSection.sheathing\":[\"[Šĥéáţĥîñĝ ~~~]\"],\"node.roofSegment.buildUpSection.sheathingName\":[\"[Šĥéáţĥîñĝ ñáɱé ~~~~]\"],\"node.roofSegment.buildUpSection.slate\":[\"[Šļáţé ~~]\"],\"node.roofSegment.buildUpSection.standingSeamMetal\":[\"[Šţáñðîñĝ-šéáɱ ɱéţáļ ~~~~~~]\"],\"node.roofSegment.buildUpSection.synthetic\":[\"[Šýñţĥéţîç ~~~]\"],\"node.roofSegment.buildUpSection.topChord\":[\"[Ţöþ çĥöŕð ~~~]\"],\"node.roofSegment.buildUpSection.trusses\":[\"[Ţŕûššéš ~~~]\"],\"node.roofSegment.buildUpSection.underlayment\":[\"[Ûñðéŕļáýɱéñţ ~~~~]\"],\"node.roofSegment.buildUpSection.underlaymentName\":[\"[Ûñðéŕļáýɱéñţ ñáɱé ~~~~~]\"],\"node.roofSegment.buildUpSection.woodShake\":[\"[Ŵööð šĥáķé ~~~]\"],\"node.roofSegment.description\":[\"[Å šîñĝļé þîţçĥéð þļáñé öƒ á þáŕéñţ ŕööƒ. ~~~~~~~~~~]\"],\"node.roofSegment.label\":[\"[Ŕööƒ Šéĝɱéñţ ~~~~]\"],\"node.roofSegment.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.roofSegment.panel.angle\":[\"[Åñĝļé ~~]\"],\"node.roofSegment.panel.arc\":[\"[Åŕç ~]\"],\"node.roofSegment.panel.autoGutters\":[\"[Åûţö ĝûţţéŕš ~~~~]\"],\"node.roofSegment.panel.autoRidgeVent\":[\"[Åûţö ŕîðĝé ṽéñţ ~~~~]\"],\"node.roofSegment.panel.barrel\":[\"[Ɓáŕŕéļ ~~]\"],\"node.roofSegment.panel.clippedVersion\":[\"[Çļîþþéð ṽéŕšîöñ ~~~~~]\"],\"node.roofSegment.panel.conical\":[\"[Çöñîçáļ ~~~]\"],\"node.roofSegment.panel.conicalShape\":[\"[Çöñîçáļ Šĥáþé ~~~~]\"],\"node.roofSegment.panel.deckThick\":[\"[Ðéçķ Ţĥîçķ. ~~~]\"],\"node.roofSegment.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.roofSegment.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.roofSegment.panel.diameter\":[\"[Ðîáɱéţéŕ ~~~]\"],\"node.roofSegment.panel.doneEditing\":[\"[Ðöñé éðîţîñĝ ~~~~]\"],\"node.roofSegment.panel.drainage\":[\"[Ðŕáîñáĝé ~~~]\"],\"node.roofSegment.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.roofSegment.panel.dutch\":[\"[Ðûţçĥ ~~]\"],\"node.roofSegment.panel.eaveCut\":[\"[Éáṽé çûţ ~~~]\"],\"node.roofSegment.panel.eaveOverhang\":[\"[Éáṽé öṽéŕĥáñĝ ~~~~]\"],\"node.roofSegment.panel.editFootprint\":[\"[Éðîţ ƒööţþŕîñţ ~~~~]\"],\"node.roofSegment.panel.endOverhang\":[\"[Éñð öṽéŕĥáñĝ ~~~~]\"],\"node.roofSegment.panel.fascia\":[\"[Ƒášçîá ~~]\"],\"node.roofSegment.panel.fasciaHeight\":[\"[Ƒášçîá ĥéîĝĥţ ~~~~]\"],\"node.roofSegment.panel.flat\":[\"[Ƒļáţ ~~]\"],\"node.roofSegment.panel.footprint\":[\"[Ƒööţþŕîñţ ~~~]\"],\"node.roofSegment.panel.gable\":[\"[Ĝáƀļé ~~]\"],\"node.roofSegment.panel.gableOverhang\":[\"[Ĝáƀļé öṽéŕĥáñĝ ~~~~]\"],\"node.roofSegment.panel.gambrel\":[\"[Ĝáɱƀŕéļ ~~~]\"],\"node.roofSegment.panel.hip\":[\"[Ĥîþ ~]\"],\"node.roofSegment.panel.kinkDepth\":[\"[Ķîñķ Ðéþţĥ ~~~]\"],\"node.roofSegment.panel.kinkHeight\":[\"[Ķîñķ Ĥéîĝĥţ ~~~]\"],\"node.roofSegment.panel.length\":[\"[Ļéñĝţĥ ~~]\"],\"node.roofSegment.panel.mansard\":[\"[Ṁáñšáŕð ~~~]\"],\"node.roofSegment.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.roofSegment.panel.pitch\":[\"[Þîţçĥ ~~]\"],\"node.roofSegment.panel.plumb\":[\"[Þļûɱƀ ~~]\"],\"node.roofSegment.panel.plumbLevel\":[\"[Þļûɱƀ + ļéṽéļ ~~~]\"],\"node.roofSegment.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.roofSegment.panel.reset\":[\"[Ŕéšéţ ~~]\"],\"node.roofSegment.panel.roofSegment\":[\"[Ŕööƒ Šéĝɱéñţ ~~~~]\"],\"node.roofSegment.panel.roofType\":[\"[Ŕööƒ Ţýþé ~~~]\"],\"node.roofSegment.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.roofSegment.panel.shape\":[\"[Šĥáþé ~~]\"],\"node.roofSegment.panel.shed\":[\"[Šĥéð ~~]\"],\"node.roofSegment.panel.shingleThick\":[\"[Šĥîñĝļé Ţĥîçķ. ~~~~]\"],\"node.roofSegment.panel.span\":[\"[Šþáñ ~~]\"],\"node.roofSegment.panel.square\":[\"[Šǫûáŕé ~~]\"],\"node.roofSegment.panel.startAngle\":[\"[Šţáŕţ Åñĝļé ~~~]\"],\"node.roofSegment.panel.structure\":[\"[Šţŕûçţûŕé ~~~]\"],\"node.roofSegment.panel.topRakeLength\":[\"[Ţöþ Ŕáķé Ļéñĝţĥ ~~~~]\"],\"node.roofSegment.panel.topRakeThick\":[\"[Ţöþ Ŕáķé Ţĥîçķ. ~~~~]\"],\"node.roofSegment.panel.trim\":[\"[Ţŕîɱ ~~]\"],\"node.roofSegment.panel.waistHeight\":[\"[Ŵáîšţ Ĥéîĝĥţ ~~~~]\"],\"node.roofSegment.panel.waistLength\":[\"[Ŵáîšţ Ļéñĝţĥ ~~~~]\"],\"node.roofSegment.panel.waistWidth\":[\"[Ŵáîšţ Ŵîðţĥ ~~~]\"],\"node.roofSegment.panel.wall\":[\"[Ŵáļļ ~~]\"],\"node.roofSegment.panel.wallHeight\":[\"[Ŵáļļ Ĥéîĝĥţ ~~~]\"],\"node.roofSegment.panel.wallThick\":[\"[Ŵáļļ Ţĥîçķ. ~~~]\"],\"node.roofSegment.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.scan.description\":[\"[Å çáþţûŕéð šéššîöñ ŵîţĥ öþţîöñáļ ɱéšĥ, ɱöţîöñ, ɱéðîá, áñð šéñšöŕ ðáţá. ~~~~~~~~~~~~~~~~~]\"],\"node.scan.label\":[\"[Çáþţûŕé ~~~]\"],\"node.segmentNumber\":[\"[Šéĝɱéñţ \",[\"number\"],\" ~~~]\"],\"node.separator.label\":[\"[Šéþáŕáţöŕ ~~~]\"],\"node.shared.buildUpControls.batt\":[\"[Ɓáţţ ~~]\"],\"node.shared.buildUpControls.blown\":[\"[Ɓļöŵñ ~~]\"],\"node.shared.buildUpControls.drywall\":[\"[Ðŕýŵáļļ ~~~]\"],\"node.shared.buildUpControls.drywallThickness\":[\"[Ðŕýŵáļļ ţĥîçķñéšš ~~~~~]\"],\"node.shared.buildUpControls.insulation\":[\"[Îñšûļáţîöñ ~~~]\"],\"node.shared.buildUpControls.insulationThickness\":[\"[Îñšûļáţîöñ ţĥîçķñéšš ~~~~~~]\"],\"node.shared.buildUpControls.labelThickness\":[\"[\",[\"label\"],\" ţĥîçķñéšš ~~~]\"],\"node.shared.buildUpControls.none\":[\"[Ñöñé ~~]\"],\"node.shared.buildUpControls.osb\":[\"[ÖŠƁ ~]\"],\"node.shared.buildUpControls.plaster\":[\"[Þļášţéŕ ~~~]\"],\"node.shared.buildUpControls.plywood\":[\"[Þļýŵööð ~~~]\"],\"node.shared.buildUpControls.rigidBoard\":[\"[Ŕîĝîð ƀöáŕð ~~~]\"],\"node.shared.buildUpControls.spacing\":[\"[Šþáçîñĝ ~~~]\"],\"node.shared.buildUpControls.spacingOC\":[\"[\",[\"spacing\"],\" ö.ç. ~]\"],\"node.shared.buildUpControls.woodPlank\":[\"[Ŵööð þļáñķ ~~~]\"],\"node.shared.itemInteractionActions.turnLightOff\":[\"[Ţûŕñ ļîĝĥţ öƒƒ ~~~~]\"],\"node.shared.itemInteractionActions.turnLightOn\":[\"[Ţûŕñ ļîĝĥţ öñ ~~~~]\"],\"node.shared.openingCasingSection.casing\":[\"[Çášîñĝ ~~]\"],\"node.shared.openingCasingSection.width\":[\"[Ŵîðţĥ ~~]\"],\"node.shared.runHangerInspector.automaticSupport\":[\"[Åûţöɱáţîç šûþþöŕţ ~~~~~]\"],\"node.shared.runHangerInspector.hangerOnSegment\":[\"[Ĥáñĝéŕ \",[\"number\"],\" · šéĝɱéñţ \",[\"segment\"],\" ~~~~]\"],\"node.shared.runHangerInspector.individualHangers\":[\"[Îñðîṽîðûáļ ĥáñĝéŕš ~~~~~~]\"],\"node.shared.runHangerInspector.missingSupport\":[\"[Ṁîššîñĝ šûþþöŕţ ~~~~~]\"],\"node.shared.runHangerInspector.noSupportWithinReachMoveThe\":[\"[Ñö šûþþöŕţ ŵîţĥîñ ŕéáçĥ. Ṁöṽé ţĥé ĥáñĝéŕ öŕ çĥööšé áñöţĥéŕ ĥöšţ. ~~~~~~~~~~~~~~~~]\"],\"node.shared.runHangerInspector.positionLabel\":[\"[Ĥáñĝéŕ \",[\"number\"],\" þöšîţîöñ îñ ɱéţŕéš ~~~~~~~]\"],\"node.shared.runHangerInspector.positionM\":[\"[Þöšîţîöñ (ɱ) ~~~]\"],\"node.shared.runHangerInspector.positionsAreMeasuredAlongEachPath\":[\"[Þöšîţîöñš áŕé ɱéášûŕéð áļöñĝ éáçĥ þáţĥ šéĝɱéñţ. Çĥáñĝîñĝ šþáçîñĝ ŕéĝéñéŕáţéš ţĥé ñûɱƀéŕéð šļöţš. ~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.shared.runHangerInspector.revealSupport\":[\"[Ŕéṽéáļ šûþþöŕţ ~~~~]\"],\"node.shared.runHangerInspector.skip\":[\"[Šķîþ ~~]\"],\"node.shared.runHangerInspector.supportLabel\":[\"[Ĥáñĝéŕ \",[\"number\"],\" šûþþöŕţ ~~~~]\"],\"node.shared.systemCheckPanel.aboutTheseChecks\":[\"[Åƀöûţ ţĥéšé çĥéçķš ~~~~~]\"],\"node.shared.systemCheckPanel.allFindings\":[\"[Åļļ ƒîñðîñĝš ~~~~]\"],\"node.shared.systemCheckPanel.allSystems\":[\"[Åļļ šýšţéɱš ~~~]\"],\"node.shared.systemCheckPanel.connections\":[\"[Çöññéçţîöñš ~~~~]\"],\"node.shared.systemCheckPanel.drainage\":[\"[Ðŕáîñáĝé ~~~]\"],\"node.shared.systemCheckPanel.error\":[\"[Éŕŕöŕ ~~]\"],\"node.shared.systemCheckPanel.errors\":[\"[Éŕŕöŕš ~~]\"],\"node.shared.systemCheckPanel.filterSystemChecks\":[\"[Ƒîļţéŕ šýšţéɱ çĥéçķš ~~~~~~]\"],\"node.shared.systemCheckPanel.hangers\":[\"[Ĥáñĝéŕš ~~~]\"],\"node.shared.systemCheckPanel.intersections\":[\"[Îñţéŕšéçţîöñš ~~~~]\"],\"node.shared.systemCheckPanel.locate\":[\"[Ļöçáţé \",[\"name\"],\" (\",[\"id\"],\") ~~]\"],\"node.shared.systemCheckPanel.missingItem\":[\"[Ṁîššîñĝ îţéɱ ~~~~]\"],\"node.shared.systemCheckPanel.noFindings\":[\"[Ñö ƒîñðîñĝš ~~~]\"],\"node.shared.systemCheckPanel.noFindingsInThisCategory\":[\"[Ñö ƒîñðîñĝš îñ ţĥîš çáţéĝöŕý ~~~~~~~~]\"],\"node.shared.systemCheckPanel.openEnds\":[\"[Öþéñ éñðš ~~~]\"],\"node.shared.systemCheckPanel.openEndsAndSeparateBranchesMay\":[\"[Öþéñ éñðš áñð šéþáŕáţé ƀŕáñçĥéš ɱáý ƀé îñţéñţîöñáļ. Îñţéŕšéçţîöñ çĥéçķš ûšé ƀöûñðîñĝ ƀöẋéš; îñšþéçţ öþéñîñĝš áñð çļéáŕáñçéš. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.shared.systemCheckPanel.selectedConnectedSystem\":[\"[Šéļéçţéð çöññéçţéð šýšţéɱ ~~~~~~~]\"],\"node.shared.systemCheckPanel.selectedRuns\":[\"[Šéļéçţéð: \",[\"count\",\"plural\",{\"one\":[[\"number\"],\" ŕûñ\"],\"other\":[[\"number\"],\" ŕûñš\"]}],\" · \",[\"length\"],\" ɱ ~~~~~]\"],\"node.shared.systemCheckPanel.separateBranches\":[\"[Šéþáŕáţé ƀŕáñçĥéš ~~~~~]\"],\"node.shared.systemCheckPanel.showAllFindings\":[\"[Šĥöŵ áļļ ƒîñðîñĝš ~~~~~]\"],\"node.shared.systemCheckPanel.systemChecks\":[\"[Šýšţéɱ çĥéçķš ~~~~]\"],\"node.shared.systemCheckPanel.systemFinding\":[\"[Šýšţéɱ ƒîñðîñĝ ~~~~]\"],\"node.shared.systemCheckPanel.systemFindings\":[\"[Šýšţéɱ ƒîñðîñĝš ~~~~~]\"],\"node.shared.systemCheckPanel.warning\":[\"[Ŵáŕñîñĝ ~~~]\"],\"node.shared.systemCheckPanel.warnings\":[\"[Ŵáŕñîñĝš ~~~]\"],\"node.shelf.description\":[\"[Å çöñƒîĝûŕáƀļé šĥéļṽîñĝ ûñîţ. Îţéɱš ĥöšţ öñ éáçĥ ŕöŵ. ~~~~~~~~~~~~~]\"],\"node.shelf.label\":[\"[Šĥéļƒ ~~]\"],\"node.site.description\":[\"[Ţĥé ţöþ-ļéṽéļ çöñţáîñéŕ ĥöļðîñĝ ƀûîļðîñĝš, žöñéš, áñð ţĥé þŕöþéŕţý ƀöûñðáŕý. ~~~~~~~~~~~~~~~~~~~]\"],\"node.site.label\":[\"[Šîţé ~~]\"],\"node.site.panel.address\":[\"[Åððŕéšš ~~~]\"],\"node.site.panel.apn\":[\"[ÅÞÑ ~]\"],\"node.site.panel.autoMostNorthFacingEdge\":[\"[Åûţö — ɱöšţ ñöŕţĥ-ƒáçîñĝ éðĝé ~~~~~~~]\"],\"node.site.panel.contourIntervalSitePlanAnd3d\":[\"[Çöñţöûŕ îñţéŕṽáļ (šîţé þļáñ áñð 3Ð) ~~~~~~~~~]\"],\"node.site.panel.county\":[\"[Çöûñţý ~~]\"],\"node.site.panel.eGRs60\":[\"[é.ĝ. ŔŠ-60 ~~]\"],\"node.site.panel.eGTampaLdc27156\":[\"[é.ĝ. Ţáɱþá ĻÐÇ §27-156 ~~~]\"],\"node.site.panel.every12In\":[\"[éṽéŕý 12 îñ ~~~]\"],\"node.site.panel.every24In\":[\"[éṽéŕý 24 îñ ~~~]\"],\"node.site.panel.every6In\":[\"[éṽéŕý 6 îñ ~~~]\"],\"node.site.panel.findParcel\":[\"[Ƒîñð þáŕçéļ ~~~]\"],\"node.site.panel.finding\":[\"[Ƒîñðîñĝ… ~~~]\"],\"node.site.panel.frontStreetEdge\":[\"[Ƒŕöñţ (šţŕééţ) éðĝé ~~~~~]\"],\"node.site.panel.lookingUpTheParcel\":[\"[Ļööķîñĝ ûþ ţĥé þáŕçéļ áñð ţĥé šţŕééţš áŕöûñð îţ… ~~~~~~~~~~~~]\"],\"node.site.panel.lotArea\":[\"[Ļöţ áŕéá ~~~]\"],\"node.site.panel.n1200WCassStTampaFl\":[\"[1200 Ŵ Çášš Šţ, Ţáɱþá, ƑĻ ~~~~~]\"],\"node.site.panel.noSurveyedLinesContoursAreDrawn\":[\"[Ñö šûŕṽéýéð ļîñéš — çöñţöûŕš áŕé ðŕáŵñ ƒŕöɱ ţĥé šçûļþţéð ĝŕöûñð. ~~~~~~~~~~~~~~~~]\"],\"node.site.panel.none\":[\"[ñöñé ~~]\"],\"node.site.panel.northRotation\":[\"[Ñöŕţĥ ŕöţáţîöñ ~~~~]\"],\"node.site.panel.orientation\":[\"[Öŕîéñţáţîöñ ~~~~]\"],\"node.site.panel.parcel\":[\"[Þáŕçéļ ~~]\"],\"node.site.panel.parcelLookupFailed\":[\"[Þáŕçéļ ļööķûþ ƒáîļéð. ~~~~~~]\"],\"node.site.panel.projectLook\":[\"[Þŕöĵéçţ ļööķ ~~~~]\"],\"node.site.panel.saveCurrentLook\":[\"[Šáṽé çûŕŕéñţ ļööķ ~~~~~]\"],\"node.site.panel.saveTheCurrentLightingAndDisplay\":[\"[Šáṽé ţĥé çûŕŕéñţ ļîĝĥţîñĝ áñð ðîšþļáý áš ţĥîš þŕöĵéçţ'š ðéƒáûļţ. Þéŕšöñáļ ðîšþļáý çĥáñĝéš šţáý îñ ţĥîš ƀŕöŵšéŕ. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.site.panel.setbacks\":[\"[Šéţƀáçķš ~~~]\"],\"node.site.panel.showGround\":[\"[Šĥöŵ ĝŕöûñð ~~~]\"],\"node.site.panel.showTheContourLinesIn3d\":[\"[Šĥöŵ ţĥé çöñţöûŕ ļîñéš îñ 3Ð ~~~~~~~]\"],\"node.site.panel.side\":[\"[šîðé ~~]\"],\"node.site.panel.site\":[\"[Šîţé ~~]\"],\"node.site.panel.source\":[\"[Šöûŕçé ~~]\"],\"node.site.panel.sourceCitation\":[\"[Šöûŕçé / çîţáţîöñ ~~~~~]\"],\"node.site.panel.streetAddress\":[\"[Šţŕééţ áððŕéšš ~~~~]\"],\"node.site.panel.survey\":[\"[šûŕṽéý ~~]\"],\"node.site.panel.surveyedContours\":[\"[\",[\"count\",\"plural\",{\"one\":[[\"lineCount\"],\" šûŕṽéýéð ļîñé\"],\"other\":[[\"lineCount\"],\" šûŕṽéýéð ļîñéš\"]}],\" áţ \",[\"interval\"],\" ƒţ (\",[\"datum\"],\") — \",[\"source\"],\" ~~~~~~~~~]\"],\"node.site.panel.terrain\":[\"[Ţéŕŕáîñ ~~~]\"],\"node.site.panel.typeAnAddressFirst\":[\"[Ţýþé áñ áððŕéšš ƒîŕšţ. ~~~~~~]\"],\"node.site.panel.useProjectLook\":[\"[Ûšé þŕöĵéçţ ļööķ ~~~~~]\"],\"node.site.panel.zone\":[\"[Žöñé ~~]\"],\"node.site.setback.front\":[\"[Ƒŕöñţ ~~]\"],\"node.site.setback.leftOverride\":[\"[Ļéƒţ (öṽéŕŕîðé) ~~~~]\"],\"node.site.setback.rear\":[\"[Ŕéáŕ ~~]\"],\"node.site.setback.rightOverride\":[\"[Ŕîĝĥţ (öṽéŕŕîðé) ~~~~]\"],\"node.site.setback.side\":[\"[Šîðé ~~]\"],\"node.skylight.description\":[\"[Ƒŕáɱéð ĝļášš öþéñîñĝ öñ á ŕööƒ šéĝɱéñţ. ~~~~~~~~~~]\"],\"node.skylight.label\":[\"[Šķýļîĝĥţ ~~~]\"],\"node.skylight.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.skylight.panel.alongX\":[\"[Åļöñĝ Ẋ ~~]\"],\"node.skylight.panel.alongZ\":[\"[Åļöñĝ Ž ~~]\"],\"node.skylight.panel.bottom\":[\"[Ɓöţţöɱ ~~]\"],\"node.skylight.panel.curb\":[\"[Çûŕƀ ~~]\"],\"node.skylight.panel.cutoutOffset\":[\"[Çûţöûţ Öƒƒšéţ ~~~~]\"],\"node.skylight.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.skylight.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.skylight.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.skylight.panel.frame\":[\"[Ƒŕáɱé ~~]\"],\"node.skylight.panel.glassThickness\":[\"[Ĝļášš Ţĥîçķñéšš ~~~~~]\"],\"node.skylight.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.skylight.panel.lanternHeight\":[\"[Ļáñţéŕñ Ĥéîĝĥţ ~~~~]\"],\"node.skylight.panel.left\":[\"[Ļéƒţ ~~]\"],\"node.skylight.panel.motor\":[\"[Ṁöţöŕ ~~]\"],\"node.skylight.panel.motorHousing\":[\"[Ṁöţöŕ Ĥöûšîñĝ ~~~~]\"],\"node.skylight.panel.no\":[\"[Ñö ~]\"],\"node.skylight.panel.noMotor\":[\"[Ñö Ṁöţöŕ ~~~]\"],\"node.skylight.panel.open\":[\"[Öþéñ ~~]\"],\"node.skylight.panel.openingAngle\":[\"[Öþéñîñĝ Åñĝļé ~~~~]\"],\"node.skylight.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.skylight.panel.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.skylight.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.skylight.panel.skylight\":[\"[Šķýļîĝĥţ ~~~]\"],\"node.skylight.panel.thickness\":[\"[Ţĥîçķñéšš ~~~]\"],\"node.skylight.panel.top\":[\"[Ţöþ ~]\"],\"node.skylight.panel.topScale\":[\"[Ţöþ Šçáļé ~~~]\"],\"node.skylight.panel.trackWidth\":[\"[Ţŕáçķ Ŵîðţĥ ~~~]\"],\"node.skylight.panel.type\":[\"[Ţýþé ~~]\"],\"node.skylight.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.skylight.panel.yes\":[\"[Ýéš ~]\"],\"node.skylight.type.flat\":[\"[Ƒļáţ ŕööƒ šķýļîĝĥţ ~~~~~]\"],\"node.skylight.type.lantern\":[\"[Ŕööƒ ļáñţéŕñ ~~~~]\"],\"node.skylight.type.opening\":[\"[Öþéñîñĝ šķýļîĝĥţ ~~~~~]\"],\"node.skylight.type.sliding\":[\"[Šļîðîñĝ šķýļîĝĥţ ~~~~~]\"],\"node.skylight.type.walkOn\":[\"[Ŵáļķ-öñ ŕööƒļîĝĥţ ~~~~~]\"],\"node.slab.description\":[\"[Å þöļýĝöñ-ƀöûñðéð ƒļööŕ šûŕƒáçé ţĥáţ ĥöšţš îţéɱš öñ ţöþ. ~~~~~~~~~~~~~~]\"],\"node.slab.label\":[\"[Šļáƀ ~~]\"],\"node.slab.panel.addHole\":[\"[Åðð Ĥöļé ~~~]\"],\"node.slab.panel.area\":[\"[Åŕéá ~~]\"],\"node.slab.panel.auto\":[\"[Åûţö ~~]\"],\"node.slab.panel.base\":[\"[Ɓášé ~~]\"],\"node.slab.panel.cutHatch\":[\"[Çûţ ĥáţçĥ ~~~]\"],\"node.slab.panel.cutOpening\":[\"[Çûţ öþéñîñĝ ~~~]\"],\"node.slab.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.slab.panel.done\":[\"[Ðöñé ~~]\"],\"node.slab.panel.elevation\":[\"[Éļéṽáţîöñ ~~~]\"],\"node.slab.panel.extendsThePerimeterDownToTerrain\":[\"[Éẋţéñðš ţĥé þéŕîɱéţéŕ ðöŵñ ţö ţéŕŕáîñ. Ţĥé ƒļáţ šûŕƒáçé, ƀášé, áñð ţĥîçķñéšš šţáý ûñçĥáñĝéð. ~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.slab.panel.fixed\":[\"[Ƒîẋéð ~~]\"],\"node.slab.panel.floor\":[\"[Ƒļööŕ ~~]\"],\"node.slab.panel.followsTerrain\":[\"[Ƒöļļöŵš ţéŕŕáîñ ~~~~~]\"],\"node.slab.panel.foundation\":[\"[Ƒöûñðáţîöñ ~~~]\"],\"node.slab.panel.holes\":[\"[Ĥöļéš ~~]\"],\"node.slab.panel.info\":[\"[Îñƒö ~~]\"],\"node.slab.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.slab.panel.noHoles\":[\"[Ñö ĥöļéš ~~~]\"],\"node.slab.panel.rim\":[\"[Ŕîɱ ~]\"],\"node.slab.panel.slab\":[\"[Šļáƀ ~~]\"],\"node.slab.panel.standard2\":[\"[Šţáñðáŕð (2\\\") ~~~]\"],\"node.slab.panel.standard5cm\":[\"[Šţáñðáŕð (5çɱ) ~~~]\"],\"node.slab.panel.sunken15cm\":[\"[Šûñķéñ (15çɱ) ~~~]\"],\"node.slab.panel.sunken6\":[\"[Šûñķéñ (6\\\") ~~]\"],\"node.slab.panel.surface\":[\"[Šûŕƒáçé ~~~]\"],\"node.slab.panel.thick15cm\":[\"[Ţĥîçķ (15çɱ) ~~~]\"],\"node.slab.panel.thick6\":[\"[Ţĥîçķ (6\\\") ~~]\"],\"node.slab.panel.thickness\":[\"[Ţĥîçķñéšš ~~~]\"],\"node.slab.panel.thin1\":[\"[Ţĥîñ (1\\\") ~~]\"],\"node.slab.panel.thin2cm\":[\"[Ţĥîñ (2çɱ) ~~]\"],\"node.solarPanel.description\":[\"[Ĝŕîð öƒ þĥöţöṽöļţáîç þáñéļš ɱöûñţéð öñ á ŕööƒ šéĝɱéñţ. ~~~~~~~~~~~~~~]\"],\"node.solarPanel.label\":[\"[Šöļáŕ Þáñéļ ~~~]\"],\"node.solarPanel.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.solarPanel.panel.array\":[\"[Åŕŕáý ~~]\"],\"node.solarPanel.panel.autoFitToRoof\":[\"[Åûţö-ƒîţ ţö ŕööƒ ~~~~]\"],\"node.solarPanel.panel.columns\":[\"[Çöļûɱñš ~~~]\"],\"node.solarPanel.panel.customDimensionsDonTMatchAny\":[\"[Çûšţöɱ — ðîɱéñšîöñš ðöñ'ţ ɱáţçĥ áñý þŕéšéţ ~~~~~~~~~~~]\"],\"node.solarPanel.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.solarPanel.panel.flipOrientation\":[\"[Ƒļîþ öŕîéñţáţîöñ ~~~~~]\"],\"node.solarPanel.panel.flush\":[\"[Ƒļûšĥ ~~]\"],\"node.solarPanel.panel.frameDepth\":[\"[Ƒŕáɱé ðéþţĥ ~~~]\"],\"node.solarPanel.panel.frameThickness\":[\"[Ƒŕáɱé ţĥîçķñéšš ~~~~~]\"],\"node.solarPanel.panel.gapX\":[\"[Ĝáþ Ẋ ~~]\"],\"node.solarPanel.panel.gapY\":[\"[Ĝáþ Ý ~~]\"],\"node.solarPanel.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.solarPanel.panel.mounting\":[\"[Ṁöûñţîñĝ ~~~]\"],\"node.solarPanel.panel.panel\":[\"[Þáñéļ ~~]\"],\"node.solarPanel.panel.preset\":[\"[Þŕéšéţ ~~]\"],\"node.solarPanel.panel.rows\":[\"[Ŕöŵš ~~]\"],\"node.solarPanel.panel.setbacksTooLarge\":[\"[Šéţƀáçķš ţöö ļáŕĝé ţö ƒîţ á þáñéļ. ~~~~~~~~~]\"],\"node.solarPanel.panel.solarPanel\":[\"[Šöļáŕ Þáñéļ ~~~]\"],\"node.solarPanel.panel.standoff\":[\"[Šţáñðöƒƒ ~~~]\"],\"node.solarPanel.panel.tiltAngle\":[\"[Ţîļţ áñĝļé ~~~]\"],\"node.solarPanel.panel.tilted\":[\"[Ţîļţéð ~~]\"],\"node.solarPanel.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.solarPanel.preset.compact\":[\"[Çöɱþáçţ ~~~]\"],\"node.solarPanel.preset.frameless\":[\"[Ƒŕáɱéļéšš ~~~]\"],\"node.solarPanel.preset.residential\":[\"[Ŕéšîðéñţîáļ ~~~~]\"],\"node.solarPanel.preset.residentialLarge\":[\"[Ŕéšîðéñţîáļ Ļáŕĝé ~~~~~]\"],\"node.spawn.description\":[\"[Þļáýéŕ öŕ çáɱéŕá öŕîĝîñ ŵîţĥîñ á ļéṽéļ. Öñé þéŕ ļéṽéļ. ~~~~~~~~~~~~~]\"],\"node.spawn.label\":[\"[Šþáŵñ Þöîñţ ~~~]\"],\"node.stair.constructionControls.body\":[\"[Ɓöðý ~~]\"],\"node.stair.constructionControls.centerStringer\":[\"[Çéñţéŕ šţŕîñĝéŕ ~~~~~]\"],\"node.stair.constructionControls.closedRisers\":[\"[Çļöšéð ŕîšéŕš ~~~~]\"],\"node.stair.constructionControls.fromStructure\":[\"[Ƒŕöɱ šţŕûçţûŕé ~~~~]\"],\"node.stair.constructionControls.inherit\":[\"[Îñĥéŕîţ ~~~]\"],\"node.stair.constructionControls.nosing\":[\"[Ñöšîñĝ ~~]\"],\"node.stair.constructionControls.open\":[\"[Öþéñ ~~]\"],\"node.stair.constructionControls.original\":[\"[Öŕîĝîñáļ ~~~]\"],\"node.stair.constructionControls.riserThickness\":[\"[Ŕîšéŕ ţĥîçķñéšš ~~~~~]\"],\"node.stair.constructionControls.sideStringers\":[\"[Šîðé šţŕîñĝéŕš ~~~~]\"],\"node.stair.constructionControls.solid\":[\"[Šöļîð ~~]\"],\"node.stair.constructionControls.stringerDepth\":[\"[Šţŕîñĝéŕ ðéþţĥ ~~~~]\"],\"node.stair.constructionControls.stringerWidth\":[\"[Šţŕîñĝéŕ ŵîðţĥ ~~~~]\"],\"node.stair.constructionControls.treadFinish\":[\"[Ţŕéáð ƒîñîšĥ ~~~~]\"],\"node.stair.constructionControls.treadThickness\":[\"[Ţŕéáð ţĥîçķñéšš ~~~~~]\"],\"node.stair.constructionControls.waist\":[\"[Ŵáîšţ ~~]\"],\"node.stair.constructionControls.waistThickness\":[\"[Ŵáîšţ ţĥîçķñéšš ~~~~~]\"],\"node.stair.description\":[\"[Å šţáîŕ çöɱþöšéð öƒ öñé öŕ ɱöŕé ƒļîĝĥţš ŵîţĥ çöñƒîĝûŕáƀļé ţŕéáðš, ŕîšéŕš, ŕáîļîñĝš. ~~~~~~~~~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.arrivalMismatch\":[\"[Ţĥé ƒļîĝĥţ çĥáîñ ðöéš ñöţ ŕéáçĥ ţĥé ðéçļáŕéð ðéšţîñáţîöñ. ~~~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.comfortTarget\":[\"[Ţŵö ŕîšéŕš þļûš ĝöîñĝ îš öûţšîðé ţĥé 0.60–0.65 ɱ ðéšîĝñ ŕáñĝé. ~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.goingTarget\":[\"[Ĝöîñĝ îš ƀéļöŵ ţĥé ðéšîĝñ ţáŕĝéţ. ~~~~~~~~~]\"],\"node.stair.diagnostic.headroomTarget\":[\"[Öṽéŕĥéáð šûŕƒáçéš ļéáṽé ļéšš ţĥáñ ţĥé ţáŕĝéţ ĥéáðŕööɱ. ~~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.headroomUnresolved\":[\"[Ðéţáîļéð ĥéáðŕööɱ çöûļð ñöţ ƀé éṽáļûáţéð: çĥéçķ ŕîšéŕ çöûñţš áñð ţĥé šûŕƒáçé ǫûéŕý ƀûðĝéţ. ~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.invalidFlight\":[\"[Ƒļîĝĥţ ðîɱéñšîöñš áñð îñţéĝéŕ ŕîšéŕ çöûñţ ɱûšţ ƀé þöšîţîṽé. ~~~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.invalidRise\":[\"[Ţĥé ðéšţîñáţîöñ ɱûšţ ƀé áƀöṽé ţĥé šţáîŕ ƀášé. ~~~~~~~~~~~~]\"],\"node.stair.diagnostic.landingOverlap\":[\"[Ļáñðîñĝ ðéþţĥ éẋçééðš á ƒûļļ çîŕçļé áţ ţĥé ŵáļķîñĝ ļîñé; ţĥé ṽîšîƀļé ļáñðîñĝ îš ļîɱîţéð ţö öñé çîŕçļé. ~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.narrowWinderEnd\":[\"[Ţĥé ñáŕŕöŵ éñð öƒ á ŵîñðéŕ ţŕéáð îš ƀéļöŵ 0.10 ɱ; çĥéçķ ţĥé îñţéñðéð šţáîŕ ûšé. ~~~~~~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.nonuniformRisers\":[\"[Ƒļîĝĥţ ŕîšéŕ ĥéîĝĥţš ðéŕ. Ûšé ûñîƒöŕɱ-ŕîšéŕ ŕéþáîŕ öñļý îƒ ţĥîš îš á þŕöþöšéð ðéšîĝñ. ~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.raisedLanding\":[\"[Å ļáñðîñĝ ĥáš á šţöŕéð ŕîšé; îñšþéçţ îţš ţŕáñšîţîöñ ƀéƒöŕé ŕéþáîŕ. ~~~~~~~~~~~~~~~~~]\"],\"node.stair.diagnostic.riserTarget\":[\"[Ŕîšéŕ ĥéîĝĥţ éẋçééðš ţĥé ðéšîĝñ ţáŕĝéţ. ~~~~~~~~~~]\"],\"node.stair.label\":[\"[Šţáîŕ ~~]\"],\"node.stair.layout.straight\":[\"[Šţŕáîĝĥţ ~~~]\"],\"node.stair.layout.turn\":[\"[\",[\"layout\"],\" ţûŕñ ~~]\"],\"node.stair.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.stair.panel.addFlight\":[\"[Åðð ƒļîĝĥţ ~~~]\"],\"node.stair.panel.addLanding\":[\"[Åðð ļáñðîñĝ ~~~]\"],\"node.stair.panel.applyLabelLayout\":[\"[Åþþļý \",[\"label\"],\" ļáýöûţ ~~~~]\"],\"node.stair.panel.autoCutout\":[\"[Åûţö Çûţöûţ ~~~]\"],\"node.stair.panel.balusters\":[\"[Ɓáļûšţéŕš ~~~]\"],\"node.stair.panel.boards\":[\"[Ɓöáŕðš ~~]\"],\"node.stair.panel.both\":[\"[Ɓöţĥ ~~]\"],\"node.stair.panel.cable\":[\"[Çáƀļé ~~]\"],\"node.stair.panel.centerColumn\":[\"[Çéñţéŕ Çöļûɱñ ~~~~]\"],\"node.stair.panel.clockwise\":[\"[Çļöçķŵîšé ~~~]\"],\"node.stair.panel.connectedTo\":[\"[Çöññéçţéð ţö \",[\"surface\"],\". Ṁöṽé ţĥé šţáîŕ ţö çöññéçţ ţö áñöţĥéŕ éðĝé. ~~~~~~~~~~~~~~]\"],\"node.stair.panel.connectedToSurface\":[\"[Çöññéçţéð ţö á šûŕƒáçé. Ṁöṽé ţĥé šţáîŕ ţö çöññéçţ ţö áñöţĥéŕ éðĝé. ~~~~~~~~~~~~~~~~]\"],\"node.stair.panel.construction\":[\"[Çöñšţŕûçţîöñ ~~~~]\"],\"node.stair.panel.counterclockwise\":[\"[Çöûñţéŕçļöçķŵîšé ~~~~~]\"],\"node.stair.panel.curved\":[\"[Çûŕṽéð ~~]\"],\"node.stair.panel.customRise\":[\"[Çûšţöɱ ŕîšé ~~~]\"],\"node.stair.panel.deck\":[\"[Ðéçķ ~~]\"],\"node.stair.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.stair.panel.designTargets\":[\"[Ðéšîĝñ ţáŕĝéţš ~~~~]\"],\"node.stair.panel.destination\":[\"[Ðéšţîñáţîöñ ~~~~]\"],\"node.stair.panel.dragNearADeckPatioConcrete\":[\"[Ðŕáĝ ñéáŕ á ðéçķ, þáţîö, çöñçŕéţé šļáƀ, öŕ ļáñðîñĝ éðĝé ţö ƒîţ ţĥé šţáîŕ. ~~~~~~~~~~~~~~~~~]\"],\"node.stair.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.stair.panel.equalAngle\":[\"[Éǫûáļ áñĝļé ~~~]\"],\"node.stair.panel.equalGoing\":[\"[Éǫûáļ ĝöîñĝ ~~~]\"],\"node.stair.panel.fitRisersAndGoing\":[\"[Ƒîţ ŕîšéŕš áñð ĝöîñĝ ~~~~~~]\"],\"node.stair.panel.fitToFloor\":[\"[Ƒîţ Ţö Ƒļööŕ ~~~]\"],\"node.stair.panel.fitUniformRisers\":[\"[Ƒîţ ûñîƒöŕɱ ŕîšéŕš ~~~~~]\"],\"node.stair.panel.flightMeasurements\":[\"[Ƒļîĝĥţ \",[\"number\"],\": \",[\"count\",\"plural\",{\"one\":[[\"riserCount\"],\" ŕîšéŕ\"],\"other\":[[\"riserCount\"],\" ŕîšéŕš\"]}],\" · Ŕ \",[\"riser\"],\" · Ţ \",[\"going\"],\" · \",[\"slope\"],\" ~~~~~~]\"],\"node.stair.panel.floorsCeilingsAndStairsOnly\":[\"[Ƒļööŕš, çéîļîñĝš áñð šţáîŕš öñļý. ~~~~~~~~~]\"],\"node.stair.panel.followsDeck\":[\"[Ƒöļļöŵš ðéçķ ~~~~]\"],\"node.stair.panel.followsLevel\":[\"[Ƒöļļöŵš ļéṽéļ ~~~~]\"],\"node.stair.panel.fromLevel\":[\"[Ƒŕöɱ Ļéṽéļ ~~~]\"],\"node.stair.panel.geometry\":[\"[Ĝéöɱéţŕý ~~~]\"],\"node.stair.panel.glass\":[\"[Ĝļášš ~~]\"],\"node.stair.panel.headroom\":[\"[Ĥéáðŕööɱ: ~~~]\"],\"node.stair.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.stair.panel.innerGap\":[\"[Îññéŕ ĝáþ ~~~]\"],\"node.stair.panel.innerRadius\":[\"[Îññéŕ Ŕáðîûš ~~~~]\"],\"node.stair.panel.integrated\":[\"[Îñţéĝŕáţéð ~~~]\"],\"node.stair.panel.landing\":[\"[Ļáñðîñĝ ~~~]\"],\"node.stair.panel.layout\":[\"[Ļáýöûţ ~~]\"],\"node.stair.panel.left\":[\"[Ļéƒţ ~~]\"],\"node.stair.panel.leftTurn\":[\"[Ļéƒţ ţûŕñ ~~~]\"],\"node.stair.panel.measurements\":[\"[Ṁéášûŕéɱéñţš ~~~~]\"],\"node.stair.panel.metal\":[\"[Ṁéţáļ ~~]\"],\"node.stair.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.stair.panel.movingThisStairKeepsItsCurrent\":[\"[Ṁöṽîñĝ ţĥîš šţáîŕ ķééþš îţš çûŕŕéñţ ŕîšé, šţéþš, áñð ŕûñ. ~~~~~~~~~~~~~~]\"],\"node.stair.panel.noOverheadSurface\":[\"[Ñö öṽéŕĥéáð šûŕƒáçé ~~~~~~]\"],\"node.stair.panel.none\":[\"[Ñöñé ~~]\"],\"node.stair.panel.notEvaluated\":[\"[Ñöţ éṽáļûáţéð ~~~~]\"],\"node.stair.panel.opening\":[\"[Öþéñîñĝ ~~~]\"],\"node.stair.panel.openingOffset\":[\"[Öþéñîñĝ Öƒƒšéţ ~~~~]\"],\"node.stair.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.stair.panel.postRail\":[\"[Þöšţ & ŕáîļ ~~~]\"],\"node.stair.panel.railing\":[\"[Ŕáîļîñĝ ~~~]\"],\"node.stair.panel.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.stair.panel.rightTurn\":[\"[Ŕîĝĥţ ţûŕñ ~~~]\"],\"node.stair.panel.rise\":[\"[Ŕîšé ~~]\"],\"node.stair.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.stair.panel.segmentType\":[\"[\",[\"type\",\"select\",{\"landing\":[\"Ļáñðîñĝ\"],\"other\":[\"Šţáîŕ\"]}],\" ~~~~]\"],\"node.stair.panel.segments\":[\"[Šéĝɱéñţš ~~~]\"],\"node.stair.panel.sizing\":[\"[Šîžîñĝ ~~]\"],\"node.stair.panel.snapToNearbySurfaces\":[\"[Šñáþ ţö ñéáŕƀý šûŕƒáçéš ~~~~~~]\"],\"node.stair.panel.spiral\":[\"[Šþîŕáļ ~~]\"],\"node.stair.panel.staircase\":[\"[Šţáîŕçášé ~~~]\"],\"node.stair.panel.stepSupports\":[\"[Šţéþ Šûþþöŕţš ~~~~]\"],\"node.stair.panel.steps\":[\"[Šţéþš ~~]\"],\"node.stair.panel.straight\":[\"[Šţŕáîĝĥţ ~~~]\"],\"node.stair.panel.style\":[\"[Šţýļé ~~]\"],\"node.stair.panel.surfaceConnection\":[\"[Šûŕƒáçé çöññéçţîöñ ~~~~~~]\"],\"node.stair.panel.sweep\":[\"[Šŵééþ ~~]\"],\"node.stair.panel.targetGoing\":[\"[Ţáŕĝéţ ĝöîñĝ ~~~~]\"],\"node.stair.panel.targetHeadroom\":[\"[Ţáŕĝéţ ĥéáðŕööɱ ~~~~~]\"],\"node.stair.panel.targetMaxRiser\":[\"[Ţáŕĝéţ ɱáẋ ŕîšéŕ ~~~~~]\"],\"node.stair.panel.targetMinimumGoing\":[\"[Ţáŕĝéţ ɱîñîɱûɱ ĝöîñĝ ~~~~~~]\"],\"node.stair.panel.thickness\":[\"[Ţĥîçķñéšš ~~~]\"],\"node.stair.panel.to\":[\"[Ţö ~]\"],\"node.stair.panel.topLanding\":[\"[Ţöþ Ļáñðîñĝ ~~~]\"],\"node.stair.panel.type\":[\"[Ţýþé ~~]\"],\"node.stair.panel.unavailable\":[\"[Ûñáṽáîļáƀļé ~~~~]\"],\"node.stair.panel.walkingLineOffset\":[\"[Ŵáļķîñĝ ļîñé öƒƒšéţ ~~~~~~]\"],\"node.stair.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.stair.panel.winder\":[\"[Ŵîñðéŕ ~~]\"],\"node.stair.railingControls.both\":[\"[Ɓöţĥ ~~]\"],\"node.stair.railingControls.bottomExtension\":[\"[Ɓöţţöɱ šļöþéð éẋţéñšîöñ ~~~~~~~]\"],\"node.stair.railingControls.continuous\":[\"[Çöñţîñûöûš ~~~]\"],\"node.stair.railingControls.floor\":[\"[Ƒļööŕ ~~]\"],\"node.stair.railingControls.handrailDiameter\":[\"[Ĥáñðŕáîļ ðîáɱéţéŕ ~~~~~]\"],\"node.stair.railingControls.handrailHeight\":[\"[Ĥáñðŕáîļ ĥéîĝĥţ ~~~~~]\"],\"node.stair.railingControls.handrailInset\":[\"[Ĥáñðŕáîļ îñšéţ ~~~~]\"],\"node.stair.railingControls.left\":[\"[Ļéƒţ ~~]\"],\"node.stair.railingControls.noReturn\":[\"[Ñö ŕéţûŕñ ~~~]\"],\"node.stair.railingControls.none\":[\"[Ñöñé ~~]\"],\"node.stair.railingControls.originalLayout\":[\"[Öŕîĝîñáļ ļáýöûţ ~~~~~]\"],\"node.stair.railingControls.postFacing\":[\"[Þöšţ-ƒáçîñĝ ~~~]\"],\"node.stair.railingControls.returnLength\":[\"[Ŕéţûŕñ ļéñĝţĥ ~~~~]\"],\"node.stair.railingControls.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.stair.railingControls.separateHandrail\":[\"[Šéþáŕáţé ĥáñðŕáîļ ~~~~~]\"],\"node.stair.railingControls.setTheLengthToReachThe\":[\"[Šéţ ţĥé ļéñĝţĥ ţö ŕéáçĥ ţĥé ŵáļļ öŕ þöšţ. ~~~~~~~~~~]\"],\"node.stair.railingControls.topExtension\":[\"[Ţöþ ĥöŕîžöñţáļ éẋţéñšîöñ ~~~~~~~]\"],\"node.stair.railingControls.wallFacing\":[\"[Ŵáļļ-ƒáçîñĝ ~~~]\"],\"node.stair.structureControls.aSolidPouredFlightOnA\":[\"[Å šöļîð þöûŕéð ƒļîĝĥţ öñ á ƒööţîñĝ; ŕîšéŕš çļöšéð, ñö šţŕîñĝéŕš. ~~~~~~~~~~~~~~~~]\"],\"node.stair.structureControls.autoAutocount\":[\"[Åûţö (\",[\"autoCount\"],\") ~~]\"],\"node.stair.structureControls.autoClosed\":[\"[Åûţö (çļöšéð) ~~~]\"],\"node.stair.structureControls.autoOpen\":[\"[Åûţö (öþéñ) ~~~]\"],\"node.stair.structureControls.autoPressureTreated\":[\"[Åûţö (þŕéššûŕé-ţŕéáţéð) ~~~~~~]\"],\"node.stair.structureControls.autoTreads\":[\"[Åûţö (\",[\"treads\"],\") ~~]\"],\"node.stair.structureControls.autoUntreated\":[\"[Åûţö (ûñţŕéáţéð) ~~~~]\"],\"node.stair.structureControls.closed1x8Boards\":[\"[Çļöšéð (1ẋ8 ƀöáŕðš) ~~~~]\"],\"node.stair.structureControls.concrete\":[\"[Çöñçŕéţé ~~~]\"],\"node.stair.structureControls.countSteelChannels\":[\"[\",[\"count\",\"plural\",{\"one\":[\"#\",\" šţééļ çĥáññéļ\"],\"other\":[\"#\",\" šţééļ çĥáññéļš\"]}],\" ~~~~~~~~]\"],\"node.stair.structureControls.countSteelChannelsAtSpacing\":[\"[\",[\"count\",\"plural\",{\"one\":[\"#\",\" šţééļ çĥáññéļ áţ \",[\"spacing\"],\" ö.ç.\"],\"other\":[\"#\",\" šţééļ çĥáññéļš áţ \",[\"spacing\"],\" ö.ç.\"]}],\" ~~~~~~~~~~]\"],\"node.stair.structureControls.countStringers\":[\"[\",[\"count\",\"plural\",{\"one\":[\"#\",\" šţŕîñĝéŕ\"],\"other\":[\"#\",\" šţŕîñĝéŕš\"]}],\" ~~~~~~]\"],\"node.stair.structureControls.countStringersAtSpacing\":[\"[\",[\"count\",\"plural\",{\"one\":[\"#\",\" šţŕîñĝéŕ áţ \",[\"spacing\"],\" ö.ç.\"],\"other\":[\"#\",\" šţŕîñĝéŕš áţ \",[\"spacing\"],\" ö.ç.\"]}],\" ~~~~~~~~]\"],\"node.stair.structureControls.cut\":[\"[Çûţ ~]\"],\"node.stair.structureControls.flightLayout\":[\"[Ƒļîĝĥţ \",[\"number\"],\": \",[\"layout\"],\" ~~]\"],\"node.stair.structureControls.housedSides\":[\"[Ĥöûšéð šîðéš ~~~~]\"],\"node.stair.structureControls.inchesInOC\":[\"[\",[\"inches\"],\" îñ ö.ç. ~~]\"],\"node.stair.structureControls.layoutAuto\":[\"[\",[\"layout\"],\" (áûţö) ~~]\"],\"node.stair.structureControls.lumber\":[\"[Ļûɱƀéŕ ~~]\"],\"node.stair.structureControls.maxSpacing\":[\"[Ṁáẋ šþáçîñĝ ~~~]\"],\"node.stair.structureControls.nosing\":[\"[Ñöšîñĝ ~~]\"],\"node.stair.structureControls.oneStock\":[\"[Öñé \",[\"stock\"],\" ~]\"],\"node.stair.structureControls.open\":[\"[Öþéñ ~~]\"],\"node.stair.structureControls.originalBody\":[\"[Öŕîĝîñáļ ƀöðý ~~~~]\"],\"node.stair.structureControls.plywoodFinish\":[\"[Þļýŵööð + ƒîñîšĥ ~~~~]\"],\"node.stair.structureControls.pressureTreated\":[\"[Þŕéššûŕé-ţŕéáţéð ~~~~~]\"],\"node.stair.structureControls.risers\":[\"[Ŕîšéŕš ~~]\"],\"node.stair.structureControls.steelStringers\":[\"[Šţééļ šţŕîñĝéŕš ~~~~~]\"],\"node.stair.structureControls.stringerCount\":[\"[Šţŕîñĝéŕ çöûñţ ~~~~]\"],\"node.stair.structureControls.stringerType\":[\"[Šţŕîñĝéŕ ţýþé ~~~~]\"],\"node.stair.structureControls.stringers\":[\"[Šţŕîñĝéŕš ~~~]\"],\"node.stair.structureControls.structure\":[\"[Šţŕûçţûŕé ~~~]\"],\"node.stair.structureControls.treads\":[\"[Ţŕéáðš ~~]\"],\"node.stair.structureControls.twoStock\":[\"[Ţŵö \",[\"stock\"],\" ~]\"],\"node.stair.structureControls.untreated\":[\"[Ûñţŕéáţéð ~~~]\"],\"node.stair.structureControls.woodStringers\":[\"[Ŵööð šţŕîñĝéŕš ~~~~]\"],\"node.stairSegment.description\":[\"[Å šîñĝļé ƒļîĝĥţ öƒ á þáŕéñţ šţáîŕ. ~~~~~~~~~]\"],\"node.stairSegment.label\":[\"[Šţáîŕ Šéĝɱéñţ ~~~~]\"],\"node.stairSegment.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.stairSegment.panel.attachment\":[\"[Åţţáçĥɱéñţ ~~~]\"],\"node.stairSegment.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.stairSegment.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.stairSegment.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.stairSegment.panel.editingSwitchesTheStairToCustom\":[\"[Éðîţîñĝ šŵîţçĥéš ţĥé šţáîŕ ţö Çûšţöɱ ŕîšé ~~~~~~~~~~~]\"],\"node.stairSegment.panel.equalAngle\":[\"[Éǫûáļ áñĝļé ~~~]\"],\"node.stairSegment.panel.equalGoing\":[\"[Éǫûáļ ĝöîñĝ ~~~]\"],\"node.stairSegment.panel.fillToFloor\":[\"[Ƒîļļ ţö ƒļööŕ ~~~~]\"],\"node.stairSegment.panel.flight\":[\"[Ƒļîĝĥţ ~~]\"],\"node.stairSegment.panel.flightShape\":[\"[Ƒļîĝĥţ šĥáþé ~~~~]\"],\"node.stairSegment.panel.front\":[\"[Ƒŕöñţ ~~]\"],\"node.stairSegment.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.stairSegment.panel.innerGap\":[\"[Îññéŕ ĝáþ ~~~]\"],\"node.stairSegment.panel.landing\":[\"[Ļáñðîñĝ ~~~]\"],\"node.stairSegment.panel.left\":[\"[Ļéƒţ ~~]\"],\"node.stairSegment.panel.leftTurn\":[\"[Ļéƒţ ţûŕñ ~~~]\"],\"node.stairSegment.panel.length\":[\"[Ļéñĝţĥ ~~]\"],\"node.stairSegment.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.stairSegment.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.stairSegment.panel.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.stairSegment.panel.rightTurn\":[\"[Ŕîĝĥţ ţûŕñ ~~~]\"],\"node.stairSegment.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.stairSegment.panel.stairSegment\":[\"[Šţáîŕ Šéĝɱéñţ ~~~~]\"],\"node.stairSegment.panel.steps\":[\"[Šţéþš ~~]\"],\"node.stairSegment.panel.straight\":[\"[Šţŕáîĝĥţ ~~~]\"],\"node.stairSegment.panel.structure\":[\"[Šţŕûçţûŕé ~~~]\"],\"node.stairSegment.panel.thickness\":[\"[Ţĥîçķñéšš ~~~]\"],\"node.stairSegment.panel.type\":[\"[Ţýþé ~~]\"],\"node.stairSegment.panel.walkingLineOffset\":[\"[Ŵáļķîñĝ ļîñé öƒƒšéţ ~~~~~~]\"],\"node.stairSegment.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.stairSegment.panel.winder\":[\"[Ŵîñðéŕ ~~]\"],\"node.structuralGrid.description\":[\"[Þéŕšîšţéñţ çöñšţŕûçţîöñ ĝŕîð áẋîš ŵîţĥ îðéñţîƒîçáţîöñ ƀûƀƀļéš. ~~~~~~~~~~~~~~~~~]\"],\"node.structuralGrid.label\":[\"[Šţŕûçţûŕáļ Ĝŕîð ~~~~~]\"],\"node.turbineVent.description\":[\"[Ŵîñð-ðŕîṽéñ šþîññîñĝ ŵĥîŕļýƀîŕð éẋĥáûšţ ṽéñţ ƒöŕ á ŕööƒ šļöþé. ~~~~~~~~~~~~~~~~]\"],\"node.turbineVent.label\":[\"[Ţûŕƀîñé Ṽéñţ ~~~~]\"],\"node.turbineVent.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.turbineVent.panel.cylinder\":[\"[Çýļîñðéŕ ~~~]\"],\"node.turbineVent.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.turbineVent.panel.diameter\":[\"[Ðîáɱéţéŕ ~~~]\"],\"node.turbineVent.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.turbineVent.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.turbineVent.panel.globe\":[\"[Ĝļöƀé ~~]\"],\"node.turbineVent.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.turbineVent.panel.motion\":[\"[Ṁöţîöñ ~~]\"],\"node.turbineVent.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.turbineVent.panel.neckHeight\":[\"[Ñéçķ Ĥéîĝĥţ ~~~]\"],\"node.turbineVent.panel.pause\":[\"[Þáûšé ~~]\"],\"node.turbineVent.panel.play\":[\"[Þļáý ~~]\"],\"node.turbineVent.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.turbineVent.panel.rotation\":[\"[Ŕöţáţîöñ ~~~]\"],\"node.turbineVent.panel.spinSpeed\":[\"[Šþîñ Šþééð ~~~]\"],\"node.turbineVent.panel.style\":[\"[Šţýļé ~~]\"],\"node.turbineVent.panel.turbineVent\":[\"[Ţûŕƀîñé Ṽéñţ ~~~~]\"],\"node.turbineVent.panel.vanes\":[\"[Ṽáñéš ~~]\"],\"node.unit.description\":[\"[Å ñáɱéð ĝŕöûþ öƒ žöñéš ƒöŕɱîñĝ öñé áþáŕţɱéñţ, ĥöţéļ ŕööɱ öŕ çöɱɱéŕçîáļ ļöţ. ~~~~~~~~~~~~~~~~~~~]\"],\"node.unit.kind.apartment\":[\"[Åþáŕţɱéñţ ~~~]\"],\"node.unit.kind.commercial\":[\"[Çöɱɱéŕçîáļ ~~~]\"],\"node.unit.kind.common\":[\"[Çöɱɱöñ ~~]\"],\"node.unit.kind.hotelRoom\":[\"[Ĥöţéļ ŕööɱ ~~~]\"],\"node.unit.label\":[\"[Ûñîţ ~~]\"],\"node.unit.panel.memberRoom\":[\"[Ŕööɱ ~~]\"],\"node.unit.panel.memberZone\":[\"[Žöñé ~~]\"],\"node.unit.panel.noZonesAssigned\":[\"[Ñö žöñéš áššîĝñéð ýéţ. ~~~~~~]\"],\"node.unit.panel.nonAdjacentLevels\":[\"[Ṁéɱƀéŕš šîţ öñ ļéṽéļš ţĥáţ áŕé ñöţ áðĵáçéñţ. ~~~~~~~~~~~]\"],\"node.unit.panel.removeMember\":[\"[Ŕéɱöṽé \",[\"name\"],\" ƒŕöɱ ûñîţ ~~~~~]\"],\"node.unit.panel.removeZone\":[\"[Ŕéɱöṽé žöñé ƒŕöɱ ûñîţ ~~~~~~]\"],\"node.unit.unitPanel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.unit.unitPanel.color\":[\"[Çöļöŕ ~~]\"],\"node.unit.unitPanel.delete\":[\"[Ðéļéţé ~~]\"],\"node.unit.unitPanel.focus\":[\"[Ƒöçûš ~~]\"],\"node.unit.unitPanel.grossArea\":[\"[Ĝŕöšš áŕéá ~~~]\"],\"node.unit.unitPanel.kind\":[\"[Ķîñð ~~]\"],\"node.unit.unitPanel.levels\":[\"[Ļéṽéļš ~~]\"],\"node.unit.unitPanel.members\":[\"[Ṁéɱƀéŕš ~~~]\"],\"node.unit.unitPanel.name\":[\"[Ñáɱé ~~]\"],\"node.unit.unitPanel.noRoomsYetPickThisUnit\":[\"[Ñö ŕööɱš ýéţ. Þîçķ ţĥîš ûñîţ ƒŕöɱ á ŕööɱ'š þáñéļ, öŕ ðŕáŵ žöñéš ŵĥîļé îţ îš ƒöçûšéð. ~~~~~~~~~~~~~~~~~~~~]\"],\"node.unit.unitPanel.report\":[\"[Ŕéþöŕţ ~~]\"],\"node.unit.unitPanel.unit\":[\"[Ûñîţ ~~]\"],\"node.wall.actions.mergeWalls\":[\"[Ṁéŕĝé ŵáļļš ~~~]\"],\"node.wall.actions.splitWall\":[\"[Šþļîţ ŵáļļ ~~~]\"],\"node.wall.actions.theseWallsCannotBeMerged\":[\"[Ţĥéšé ŵáļļš çáññöţ ƀé ɱéŕĝéð. ~~~~~~~~]\"],\"node.wall.curtain.cell\":[\"[Çöļûɱñ \",[\"column\"],\", ŕöŵ \",[\"row\"],\": \",[\"type\",\"select\",{\"glass\":[\"ĝļášš\"],\"solid\":[\"šöļîð\"],\"other\":[\"éɱþţý\"]}],\" ~~~~~~~~]\"],\"node.wall.curtain.columnSpacing\":[\"[\",[\"count\",\"plural\",{\"one\":[[\"number\"],\" çöļûɱñ\"],\"other\":[[\"number\"],\" çöļûɱñš\"]}],\" · \",[\"spacing\"],\" ĝŕîð šþáçîñĝ ~~~~~~~~]\"],\"node.wall.curtain.noPanels\":[\"[Ñö þáñéļš ~~~]\"],\"node.wall.curtain.rowSpacing\":[\"[\",[\"count\",\"plural\",{\"one\":[[\"number\"],\" ŕöŵ\"],\"other\":[[\"number\"],\" ŕöŵš\"]}],\" · \",[\"spacing\"],\" ĝŕîð šþáçîñĝ ~~~~~~]\"],\"node.wall.curtainWallPanel.applyTint\":[\"[Åþþļý ţîñţ ~~~]\"],\"node.wall.curtainWallPanel.borderOpeningFrame\":[\"[Ɓöŕðéŕ / öþéñîñĝ ƒŕáɱé ~~~~~~]\"],\"node.wall.curtainWallPanel.bottom\":[\"[Ɓöţţöɱ ~~]\"],\"node.wall.curtainWallPanel.bottomRow\":[\"[Ɓöţţöɱ ŕöŵ ~~~]\"],\"node.wall.curtainWallPanel.cancelTint\":[\"[Çáñçéļ ţîñţ ~~~]\"],\"node.wall.curtainWallPanel.center\":[\"[Çéñţéŕ ~~]\"],\"node.wall.curtainWallPanel.chooseACellOrEnterIts\":[\"[Çĥööšé á çéļļ öŕ éñţéŕ îţš çöļûɱñ áñð ŕöŵ. Ûšé áŕŕöŵ ķéýš ţö ɱöṽé ƀéţŵééñ çéļļš. Çöļûɱñš ŕûñ ƒŕöɱ ţĥé ŵáļļ šţáŕţ; ŕöŵš çöûñţ ûþŵáŕð. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.clearHiddenOverrides\":[\"[Çļéáŕ ĥîððéñ öṽéŕŕîðéš ~~~~~~]\"],\"node.wall.curtainWallPanel.column\":[\"[Çöļûɱñ ~~]\"],\"node.wall.curtainWallPanel.columnLayout\":[\"[Çöļûɱñ ļáýöûţ ~~~~]\"],\"node.wall.curtainWallPanel.columnRow\":[\"[Çöļûɱñ \",[\"column\"],\", ŕöŵ \",[\"row\"],\" ~~~]\"],\"node.wall.curtainWallPanel.construction\":[\"[Çöñšţŕûçţîöñ ~~~~]\"],\"node.wall.curtainWallPanel.continuousMullionsAndTransomsAssembledAlong\":[\"[Çöñţîñûöûš ɱûļļîöñš áñð ţŕáñšöɱš áššéɱƀļéð áļöñĝ ţĥé ŵáļļ. ~~~~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.curtainWallPanelSelection\":[\"[Çûŕţáîñ ŵáļļ þáñéļ šéļéçţîöñ ~~~~~~~~]\"],\"node.wall.curtainWallPanel.customInfill\":[\"[Çûšţöɱ îñƒîļļ ~~~~]\"],\"node.wall.curtainWallPanel.defaultPanel\":[\"[Ðéƒáûļţ þáñéļ ~~~~]\"],\"node.wall.curtainWallPanel.editIndividualPanels\":[\"[Éðîţ îñðîṽîðûáļ þáñéļš ~~~~~~]\"],\"node.wall.curtainWallPanel.effectiveThicknessLimited\":[\"[Ƀƒéçţîṽé ţĥîçķñéšš: \",[\"thickness\"],\", ļîɱîţéð ƀý ƒŕáɱé ðéþţĥ. ~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.empty\":[\"[Éɱþţý ~~]\"],\"node.wall.curtainWallPanel.enablePanelEditing\":[\"[Éñáƀļé þáñéļ éðîţîñĝ ~~~~~~]\"],\"node.wall.curtainWallPanel.end\":[\"[Éñð ~]\"],\"node.wall.curtainWallPanel.fixedSpacing\":[\"[Ƒîẋéð šþáçîñĝ ~~~~]\"],\"node.wall.curtainWallPanel.followingWallDefaults\":[\"[Ƒöļļöŵîñĝ ŵáļļ ðéƒáûļţš ~~~~~~~]\"],\"node.wall.curtainWallPanel.frameDimensions\":[\"[Ƒŕáɱé ðîɱéñšîöñš ~~~~~]\"],\"node.wall.curtainWallPanel.framing\":[\"[Ƒŕáɱîñĝ ~~~]\"],\"node.wall.curtainWallPanel.fullyCapped\":[\"[Ƒûļļý çáþþéð ~~~~]\"],\"node.wall.curtainWallPanel.glass\":[\"[Ĝļášš ~~]\"],\"node.wall.curtainWallPanel.glassAppearance\":[\"[Ĝļášš áþþéáŕáñçé ~~~~~]\"],\"node.wall.curtainWallPanel.glassAppearanceIsControlledByThe\":[\"[Ĝļášš áþþéáŕáñçé îš çöñţŕöļļéð ƀý ţĥé þáîñţ ţööļ. ~~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.glassTint\":[\"[Ĝļášš ţîñţ ~~~]\"],\"node.wall.curtainWallPanel.glazingGap\":[\"[Ĝļážîñĝ ĝáþ ~~~]\"],\"node.wall.curtainWallPanel.gridLimitedTo32PanelsPer\":[\"[Ĝŕîð ļîɱîţéð ţö 32 þáñéļš þéŕ áẋîš. Šþáçîñĝ éẋþáñðš ţö ƒîţ ţĥîš ŵáļļ. ~~~~~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.hiddenCustomPanelCount\":[\"[\",[\"length\",\"plural\",{\"one\":[[\"number\"],\" çûšţöɱ þáñéļ îš öûţšîðé ţĥîš ĝŕîð. Îţ ŕéţûŕñš îƒ ţĥé ĝŕîð éẋþáñðš.\"],\"other\":[[\"number\"],\" çûšţöɱ þáñéļš áŕé öûţšîðé ţĥîš ĝŕîð. Ţĥéý ŕéţûŕñ îƒ ţĥé ĝŕîð éẋþáñðš.\"]}],\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.horizontalCaps\":[\"[Ĥöŕîžöñţáļ çáþš ~~~~~]\"],\"node.wall.curtainWallPanel.horizontalFrameWidth\":[\"[Ĥöŕîžöñţáļ ƒŕáɱé ŵîðţĥ ~~~~~~]\"],\"node.wall.curtainWallPanel.layout\":[\"[Ļáýöûţ ~~]\"],\"node.wall.curtainWallPanel.lowRoughnessIsSmoothHighRoughness\":[\"[Ļöŵ ŕöûĝĥñéšš îš šɱööţĥ; ĥîĝĥ ŕöûĝĥñéšš ĝîṽéš á ɱáţţé šûŕƒáçé îñ ŕéñðéŕéð šĥáðîñĝ. ~~~~~~~~~~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.maximumSpacing\":[\"[Ṁáẋîɱûɱ šþáçîñĝ ~~~~~]\"],\"node.wall.curtainWallPanel.moduleJointWidth\":[\"[Ṁöðûļé ĵöîñţ ŵîðţĥ ~~~~~]\"],\"node.wall.curtainWallPanel.none\":[\"[Ñöñé ~~]\"],\"node.wall.curtainWallPanel.opacity\":[\"[Öþáçîţý ~~~]\"],\"node.wall.curtainWallPanel.opaqueBand\":[\"[Öþáǫûé ƀáñð ~~~]\"],\"node.wall.curtainWallPanel.opaqueBandsReplaceAFullRow\":[\"[Öþáǫûé ƀáñðš ŕéþļáçé á ƒûļļ ŕöŵ ŵîţĥ šöļîð þáñéļš. Åþþļý ţĥéîŕ ƒîñîšĥ ŵîţĥ ţĥé þáîñţ ţööļ. ~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.panelCount\":[\"[Þáñéļ çöûñţ ~~~]\"],\"node.wall.curtainWallPanel.panelInfill\":[\"[Þáñéļ îñƒîļļ ~~~~]\"],\"node.wall.curtainWallPanel.panelThickness\":[\"[Þáñéļ ţĥîçķñéšš ~~~~~]\"],\"node.wall.curtainWallPanel.panels\":[\"[Þáñéļš ~~]\"],\"node.wall.curtainWallPanel.resetThisPanel\":[\"[Ŕéšéţ ţĥîš þáñéļ ~~~~~]\"],\"node.wall.curtainWallPanel.row2\":[\"[Ŕöŵ ~]\"],\"node.wall.curtainWallPanel.rowLayout\":[\"[Ŕöŵ ļáýöûţ ~~~]\"],\"node.wall.curtainWallPanel.separateFramedModulesWithJointsBetween\":[\"[Šéþáŕáţé ƒŕáɱéð ɱöðûļéš ŵîţĥ ĵöîñţš ƀéţŵééñ ûñîţš. ~~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.solid\":[\"[Šöļîð ~~]\"],\"node.wall.curtainWallPanel.spacing\":[\"[Šþáçîñĝ ~~~]\"],\"node.wall.curtainWallPanel.start\":[\"[Šţáŕţ ~~]\"],\"node.wall.curtainWallPanel.stickBuilt\":[\"[Šţîçķ-ƀûîļţ ~~~]\"],\"node.wall.curtainWallPanel.structuralGlazing\":[\"[Šţŕûçţûŕáļ ĝļážîñĝ ~~~~~~]\"],\"node.wall.curtainWallPanel.surfaceRoughness\":[\"[Šûŕƒáçé ŕöûĝĥñéšš ~~~~~]\"],\"node.wall.curtainWallPanel.top\":[\"[Ţöþ ~]\"],\"node.wall.curtainWallPanel.topRow\":[\"[Ţöþ ŕöŵ ~~]\"],\"node.wall.curtainWallPanel.uncappedMembersSitBehindTheGlazing\":[\"[Ûñçáþþéð ɱéɱƀéŕš šîţ ƀéĥîñð ţĥé ĝļážîñĝ. ~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.unitized\":[\"[Ûñîţîžéð ~~~]\"],\"node.wall.curtainWallPanel.useGlassSettingsInstead\":[\"[Ûšé ĝļášš šéţţîñĝš îñšţéáð ~~~~~~~]\"],\"node.wall.curtainWallPanel.useTheDoorOrWindowTool\":[\"[Ûšé ţĥé Ðööŕ öŕ Ŵîñðöŵ ţööļ ţö áðð áñ öþéñîñĝ ţĥŕöûĝĥ ţĥé ŵáļļ. ~~~~~~~~~~~~~~~]\"],\"node.wall.curtainWallPanel.verticalCaps\":[\"[Ṽéŕţîçáļ çáþš ~~~~]\"],\"node.wall.curtainWallPanel.verticalFrameWidth\":[\"[Ṽéŕţîçáļ ƒŕáɱé ŵîðţĥ ~~~~~~]\"],\"node.wall.curtainWallPanel.wallSystem\":[\"[Ŵáļļ šýšţéɱ ~~~]\"],\"node.wall.description\":[\"[Å šţŕáîĝĥţ öŕ çûŕṽéð ŵáļļ šéĝɱéñţ. Ĥöšţš ðööŕš, ŵîñðöŵš, ļéáñ-ţö éẋţéñšîöñš, áñð ŵáļļ-ɱöûñţéð îţéɱš. ~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.wall.label\":[\"[Ŵáļļ ~~]\"],\"node.wall.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.wall.panel.assembly\":[\"[Åššéɱƀļý ~~~]\"],\"node.wall.panel.auto\":[\"[Åûţö ~~]\"],\"node.wall.panel.both\":[\"[Ɓöţĥ ~~]\"],\"node.wall.panel.bottom\":[\"[Ɓöţţöɱ ~~]\"],\"node.wall.panel.brickVeneer\":[\"[Ɓŕîçķ ṽéñééŕ ~~~~]\"],\"node.wall.panel.chairRail\":[\"[Çĥáîŕ ŕáîļ ~~~]\"],\"node.wall.panel.cmu\":[\"[ÇṀÛ ~]\"],\"node.wall.panel.colonial\":[\"[Çöļöñîáļ ~~~]\"],\"node.wall.panel.cove\":[\"[Çöṽé ~~]\"],\"node.wall.panel.craft\":[\"[Çŕáƒţ ~~]\"],\"node.wall.panel.crownMolding\":[\"[Çŕöŵñ ɱöļðîñĝ ~~~~]\"],\"node.wall.panel.curtainWall\":[\"[Çûŕţáîñ ŵáļļ ~~~~]\"],\"node.wall.panel.curve\":[\"[Çûŕṽé ~~]\"],\"node.wall.panel.custom\":[\"[Çûšţöɱ ~~]\"],\"node.wall.panel.customHeight\":[\"[Çûšţöɱ ĥéîĝĥţ ~~~~]\"],\"node.wall.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.wall.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.wall.panel.drywall\":[\"[Ðŕýŵáļļ ~~~]\"],\"node.wall.panel.extendsDownwardToMeetTheTerrain\":[\"[Éẋţéñðš ðöŵñŵáŕð ţö ɱééţ ţĥé ţéŕŕáîñ. Ĥéîĝĥţ áñð ţöþ šţáý ûñçĥáñĝéð. ~~~~~~~~~~~~~~~~~]\"],\"node.wall.panel.exterior\":[\"[Éẋţéŕîöŕ ~~~]\"],\"node.wall.panel.fiberCement\":[\"[Ƒîƀéŕ çéɱéñţ ~~~~]\"],\"node.wall.panel.fillToTerrain\":[\"[Ƒîļļ ţö ţéŕŕáîñ ~~~~]\"],\"node.wall.panel.flat\":[\"[Ƒļáţ ~~]\"],\"node.wall.panel.followsLevel\":[\"[Ƒöļļöŵš ļéṽéļ ~~~~]\"],\"node.wall.panel.frameDepth\":[\"[Ƒŕáɱé ðéþţĥ ~~~]\"],\"node.wall.panel.framersDefault\":[\"[Ƒŕáɱéŕ'š ðéƒáûļţ ~~~~~]\"],\"node.wall.panel.framing\":[\"[Ƒŕáɱîñĝ ~~~]\"],\"node.wall.panel.gypsum\":[\"[Ĝýþšûɱ ~~]\"],\"node.wall.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.wall.panel.hideCode\":[\"[Ĥîðé çöðé ~~~]\"],\"node.wall.panel.icf\":[\"[ÎÇƑ ~]\"],\"node.wall.panel.interior\":[\"[Îñţéŕîöŕ ~~~]\"],\"node.wall.panel.lapSiding\":[\"[Ļáþ šîðîñĝ ~~~]\"],\"node.wall.panel.layerThicknessesFollowThe2021Irc\":[\"[Ļáýéŕ ţĥîçķñéššéš ƒöļļöŵ ţĥé 2021 ÎŔÇ áššéɱƀļý ðáţá. Ðŕáƒţîñĝ áîð, ñöţ éñĝîñééŕîñĝ — ṽéŕîƒý ŵîţĥ ţĥé áûţĥöŕîţý ĥáṽîñĝ ĵûŕîšðîçţîöñ. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.wall.panel.layered\":[\"[Ļáýéŕéð ~~~]\"],\"node.wall.panel.length\":[\"[Ļéñĝţĥ ~~]\"],\"node.wall.panel.loading\":[\"[Ļöáðîñĝ… ~~~]\"],\"node.wall.panel.modern\":[\"[Ṁöðéŕñ ~~]\"],\"node.wall.panel.none\":[\"[Ñöñé ~~]\"],\"node.wall.panel.noneSingleLayer\":[\"[Ñöñé (šîñĝļé ļáýéŕ) ~~~~~]\"],\"node.wall.panel.offset\":[\"[Öƒƒšéţ ~~]\"],\"node.wall.panel.ogee\":[\"[Öĝéé ~~]\"],\"node.wall.panel.osb\":[\"[ÖŠƁ ~]\"],\"node.wall.panel.partitionTheInteriorFinishIsApplied\":[\"[Þáŕţîţîöñ: ţĥé îñţéŕîöŕ ƒîñîšĥ îš áþþļîéð ţö ƀöţĥ ƒáçéš. ~~~~~~~~~~~~~~]\"],\"node.wall.panel.picture\":[\"[Þîçţûŕé ~~~]\"],\"node.wall.panel.plaster\":[\"[Þļášţéŕ ~~~]\"],\"node.wall.panel.plywood\":[\"[Þļýŵööð ~~~]\"],\"node.wall.panel.preset\":[\"[Þŕéšéţ ~~]\"],\"node.wall.panel.railing\":[\"[Ŕáîļîñĝ ~~~]\"],\"node.wall.panel.reference\":[\"[Ŕéƒéŕéñçé ~~~]\"],\"node.wall.panel.remove\":[\"[Ŕéɱöṽé ~~]\"],\"node.wall.panel.round\":[\"[Ŕöûñð ~~]\"],\"node.wall.panel.scriptedFinish\":[\"[Šçŕîþţéð ƒîñîšĥ ~~~~~]\"],\"node.wall.panel.sheathing\":[\"[Šĥéáţĥîñĝ ~~~]\"],\"node.wall.panel.shoe\":[\"[Šĥöé ~~]\"],\"node.wall.panel.sideA\":[\"[Šîðé Å ~~]\"],\"node.wall.panel.sideB\":[\"[Šîðé Ɓ ~~]\"],\"node.wall.panel.sideFace\":[\"[Šîðé \",[\"face\"],\" ~~]\"],\"node.wall.panel.skirting\":[\"[Šķîŕţîñĝ ~~~]\"],\"node.wall.panel.standard\":[\"[Šţáñðáŕð ~~~]\"],\"node.wall.panel.steelStuds\":[\"[Šţééļ šţûðš ~~~]\"],\"node.wall.panel.step\":[\"[Šţéþ ~~]\"],\"node.wall.panel.stoneVeneer\":[\"[Šţöñé ṽéñééŕ ~~~~]\"],\"node.wall.panel.stucco\":[\"[Šţûççö ~~]\"],\"node.wall.panel.studs\":[\"[Šţûðš ~~]\"],\"node.wall.panel.thickness\":[\"[Ţĥîçķñéšš ~~~]\"],\"node.wall.panel.thicknessFromAssembly\":[\"[\",[\"thickness\"],\" · ƒŕöɱ áššéɱƀļý ~~~~]\"],\"node.wall.panel.thisProject\":[\"[Ţĥîš þŕöĵéçţ ~~~~]\"],\"node.wall.panel.top\":[\"[Ţöþ ~]\"],\"node.wall.panel.totalThickness\":[\"[Ţöţáļ ţĥîçķñéšš ~~~~~]\"],\"node.wall.panel.unverifiedPresetnote\":[\"[Ûñṽéŕîƒîéð: \",[\"presetNote\"],\" ~~~]\"],\"node.wall.panel.viewCode\":[\"[Ṽîéŵ çöðé ~~~]\"],\"node.wall.panel.wall\":[\"[Ŵáļļ ~~]\"],\"node.wall.panel.wallType\":[\"[Ŵáļļ ţýþé ~~~]\"],\"node.wall.panel.whichFaceIsOutsideIsUndetermined\":[\"[Ŵĥîçĥ ƒáçé îš öûţšîðé îš ûñðéţéŕɱîñéð (ñö ŕööɱ ðéţéçţéð öñ éîţĥéŕ šîðé) — ţĥé éẋţéŕîöŕ ļáýéŕš áŕé ðŕáŵñ öñ šîðé Ɓ. ~~~~~~~~~~~~~~~~~~~~~~~~~~~]\"],\"node.wall.panel.woodStuds\":[\"[Ŵööð šţûðš ~~~]\"],\"node.wall.railingWallPanel.aGuardSOpeningsMustNot\":[\"[Å ĝûáŕð'š öþéñîñĝš ɱûšţ ñöţ þášš á 4 îñ šþĥéŕé (ÎŔÇ Ŕ312.1.3). ~~~~~~~~~~~~]\"],\"node.wall.railingWallPanel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.wall.railingWallPanel.infill\":[\"[Îñƒîļļ ~~]\"],\"node.wall.railingWallPanel.n2x6Cap\":[\"[2ẋ6 çáþ ~~]\"],\"node.wall.railingWallPanel.n36In\":[\"[36 îñ ~]\"],\"node.wall.railingWallPanel.n42In\":[\"[42 îñ ~]\"],\"node.wall.railingWallPanel.posts\":[\"[Þöšţš ~~]\"],\"node.wall.railingWallPanel.railing\":[\"[Ŕáîļîñĝ ~~~]\"],\"node.wall.railingWallPanel.style\":[\"[Šţýļé ~~]\"],\"node.wall.reference.center\":[\"[Çéñţéŕ ~~]\"],\"node.wall.reference.inside\":[\"[Îñšîðé ƒáçé ~~~]\"],\"node.wall.reference.left\":[\"[Ļéƒţ ~~]\"],\"node.wall.reference.outside\":[\"[Öûţšîðé ƒáçé ~~~~]\"],\"node.wall.reference.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.wall.trim.hide\":[\"[\",[\"trim\",\"select\",{\"skirting\":[\"Ĥîðé šķîŕţîñĝ\"],\"crown\":[\"Ĥîðé çŕöŵñ ɱöļðîñĝ\"],\"other\":[\"Ĥîðé çĥáîŕ ŕáîļ\"]}],\" ~~~~~~~~~~~~~]\"],\"node.wall.trim.show\":[\"[\",[\"trim\",\"select\",{\"skirting\":[\"Šĥöŵ šķîŕţîñĝ\"],\"crown\":[\"Šĥöŵ çŕöŵñ ɱöļðîñĝ\"],\"other\":[\"Šĥöŵ çĥáîŕ ŕáîļ\"]}],\" ~~~~~~~~~~~~~]\"],\"node.window.actions.swapHingeSide\":[\"[Šŵáþ ĥîñĝé šîðé ~~~~]\"],\"node.window.description\":[\"[Å ŵîñðöŵ çûţ îñţö á ŵáļļ. Åñîɱáţéð öþéñ/çļöšé ƒöŕ öþéñîñĝ ŵîñðöŵš. ~~~~~~~~~~~~~~~~]\"],\"node.window.label\":[\"[Ŵîñðöŵ ~~]\"],\"node.window.operation.raise\":[\"[Ŕáîšé ~~]\"],\"node.window.operation.slats\":[\"[Šļáţš ~~]\"],\"node.window.operation.slide\":[\"[Šļîðé ~~]\"],\"node.window.operation.swing\":[\"[Šŵîñĝ ~~]\"],\"node.window.operation.tilt\":[\"[Ţîļţ ~~]\"],\"node.window.panel.actions\":[\"[Åçţîöñš ~~~]\"],\"node.window.panel.all\":[\"[Åļļ ~]\"],\"node.window.panel.arch\":[\"[Åŕçĥ ~~]\"],\"node.window.panel.archHeight\":[\"[Åŕçĥ Ĥéîĝĥţ ~~~]\"],\"node.window.panel.auto\":[\"[Åûţö ~~]\"],\"node.window.panel.autoFollowsTheWall\":[\"[Åûţö ƒöļļöŵš ţĥé ŵáļļ ~~~~~~]\"],\"node.window.panel.colWidths\":[\"[Çöļ Ŵîðţĥš ~~~]\"],\"node.window.panel.columns\":[\"[Çöļûɱñš ~~~]\"],\"node.window.panel.corner\":[\"[Çöŕñéŕ ~~]\"],\"node.window.panel.cornerPost\":[\"[Çöŕñéŕ þöšţ ~~~]\"],\"node.window.panel.cornerRadius\":[\"[Çöŕñéŕ Ŕáðîûš ~~~~]\"],\"node.window.panel.customThePanesMatchNoStyle\":[\"[Çûšţöɱ: ţĥé þáñéš ɱáţçĥ ñö šţýļé. ~~~~~~~~]\"],\"node.window.panel.delete\":[\"[Ðéļéţé ~~]\"],\"node.window.panel.depth\":[\"[Ðéþţĥ ~~]\"],\"node.window.panel.dimensions\":[\"[Ðîɱéñšîöñš ~~~]\"],\"node.window.panel.divider\":[\"[Ðîṽîðéŕ ~~~]\"],\"node.window.panel.down\":[\"[Ðöŵñ ~~]\"],\"node.window.panel.duplicate\":[\"[Ðûþļîçáţé ~~~]\"],\"node.window.panel.enableSill\":[\"[Éñáƀļé Šîļļ ~~~]\"],\"node.window.panel.flipSide\":[\"[Ƒļîþ Šîðé ~~~]\"],\"node.window.panel.frame\":[\"[Ƒŕáɱé ~~]\"],\"node.window.panel.frameDepthAuto\":[\"[Ðéþţĥ (áûţö) ~~~]\"],\"node.window.panel.french\":[\"[Ƒŕéñçĥ ~~]\"],\"node.window.panel.fusedGlass\":[\"[Ƒûšéð ĝļášš ~~~]\"],\"node.window.panel.grid\":[\"[Ĝŕîð ~~]\"],\"node.window.panel.height\":[\"[Ĥéîĝĥţ ~~]\"],\"node.window.panel.individual\":[\"[Îñðîṽîðûáļ ~~~]\"],\"node.window.panel.left\":[\"[Ļéƒţ ~~]\"],\"node.window.panel.move\":[\"[Ṁöṽé ~~]\"],\"node.window.panel.opening\":[\"[Öþéñîñĝ ~~~]\"],\"node.window.panel.openingShape\":[\"[Öþéñîñĝ Šĥáþé ~~~~]\"],\"node.window.panel.otherSide\":[\"[Öţĥéŕ šîðé ~~~]\"],\"node.window.panel.pos\":[\"[þöš ~]\"],\"node.window.panel.position\":[\"[Þöšîţîöñ ~~~]\"],\"node.window.panel.rect\":[\"[Ŕéçţ ~~]\"],\"node.window.panel.revealRadius\":[\"[Ŕéṽéáļ Ŕáðîûš ~~~~]\"],\"node.window.panel.right\":[\"[Ŕîĝĥţ ~~]\"],\"node.window.panel.rounded\":[\"[Ŕöûñðéð ~~~]\"],\"node.window.panel.rowHeights\":[\"[Ŕöŵ Ĥéîĝĥţš ~~~]\"],\"node.window.panel.rows\":[\"[Ŕöŵš ~~]\"],\"node.window.panel.sill\":[\"[Šîļļ ~~]\"],\"node.window.panel.single\":[\"[Šîñĝļé ~~]\"],\"node.window.panel.sizeIsLimitedToTheWall\":[\"[Šîžé îš ļîɱîţéð ţö ţĥé ŵáļļ, îñçļûðîñĝ çļéáŕáñçé ƒöŕ ţĥé öþéñîñĝ ƒŕáɱé. ~~~~~~~~~~~~~~~~~~]\"],\"node.window.panel.style\":[\"[Šţýļé ~~]\"],\"node.window.panel.thickness\":[\"[Ţĥîçķñéšš ~~~]\"],\"node.window.panel.thisSide\":[\"[Ţĥîš šîðé ~~~]\"],\"node.window.panel.topShape\":[\"[Ţöþ Šĥáþé ~~~]\"],\"node.window.panel.type\":[\"[Ţýþé ~~]\"],\"node.window.panel.unwrap\":[\"[Ûñŵŕáþ ~~]\"],\"node.window.panel.up\":[\"[Ûþ ~]\"],\"node.window.panel.width\":[\"[Ŵîðţĥ ~~]\"],\"node.window.panel.window\":[\"[Ŵîñðöŵ ~~]\"],\"node.window.panel.windowType\":[\"[Ŵîñðöŵ Ţýþé ~~~]\"],\"node.window.panel.wrapTheCorner\":[\"[Ŵŕáþ ţĥé çöŕñéŕ ~~~~]\"],\"node.window.panel.wrapsTheCornerWithNamed\":[\"[Ŵŕáþš ţĥé çöŕñéŕ ŵîţĥ \",[\"partner\"],\" ~~~~~~]\"],\"node.window.panel.wrapsTheCornerWithPartner\":[\"[Ŵŕáþš ţĥé çöŕñéŕ ŵîţĥ îţš þáŕţñéŕ ~~~~~~~~~]\"],\"node.window.style.casement\":[\"[Çášéɱéñţ ~~~]\"],\"node.window.style.doubleHung\":[\"[Ðöûƀļé-ĥûñĝ ~~~]\"],\"node.window.style.grid\":[\"[Ĝŕîð ~~]\"],\"node.window.style.horizontalBands\":[\"[Ĥöŕîžöñţáļ ƀáñðš ~~~~~]\"],\"node.window.style.picture\":[\"[Þîçţûŕé ~~~]\"],\"node.window.style.single\":[\"[Šîñĝļé ~~]\"],\"node.window.style.sliding\":[\"[Šļîðîñĝ ~~~]\"],\"node.window.style.tallGrid\":[\"[Ţáļļ ĝŕîð ~~~]\"],\"node.window.style.transom\":[\"[Ţŕáñšöɱ ~~~]\"],\"node.window.style.tripleHung\":[\"[Ţŕîþļé-ĥûñĝ ~~~]\"],\"node.window.style.wideGrid\":[\"[Ŵîðé ĝŕîð ~~~]\"],\"node.window.type.awning\":[\"[Åŵñîñĝ ~~]\"],\"node.window.type.bay\":[\"[Ɓáý ~]\"],\"node.window.type.bow\":[\"[Ɓöŵ ~]\"],\"node.window.type.casement\":[\"[Çášéɱéñţ ~~~]\"],\"node.window.type.doubleHung\":[\"[Ðöûƀļé Ĥûñĝ ~~~]\"],\"node.window.type.fixed\":[\"[Ƒîẋéð ~~]\"],\"node.window.type.hopper\":[\"[Ĥöþþéŕ ~~]\"],\"node.window.type.louvered\":[\"[Ļöûṽéŕéð ~~~]\"],\"node.window.type.singleHung\":[\"[Šîñĝļé Ĥûñĝ ~~~]\"],\"node.window.type.sliding\":[\"[Šļîðîñĝ ~~~]\"],\"node.zone.description\":[\"[Å þöļýĝöñáļ šîţé žöñé (ļáŵñ, ŵáţéŕ, þáṽîñĝ) ŵîţĥ á ŢŠĻ ĝŕáðîéñţ ɱáţéŕîáļ. ~~~~~~~~~~~~~~~~~~]\"],\"node.zone.label\":[\"[Žöñé ~~]\"],\"node.zone.quantitiesPanel.enclosedRoom\":[\"[Éñçļöšéð ŕööɱ ~~~~]\"],\"node.zone.quantitiesPanel.floorSurface\":[\"[Ƒļööŕ šûŕƒáçé ~~~~]\"],\"node.zone.quantitiesPanel.footprintOnly\":[\"[Ƒööţþŕîñţ öñļý ~~~~]\"],\"node.zone.quantitiesPanel.none\":[\"[Ñöñé ~~]\"],\"node.zone.quantitiesPanel.notProven\":[\"[Ñöţ þŕöṽéñ ~~~]\"],\"node.zone.quantitiesPanel.roomQuantities\":[\"[Ŕööɱ ǫûáñţîţîéš ~~~~~]\"],\"node.zone.quantitiesPanel.topViewWithZoneEdgeDimensions\":[\"[Ţöþ ṽîéŵ ŵîţĥ žöñé éðĝé ðîɱéñšîöñš ~~~~~~~~~]\"],\"node.zone.quantitiesPanel.unit\":[\"[Ûñîţ ~~]\"],\"node.zone.quantitiesPanel.volume\":[\"[Ṽöļûɱé ~~]\"],\"node.zone.quantitiesPanel.wallSurface\":[\"[Ŵáļļ šûŕƒáçé ~~~~]\"],\"node.zone.quantitiesPanel.zoneBoundaryUnavailable\":[\"[Žöñé ƀöûñðáŕý ûñáṽáîļáƀļé ~~~~~~~]\"],\"node.zone.quantitiesPanel.zoneQuantities\":[\"[Žöñé ǫûáñţîţîéš ~~~~~]\"],\"viewer.camera.orbitLeft\":[\"[Öŕƀîţ ļéƒţ ~~~]\"],\"viewer.camera.orbitRight\":[\"[Öŕƀîţ ŕîĝĥţ ~~~]\"],\"viewer.camera.topView\":[\"[Ţöþ ṽîéŵ ~~~]\"],\"viewer.common.off\":[\"[Öƒƒ ~]\"],\"viewer.common.on\":[\"[Öñ ~]\"],\"viewer.display.camera\":[\"[Çáɱéŕá ~~]\"],\"viewer.display.colored\":[\"[Çöļöŕéð ~~~]\"],\"viewer.display.colors\":[\"[Çöļöŕš ~~]\"],\"viewer.display.edges.off\":[\"[Öƒƒ ~]\"],\"viewer.display.edges.offDetail\":[\"[Ñö éðĝé ļîñéš ~~~~]\"],\"viewer.display.edges.soft\":[\"[Šöƒţ ~~]\"],\"viewer.display.edges.softDetail\":[\"[Ƒáîñţ öûţļîñé öƒ ɱáĵöŕ çŕéášéš ~~~~~~~~]\"],\"viewer.display.edges.strong\":[\"[Šţŕöñĝ ~~]\"],\"viewer.display.edges.strongDetail\":[\"[Çŕîšþ, öþáǫûé éðĝé ļîñéš ~~~~~~]\"],\"viewer.display.edges.title\":[\"[Éðĝéš ~~]\"],\"viewer.display.monochrome\":[\"[Ṁöñöçĥŕöɱé ~~~]\"],\"viewer.display.orthographic\":[\"[Öŕţĥöĝŕáþĥîç ~~~~]\"],\"viewer.display.perspective\":[\"[Þéŕšþéçţîṽé ~~~~]\"],\"viewer.display.render.rendered\":[\"[Ŕéñðéŕéð ~~~]\"],\"viewer.display.render.renderedDetail\":[\"[Ƒûļļ áɱƀîéñţ öççļûšîöñ ~~~~~~]\"],\"viewer.display.render.solid\":[\"[Šöļîð ~~]\"],\"viewer.display.render.solidDetail\":[\"[Ƒļáţ áñð ƒášţ — ñö áɱƀîéñţ öççļûšîöñ ~~~~~~~~~]\"],\"viewer.display.render.title\":[\"[Ŕéñðéŕ ~~]\"],\"viewer.display.shadows\":[\"[Šĥáðöŵš ~~~]\"],\"viewer.display.title\":[\"[Ðîšþļáý šéţţîñĝš ~~~~~]\"],\"viewer.floorplan.alignNorth\":[\"[Åļîĝñ ṽîéŵ ţö ñöŕţĥ ~~~~~]\"],\"viewer.floorplan.empty\":[\"[Ñö ƒļööŕ þļáñš áŕé áṽáîļáƀļé ƒöŕ ţĥîš šçéñé. ~~~~~~~~~~~]\"],\"viewer.floorplan.fit\":[\"[Ƒîţ ƒļööŕ þļáñ ~~~~]\"],\"viewer.floorplan.floor\":[\"[Ƒļööŕ ~~]\"],\"viewer.floorplan.floorPlan\":[\"[Ƒļööŕ þļáñ ~~~]\"],\"viewer.floorplan.viewLabel\":[\"[\",[\"floor\"],\" 2Ð ṽîéŵ ~~]\"],\"viewer.floorplan.zoomIn\":[\"[Žööɱ îñ ~~]\"],\"viewer.floorplan.zoomOut\":[\"[Žööɱ öûţ ~~~]\"],\"viewer.header.back\":[\"[Ɓáçķ ~~]\"],\"viewer.header.levels\":[\"[Ļéṽéļš ~~]\"],\"viewer.header.rooms\":[\"[Ŕööɱš ~~]\"],\"viewer.header.selection\":[\"[Šéļéçţîöñ ~~~]\"],\"viewer.header.units\":[\"[Ûñîţš ~~]\"],\"viewer.header.untitled\":[\"[Ûñţîţļéð ~~~]\"],\"viewer.header.zones\":[\"[Žöñéš ~~]\"],\"viewer.levels.exploded\":[\"[Éẋþļöðéð ~~~]\"],\"viewer.levels.label\":[\"[Ļéṽéļš: \",[\"mode\"],\" ~~]\"],\"viewer.levels.manual\":[\"[Ṁáñûáļ ~~]\"],\"viewer.levels.solo\":[\"[Šöļö ~~]\"],\"viewer.levels.stacked\":[\"[Šţáçķéð ~~~]\"],\"viewer.stage.layout\":[\"[Ṽîéŵéŕ ļáýöûţ ~~~~]\"],\"viewer.stage.split\":[\"[Šþļîţ ~~]\"],\"viewer.theme.blueprint\":[\"[Ɓļûéþŕîñţ ~~~]\"],\"viewer.theme.mediterranean\":[\"[Ṁéðîţéŕŕáñéáñ ~~~~]\"],\"viewer.theme.night\":[\"[Ñîĝĥţ ~~]\"],\"viewer.theme.overcast\":[\"[Öṽéŕçášţ ~~~]\"],\"viewer.theme.paper\":[\"[Þáþéŕ ~~]\"],\"viewer.theme.studio\":[\"[Šţûðîö ~~]\"],\"viewer.theme.sunset\":[\"[Šûñšéţ ~~]\"],\"viewer.theme.title\":[\"[Šçéñé ţĥéɱé ~~~]\"],\"viewer.theme.twilight\":[\"[Ţŵîļîĝĥţ ~~~]\"],\"viewer.theme.verdant\":[\"[Ṽéŕðáñţ ~~~]\"],\"viewer.visibility.guides\":[\"[Ĝûîðéš ~~]\"],\"viewer.visibility.scans\":[\"[Šçáñš ~~]\"],\"viewer.visibility.title\":[\"[Ṽîšîƀîļîţý ~~~]\"],\"viewer.walkthrough.label\":[\"[Ŵáļķţĥŕöûĝĥ: \",[\"state\"],\" ~~~~]\"],\"viewer.walls.cutaway\":[\"[Çûţáŵáý ~~~]\"],\"viewer.walls.fullHeight\":[\"[Ƒûļļ ĥéîĝĥţ ~~~]\"],\"viewer.walls.label\":[\"[Ŵáļļš: \",[\"mode\"],\" ~~]\"],\"viewer.walls.low\":[\"[Ļöŵ ~]\"]}")as Messages; \ No newline at end of file diff --git a/packages/editor/src/i18n/locales/en/messages.po b/packages/editor/src/i18n/locales/en/messages.po index cf0d5474f6..df72cc083d 100644 --- a/packages/editor/src/i18n/locales/en/messages.po +++ b/packages/editor/src/i18n/locales/en/messages.po @@ -259,6 +259,10 @@ msgstr "Liquid Line" msgid "app.lib.buildPalette.mep" msgstr "MEP" +#: apps/editor/lib/build-palette.ts +msgid "app.lib.buildPalette.post" +msgstr "Post" + #: apps/editor/lib/build-palette.ts msgid "app.lib.buildPalette.register" msgstr "Register" @@ -527,14 +531,30 @@ msgstr "Public link" msgid "app.sharePanel.shareProject" msgstr "Share project" +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.above" +msgstr "Above" + #: apps/editor/components/viewer-toolbar.tsx msgid "app.viewerToolbar.automaticDimensions" msgstr "Automatic dimensions" +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.below" +msgstr "Below" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.both" +msgstr "Both" + #: apps/editor/components/viewer-toolbar.tsx msgid "app.viewerToolbar.camera" msgstr "Camera" +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.ceilings" +msgstr "Ceilings" + #: apps/editor/components/viewer-toolbar.tsx msgid "app.viewerToolbar.cleanPlanDimensionsAppearWithSelection" msgstr "Clean plan; dimensions appear with selection" @@ -555,6 +575,10 @@ msgstr "Cutaway" msgid "app.viewerToolbar.default" msgstr "Default" +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.dimensions" +msgstr "Dimensions" + #: apps/editor/components/viewer-toolbar.tsx msgid "app.viewerToolbar.display" msgstr "Display" @@ -571,6 +595,10 @@ msgstr "Door/window marks" msgid "app.viewerToolbar.edges" msgstr "Edges" +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.editing" +msgstr "Editing" + #: apps/editor/components/viewer-toolbar.tsx msgid "app.viewerToolbar.enterVr" msgstr "Enter VR" @@ -591,10 +619,6 @@ msgstr "Expert" msgid "app.viewerToolbar.exploded" msgstr "Exploded" -#: apps/editor/components/viewer-toolbar.tsx -msgid "app.viewerToolbar.faceOfStud" -msgstr "Face of stud" - #: apps/editor/components/viewer-toolbar.tsx msgid "app.viewerToolbar.faintOutlineOfMajorCreases" msgstr "Faint outline of major creases" @@ -603,10 +627,6 @@ msgstr "Faint outline of major creases" msgid "app.viewerToolbar.feetInches" msgstr "Feet & inches" -#: apps/editor/components/viewer-toolbar.tsx -msgid "app.viewerToolbar.finishedFaces" -msgstr "Finished faces" - #: apps/editor/components/viewer-toolbar.tsx msgid "app.viewerToolbar.flatAndFastNoAmbientOcclusion" msgstr "Flat and fast — no ambient occlusion" @@ -632,13 +652,27 @@ msgid "app.viewerToolbar.fullHeight" msgstr "Full height" #: apps/editor/components/viewer-toolbar.tsx -msgid "app.viewerToolbar.fullWallThickness" -msgstr "Full wall thickness" +msgid "app.viewerToolbar.ghostedForReference" +msgstr "Ghosted for reference" #: apps/editor/components/viewer-toolbar.tsx msgid "app.viewerToolbar.grid" msgstr "Grid" +#. Short for inside dimension: measured between the inside faces of walls. +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.id" +msgstr "ID" + +#. Inside and outside dimensions together. +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.idOd" +msgstr "ID + OD" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.inside" +msgstr "Inside" + #: apps/editor/components/viewer-toolbar.tsx msgid "app.viewerToolbar.levelsMode" msgstr "Levels: {mode}" @@ -663,6 +697,10 @@ msgstr "Manual dimensions" msgid "app.viewerToolbar.measurements" msgstr "Measurements" +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.measureWalls" +msgstr "Measure walls" + #: apps/editor/components/viewer-toolbar.tsx msgid "app.viewerToolbar.meters" msgstr "Meters" @@ -672,13 +710,22 @@ msgid "app.viewerToolbar.millimeters" msgstr "Millimeters" #: apps/editor/components/viewer-toolbar.tsx -msgid "app.viewerToolbar.n3dMeasurements" -msgstr "3D measurements" +msgid "app.viewerToolbar.n2dOnly" +msgstr "2D only" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.n3dOnly" +msgstr "3D only" #: apps/editor/components/viewer-toolbar.tsx msgid "app.viewerToolbar.noEdgeLines" msgstr "No edge lines" +#. Short for outside dimension: measured between the outside faces of walls. +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.od" +msgstr "OD" + #: apps/editor/components/viewer-toolbar.tsx msgid "app.viewerToolbar.off" msgstr "Off" @@ -691,10 +738,26 @@ msgstr "On" msgid "app.viewerToolbar.orthographic" msgstr "Orthographic" +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.otherLevels" +msgstr "Other levels" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.outside" +msgstr "Outside" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.overallSizeOutsideFaceToOutsideFace" +msgstr "Overall size, outside face to outside face" + #: apps/editor/components/viewer-toolbar.tsx msgid "app.viewerToolbar.perspective" msgstr "Perspective" +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.plan" +msgstr "Plan" + #: apps/editor/components/viewer-toolbar.tsx msgid "app.viewerToolbar.preview" msgstr "Preview" @@ -715,6 +778,18 @@ msgstr "Rendered" msgid "app.viewerToolbar.roomLabels" msgstr "Room labels" +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.roomSizesInsideFaceToInsideFace" +msgstr "Room sizes, inside face to inside face" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.roomSizesInsideOverallSizeOutside" +msgstr "Room sizes inside, overall size outside" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.scene" +msgstr "Scene" + #: apps/editor/components/viewer-toolbar.tsx msgid "app.viewerToolbar.sceneTheme" msgstr "Scene theme" @@ -724,8 +799,12 @@ msgid "app.viewerToolbar.shadows" msgstr "Shadows" #: apps/editor/components/viewer-toolbar.tsx -msgid "app.viewerToolbar.singleWallAxis" -msgstr "Single wall axis" +msgid "app.viewerToolbar.sharedBy2dAnd3d" +msgstr "Shared by 2D and 3D" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.show" +msgstr "Show" #: apps/editor/components/viewer-toolbar.tsx msgid "app.viewerToolbar.soft" @@ -751,10 +830,6 @@ msgstr "Stair annotations" msgid "app.viewerToolbar.strong" msgstr "Strong" -#: apps/editor/components/viewer-toolbar.tsx -msgid "app.viewerToolbar.structuralCoreFace" -msgstr "Structural core face" - #: apps/editor/components/viewer-toolbar.tsx msgid "app.viewerToolbar.structuralGridsColumnCenters" msgstr "Structural grids & column centers" @@ -763,6 +838,10 @@ msgstr "Structural grids & column centers" msgid "app.viewerToolbar.translucent" msgstr "Translucent" +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.turnOnDimensionsToShowThem" +msgstr "Turn on Dimensions to show them" + #: apps/editor/components/viewer-toolbar.tsx msgid "app.viewerToolbar.units" msgstr "Units" @@ -771,14 +850,6 @@ msgstr "Units" msgid "app.viewerToolbar.walkthrough" msgstr "Walkthrough" -#: apps/editor/components/viewer-toolbar.tsx -msgid "app.viewerToolbar.wallCenterline" -msgstr "Wall centerline" - -#: apps/editor/components/viewer-toolbar.tsx -msgid "app.viewerToolbar.wallDimensions" -msgstr "Wall dimensions" - #: apps/editor/components/viewer-toolbar.tsx msgid "app.viewerToolbar.wallsLabel" msgstr "Walls: {label}" @@ -939,6 +1010,10 @@ msgstr "Point and ask (C)" msgid "editor.actionMenu.pointAskButton.pointAndAskWorksInThe" msgstr "Point and ask works in the 3D view" +#: packages/editor/src/components/ui/action-menu/structure-tools.tsx +msgid "editor.actionMenu.structureTools.beam" +msgstr "Beam" + #: packages/editor/src/components/ui/action-menu/structure-tools.tsx msgid "editor.actionMenu.structureTools.ceiling" msgstr "Ceiling" @@ -1027,6 +1102,10 @@ msgstr "Window" msgid "editor.actionMenu.structureTools.zone" msgstr "Zone" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +msgid "editor.actionMenu.viewToggles.dashedOutlinesOfTheNeighbouringLevels" +msgstr "Dashed outlines of the neighbouring levels’ walls, to line walls up and check a roof against the walls under it." + #: packages/editor/src/components/ui/action-menu/view-toggles.tsx msgid "editor.actionMenu.viewToggles.deleteGuideImage" msgstr "Delete guide image" @@ -1079,6 +1158,14 @@ msgstr "Hide scans" msgid "editor.actionMenu.viewToggles.levelsBelow" msgstr "{count} below" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +msgid "editor.actionMenu.viewToggles.noLevelAbove" +msgstr "No level above" + +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +msgid "editor.actionMenu.viewToggles.noLevelBelow" +msgstr "No level below" + #: packages/editor/src/components/ui/action-menu/view-toggles.tsx msgid "editor.actionMenu.viewToggles.noLowerFloorAvailable" msgstr "No lower floor available." @@ -1159,10 +1246,36 @@ msgstr "Show reference floor" msgid "editor.actionMenu.viewToggles.showScans" msgstr "Show scans" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +msgid "editor.actionMenu.viewToggles.showWallsBelowAndAbove" +msgstr "Show walls below and above" + #: packages/editor/src/components/ui/action-menu/view-toggles.tsx msgid "editor.actionMenu.viewToggles.uploadScanOrGuideImage" msgstr "Upload scan or guide image" +#: apps/editor/components/viewer-toolbar.tsx +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +msgid "editor.actionMenu.viewToggles.wallsAbove" +msgstr "Walls above" + +#: apps/editor/components/viewer-toolbar.tsx +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +msgid "editor.actionMenu.viewToggles.wallsBelow" +msgstr "Walls below" + +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +msgid "editor.actionMenu.viewToggles.wallsBelowAndAbove" +msgstr "Walls below and above" + +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +msgid "editor.actionMenu.viewToggles.wallsBelowAndAboveSettings" +msgstr "Walls below and above settings" + +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +msgid "editor.actionMenu.viewToggles.wallsBelowAndAboveShown" +msgstr "Walls below and above: shown" + #: packages/editor/src/components/editor/index.tsx msgid "editor.backToHome" msgstr "Back to home" @@ -1216,21 +1329,213 @@ msgid "editor.buildPanel.rooms.title" msgstr "Rooms" #: packages/editor/src/components/ui/build-panel/build-panel.tsx -msgid "editor.buildPanel.rooms.walls.caption" -msgstr "{lead} Close a loop and it becomes a room; leave it open for partitions." +msgid "editor.buildPanel.rooms.wallKinds.invisibleHelp" +msgstr "Divides a room or closes off a porch without building a wall; rooms close on it. Change any wall later from its controls." #: packages/editor/src/components/ui/build-panel/build-panel.tsx -msgid "editor.buildPanel.rooms.walls.label" -msgstr "Walls" +msgid "editor.buildPanel.rooms.wallKinds.label" +msgstr "Wall kind" #: packages/editor/src/components/ui/build-panel/build-panel.tsx -msgid "editor.buildPanel.rooms.walls.lead" -msgstr "Draw one wall at a time." +msgid "editor.buildPanel.rooms.wallKinds.railingHelp" +msgstr "A guard for stairs, balconies and mezzanines; rooms close on it. Change any wall later from its controls." + +#: packages/editor/src/components/ui/build-panel/build-panel.tsx +msgid "editor.buildPanel.rooms.wallKinds.standardHelp" +msgstr "One wall per two clicks. Its sides become exterior or interior from the rooms it bounds. Change any wall later from its controls." + +#: packages/editor/src/components/ui/build-panel/build-panel.tsx +msgid "editor.buildPanel.rooms.walls.label" +msgstr "Walls" #: packages/editor/src/components/ui/build-panel/build-panel.tsx msgid "editor.buildPanel.rooms.walls.title" msgstr "Walls" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx +msgid "editor.buildPanel.wallTypeControls.deleteFromThisProject" +msgstr "Delete from this project" + +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx +msgid "editor.buildPanel.wallTypeControls.duplicateAsANewType" +msgstr "Duplicate as a new type…" + +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx +msgid "editor.buildPanel.wallTypeControls.editLayers" +msgstr "Edit layers…" + +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx +msgid "editor.buildPanel.wallTypeControls.editOrDuplicateThisWallType" +msgstr "Edit or duplicate this wall type" + +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx +msgid "editor.buildPanel.wallTypeControls.newWallType" +msgstr "New wall type…" + +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx +msgid "editor.buildPanel.wallTypeControls.presetsStayAsCitedDuplicateOne" +msgstr "Presets stay as cited. Duplicate one to change its layers." + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.add" +msgstr "Add" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.airSpace" +msgstr "Air space" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.aWallTypeHoldsAtMost" +msgstr "A wall type holds at most {limit, plural, one {# layer} other {# layers}}." + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.brickVeneer" +msgstr "Brick veneer" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.cancel" +msgstr "Cancel" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.drywall" +msgstr "Drywall" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.duplicateWallType" +msgstr "Duplicate wall type" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.editWallType" +msgstr "Edit wall type" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.everyWallTypeHasOneFraming" +msgstr "Every wall type has one framing core" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.fiberCement" +msgstr "Fiber cement" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.finish" +msgstr "Finish" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.framingCore" +msgstr "Framing core" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.fullreasonRemoveOneToAddAnother" +msgstr "{fullReason} Remove one to add another." + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.gypsumSheathing" +msgstr "Gypsum sheathing" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.inside" +msgstr "Inside" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.insulation" +msgstr "Insulation" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.lapSiding" +msgstr "Lap siding" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.layer" +msgstr "Layer" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.layerRole" +msgstr "Layer role" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.lining" +msgstr "Lining" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.material" +msgstr "Material" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.mineralWoolBoard" +msgstr "Mineral wool board" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.moveIn" +msgstr "Move in" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.moveOut" +msgstr "Move out" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.name" +msgstr "Name" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.newWallType" +msgstr "New wall type" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.osb" +msgstr "OSB" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.outside" +msgstr "Outside" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.plaster" +msgstr "Plaster" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.plywood" +msgstr "Plywood" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.removeLayer" +msgstr "Remove layer" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.rigidFoam" +msgstr "Rigid foam" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.saveWallType" +msgstr "Save wall type" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.sheathing" +msgstr "Sheathing" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.stoneVeneer" +msgstr "Stone veneer" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.stucco" +msgstr "Stucco" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.thickness" +msgstr "Thickness" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.totalThickness" +msgstr "Total {thickness}" + +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.buildPanel.wallTypeEditorDialog.wallType" +msgstr "Wall type" + +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx +msgid "editor.buildPanel.wallTypes.plainWall" +msgstr "Plain wall" + #: packages/editor/src/components/editor/index.tsx msgid "editor.cameraControlsHint" msgstr "Camera controls hint" @@ -3685,6 +3990,22 @@ msgstr "Structure with the current material and finish assignments." msgid "editor.levelDuplicateDialog.wallsSlabsRoofsStairsWindowsAnd" msgstr "Walls, slabs, roofs, stairs, windows, and doors without finishes." +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx +msgid "editor.levelWallCopyPrompt.copy" +msgstr "Copy" + +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx +msgid "editor.levelWallCopyPrompt.copyExteriorWallsFromTheLevel" +msgstr "Copy exterior walls from the level {direction}?" + +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx +msgid "editor.levelWallCopyPrompt.noThanks" +msgstr "No thanks" + +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx +msgid "editor.levelWallCopyPrompt.sourcenameSOutsideWallsInPlace" +msgstr "{sourceName}’s outside walls, in place, so this level lines up with it." + #: packages/editor/src/lib/contextual-help.ts msgid "editor.lib.contextualHelp.addOrRemoveObjectsFromThe" msgstr "Add or remove objects from the selection" @@ -3889,6 +4210,18 @@ msgstr "Split {kind}" msgid "editor.lib.hudTitle.terrace" msgstr "Terrace" +#: packages/editor/src/lib/wall-draw-variant.ts +msgid "editor.lib.wallDrawVariant.kind.invisible" +msgstr "Invisible" + +#: packages/editor/src/lib/wall-draw-variant.ts +msgid "editor.lib.wallDrawVariant.kind.railing" +msgstr "Railing" + +#: packages/editor/src/lib/wall-draw-variant.ts +msgid "editor.lib.wallDrawVariant.kind.standard" +msgstr "Standard" + #: packages/editor/src/lib/wall-draw-variant.ts msgid "editor.lib.wallDrawVariant.polygonRoom" msgstr "Polygon room" @@ -4053,6 +4386,38 @@ msgstr "No collections yet. Create one to group elements together." msgid "editor.panels.collections.collectionsPopover.rename" msgstr "Rename" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx +msgid "editor.panels.deckBoardsFields.alongHouse" +msgstr "Along house" + +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx +msgid "editor.panels.deckBoardsFields.boards" +msgstr "Boards" + +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx +msgid "editor.panels.deckBoardsFields.boardsSummary" +msgstr "{label} boards {thickness} × {width} in, {gap} in apart, {direction, select, parallel {along the house, on joists square to it} diagonal {at 45° to the house} other {out from the house, on joists along it, carried by beams square to the house}}; joists {spacing} in on centre." + +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx +msgid "editor.panels.deckBoardsFields.deckBoards" +msgstr "Deck boards" + +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx +msgid "editor.panels.deckBoardsFields.diagonal" +msgstr "Diagonal" + +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx +msgid "editor.panels.deckBoardsFields.gap" +msgstr "Gap" + +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx +msgid "editor.panels.deckBoardsFields.outFromHouse" +msgstr "Out from house" + +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx +msgid "editor.panels.deckBoardsFields.run" +msgstr "Run" + #: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx msgid "editor.panels.floorFoundationPanel.aThickerFloorGrowsUpwardThe" msgstr "A thicker floor grows upward: the rooms below keep their height." @@ -4201,6 +4566,10 @@ msgstr "{area} · Drag its corners to change the shape." msgid "editor.panels.floorOpeningPanel.areaOwned" msgstr "{area} · Shape follows its owner." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +msgid "editor.panels.floorOpeningPanel.areaStairResize" +msgstr "{area} · Drag its sides or corners to resize it; it moves with the stair." + #: packages/editor/src/components/ui/panels/floor-opening-panel.tsx msgid "editor.panels.floorOpeningPanel.delete" msgstr "Delete" @@ -4418,10 +4787,6 @@ msgstr "Back" msgid "editor.panels.panelWrapper.close" msgstr "Close" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx -msgid "editor.panels.panelWrapper.closeTitle" -msgstr "Close {title}" - #: packages/editor/src/components/ui/panels/panel-wrapper.tsx msgid "editor.panels.panelWrapper.collapsePanel" msgstr "Collapse panel" @@ -4438,10 +4803,6 @@ msgstr "Expand panel" msgid "editor.panels.panelWrapper.manageCollections" msgstr "Manage collections…" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx -msgid "editor.panels.panelWrapper.openTitle" -msgstr "Open {title}" - #: packages/editor/src/components/ui/panels/panel-wrapper.tsx msgid "editor.panels.panelWrapper.reset" msgstr "Reset" @@ -4626,6 +4987,14 @@ msgstr "A drawn slab: set its thickness and finishes here. It has no footprint h msgid "editor.panels.roomConstructionRows.atFloorLevel" msgstr "At floor level" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.beam" +msgstr "Beam" + +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.beamSize" +msgstr "Beam size" + #: packages/editor/src/components/ui/panels/room-construction-rows.tsx msgid "editor.panels.roomConstructionRows.builtOn" msgstr "Built on" @@ -4686,6 +5055,30 @@ msgstr "Floor thickness" msgid "editor.panels.roomConstructionRows.floorUp" msgstr "{distance} up" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.framingAutoHint" +msgstr "{posts, plural, one {{postCount} post} other {{postCount} posts}} and {beams, plural, one {{beamCount} beam} other {{beamCount} beams}}, a post on each outside corner, kept with {room, select, deck {the deck} patio {the patio} other {the porch}}." + +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.framingAutomatic" +msgstr "Automatic" + +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.framingManual" +msgstr "Manual" + +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.framingManualHint" +msgstr "Kept as you edited them. Automatic rebuilds them from these settings." + +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.framingOff" +msgstr "Off" + +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.framingOffHint" +msgstr "None. Automatic puts a post on each outside corner and a beam on them, to carry a roof over {room, select, deck {the deck} patio {the patio} other {the porch}}." + #: packages/editor/src/components/ui/panels/room-construction-rows.tsx msgid "editor.panels.roomConstructionRows.handDrawnCeiling" msgstr "Hand-drawn ceiling" @@ -4750,6 +5143,18 @@ msgstr "Partial · {coverage, number, percent} covered" msgid "editor.panels.roomConstructionRows.partialWalls" msgstr "Partial · {walls, plural, one {{wallCount} wall} other {{wallCount} walls}}, {openSides, plural, one {{openSideCount} open side} other {{openSideCount} open sides}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.postsAndBeam" +msgstr "Posts and beam" + +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.postSize" +msgstr "Post size" + +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.postSpacingMax" +msgstr "Post spacing (max)" + #: packages/editor/src/components/ui/panels/room-construction-rows.tsx msgid "editor.panels.roomConstructionRows.raised" msgstr "Raised {lift}" @@ -4758,6 +5163,42 @@ msgstr "Raised {lift}" msgid "editor.panels.roomConstructionRows.replace" msgstr "Replace" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.roomType" +msgstr "Room type" + +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.roomTypeDeck" +msgstr "Deck" + +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.roomTypeDeckHint" +msgstr "Outdoors: deck boards on a wood frame and posts, 1 in down from the house; no ceiling." + +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.roomTypePatio" +msgstr "Patio" + +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.roomTypePatioHint" +msgstr "Outdoors and open: a concrete slab 1½ in down from the house, no ceiling." + +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.roomTypePorch" +msgstr "Porch" + +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.roomTypePorchHint" +msgstr "Outdoors under a ceiling: a concrete slab 1½ in down from the house, ceiling at the house’s." + +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.roomTypeRoom" +msgstr "Room" + +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +msgid "editor.panels.roomConstructionRows.roomTypeRoomHint" +msgstr "An ordinary room inside the house." + #: packages/editor/src/components/ui/panels/room-construction-rows.tsx msgid "editor.panels.roomConstructionRows.select" msgstr "Select" @@ -5136,6 +5577,22 @@ msgstr "{current} · {distance} below {shared}" msgid "editor.room.builtOn.levelWith" msgstr "{current} · level with {shared}" +#: packages/editor/src/components/editor/room-handles.tsx +msgid "editor.roomHandles.cannotReadInput" +msgstr "Cannot read \"{input}\"" + +#: packages/editor/src/components/editor/room-handles.tsx +msgid "editor.roomHandles.dimensionValue" +msgstr "Dimension value" + +#: packages/editor/src/components/editor/room-handles.tsx +msgid "editor.roomHandles.floor" +msgstr "Floor" + +#: packages/editor/src/components/editor/room-handles.tsx +msgid "editor.roomHandles.typeASizeToMoveThe" +msgstr "Type a size to move the wall" + #: packages/editor/src/components/editor/room-labels.tsx #: packages/editor/src/lib/viewer-selection.ts msgid "editor.roomLabel.room" @@ -5474,6 +5931,46 @@ msgstr "No results for “{search}”" msgid "editor.sidebar.panels.itemsPanel.search" msgstr "Search..." +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.buildTools" +msgstr "Build Tools" + +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.camera" +msgstr "Camera" + +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.directManipulation" +msgstr "Direct Manipulation" + +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.drawingTools" +msgstr "Drawing Tools" + +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.editorNavigation" +msgstr "Editor Navigation" + +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.itemPlacement" +msgstr "Item Placement" + +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.keyboardShortcuts" +msgstr "Keyboard shortcuts" + +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.modesHistory" +msgstr "Modes & History" + +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.selection" +msgstr "Selection" + +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.shortcutsAreContextAwareGuidedConstraints" +msgstr "Shortcuts are context-aware. Snapping is a visible mode: tap Shift to cycle it, hold Alt during a gesture to place freely." + #: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx msgid "editor.sidebar.panels.sitePanel.addLevel" msgstr "Add level" @@ -5882,6 +6379,10 @@ msgstr "Duct diameter down / up" msgid "editor.toolHint.endRunCancel.59dh2w" msgstr "End run / cancel" +#: packages/nodes/src/i18n/definition-messages.ts +msgid "editor.toolHint.endTheRun.1c1raig" +msgstr "End the run" + #: packages/nodes/src/i18n/definition-messages.ts msgid "editor.toolHint.exit.engmg5" msgstr "Exit" @@ -5926,6 +6427,14 @@ msgstr "Follow: trace a lineset" msgid "editor.toolHint.forcePlace.1hq1nr" msgstr "Force place" +#: packages/nodes/src/i18n/definition-messages.ts +msgid "editor.toolHint.freeAngle.1ptblho" +msgstr "Free angle" + +#: packages/nodes/src/i18n/definition-messages.ts +msgid "editor.toolHint.freePlace.1s1uusw" +msgstr "Free place" + #: packages/nodes/src/i18n/definition-messages.ts msgid "editor.toolHint.freePlacement.1nztdac" msgstr "Free placement" @@ -6010,6 +6519,10 @@ msgstr "Middle click" msgid "editor.toolHint.key.rightClick.1ovld0h" msgstr "Right click" +#: packages/nodes/src/i18n/definition-messages.ts +msgid "editor.toolHint.key.room.1f3jkpm" +msgstr "Room" + #: packages/nodes/src/i18n/definition-messages.ts msgid "editor.toolHint.key.rShiftR.13bnobh" msgstr "R / Shift+R" @@ -6038,6 +6551,10 @@ msgstr "Mount: floor / ceiling / wall" msgid "editor.toolHint.noRoomForTheMatchingWindow.1755948" msgstr "No room for the matching window on the other wall" +#: packages/nodes/src/i18n/definition-messages.ts +msgid "editor.toolHint.notARectangleDrawThisRoof.100pa5g" +msgstr "Not a rectangle: draw this roof instead" + #: packages/nodes/src/i18n/definition-messages.ts msgid "editor.toolHint.noWallMeetsHere.19n99yc" msgstr "No wall meets here" @@ -6206,6 +6723,10 @@ msgstr "Place window on wall" msgid "editor.toolHint.placeWithoutTheCornerSnap.1nifqew" msgstr "Place without the corner snap" +#: packages/nodes/src/i18n/definition-messages.ts +msgid "editor.toolHint.pointInsideARoomPorchOr.58w64l" +msgstr "Point inside a room, porch or deck" + #: packages/nodes/src/i18n/definition-messages.ts msgid "editor.toolHint.removeLastPoint.2dmdcx" msgstr "Remove last point" @@ -6214,6 +6735,22 @@ msgstr "Remove last point" msgid "editor.toolHint.removeLastWitness.1b6vvzw" msgstr "Remove last witness" +#: packages/nodes/src/i18n/definition-messages.ts +msgid "editor.toolHint.ridgeDirection.5m1369" +msgstr "Ridge direction" + +#: packages/nodes/src/i18n/definition-messages.ts +msgid "editor.toolHint.ridgeDirectionClickOrPressR.1t14dyk" +msgstr "Ridge direction - click or press R to turn it 90°" + +#: packages/nodes/src/i18n/definition-messages.ts +msgid "editor.toolHint.ridgeLongSide.ew0euv" +msgstr "Ridge: Long side" + +#: packages/nodes/src/i18n/definition-messages.ts +msgid "editor.toolHint.ridgeShortSide.gye8pb" +msgstr "Ridge: Short side" + #: packages/nodes/src/i18n/definition-messages.ts msgid "editor.toolHint.rotate.1thqa0a" msgstr "Rotate" @@ -6234,10 +6771,6 @@ msgstr "Rotate ghost ±15°" msgid "editor.toolHint.rotateOrFlipTheRunSide.t5ior7" msgstr "Rotate or flip the run side" -#: packages/nodes/src/i18n/definition-messages.ts -msgid "editor.toolHint.rotateRoofDirection90.tvbji2" -msgstr "Rotate roof direction 90°" - #: packages/nodes/src/i18n/definition-messages.ts msgid "editor.toolHint.rotateSpawnPoint.1opcuu7" msgstr "Rotate spawn point" @@ -6246,6 +6779,10 @@ msgstr "Rotate spawn point" msgid "editor.toolHint.roundRectangularOval.e4nh6x" msgstr "Round / rectangular / oval" +#: packages/nodes/src/i18n/definition-messages.ts +msgid "editor.toolHint.setBeamStartEndTheNext.di3bzj" +msgstr "Set beam start / end; the next beam starts there" + #: packages/nodes/src/i18n/definition-messages.ts msgid "editor.toolHint.setFenceStartEnd.1phbwsq" msgstr "Set fence start / end" @@ -6598,10 +7135,106 @@ msgstr "Veil the ground over a level below grade" msgid "editor.views.viewBar.views" msgstr "Views" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +msgid "editor.wallTypeEditorDialog.listTheLayersAppliedToThisWall" +msgstr "List the layers from the outside in, around one framing core. The type is saved with the project and applied to this wall; other walls keep their layers." + +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx +msgid "editor.wallTypeMenu.custom" +msgstr "Custom" + +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx +msgid "editor.wallTypeMenu.wallTypesOf" +msgstr "Wall types: new, edit or duplicate {label}" + #: packages/editor/src/components/editor/index.tsx msgid "editor.youCanRetryTheSceneOr" msgstr "You can retry the scene or return home without reloading the whole app shell." +#: packages/nodes/src/i18n/definition-messages.ts +msgid "node.beam.description" +msgstr "A framing beam drawn end to end: a porch header, a deck beam, a girder." + +#: packages/nodes/src/i18n/definition-messages.ts +msgid "node.beam.label" +msgstr "Beam" + +#: packages/nodes/src/beam/panel.tsx +msgid "node.beam.panel.actions" +msgstr "Actions" + +#: packages/nodes/src/beam/panel.tsx +msgid "node.beam.panel.addPosts" +msgstr "Add posts" + +#: packages/nodes/src/beam/panel.tsx +msgid "node.beam.panel.beam" +msgstr "Beam" + +#: packages/nodes/src/beam/panel.tsx +msgid "node.beam.panel.beamSize" +msgstr "Beam {size}" + +#: packages/nodes/src/beam/panel.tsx +msgid "node.beam.panel.delete" +msgstr "Delete" + +#: packages/nodes/src/beam/panel.tsx +msgid "node.beam.panel.depth" +msgstr "Depth" + +#: packages/nodes/src/beam/panel.tsx +msgid "node.beam.panel.dropped" +msgstr "Dropped" + +#: packages/nodes/src/beam/panel.tsx +msgid "node.beam.panel.flush" +msgstr "Flush" + +#: packages/nodes/src/beam/panel.tsx +msgid "node.beam.panel.followTheCeilingPlane" +msgstr "Follow the ceiling plane" + +#: packages/nodes/src/beam/panel.tsx +msgid "node.beam.panel.lengthLongItsUnderside" +msgstr "{length} long; its underside {underside} over the floor, the ceiling plane {plane}." + +#: packages/nodes/src/beam/panel.tsx +msgid "node.beam.panel.material" +msgstr "Material" + +#: packages/nodes/src/beam/panel.tsx +msgid "node.beam.panel.move" +msgstr "Move" + +#: packages/nodes/src/beam/panel.tsx +msgid "node.beam.panel.n1Ply" +msgstr "1 ply" + +#: packages/nodes/src/beam/panel.tsx +msgid "node.beam.panel.placement" +msgstr "Placement" + +#: packages/nodes/src/beam/panel.tsx +msgid "node.beam.panel.pliesPlies" +msgstr "{plies} plies" + +#: packages/nodes/src/beam/panel.tsx +msgid "node.beam.panel.size" +msgstr "Size" + +#: packages/nodes/src/beam/panel.tsx +msgid "node.beam.panel.top" +msgstr "Top" + +#: packages/nodes/src/beam/panel.tsx +msgid "node.beam.panel.topElevation" +msgstr "Top elevation" + +#: packages/nodes/src/beam/panel.tsx +msgid "node.beam.panel.width" +msgstr "Width" + #: packages/nodes/src/i18n/definition-messages.ts msgid "node.block.description" msgstr "A topology-backed solid edited directly in the canvas." @@ -7710,6 +8343,54 @@ msgstr "An editable module inside a modular cabinet run." msgid "node.cabinetModule.label" msgstr "Cabinet Module" +#: packages/nodes/src/ceiling/build-up-section.tsx +msgid "node.ceiling.buildUpSection.bottomChord" +msgstr "Bottom chord" + +#: packages/nodes/src/ceiling/build-up-section.tsx +msgid "node.ceiling.buildUpSection.ceilingJoists" +msgstr "Ceiling joists" + +#: packages/nodes/src/ceiling/build-up-section.tsx +msgid "node.ceiling.buildUpSection.decking" +msgstr "Decking" + +#: packages/nodes/src/ceiling/build-up-section.tsx +msgid "node.ceiling.buildUpSection.finish" +msgstr "Finish" + +#: packages/nodes/src/ceiling/build-up-section.tsx +msgid "node.ceiling.buildUpSection.framing" +msgstr "Framing" + +#: packages/nodes/src/ceiling/build-up-section.tsx +msgid "node.ceiling.buildUpSection.joists" +msgstr "Joists" + +#: packages/nodes/src/ceiling/build-up-section.tsx +msgid "node.ceiling.buildUpSection.layers" +msgstr "Layers" + +#: packages/nodes/src/ceiling/build-up-section.tsx +msgid "node.ceiling.buildUpSection.none" +msgstr "None" + +#: packages/nodes/src/ceiling/build-up-section.tsx +msgid "node.ceiling.buildUpSection.preset" +msgstr "Preset" + +#: packages/nodes/src/ceiling/build-up-section.tsx +msgid "node.ceiling.buildUpSection.theHeightIsTheFinishedUnderside" +msgstr "The height is the finished underside; the layers rise from it." + +#: packages/nodes/src/ceiling/build-up-section.tsx +msgid "node.ceiling.buildUpSection.thickness" +msgstr "Thickness" + +#: packages/nodes/src/ceiling/build-up-section.tsx +msgid "node.ceiling.buildUpSection.trussBottomChords" +msgstr "Truss bottom chords" + #: packages/nodes/src/i18n/definition-messages.ts msgid "node.ceiling.description" msgstr "A polygon-bounded ceiling surface that hosts ceiling-mounted items." @@ -8330,6 +9011,46 @@ msgstr "Yaw" msgid "node.column.panel.ySupport" msgstr "Y Support" +#: packages/nodes/src/column/post-section.tsx +msgid "node.column.postSection.aSizeDeckPostStandsNo" +msgstr "A {size} deck post stands no taller than {limit} (IRC Table R507.4, by species and the area it carries): check it, or use the next size up." + +#: packages/nodes/src/column/post-section.tsx +msgid "node.column.postSection.custom" +msgstr "Custom" + +#: packages/nodes/src/column/post-section.tsx +msgid "node.column.postSection.fitToTheBeamOverIt" +msgstr "Fit to the beam over it ({height})" + +#: packages/nodes/src/column/post-section.tsx +msgid "node.column.postSection.fitToTheCeilingPlane" +msgstr "Fit to the ceiling plane ({height})" + +#: packages/nodes/src/column/post-section.tsx +msgid "node.column.postSection.height" +msgstr "Height" + +#: packages/nodes/src/column/post-section.tsx +msgid "node.column.postSection.keepItsShapeAndStyleIt" +msgstr "Keep its shape and style it as a column" + +#: packages/nodes/src/column/post-section.tsx +msgid "node.column.postSection.makeItAColumn" +msgstr "Make it a column" + +#: packages/nodes/src/column/post-section.tsx +msgid "node.column.postSection.post" +msgstr "Post" + +#: packages/nodes/src/column/post-section.tsx +msgid "node.column.postSection.treated" +msgstr "Treated" + +#: packages/nodes/src/column/post-section.tsx +msgid "node.column.postSection.untreated" +msgstr "Untreated" + #: packages/nodes/src/column/panel.tsx msgid "node.column.preset.aFrameSupport" msgstr "A-Frame Support" @@ -8506,6 +9227,14 @@ msgstr "Opening" msgid "node.cutout.room" msgstr "Room cutout" +#: packages/nodes/src/door/actions.tsx +msgid "node.door.actions.swapHingeSide" +msgstr "Swap hinge side" + +#: packages/nodes/src/door/actions.tsx +msgid "node.door.actions.swapSwingSide" +msgstr "Swap swing side" + #: packages/nodes/src/i18n/definition-messages.ts msgid "node.door.description" msgstr "A door cut into a wall. Animated open/close state." @@ -9693,7 +10422,7 @@ msgstr "Hole {number}" #: packages/nodes/src/ceiling/panel.tsx #: packages/nodes/src/slab/panel.tsx msgid "node.holeSummary" -msgstr "{area} m² · {count, plural, one {{points} pt} other {{points} pts}} · {source}" +msgstr "{area} {unit} · {count, plural, one {{points} pt} other {{points} pts}} · {source}" #: packages/nodes/src/i18n/definition-messages.ts msgid "node.hvacEquipment.description" @@ -10330,6 +11059,14 @@ msgstr "Draw Segment" msgid "node.roof.panel.duplicate" msgstr "Duplicate" +#: packages/nodes/src/roof/panel.tsx +msgid "node.roof.panel.eaveOverhang" +msgstr "Eave overhang" + +#: packages/nodes/src/roof/panel.tsx +msgid "node.roof.panel.eaves" +msgstr "Eaves" + #: packages/nodes/src/roof/panel.tsx msgid "node.roof.panel.elements" msgstr "Elements" @@ -10338,6 +11075,10 @@ msgstr "Elements" msgid "node.roof.panel.followsWalls" msgstr "Follows walls" +#: packages/nodes/src/roof/panel.tsx +msgid "node.roof.panel.gableOverhang" +msgstr "Gable overhang" + #: packages/nodes/src/roof/panel.tsx msgid "node.roof.panel.gutter" msgstr "gutter" @@ -10406,6 +11147,126 @@ msgstr "Turbine" msgid "node.roof.panel.turbineVent" msgstr "turbine vent" +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.applyToAllPlanesOfThis" +msgstr "Apply to all planes of this roof" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.architecturalShingle" +msgstr "Architectural shingle" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.asphalt3Tab" +msgstr "Asphalt 3-tab" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.clayTile" +msgstr "Clay tile" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.concreteTile" +msgstr "Concrete tile" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.covering" +msgstr "Covering" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.deck" +msgstr "Deck" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.editLayers" +msgstr "Edit layers" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.finishName" +msgstr "Finish name" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.iceAndWaterShield" +msgstr "Ice and water shield" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.insulationName" +msgstr "Insulation name" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.interiorFinish" +msgstr "Interior finish" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.layers" +msgstr "Layers" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.n15Felt" +msgstr "#15 felt" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.n30Felt" +msgstr "#30 felt" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.none" +msgstr "None" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.preset" +msgstr "Preset" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.rafters" +msgstr "Rafters" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.roofing" +msgstr "Roofing" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.roofingName" +msgstr "Roofing name" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.sheathing" +msgstr "Sheathing" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.sheathingName" +msgstr "Sheathing name" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.slate" +msgstr "Slate" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.standingSeamMetal" +msgstr "Standing-seam metal" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.synthetic" +msgstr "Synthetic" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.topChord" +msgstr "Top chord" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.trusses" +msgstr "Trusses" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.underlayment" +msgstr "Underlayment" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.underlaymentName" +msgstr "Underlayment name" + +#: packages/nodes/src/roof-segment/build-up-section.tsx +msgid "node.roofSegment.buildUpSection.woodShake" +msgstr "Wood shake" + #: packages/nodes/src/i18n/definition-messages.ts msgid "node.roofSegment.description" msgstr "A single pitched plane of a parent roof." @@ -10482,6 +11343,10 @@ msgstr "Duplicate" msgid "node.roofSegment.panel.dutch" msgstr "Dutch" +#: packages/nodes/src/roof-segment/panel.tsx +msgid "node.roofSegment.panel.eaveCut" +msgstr "Eave cut" + #: packages/nodes/src/roof-segment/panel.tsx msgid "node.roofSegment.panel.eaveOverhang" msgstr "Eave overhang" @@ -10550,6 +11415,14 @@ msgstr "Move" msgid "node.roofSegment.panel.pitch" msgstr "Pitch" +#: packages/nodes/src/roof-segment/panel.tsx +msgid "node.roofSegment.panel.plumb" +msgstr "Plumb" + +#: packages/nodes/src/roof-segment/panel.tsx +msgid "node.roofSegment.panel.plumbLevel" +msgstr "Plumb + level" + #: packages/nodes/src/roof-segment/panel.tsx msgid "node.roofSegment.panel.position" msgstr "Position" @@ -10586,6 +11459,10 @@ msgstr "Shingle Thick." msgid "node.roofSegment.panel.span" msgstr "Span" +#: packages/nodes/src/roof-segment/panel.tsx +msgid "node.roofSegment.panel.square" +msgstr "Square" + #: packages/nodes/src/roof-segment/panel.tsx msgid "node.roofSegment.panel.startAngle" msgstr "Start Angle" @@ -10652,6 +11529,67 @@ msgstr "Segment {number}" msgid "node.separator.label" msgstr "Separator" +#: packages/nodes/src/shared/build-up-controls.tsx +msgid "node.shared.buildUpControls.batt" +msgstr "Batt" + +#: packages/nodes/src/shared/build-up-controls.tsx +msgid "node.shared.buildUpControls.blown" +msgstr "Blown" + +#: packages/nodes/src/shared/build-up-controls.tsx +msgid "node.shared.buildUpControls.drywall" +msgstr "Drywall" + +#: packages/nodes/src/shared/build-up-controls.tsx +msgid "node.shared.buildUpControls.drywallThickness" +msgstr "Drywall thickness" + +#: packages/nodes/src/shared/build-up-controls.tsx +msgid "node.shared.buildUpControls.insulation" +msgstr "Insulation" + +#: packages/nodes/src/shared/build-up-controls.tsx +msgid "node.shared.buildUpControls.insulationThickness" +msgstr "Insulation thickness" + +#: packages/nodes/src/shared/build-up-controls.tsx +msgid "node.shared.buildUpControls.labelThickness" +msgstr "{label} thickness" + +#: packages/nodes/src/shared/build-up-controls.tsx +msgid "node.shared.buildUpControls.none" +msgstr "None" + +#: packages/nodes/src/shared/build-up-controls.tsx +msgid "node.shared.buildUpControls.osb" +msgstr "OSB" + +#: packages/nodes/src/shared/build-up-controls.tsx +msgid "node.shared.buildUpControls.plaster" +msgstr "Plaster" + +#: packages/nodes/src/shared/build-up-controls.tsx +msgid "node.shared.buildUpControls.plywood" +msgstr "Plywood" + +#: packages/nodes/src/shared/build-up-controls.tsx +msgid "node.shared.buildUpControls.rigidBoard" +msgstr "Rigid board" + +#: packages/nodes/src/shared/build-up-controls.tsx +msgid "node.shared.buildUpControls.spacing" +msgstr "Spacing" + +#. A framing spacing on centre (centre of one member to the next), e.g. 16" o.c. +#: packages/nodes/src/shared/build-up-controls.tsx +msgid "node.shared.buildUpControls.spacingOC" +msgstr "{spacing} o.c." + +#: packages/nodes/src/shared/build-up-controls.tsx +msgid "node.shared.buildUpControls.woodPlank" +msgstr "Wood plank" + #: packages/nodes/src/shared/item-interaction-actions.tsx msgid "node.shared.itemInteractionActions.turnLightOff" msgstr "Turn light off" @@ -10660,6 +11598,14 @@ msgstr "Turn light off" msgid "node.shared.itemInteractionActions.turnLightOn" msgstr "Turn light on" +#: packages/nodes/src/shared/opening-casing-section.tsx +msgid "node.shared.openingCasingSection.casing" +msgstr "Casing" + +#: packages/nodes/src/shared/opening-casing-section.tsx +msgid "node.shared.openingCasingSection.width" +msgstr "Width" + #: packages/nodes/src/shared/run-hanger-inspector.tsx msgid "node.shared.runHangerInspector.automaticSupport" msgstr "Automatic support" @@ -11412,6 +12358,10 @@ msgstr "Center stringer" msgid "node.stair.constructionControls.closedRisers" msgstr "Closed risers" +#: packages/nodes/src/stair/construction-controls.tsx +msgid "node.stair.constructionControls.fromStructure" +msgstr "From structure" + #: packages/nodes/src/stair/construction-controls.tsx msgid "node.stair.constructionControls.inherit" msgstr "Inherit" @@ -11936,6 +12886,151 @@ msgstr "Top horizontal extension" msgid "node.stair.railingControls.wallFacing" msgstr "Wall-facing" +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.aSolidPouredFlightOnA" +msgstr "A solid poured flight on a footing; risers closed, no stringers." + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.autoAutocount" +msgstr "Auto ({autoCount})" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.autoClosed" +msgstr "Auto (closed)" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.autoOpen" +msgstr "Auto (open)" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.autoPressureTreated" +msgstr "Auto (pressure-treated)" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.autoTreads" +msgstr "Auto ({treads})" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.autoUntreated" +msgstr "Auto (untreated)" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.closed1x8Boards" +msgstr "Closed (1x8 boards)" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.concrete" +msgstr "Concrete" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.countSteelChannels" +msgstr "{count, plural, one {# steel channel} other {# steel channels}}" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.countSteelChannelsAtSpacing" +msgstr "{count, plural, one {# steel channel at {spacing} o.c.} other {# steel channels at {spacing} o.c.}}" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.countStringers" +msgstr "{count, plural, one {# stringer} other {# stringers}}" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.countStringersAtSpacing" +msgstr "{count, plural, one {# stringer at {spacing} o.c.} other {# stringers at {spacing} o.c.}}" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.cut" +msgstr "Cut" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.flightLayout" +msgstr "Flight {number}: {layout}" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.housedSides" +msgstr "Housed sides" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.inchesInOC" +msgstr "{inches} in o.c." + +#. The stringer count was chosen automatically, not set by hand. +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.layoutAuto" +msgstr "{layout} (auto)" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.lumber" +msgstr "Lumber" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.maxSpacing" +msgstr "Max spacing" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.nosing" +msgstr "Nosing" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.oneStock" +msgstr "One {stock}" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.open" +msgstr "Open" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.originalBody" +msgstr "Original body" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.plywoodFinish" +msgstr "Plywood + finish" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.pressureTreated" +msgstr "Pressure-treated" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.risers" +msgstr "Risers" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.steelStringers" +msgstr "Steel stringers" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.stringerCount" +msgstr "Stringer count" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.stringers" +msgstr "Stringers" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.stringerType" +msgstr "Stringer type" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.structure" +msgstr "Structure" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.treads" +msgstr "Treads" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.twoStock" +msgstr "Two {stock}" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.untreated" +msgstr "Untreated" + +#: packages/nodes/src/stair/structure-controls.tsx +msgid "node.stair.structureControls.woodStringers" +msgstr "Wood stringers" + #: packages/nodes/src/i18n/definition-messages.ts msgid "node.stairSegment.description" msgstr "A single flight of a parent stair." @@ -12268,6 +13363,10 @@ msgstr "Merge walls" msgid "node.wall.actions.splitWall" msgstr "Split wall" +#: packages/nodes/src/wall/actions.tsx +msgid "node.wall.actions.theseWallsCannotBeMerged" +msgstr "These walls cannot be merged." + #: packages/nodes/src/wall/curtain-wall-panel.tsx msgid "node.wall.curtain.cell" msgstr "Column {column}, row {row}: {type, select, glass {glass} solid {solid} other {empty}}" @@ -12660,6 +13759,10 @@ msgstr "Follows level" msgid "node.wall.panel.frameDepth" msgstr "Frame depth" +#: packages/nodes/src/wall/panel.tsx +msgid "node.wall.panel.framersDefault" +msgstr "Framer's default" + #: packages/nodes/src/wall/panel.tsx msgid "node.wall.panel.framing" msgstr "Framing" @@ -12748,6 +13851,10 @@ msgstr "Plywood" msgid "node.wall.panel.preset" msgstr "Preset" +#: packages/nodes/src/wall/panel.tsx +msgid "node.wall.panel.railing" +msgstr "Railing" + #: packages/nodes/src/wall/panel.tsx msgid "node.wall.panel.reference" msgstr "Reference" @@ -12808,6 +13915,10 @@ msgstr "Stone veneer" msgid "node.wall.panel.stucco" msgstr "Stucco" +#: packages/nodes/src/wall/panel.tsx +msgid "node.wall.panel.studs" +msgstr "Studs" + #: packages/nodes/src/wall/panel.tsx msgid "node.wall.panel.thickness" msgstr "Thickness" @@ -12816,6 +13927,10 @@ msgstr "Thickness" msgid "node.wall.panel.thicknessFromAssembly" msgstr "{thickness} · from assembly" +#: packages/nodes/src/wall/panel.tsx +msgid "node.wall.panel.thisProject" +msgstr "This project" + #: packages/nodes/src/wall/panel.tsx msgid "node.wall.panel.top" msgstr "Top" @@ -12848,6 +13963,42 @@ msgstr "Which face is outside is undetermined (no room detected on either side) msgid "node.wall.panel.woodStuds" msgstr "Wood studs" +#: packages/nodes/src/wall/railing-wall-panel.tsx +msgid "node.wall.railingWallPanel.aGuardSOpeningsMustNot" +msgstr "A guard's openings must not pass a 4 in sphere (IRC R312.1.3)." + +#: packages/nodes/src/wall/railing-wall-panel.tsx +msgid "node.wall.railingWallPanel.height" +msgstr "Height" + +#: packages/nodes/src/wall/railing-wall-panel.tsx +msgid "node.wall.railingWallPanel.infill" +msgstr "Infill" + +#: packages/nodes/src/wall/railing-wall-panel.tsx +msgid "node.wall.railingWallPanel.n2x6Cap" +msgstr "2x6 cap" + +#: packages/nodes/src/wall/railing-wall-panel.tsx +msgid "node.wall.railingWallPanel.n36In" +msgstr "36 in" + +#: packages/nodes/src/wall/railing-wall-panel.tsx +msgid "node.wall.railingWallPanel.n42In" +msgstr "42 in" + +#: packages/nodes/src/wall/railing-wall-panel.tsx +msgid "node.wall.railingWallPanel.posts" +msgstr "Posts" + +#: packages/nodes/src/wall/railing-wall-panel.tsx +msgid "node.wall.railingWallPanel.railing" +msgstr "Railing" + +#: packages/nodes/src/wall/railing-wall-panel.tsx +msgid "node.wall.railingWallPanel.style" +msgstr "Style" + #: packages/nodes/src/wall/panel.tsx msgid "node.wall.reference.center" msgstr "Center" @@ -12876,6 +14027,10 @@ msgstr "{trim, select, skirting {Hide skirting} crown {Hide crown molding} other msgid "node.wall.trim.show" msgstr "{trim, select, skirting {Show skirting} crown {Show crown molding} other {Show chair rail}}" +#: packages/nodes/src/window/actions.tsx +msgid "node.window.actions.swapHingeSide" +msgstr "Swap hinge side" + #: packages/nodes/src/i18n/definition-messages.ts msgid "node.window.description" msgstr "A window cut into a wall. Animated open/close for opening windows." diff --git a/packages/editor/src/i18n/locales/en/messages.ts b/packages/editor/src/i18n/locales/en/messages.ts index 13e08a189a..e7c817ac28 100644 --- a/packages/editor/src/i18n/locales/en/messages.ts +++ b/packages/editor/src/i18n/locales/en/messages.ts @@ -1 +1 @@ -/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"app.appShell.pascalHome\":[\"Pascal home\"],\"app.buildTab.addGate\":[\"Add Gate\"],\"app.buildTab.addOpenPassage\":[\"Add Open Passage\"],\"app.buildTab.addToRooms\":[\"Add to rooms\"],\"app.buildTab.allBuildTools\":[\"← All build tools\"],\"app.buildTab.chooseGateOrOpenPassageThen\":[\"Choose Gate or Open Passage, then click its position on any fence. Find placed gates and openings under their fence in the scene graph.\"],\"app.buildTab.clickALinesetToLayThe\":[\"Click a lineset to lay the line beside it.\"],\"app.buildTab.doubleGate\":[\"Double gate\"],\"app.buildTab.featuresExtensions\":[\"Features & extensions\"],\"app.buildTab.fenceFeatures\":[\"Fence features\"],\"app.buildTab.followLineset\":[\"Follow lineset\"],\"app.buildTab.gate\":[\"Gate\"],\"app.buildTab.gateStyle\":[\"Gate style\"],\"app.buildTab.horizontalBoards\":[\"Horizontal boards\"],\"app.buildTab.hoverAFenceToPreviewClick\":[\"Hover a fence to preview. Click to place. Esc cancels. Leave room between openings.\"],\"app.buildTab.leaves\":[\"Leaves\"],\"app.buildTab.liquidLine\":[\"Liquid Line\"],\"app.buildTab.matchFenceStyle\":[\"Match fence style\"],\"app.buildTab.mep\":[\"MEP\"],\"app.buildTab.off\":[\"Off\"],\"app.buildTab.on\":[\"On\"],\"app.buildTab.openRails\":[\"Open rails\"],\"app.buildTab.opening\":[\"Opening\"],\"app.buildTab.openingWidthM\":[\"Opening width (m)\"],\"app.buildTab.outdoor\":[\"Outdoor\"],\"app.buildTab.picket\":[\"Picket\"],\"app.buildTab.roofType\":[\"Roof type\"],\"app.buildTab.roomsAlreadyCreateTheirFloorAnd\":[\"Rooms already create their floor and ceiling. Use these for platforms and one-off structure.\"],\"app.buildTab.searchBuildToolsAndKitchenItems\":[\"Search build tools and kitchen items\"],\"app.buildTab.searchToolsFridgeSink\":[\"Search tools, fridge, sink…\"],\"app.buildTab.selectACurvedWallToMatch\":[\"Select a curved wall to match its radius and arc.\"],\"app.buildTab.singleGate\":[\"Single gate\"],\"app.buildTab.slabCeilingColumn\":[\"Slab, ceiling, column…\"],\"app.buildTab.solidPrivacy\":[\"Solid privacy\"],\"app.buildTab.traceALineAlongsideAnExisting\":[\"Trace a line alongside an existing lineset (F).\"],\"app.buildTab.verticalSlats\":[\"Vertical slats\"],\"app.editorNavbar.allProjects\":[\"All projects\"],\"app.editorNavbar.preview\":[\"Preview\"],\"app.editorNavbar.projectName\":[\"Project name\"],\"app.editorNavbar.renameProject\":[\"Rename project\"],\"app.editorNavbar.share\":[\"Share\"],\"app.kitchenBrowser.addLabel\":[\"Add \",[\"label\"]],\"app.kitchenBrowser.addToKitchen\":[\"Add to kitchen\"],\"app.kitchenBrowser.chooseAnItemThenClickTo\":[\"Choose an item, then click to place it. Appliances include their cabinetry.\"],\"app.kitchenBrowser.findInThisProjectLength\":[\"Find in this project · \",[\"length\"]],\"app.kitchenBrowser.findName\":[\"Find \",[\"name\"]],\"app.kitchenBrowser.groupAdd\":[\"Kitchen · Add\"],\"app.kitchenBrowser.groupInThisProject\":[\"Kitchen · In this project\"],\"app.kitchenBrowser.kitchenCabinet\":[\"Kitchen cabinet\"],\"app.kitchenBrowser.noMatchingKitchenItemsPlacedYet\":[\"No matching kitchen items placed yet.\"],\"app.kitchenBrowser.selectAndShowInScene\":[\"Select and show in scene\"],\"app.lib.buildPalette.ceiling\":[\"Ceiling\"],\"app.lib.buildPalette.column\":[\"Column\"],\"app.lib.buildPalette.door\":[\"Door\"],\"app.lib.buildPalette.duct\":[\"Duct\"],\"app.lib.buildPalette.dwvPipe\":[\"DWV Pipe\"],\"app.lib.buildPalette.elevator\":[\"Elevator\"],\"app.lib.buildPalette.fence\":[\"Fence\"],\"app.lib.buildPalette.hvacUnit\":[\"HVAC Unit\"],\"app.lib.buildPalette.kitchen\":[\"Kitchen\"],\"app.lib.buildPalette.lineset\":[\"Lineset\"],\"app.lib.buildPalette.liquidLine\":[\"Liquid Line\"],\"app.lib.buildPalette.mep\":[\"MEP\"],\"app.lib.buildPalette.register\":[\"Register\"],\"app.lib.buildPalette.roof\":[\"Roof\"],\"app.lib.buildPalette.shelf\":[\"Shelf\"],\"app.lib.buildPalette.slab\":[\"Slab\"],\"app.lib.buildPalette.spawnPoint\":[\"Spawn point\"],\"app.lib.buildPalette.stairs\":[\"Stairs\"],\"app.lib.buildPalette.terrace\":[\"Terrace\"],\"app.lib.buildPalette.terrain\":[\"Terrain\"],\"app.lib.buildPalette.wall\":[\"Wall\"],\"app.lib.buildPalette.window\":[\"Window\"],\"app.lib.buildPanelModel.addFitting\":[\"Add Fitting\"],\"app.lib.buildPanelModel.addGate\":[\"Add Gate\"],\"app.lib.buildPanelModel.addOpenPassage\":[\"Add Open Passage\"],\"app.lib.buildPanelModel.addTrap\":[\"Add Trap\"],\"app.lib.buildPanelModel.build\":[\"Build\"],\"app.lib.buildPanelModel.createFrom\":[\"Create from\"],\"app.lib.buildPanelModel.drawTheRoofFootprintWithTwo\":[\"Draw the roof footprint with two corner clicks.\"],\"app.lib.buildPanelModel.duct\":[\"Duct\"],\"app.lib.buildPanelModel.dwvPipe\":[\"DWV Pipe\"],\"app.lib.buildPanelModel.featuresExtensions\":[\"Features & extensions\"],\"app.lib.buildPanelModel.fence\":[\"Fence\"],\"app.lib.buildPanelModel.followLineset\":[\"Follow lineset\"],\"app.lib.buildPanelModel.gatesOpenings\":[\"Gates & openings\"],\"app.lib.buildPanelModel.hoverARoomToPreviewIts\":[\"Hover a room to preview its boundary, then click to place.\"],\"app.lib.buildPanelModel.kitchen\":[\"Kitchen\"],\"app.lib.buildPanelModel.mep\":[\"MEP\"],\"app.lib.buildPanelModel.modularCabinet\":[\"Modular Cabinet\"],\"app.lib.buildPanelModel.off\":[\"Off\"],\"app.lib.buildPanelModel.on\":[\"On\"],\"app.lib.buildPanelModel.painting\":[\"Painting\"],\"app.lib.buildPanelModel.roof\":[\"Roof\"],\"app.lib.buildPanelModel.roofType\":[\"Roof type\"],\"app.lib.buildPanelModel.toolCount\":[[\"count\",\"plural\",{\"one\":[\"#\",\" tool\"],\"other\":[\"#\",\" tools\"]}]],\"app.lib.buildTabState.conical\":[\"Conical\"],\"app.lib.buildTabState.draw\":[\"Draw\"],\"app.lib.buildTabState.dutch\":[\"Dutch\"],\"app.lib.buildTabState.flat\":[\"Flat\"],\"app.lib.buildTabState.gable\":[\"Gable\"],\"app.lib.buildTabState.gambrel\":[\"Gambrel\"],\"app.lib.buildTabState.hip\":[\"Hip\"],\"app.lib.buildTabState.mansard\":[\"Mansard\"],\"app.lib.buildTabState.room\":[\"Room\"],\"app.lib.buildTabState.shed\":[\"Shed\"],\"app.lib.buildTabState.wall\":[\"Wall\"],\"app.sceneLoader.anotherSessionSavedFirstRefresh\":[\"Another session saved first — refresh?\"],\"app.sceneLoader.build\":[\"Build\"],\"app.sceneLoader.dismiss\":[\"Dismiss\"],\"app.sceneLoader.items\":[\"Items\"],\"app.sceneLoader.paint\":[\"Paint\"],\"app.sceneLoader.reload\":[\"Reload\"],\"app.sceneLoader.scene\":[\"Scene\"],\"app.sceneLoader.settings\":[\"Settings\"],\"app.sceneLoader.yourChangesHavenTBeenSaved\":[\"Your changes haven't been saved. Reload to pick up the latest version.\"],\"app.sharePanel.anyoneWithTheLinkCanView\":[\"Anyone with the link can view this project. They cannot edit it.\"],\"app.sharePanel.copied\":[\"Copied\"],\"app.sharePanel.copy\":[\"Copy\"],\"app.sharePanel.couldNotReadTheSharingState\":[\"Could not read the sharing state.\"],\"app.sharePanel.couldNotTurnOffThePublic\":[\"Could not turn off the public link.\"],\"app.sharePanel.couldNotTurnOnThePublic\":[\"Could not turn on the public link.\"],\"app.sharePanel.embedCode\":[\"Embed code\"],\"app.sharePanel.embedLink\":[\"Embed link\"],\"app.sharePanel.hideControls\":[\"Hide controls\"],\"app.sharePanel.link\":[\"Link\"],\"app.sharePanel.onlyThe3dViewNoHeader\":[\"Only the 3D view, no header or toolbar.\"],\"app.sharePanel.open\":[\"Open\"],\"app.sharePanel.publicLink\":[\"Public link\"],\"app.sharePanel.shareProject\":[\"Share project\"],\"app.viewerToolbar.automaticDimensions\":[\"Automatic dimensions\"],\"app.viewerToolbar.camera\":[\"Camera\"],\"app.viewerToolbar.cleanPlanDimensionsAppearWithSelection\":[\"Clean plan; dimensions appear with selection\"],\"app.viewerToolbar.collapseSidebar\":[\"Collapse sidebar\"],\"app.viewerToolbar.crispOpaqueEdgeLines\":[\"Crisp, opaque edge lines\"],\"app.viewerToolbar.cutaway\":[\"Cutaway\"],\"app.viewerToolbar.default\":[\"Default\"],\"app.viewerToolbar.display\":[\"Display\"],\"app.viewerToolbar.displaySettings\":[\"Display settings\"],\"app.viewerToolbar.doorWindowMarks\":[\"Door/window marks\"],\"app.viewerToolbar.edges\":[\"Edges\"],\"app.viewerToolbar.enterVr\":[\"Enter VR\"],\"app.viewerToolbar.exitVr\":[\"Exit VR\"],\"app.viewerToolbar.expandSidebar\":[\"Expand sidebar\"],\"app.viewerToolbar.expert\":[\"Expert\"],\"app.viewerToolbar.exploded\":[\"Exploded\"],\"app.viewerToolbar.faceOfStud\":[\"Face of stud\"],\"app.viewerToolbar.faintOutlineOfMajorCreases\":[\"Faint outline of major creases\"],\"app.viewerToolbar.feetInches\":[\"Feet & inches\"],\"app.viewerToolbar.finishedFaces\":[\"Finished faces\"],\"app.viewerToolbar.flatAndFastNoAmbientOcclusion\":[\"Flat and fast — no ambient occlusion\"],\"app.viewerToolbar.floorPlanAnnotations\":[\"Floor plan annotations\"],\"app.viewerToolbar.floorPlanMode\":[\"Floor plan mode\"],\"app.viewerToolbar.fullAmbientOcclusion\":[\"Full ambient occlusion\"],\"app.viewerToolbar.fullDocumentationAndAnnotationControls\":[\"Full documentation and annotation controls\"],\"app.viewerToolbar.fullHeight\":[\"Full height\"],\"app.viewerToolbar.fullWallThickness\":[\"Full wall thickness\"],\"app.viewerToolbar.grid\":[\"Grid\"],\"app.viewerToolbar.levelsMode\":[\"Levels: \",[\"mode\"]],\"app.viewerToolbar.low\":[\"Low\"],\"app.viewerToolbar.magneticSnap\":[\"Magnetic snap\"],\"app.viewerToolbar.manual\":[\"Manual\"],\"app.viewerToolbar.manualDimensions\":[\"Manual dimensions\"],\"app.viewerToolbar.measurements\":[\"Measurements\"],\"app.viewerToolbar.meters\":[\"Meters\"],\"app.viewerToolbar.millimeters\":[\"Millimeters\"],\"app.viewerToolbar.n3dMeasurements\":[\"3D measurements\"],\"app.viewerToolbar.noEdgeLines\":[\"No edge lines\"],\"app.viewerToolbar.off\":[\"Off\"],\"app.viewerToolbar.on\":[\"On\"],\"app.viewerToolbar.orthographic\":[\"Orthographic\"],\"app.viewerToolbar.perspective\":[\"Perspective\"],\"app.viewerToolbar.preview\":[\"Preview\"],\"app.viewerToolbar.previewMode\":[\"Preview mode\"],\"app.viewerToolbar.render\":[\"Render\"],\"app.viewerToolbar.rendered\":[\"Rendered\"],\"app.viewerToolbar.roomLabels\":[\"Room labels\"],\"app.viewerToolbar.sceneTheme\":[\"Scene theme\"],\"app.viewerToolbar.shadows\":[\"Shadows\"],\"app.viewerToolbar.singleWallAxis\":[\"Single wall axis\"],\"app.viewerToolbar.soft\":[\"Soft\"],\"app.viewerToolbar.solid\":[\"Solid\"],\"app.viewerToolbar.solo\":[\"Solo\"],\"app.viewerToolbar.stack\":[\"Stack\"],\"app.viewerToolbar.stairAnnotations\":[\"Stair annotations\"],\"app.viewerToolbar.strong\":[\"Strong\"],\"app.viewerToolbar.structuralCoreFace\":[\"Structural core face\"],\"app.viewerToolbar.structuralGridsColumnCenters\":[\"Structural grids & column centers\"],\"app.viewerToolbar.translucent\":[\"Translucent\"],\"app.viewerToolbar.units\":[\"Units\"],\"app.viewerToolbar.walkthrough\":[\"Walkthrough\"],\"app.viewerToolbar.wallCenterline\":[\"Wall centerline\"],\"app.viewerToolbar.wallDimensions\":[\"Wall dimensions\"],\"app.viewerToolbar.wallsLabel\":[\"Walls: \",[\"label\"]],\"core.level.basement\":[\"Basement\"],\"core.level.basementNumber\":[\"Basement \",[\"number\"]],\"core.level.floorNumber\":[\"Floor \",[\"number\"]],\"core.level.groundFloor\":[\"Ground floor\"],\"editor.actionMenu.cameraActions.orbitLeft\":[\"Orbit Left\"],\"editor.actionMenu.cameraActions.orbitRight\":[\"Orbit Right\"],\"editor.actionMenu.cameraActions.topView\":[\"Top View\"],\"editor.actionMenu.controlModes.delete\":[\"Delete\"],\"editor.actionMenu.controlModes.select\":[\"Select\"],\"editor.actionMenu.followPascalPill.resumeFollowing\":[\"Resume following\"],\"editor.actionMenu.followPascalToggle.off\":[\"Follow Pascal: Off\"],\"editor.actionMenu.followPascalToggle.on\":[\"Follow Pascal: On\"],\"editor.actionMenu.furnishTools.appliance\":[\"Appliance\"],\"editor.actionMenu.furnishTools.bathroom\":[\"Bathroom\"],\"editor.actionMenu.furnishTools.furniture\":[\"Furniture\"],\"editor.actionMenu.furnishTools.kitchen\":[\"Kitchen\"],\"editor.actionMenu.furnishTools.outdoor\":[\"Outdoor\"],\"editor.actionMenu.measurementControl.angle\":[\"Angle\"],\"editor.actionMenu.measurementControl.angularDimension\":[\"Angular dimension\"],\"editor.actionMenu.measurementControl.arcLength\":[\"Arc length\"],\"editor.actionMenu.measurementControl.area\":[\"Area\"],\"editor.actionMenu.measurementControl.centerMark\":[\"Center mark\"],\"editor.actionMenu.measurementControl.chordDimension\":[\"Chord dimension\"],\"editor.actionMenu.measurementControl.continuousDimension\":[\"Continuous dimension\"],\"editor.actionMenu.measurementControl.coordinateDimensions\":[\"Coordinate dimensions\"],\"editor.actionMenu.measurementControl.diameterDimension\":[\"Diameter dimension\"],\"editor.actionMenu.measurementControl.distance\":[\"Distance\"],\"editor.actionMenu.measurementControl.floorPlan\":[\"Floor plan\"],\"editor.actionMenu.measurementControl.linearDimension\":[\"Linear dimension\"],\"editor.actionMenu.measurementControl.measureSelectedlabel\":[\"Measure: \",[\"selectedLabel\"]],\"editor.actionMenu.measurementControl.measurementOptions\":[\"Measurement options\"],\"editor.actionMenu.measurementControl.measurementType\":[\"Measurement type\"],\"editor.actionMenu.measurementControl.perimeter\":[\"Perimeter\"],\"editor.actionMenu.measurementControl.radiusDimension\":[\"Radius dimension\"],\"editor.actionMenu.measurementControl.smart\":[\"Smart\"],\"editor.actionMenu.measurementControl.volume\":[\"Volume\"],\"editor.actionMenu.pointAskButton.pointAndAsk\":[\"Point and ask\"],\"editor.actionMenu.pointAskButton.pointAndAskC\":[\"Point and ask (C)\"],\"editor.actionMenu.pointAskButton.pointAndAskWorksInThe\":[\"Point and ask works in the 3D view\"],\"editor.actionMenu.structureTools.ceiling\":[\"Ceiling\"],\"editor.actionMenu.structureTools.column\":[\"Column\"],\"editor.actionMenu.structureTools.door\":[\"Door\"],\"editor.actionMenu.structureTools.duct\":[\"Duct\"],\"editor.actionMenu.structureTools.ductFitting\":[\"Duct Fitting\"],\"editor.actionMenu.structureTools.dwvPipe\":[\"DWV Pipe\"],\"editor.actionMenu.structureTools.elevator\":[\"Elevator\"],\"editor.actionMenu.structureTools.fence\":[\"Fence\"],\"editor.actionMenu.structureTools.gableRoof\":[\"Gable Roof\"],\"editor.actionMenu.structureTools.hvacUnit\":[\"HVAC Unit\"],\"editor.actionMenu.structureTools.lineset\":[\"Lineset\"],\"editor.actionMenu.structureTools.liquidLine\":[\"Liquid Line\"],\"editor.actionMenu.structureTools.pipeFitting\":[\"Pipe Fitting\"],\"editor.actionMenu.structureTools.register\":[\"Register\"],\"editor.actionMenu.structureTools.shelf\":[\"Shelf\"],\"editor.actionMenu.structureTools.slab\":[\"Slab\"],\"editor.actionMenu.structureTools.spawnPoint\":[\"Spawn Point\"],\"editor.actionMenu.structureTools.stairs\":[\"Stairs\"],\"editor.actionMenu.structureTools.trap\":[\"Trap\"],\"editor.actionMenu.structureTools.wall\":[\"Wall\"],\"editor.actionMenu.structureTools.window\":[\"Window\"],\"editor.actionMenu.structureTools.zone\":[\"Zone\"],\"editor.actionMenu.viewToggles.deleteGuideImage\":[\"Delete guide image\"],\"editor.actionMenu.viewToggles.deleteScan\":[\"Delete scan\"],\"editor.actionMenu.viewToggles.guideCount\":[[\"count\",\"plural\",{\"one\":[\"#\",\" guide image on this level\"],\"other\":[\"#\",\" guide images on this level\"]}]],\"editor.actionMenu.viewToggles.guideImageNumber\":[\"Guide image \",[\"number\"]],\"editor.actionMenu.viewToggles.guideImageSettings\":[\"Guide image settings\"],\"editor.actionMenu.viewToggles.guideImages\":[\"Guide images\"],\"editor.actionMenu.viewToggles.guides\":[\"Guides\"],\"editor.actionMenu.viewToggles.guidesHidden\":[\"Guides: Hidden\"],\"editor.actionMenu.viewToggles.guidesVisible\":[\"Guides: Visible\"],\"editor.actionMenu.viewToggles.hideGuideImages\":[\"Hide guide images\"],\"editor.actionMenu.viewToggles.hideReferenceFloor\":[\"Hide reference floor\"],\"editor.actionMenu.viewToggles.hideScans\":[\"Hide scans\"],\"editor.actionMenu.viewToggles.levelsBelow\":[[\"count\"],\" below\"],\"editor.actionMenu.viewToggles.noLowerFloorAvailable\":[\"No lower floor available.\"],\"editor.actionMenu.viewToggles.opacity\":[\"Opacity\"],\"editor.actionMenu.viewToggles.referenceFloor\":[\"Reference floor\"],\"editor.actionMenu.viewToggles.referenceFloorSelectedlevelname\":[\"Reference floor: \",[\"selectedLevelName\"]],\"editor.actionMenu.viewToggles.referenceFloorSettings\":[\"Reference floor settings\"],\"editor.actionMenu.viewToggles.referenceSettings\":[\"Reference settings\"],\"editor.actionMenu.viewToggles.references\":[\"References\"],\"editor.actionMenu.viewToggles.referencesEmpty\":[\"Upload GLB meshes as scan references or blueprint images as guide references.\"],\"editor.actionMenu.viewToggles.referencesHidden\":[\"References: Hidden\"],\"editor.actionMenu.viewToggles.referencesVisible\":[\"References: Visible\"],\"editor.actionMenu.viewToggles.riserDiagram\":[\"Riser diagram\"],\"editor.actionMenu.viewToggles.scanCount\":[[\"count\",\"plural\",{\"one\":[\"#\",\" scan on this level\"],\"other\":[\"#\",\" scans on this level\"]}]],\"editor.actionMenu.viewToggles.scanNumber\":[\"Scan \",[\"number\"]],\"editor.actionMenu.viewToggles.scanSettings\":[\"Scan settings\"],\"editor.actionMenu.viewToggles.scans\":[\"Scans\"],\"editor.actionMenu.viewToggles.scansHidden\":[\"Scans: Hidden\"],\"editor.actionMenu.viewToggles.scansVisible\":[\"Scans: Visible\"],\"editor.actionMenu.viewToggles.showGuideImages\":[\"Show guide images\"],\"editor.actionMenu.viewToggles.showReferenceFloor\":[\"Show reference floor\"],\"editor.actionMenu.viewToggles.showScans\":[\"Show scans\"],\"editor.actionMenu.viewToggles.uploadScanOrGuideImage\":[\"Upload scan or guide image\"],\"editor.backToHome\":[\"Back to home\"],\"editor.buildPanel.advanced\":[\"Advanced\"],\"editor.buildPanel.rooms.hint\":[\"walls · floor · ceiling\"],\"editor.buildPanel.rooms.idle\":[\"Pick a shape to start. Every room brings its own walls, floor and ceiling.\"],\"editor.buildPanel.rooms.polygon.caption\":[[\"lead\"],\" then the first one again to close. For L-shapes and angled rooms.\"],\"editor.buildPanel.rooms.polygon.label\":[\"Polygon\"],\"editor.buildPanel.rooms.polygon.lead\":[\"Click each corner,\"],\"editor.buildPanel.rooms.polygon.title\":[\"Polygon room\"],\"editor.buildPanel.rooms.rectangle.caption\":[[\"lead\"],\" on the grid. Walls, floor and ceiling are created together.\"],\"editor.buildPanel.rooms.rectangle.label\":[\"Rectangle\"],\"editor.buildPanel.rooms.rectangle.lead\":[\"Click two corners\"],\"editor.buildPanel.rooms.rectangle.title\":[\"Rectangle room\"],\"editor.buildPanel.rooms.title\":[\"Rooms\"],\"editor.buildPanel.rooms.walls.caption\":[[\"lead\"],\" Close a loop and it becomes a room; leave it open for partitions.\"],\"editor.buildPanel.rooms.walls.label\":[\"Walls\"],\"editor.buildPanel.rooms.walls.lead\":[\"Draw one wall at a time.\"],\"editor.buildPanel.rooms.walls.title\":[\"Walls\"],\"editor.cameraControlsHint\":[\"Camera controls hint\"],\"editor.cameraHint.pan\":[\"Pan\"],\"editor.cameraHint.rotate\":[\"Rotate\"],\"editor.cameraHint.zoom\":[\"Zoom\"],\"editor.controls.finishSwatch.ariaLabel\":[[\"label\"],\": \",[\"finish\"]],\"editor.controls.finishSwatch.default\":[\"Default\"],\"editor.dismiss\":[\"Dismiss\"],\"editor.dismissCameraControlsHint\":[\"Dismiss camera controls hint\"],\"editor.expandSidebar\":[\"Expand sidebar\"],\"editor.floatingActionMenu.axis\":[\"Axis\"],\"editor.floatingActionMenu.axis2\":[\"⌥ axis\"],\"editor.floatingActionMenu.noEquipment\":[\"⚠ no equipment\"],\"editor.floatingActionMenu.rTRotate\":[\"R/T rotate\"],\"editor.floatingActionMenu.registerCount\":[[\"count\",\"plural\",{\"one\":[\"#\",\" register\"],\"other\":[\"#\",\" registers\"]}]],\"editor.floatingActionMenu.runCount\":[[\"count\",\"plural\",{\"one\":[[\"number\"],\" run\"],\"other\":[[\"number\"],\" runs\"]}]],\"editor.floatingActionMenu.system\":[\"System\"],\"editor.floatingLevelSelector.addAFloorUnderTheRoof\":[\"Add a floor under the roof\"],\"editor.floatingLevelSelector.addLevelAbove\":[\"Add level above\"],\"editor.floatingLevelSelector.addLevelBelow\":[\"Add level below\"],\"editor.floatingLevelSelector.cancel\":[\"Cancel\"],\"editor.floatingLevelSelector.delete\":[\"Delete\"],\"editor.floatingLevelSelector.deleteLevel\":[\"Delete level\"],\"editor.floatingLevelSelector.deleteLevelConfirm\":[\"Are you sure you want to delete \",[\"levelName\"],\"? All walls, floors, and objects on this level will be permanently removed.\"],\"editor.floatingLevelSelector.dragToReorder\":[\"Drag to reorder\"],\"editor.floatingLevelSelector.duplicateLevel\":[\"Duplicate level\"],\"editor.floatingLevelSelector.duplicateWithOptions\":[\"Duplicate with options...\"],\"editor.floatingLevelSelector.exitUnitFocus\":[\"Exit unit focus\"],\"editor.floatingLevelSelector.focusedUnitHasZonesHere\":[\"Focused unit has zones here\"],\"editor.floatingLevelSelector.groundFloorOverGrade\":[\"The ground floor stands \",[\"distance\"],\" over grade. Seat the ground floor 8 in over grade\"],\"editor.floatingLevelSelector.groundFloorUnderGrade\":[\"The ground floor stands \",[\"distance\"],\" under grade. Seat the ground floor 8 in over grade\"],\"editor.floatingLevelSelector.groundLineTheLevelsUnderIt\":[\"Ground line: the levels under it are below grade\"],\"editor.floatingLevelSelector.groundOffset\":[\"Ground · \",[\"offset\"]],\"editor.floatingLevelSelector.insertLevelHere\":[\"Insert level here\"],\"editor.floatingLevelSelector.levelHeight\":[\"Level height\"],\"editor.floatingLevelSelector.pasteCopiedSelection\":[\"Paste copied selection\"],\"editor.floatingLevelSelector.reorderLevelname\":[\"Reorder \",[\"levelName\"]],\"editor.floatingLevelSelector.seatTheBuildingSoThisFloor\":[\"Seat the building so this floor stands at grade; the floors under it are below grade\"],\"editor.floatingLevelSelector.setAsGroundFloor\":[\"Set as ground floor\"],\"editor.floatingLevelSelector.theGroundLevelCannotBeDeleted\":[\"The ground level cannot be deleted\"],\"editor.floatingLevelSelector.thisFloorStandsAtGrade\":[\"This floor stands at grade\"],\"editor.floatingLevelSelector.unit\":[\"Unit\"],\"editor.floorFootprint.area\":[\"Floor area\"],\"editor.floorFootprint.room\":[[\"room\"],\" floor\"],\"editor.floorFootprint.shared\":[\"Shared floor\"],\"editor.helpers.buildingHelper.cancel\":[\"Cancel\"],\"editor.helpers.buildingHelper.placeBuilding\":[\"Place building\"],\"editor.helpers.buildingHelper.rotate\":[\"Rotate\"],\"editor.helpers.contextualHelperPanel.cancelPlacement\":[\"Cancel placement\"],\"editor.helpers.contextualHelperPanel.continuationClickOrPressCTo\":[\"Continuation — click or press C to cycle\"],\"editor.helpers.contextualHelperPanel.continuationLabel\":[\"Continuation: \",[\"label\"]],\"editor.helpers.contextualHelperPanel.dragToDrawFence\":[\"Drag to draw fence\"],\"editor.helpers.contextualHelperPanel.eraseScope\":[\"Erase: \",[\"scope\"]],\"editor.helpers.contextualHelperPanel.eraseScopeClickOrPressShift\":[\"Erase scope — click or press Shift to cycle\"],\"editor.helpers.contextualHelperPanel.eraseScopeLabel\":[\"Erase scope: \",[\"scope\"]],\"editor.helpers.contextualHelperPanel.fenceTypeClickOrPressT\":[\"Fence type — click or press T to switch between straight, curved and freehand\"],\"editor.helpers.contextualHelperPanel.fewerShortcuts\":[\"Fewer shortcuts\"],\"editor.helpers.contextualHelperPanel.finishCurveOrDoubleClick\":[\"Finish curve (or double-click)\"],\"editor.helpers.contextualHelperPanel.gridLength\":[\"Grid: \",[\"length\"]],\"editor.helpers.contextualHelperPanel.gridStepClickOrTapCtrl\":[\"Grid step — click or tap Ctrl to cycle\"],\"editor.helpers.contextualHelperPanel.gridStepLength\":[\"Grid step: \",[\"length\"]],\"editor.helpers.contextualHelperPanel.hoverAPaintedSurfaceToErase\":[\"Hover a painted surface to erase\"],\"editor.helpers.contextualHelperPanel.hoverASurfaceToPaint\":[\"Hover a surface to paint\"],\"editor.helpers.contextualHelperPanel.hoverASurfaceToPickIts\":[\"Hover a surface to pick its material\"],\"editor.helpers.contextualHelperPanel.moreShortcuts\":[\"More shortcuts\"],\"editor.helpers.contextualHelperPanel.paintScope\":[\"Paint: \",[\"scope\"]],\"editor.helpers.contextualHelperPanel.paintScopeClickOrPressShift\":[\"Paint scope — click or press Shift to cycle\"],\"editor.helpers.contextualHelperPanel.paintScopeLabel\":[\"Paint scope: \",[\"scope\"]],\"editor.helpers.contextualHelperPanel.pickScope\":[\"Pick: \",[\"scope\"]],\"editor.helpers.contextualHelperPanel.placeGateOnAFence\":[\"Place gate on a fence\"],\"editor.helpers.contextualHelperPanel.placePassageOnAFence\":[\"Place passage on a fence\"],\"editor.helpers.contextualHelperPanel.selectAMaterialToPaint\":[\"Select a material to paint\"],\"editor.helpers.contextualHelperPanel.snappingAngles\":[\"Snapping: Angles\"],\"editor.helpers.contextualHelperPanel.snappingGrid\":[\"Snapping: Grid\"],\"editor.helpers.contextualHelperPanel.snappingLines\":[\"Snapping: Lines\"],\"editor.helpers.contextualHelperPanel.snappingModeClickOrPressShift\":[\"Snapping mode — click or press Shift to cycle\"],\"editor.helpers.contextualHelperPanel.snappingOff\":[\"Snapping: Off\"],\"editor.helpers.contextualHelperPanel.straightContinuationIsUnavailableForCurved\":[\"Straight continuation is unavailable for curved or freehand fences\"],\"editor.helpers.contextualHelperPanel.straightContinuous\":[\"Straight: Continuous\"],\"editor.helpers.contextualHelperPanel.straightFenceContinuationClickOrPress\":[\"Straight fence continuation — click or press C to toggle\"],\"editor.helpers.contextualHelperPanel.straightSingle\":[\"Straight: Single\"],\"editor.helpers.helperManager.addPoint\":[\"Add point\"],\"editor.helpers.helperManager.addPointClickTheFirstTo\":[\"Add point · click the first to close\"],\"editor.helpers.helperManager.brushSize\":[\"Brush size\"],\"editor.helpers.helperManager.cancel\":[\"Cancel\"],\"editor.helpers.helperManager.cancelPicking\":[\"Cancel picking\"],\"editor.helpers.helperManager.cancelStroke\":[\"Cancel stroke\"],\"editor.helpers.helperManager.done\":[\"Done\"],\"editor.helpers.helperManager.drawTheMezzanine\":[\"Draw the mezzanine\"],\"editor.helpers.helperManager.drawTheOpening\":[\"Draw the opening\"],\"editor.helpers.helperManager.drawTheTerrace\":[\"Draw the terrace\"],\"editor.helpers.helperManager.exitSmartMeasure\":[\"Exit smart measure\"],\"editor.helpers.helperManager.finish\":[\"Finish\"],\"editor.helpers.helperManager.finishAtTheEdge\":[\"Finish at the edge\"],\"editor.helpers.helperManager.freeMove\":[\"Free move\"],\"editor.helpers.helperManager.freeMoveSlideDoorsAndWindows\":[\"Free move · slide doors and windows\"],\"editor.helpers.helperManager.holdToPickAMaterial\":[\"Hold to pick a material\"],\"editor.helpers.helperManager.inspectSurfaceDimensions\":[\"Inspect surface dimensions\"],\"editor.helpers.helperManager.paintWithThisMaterial\":[\"Paint with this material\"],\"editor.helpers.helperManager.pickTargetHeight\":[\"Pick target height\"],\"editor.helpers.helperManager.pinMeasurementLens\":[\"Pin measurement lens\"],\"editor.helpers.helperManager.place\":[\"Place\"],\"editor.helpers.helperManager.placeInsideTheRoom\":[\"Place inside the room\"],\"editor.helpers.helperManager.pressAnywhereDragToTheOpposite\":[\"Press anywhere, drag to the opposite corner\"],\"editor.helpers.helperManager.raiseOrLower\":[\"Raise or lower\"],\"editor.helpers.helperManager.removeAPaintedPartOrReset\":[\"Remove a painted part, or reset a surface\"],\"editor.helpers.helperManager.removeLastPoint\":[\"Remove last point\"],\"editor.helpers.helperManager.resize\":[\"Resize\"],\"editor.helpers.helperManager.rotate45\":[\"Rotate ±45°\"],\"editor.helpers.helperManager.rotateTheSelection45\":[\"Rotate the selection ±45°\"],\"editor.helpers.helperManager.setOneCornerThenTheOpposite\":[\"Set one corner, then the opposite\"],\"editor.helpers.itemHelper.cancel\":[\"Cancel\"],\"editor.helpers.itemHelper.forcePlace\":[\"Force place\"],\"editor.helpers.itemHelper.place\":[\"Place\"],\"editor.helpers.itemHelper.rotate\":[\"Rotate\"],\"editor.helpers.registeredToolHelper.guidedConstraintsBypassed\":[\"Guided constraints bypassed\"],\"editor.inspector.field.angle.g10zaw\":[\"Angle\"],\"editor.inspector.field.armLengthM.1jclqgw\":[\"Arm length m\"],\"editor.inspector.field.attachmentSide.6n9s5v\":[\"Attachment side\"],\"editor.inspector.field.autoHangers.10554ka\":[\"Auto hangers\"],\"editor.inspector.field.autoMiterCorners.zxr5lt\":[\"Auto miter corners\"],\"editor.inspector.field.autoSpan.1gas9r6\":[\"Auto span\"],\"editor.inspector.field.backRatio.1ughd99\":[\"Back ratio\"],\"editor.inspector.field.baseHeight.1hs4zdf\":[\"Base height\"],\"editor.inspector.field.baseStyle.24vty5\":[\"Base style\"],\"editor.inspector.field.beamHeight.1kq0oh1\":[\"Beam height\"],\"editor.inspector.field.beamWidth.1q1mzbe\":[\"Beam width\"],\"editor.inspector.field.bodyShape.arvkuw\":[\"Body shape\"],\"editor.inspector.field.bracketStyle.1vvoptm\":[\"Bracket style\"],\"editor.inspector.field.branchAngle.v56zme\":[\"Branch angle\"],\"editor.inspector.field.cabHeight.1yn34mk\":[\"Cab height\"],\"editor.inspector.field.canopyForm.1czzggp\":[\"Canopy form\"],\"editor.inspector.field.cap.s0thej\":[\"Cap\"],\"editor.inspector.field.capOverhang.kxxz9j\":[\"Cap overhang\"],\"editor.inspector.field.capShape.17mbxhu\":[\"Cap shape\"],\"editor.inspector.field.capThickness.u835q9\":[\"Cap thickness\"],\"editor.inspector.field.carcassHeight.1aks0zy\":[\"Carcass height\"],\"editor.inspector.field.cleanoutStyle.127zz6z\":[\"Cleanout style\"],\"editor.inspector.field.collarDiameter.1d5k28r\":[\"Collar diameter\"],\"editor.inspector.field.collarHeight.1dqwsrf\":[\"Collar height\"],\"editor.inspector.field.collarShape.1gacv11\":[\"Collar shape\"],\"editor.inspector.field.collarWidth.qvc9ik\":[\"Collar width\"],\"editor.inspector.field.columns.1sy73ks\":[\"Columns\"],\"editor.inspector.field.conicalFullCircle.1pgkpz5\":[\"Conical full circle\"],\"editor.inspector.field.connectionMode.1nty478\":[\"Connection mode\"],\"editor.inspector.field.connectionOffset.2m70s8\":[\"Connection offset\"],\"editor.inspector.field.cornerBevel.16iniho\":[\"Corner bevel\"],\"editor.inspector.field.coveringType.95yd3k\":[\"Covering type\"],\"editor.inspector.field.cricketHeight.pok31n\":[\"Cricket height\"],\"editor.inspector.field.cricketLength.i2aht8\":[\"Cricket length\"],\"editor.inspector.field.cricketSide.1xnwil7\":[\"Cricket side\"],\"editor.inspector.field.cricketStyle.10j0lat\":[\"Cricket style\"],\"editor.inspector.field.curb.5xi2ol\":[\"Curb\"],\"editor.inspector.field.curbHeight.1yn97sg\":[\"Curb height\"],\"editor.inspector.field.curveOffset.l4xhvr\":[\"Curve offset\"],\"editor.inspector.field.damperAngle.h5fxn7\":[\"Damper angle\"],\"editor.inspector.field.deckThickness.4jmqze\":[\"Deck thickness\"],\"editor.inspector.field.defaultLevelId.xmrjzp\":[\"Default level id\"],\"editor.inspector.field.depth.1lu11u2\":[\"Depth\"],\"editor.inspector.field.diameter.s3robe\":[\"Diameter\"],\"editor.inspector.field.diameter2.pm6cl4\":[\"Diameter2\"],\"editor.inspector.field.doorDurationMs.13nx909\":[\"Door duration ms\"],\"editor.inspector.field.doorHeight.92r9k4\":[\"Door height\"],\"editor.inspector.field.doorPanelStyle.2qog4q\":[\"Door panel style\"],\"editor.inspector.field.doorStyle.gerpos\":[\"Door style\"],\"editor.inspector.field.doorWidth.sy732l\":[\"Door width\"],\"editor.inspector.field.downspoutEnabled.1gn00nv\":[\"Downspout enabled\"],\"editor.inspector.field.downspoutPosition.fxcsop\":[\"Downspout position\"],\"editor.inspector.field.ductMaterial.i8eonq\":[\"Duct material\"],\"editor.inspector.field.dutchGabletRake.6paydp\":[\"Dutch gablet rake\"],\"editor.inspector.field.dutchHipHeightRatio.1etnwgg\":[\"Dutch hip height ratio\"],\"editor.inspector.field.dutchHipWidthRatio.1dopfvb\":[\"Dutch hip width ratio\"],\"editor.inspector.field.dutchTopRakeThickness.1w9khxt\":[\"Dutch top rake thickness\"],\"editor.inspector.field.dutchWaistLengthRatio.agtoxw\":[\"Dutch waist length ratio\"],\"editor.inspector.field.dwellMs.1lkk0o5\":[\"Dwell ms\"],\"editor.inspector.field.edgeInset.1obeimx\":[\"Edge inset\"],\"editor.inspector.field.elevation.4jbp44\":[\"Elevation\"],\"editor.inspector.field.endCapLeft.19jel4v\":[\"End cap left\"],\"editor.inspector.field.endCapRight.lhse9c\":[\"End cap right\"],\"editor.inspector.field.endCaps.4fsb5b\":[\"End caps\"],\"editor.inspector.field.endPost.1guwsk0\":[\"End post\"],\"editor.inspector.field.equipmentType.1mc2ywt\":[\"Equipment type\"],\"editor.inspector.field.fillToFloor.1oppnkf\":[\"Fill to floor\"],\"editor.inspector.field.finial.1ertf4s\":[\"Finial\"],\"editor.inspector.field.fittingType.18mz17s\":[\"Fitting type\"],\"editor.inspector.field.flashingHeight.3e8nn6\":[\"Flashing height\"],\"editor.inspector.field.flashingProjection.hhf0fk\":[\"Flashing projection\"],\"editor.inspector.field.flueCount.j3t2ci\":[\"Flue count\"],\"editor.inspector.field.flueDiameter.cjhubg\":[\"Flue diameter\"],\"editor.inspector.field.flueHeight.1dhc4y4\":[\"Flue height\"],\"editor.inspector.field.flueShape.1ealiy4\":[\"Flue shape\"],\"editor.inspector.field.flueSpacing.exhzco\":[\"Flue spacing\"],\"editor.inspector.field.footingStyle.e3btg6\":[\"Footing style\"],\"editor.inspector.field.frameDepth.1934a5n\":[\"Frame depth\"],\"editor.inspector.field.frameThickness.1agxzd8\":[\"Frame thickness\"],\"editor.inspector.field.framingStrategy.3jx9qe\":[\"Framing strategy\"],\"editor.inspector.field.fromLevelId.15ieejs\":[\"From level id\"],\"editor.inspector.field.gableOverhang.2z0obw\":[\"Gable overhang\"],\"editor.inspector.field.gambrelLowerHeightRatio.wqq7lg\":[\"Gambrel lower height ratio\"],\"editor.inspector.field.gambrelLowerWidthRatio.uvyb1v\":[\"Gambrel lower width ratio\"],\"editor.inspector.field.gapX.wjxa7\":[\"Gap x\"],\"editor.inspector.field.gapY.mkbl8\":[\"Gap y\"],\"editor.inspector.field.glassThickness.s97b0x\":[\"Glass thickness\"],\"editor.inspector.field.groundClearance.4os7f0\":[\"Ground clearance\"],\"editor.inspector.field.guardInfill.16heiig\":[\"Guard infill\"],\"editor.inspector.field.gutterEnabled.1oxiltf\":[\"Gutter enabled\"],\"editor.inspector.field.gutterProfile.1ngzqi3\":[\"Gutter profile\"],\"editor.inspector.field.gutterSize.jgavtz\":[\"Gutter size\"],\"editor.inspector.field.hangerMaxReach.1869epv\":[\"Hanger max reach\"],\"editor.inspector.field.hangerSpacing.i2b5d7\":[\"Hanger spacing\"],\"editor.inspector.field.hangerStyle.l7v7gb\":[\"Hanger style\"],\"editor.inspector.field.height.7puwki\":[\"Height\"],\"editor.inspector.field.height2.7b3jlc\":[\"Height2\"],\"editor.inspector.field.heightAboveRidge.1k99brk\":[\"Height above ridge\"],\"editor.inspector.field.highEdgeHeight.1s7v90t\":[\"High edge height\"],\"editor.inspector.field.highOverhang.67w55d\":[\"High overhang\"],\"editor.inspector.field.highSideMode.1rc1r5j\":[\"High side mode\"],\"editor.inspector.field.hoodOverhang.1q1hcin\":[\"Hood overhang\"],\"editor.inspector.field.infillPlacement.11dxzpo\":[\"Infill placement\"],\"editor.inspector.field.inletShape.ypayh2\":[\"Inlet shape\"],\"editor.inspector.field.innerRadius.1fkmg0j\":[\"Inner radius\"],\"editor.inspector.field.insulated.iwziey\":[\"Insulated\"],\"editor.inspector.field.insulationR.663ufx\":[\"Insulation r\"],\"editor.inspector.field.lanternHeight.oz7zpm\":[\"Lantern height\"],\"editor.inspector.field.lanternTopScale.hkmpp2\":[\"Lantern top scale\"],\"editor.inspector.field.ledgerDepth.7av8k9\":[\"Ledger depth\"],\"editor.inspector.field.ledgerHeight.zo2oif\":[\"Ledger height\"],\"editor.inspector.field.ledgerVerticalOffset.1athbgt\":[\"Ledger vertical offset\"],\"editor.inspector.field.leftEndCondition.1syqlaw\":[\"Left end condition\"],\"editor.inspector.field.leftOverhang.1ydl9ma\":[\"Left overhang\"],\"editor.inspector.field.length.1kpdcfp\":[\"Length\"],\"editor.inspector.field.liquidDiameter.w3pk7c\":[\"Liquid diameter\"],\"editor.inspector.field.louverCount.lhw2gr\":[\"Louver count\"],\"editor.inspector.field.lowBeamInset.1g7yw5l\":[\"Low beam inset\"],\"editor.inspector.field.lowEdgeHeight.47mae1\":[\"Low edge height\"],\"editor.inspector.field.lowOverhang.t4nz1h\":[\"Low overhang\"],\"editor.inspector.field.mansardSteepHeightRatio.1hbb8rq\":[\"Mansard steep height ratio\"],\"editor.inspector.field.mansardSteepWidthRatio.6xk6vd\":[\"Mansard steep width ratio\"],\"editor.inspector.field.matchHostRoofMaterial.s56zwj\":[\"Match host roof material\"],\"editor.inspector.field.matchHostRoofStructure.bojht3\":[\"Match host roof structure\"],\"editor.inspector.field.mount.h80tay\":[\"Mount\"],\"editor.inspector.field.mountingType.1xvin1e\":[\"Mounting type\"],\"editor.inspector.field.neckHeight.19ym8n1\":[\"Neck height\"],\"editor.inspector.field.opacity.1pmpfd2\":[\"Opacity\"],\"editor.inspector.field.openingAngle.brhi7c\":[\"Opening angle\"],\"editor.inspector.field.openingOffset.wpoqt6\":[\"Opening offset\"],\"editor.inspector.field.openingSide.18l2iwe\":[\"Opening side\"],\"editor.inspector.field.operationState.1lwrz07\":[\"Operation state\"],\"editor.inspector.field.outletShape.lgpqhx\":[\"Outlet shape\"],\"editor.inspector.field.overhang.b5ljpv\":[\"Overhang\"],\"editor.inspector.field.panelHeight.1kf31vk\":[\"Panel height\"],\"editor.inspector.field.panelWidth.946581\":[\"Panel width\"],\"editor.inspector.field.patternAlignment.jd1ht0\":[\"Pattern alignment\"],\"editor.inspector.field.patternCount.1r37pve\":[\"Pattern count\"],\"editor.inspector.field.patternDistribution.fmam51\":[\"Pattern distribution\"],\"editor.inspector.field.patternRemainder.i47p5y\":[\"Pattern remainder\"],\"editor.inspector.field.picketProfile.1xgzuyc\":[\"Picket profile\"],\"editor.inspector.field.picketRailCount.atgt6w\":[\"Picket rail count\"],\"editor.inspector.field.picketSpacing.p8d98w\":[\"Picket spacing\"],\"editor.inspector.field.picketTop.1tskplu\":[\"Picket top\"],\"editor.inspector.field.picketTopClearance.16eq1k0\":[\"Picket top clearance\"],\"editor.inspector.field.picketVariation.f7vl1c\":[\"Picket variation\"],\"editor.inspector.field.picketWidth.3fr3rh\":[\"Picket width\"],\"editor.inspector.field.pipeMaterial.1ggc2wy\":[\"Pipe material\"],\"editor.inspector.field.pitch.xe6ekx\":[\"Pitch\"],\"editor.inspector.field.position.1quewx6\":[\"Position\"],\"editor.inspector.field.postBracing.crq8nn\":[\"Post bracing\"],\"editor.inspector.field.postCap.1xcvxrv\":[\"Post cap\"],\"editor.inspector.field.postCount.22r56c\":[\"Post count\"],\"editor.inspector.field.postDepth.1ko6j1m\":[\"Post depth\"],\"editor.inspector.field.postInset.le36li\":[\"Post inset\"],\"editor.inspector.field.postLayoutMode.16jre62\":[\"Post layout mode\"],\"editor.inspector.field.postSize.1jodxek\":[\"Post size\"],\"editor.inspector.field.postSpacing.voppfi\":[\"Post spacing\"],\"editor.inspector.field.postThrough.1abgu4a\":[\"Post through\"],\"editor.inspector.field.postWidth.rk26fz\":[\"Post width\"],\"editor.inspector.field.profile.1kwlci6\":[\"Profile\"],\"editor.inspector.field.projection.jhtig0\":[\"Projection\"],\"editor.inspector.field.purlinHeight.eo9cjm\":[\"Purlin height\"],\"editor.inspector.field.purlinSpacing.4gbzb2\":[\"Purlin spacing\"],\"editor.inspector.field.purlinWidth.r6tu3j\":[\"Purlin width\"],\"editor.inspector.field.rafterEndInset.14c0wy5\":[\"Rafter end inset\"],\"editor.inspector.field.rafterHeight.1e1n99w\":[\"Rafter height\"],\"editor.inspector.field.rafterSpacing.19subc0\":[\"Rafter spacing\"],\"editor.inspector.field.rafterWidth.eksj4t\":[\"Rafter width\"],\"editor.inspector.field.railingHeight.6wf4bm\":[\"Railing height\"],\"editor.inspector.field.railingMode.ov7xpu\":[\"Railing mode\"],\"editor.inspector.field.railingStyle.1nyd2u\":[\"Railing style\"],\"editor.inspector.field.resizeLock.b2hbr0\":[\"Resize lock\"],\"editor.inspector.field.returnDiameter.166ozhe\":[\"Return diameter\"],\"editor.inspector.field.returnHeight.b9sq6y\":[\"Return height\"],\"editor.inspector.field.returnShape.1e3a27i\":[\"Return shape\"],\"editor.inspector.field.returnWidth.z9r3h3\":[\"Return width\"],\"editor.inspector.field.rightEndCondition.tjlw3l\":[\"Right end condition\"],\"editor.inspector.field.rightOverhang.yqbeft\":[\"Right overhang\"],\"editor.inspector.field.roofHeight.1uhy6qy\":[\"Roof height\"],\"editor.inspector.field.roofStyle.pawqfy\":[\"Roof style\"],\"editor.inspector.field.roofThickness.1xlr3rx\":[\"Roof thickness\"],\"editor.inspector.field.roofType.1m9kv5h\":[\"Roof type\"],\"editor.inspector.field.rotation.ly2rj\":[\"Rotation\"],\"editor.inspector.field.rows.1ba1neg\":[\"Rows\"],\"editor.inspector.field.scale.b6rpxt\":[\"Scale\"],\"editor.inspector.field.seamDetail.197za48\":[\"Seam detail\"],\"editor.inspector.field.segmentType.l667sy\":[\"Segment type\"],\"editor.inspector.field.shaftStyle.1i5ampa\":[\"Shaft style\"],\"editor.inspector.field.shaftWallThickness.bduslr\":[\"Shaft wall thickness\"],\"editor.inspector.field.shape.iq9t52\":[\"Shape\"],\"editor.inspector.field.shape2.fi0nx8\":[\"Shape2\"],\"editor.inspector.field.shedHighSide.bzzddg\":[\"Shed high side\"],\"editor.inspector.field.shingleThickness.1hn5wxr\":[\"Shingle thickness\"],\"editor.inspector.field.shoulderExtent.11j8uiv\":[\"Shoulder extent\"],\"editor.inspector.field.shoulderHeight.xyqn6g\":[\"Shoulder height\"],\"editor.inspector.field.shoulderStyle.1hkcv2w\":[\"Shoulder style\"],\"editor.inspector.field.showCenterColumn.1uggg45\":[\"Show center column\"],\"editor.inspector.field.showInfill.33rv7u\":[\"Show infill\"],\"editor.inspector.field.showStepSupports.1kg8h8m\":[\"Show step supports\"],\"editor.inspector.field.sideFlashing.cv744o\":[\"Side flashing\"],\"editor.inspector.field.size.1a4x3zw\":[\"Size\"],\"editor.inspector.field.skylightType.1a5vj3i\":[\"Skylight type\"],\"editor.inspector.field.slabOpeningMode.g4f730\":[\"Slab opening mode\"],\"editor.inspector.field.slatGap.slmk93\":[\"Slat gap\"],\"editor.inspector.field.slideDirection.1527q13\":[\"Slide direction\"],\"editor.inspector.field.span.1bmmuw1\":[\"Span\"],\"editor.inspector.field.speed.2w2xwg\":[\"Speed\"],\"editor.inspector.field.spinSpeed.1ozx746\":[\"Spin speed\"],\"editor.inspector.field.stairType.1u05e02\":[\"Stair type\"],\"editor.inspector.field.standoff.4wv2g0\":[\"Standoff\"],\"editor.inspector.field.standoffHeight.1qdnff\":[\"Standoff height\"],\"editor.inspector.field.startPost.1ood9kv\":[\"Start post\"],\"editor.inspector.field.stepCount.nzorrw\":[\"Step count\"],\"editor.inspector.field.strapSpacing.1cyt3dc\":[\"Strap spacing\"],\"editor.inspector.field.strapStyle.fh1oy4\":[\"Strap style\"],\"editor.inspector.field.style.nf3vcm\":[\"Style\"],\"editor.inspector.field.suctionDiameter.nutxtj\":[\"Suction diameter\"],\"editor.inspector.field.supplyDiameter.h5ldh5\":[\"Supply diameter\"],\"editor.inspector.field.supplyHeight.zy6ru1\":[\"Supply height\"],\"editor.inspector.field.supplyShape.k39wnb\":[\"Supply shape\"],\"editor.inspector.field.supplyWidth.g66axi\":[\"Supply width\"],\"editor.inspector.field.supportOffset.1w4cocr\":[\"Support offset\"],\"editor.inspector.field.sweepAngle.ucmmlw\":[\"Sweep angle\"],\"editor.inspector.field.system.13qbhrw\":[\"System\"],\"editor.inspector.field.terminal.1501knl\":[\"Terminal\"],\"editor.inspector.field.terminalType.1ne8lgb\":[\"Terminal type\"],\"editor.inspector.field.thickness.1l8hu45\":[\"Thickness\"],\"editor.inspector.field.tiltAngle.1312yw1\":[\"Tilt angle\"],\"editor.inspector.field.toLevelId.8i5qx7\":[\"To level id\"],\"editor.inspector.field.topLandingDepth.ki7gk2\":[\"Top landing depth\"],\"editor.inspector.field.topLandingMode.zk0h7e\":[\"Top landing mode\"],\"editor.inspector.field.topRailHeight.fscisv\":[\"Top rail height\"],\"editor.inspector.field.transitionMode.f3evgt\":[\"Transition mode\"],\"editor.inspector.field.transitionWidth.rtgz3m\":[\"Transition width\"],\"editor.inspector.field.vaneCount.55vtye\":[\"Vane count\"],\"editor.inspector.field.wallHeight.18vmh5c\":[\"Wall height\"],\"editor.inspector.field.wallShell.vqsyhv\":[\"Wall shell\"],\"editor.inspector.field.wallSkirtHeight.1uea2ad\":[\"Wall skirt height\"],\"editor.inspector.field.wallThickness.17wn4iv\":[\"Wall thickness\"],\"editor.inspector.field.width.gfxz9b\":[\"Width\"],\"editor.inspector.field.width2.1nqawvr\":[\"Width2\"],\"editor.inspector.field.withBack.1ay8nus\":[\"With back\"],\"editor.inspector.field.withBottom.1x1z1vo\":[\"With bottom\"],\"editor.inspector.field.withSides.uq066x\":[\"With sides\"],\"editor.inspector.group.advanced.qwfkor\":[\"Advanced\"],\"editor.inspector.group.air.15jotdj\":[\"Air\"],\"editor.inspector.group.appearance.dli9wf\":[\"Appearance\"],\"editor.inspector.group.body.ign4wl\":[\"Body\"],\"editor.inspector.group.cab.o4z1ox\":[\"Cab\"],\"editor.inspector.group.cabinet.rzvymr\":[\"Cabinet\"],\"editor.inspector.group.cap.s0thej\":[\"Cap\"],\"editor.inspector.group.collar.1am2iqo\":[\"Collar\"],\"editor.inspector.group.connection.2r1h4p\":[\"Connection\"],\"editor.inspector.group.connections.ai4w8u\":[\"Connections\"],\"editor.inspector.group.construction.j6p9kc\":[\"Construction\"],\"editor.inspector.group.cricket.6iwg8g\":[\"Cricket\"],\"editor.inspector.group.curb.5xi2ol\":[\"Curb\"],\"editor.inspector.group.curvePoints.ztdcnn\":[\"Curve points\"],\"editor.inspector.group.dimensions.pewa8g\":[\"Dimensions\"],\"editor.inspector.group.doors.18w2kpa\":[\"Doors\"],\"editor.inspector.group.dormer.1fjs5tq\":[\"Dormer\"],\"editor.inspector.group.dormerRoof.u9uy2g\":[\"Dormer roof\"],\"editor.inspector.group.drainage.7easy0\":[\"Drainage\"],\"editor.inspector.group.elevation.4jbp44\":[\"Elevation\"],\"editor.inspector.group.endCaps.4fsb5b\":[\"End caps\"],\"editor.inspector.group.equipment.1xtq0ev\":[\"Equipment\"],\"editor.inspector.group.face.1531fr0\":[\"Face\"],\"editor.inspector.group.fitting.171z1r4\":[\"Fitting\"],\"editor.inspector.group.flues.nq6pye\":[\"Flues\"],\"editor.inspector.group.footprint.g8q2pg\":[\"Footprint\"],\"editor.inspector.group.frame.q7q9fq\":[\"Frame\"],\"editor.inspector.group.geometry.a21os1\":[\"Geometry\"],\"editor.inspector.group.grid.d8gwxd\":[\"Grid\"],\"editor.inspector.group.hangers.agnfzn\":[\"Hangers\"],\"editor.inspector.group.hardware.1nygwm1\":[\"Hardware\"],\"editor.inspector.group.hungWall.1ftr1gz\":[\"Hung wall\"],\"editor.inspector.group.insulation.1kyo5e7\":[\"Insulation\"],\"editor.inspector.group.lantern.1h7o2xb\":[\"Lantern\"],\"editor.inspector.group.levels.1s6yaru\":[\"Levels\"],\"editor.inspector.group.line.166mv5z\":[\"Line\"],\"editor.inspector.group.lines.12bghr0\":[\"Lines\"],\"editor.inspector.group.motion.1be7sjr\":[\"Motion\"],\"editor.inspector.group.mounting.feutd2\":[\"Mounting\"],\"editor.inspector.group.opening.dfet3\":[\"Opening\"],\"editor.inspector.group.panelDimensions.b59qe6\":[\"Panel dimensions\"],\"editor.inspector.group.patternDistribution.fmam51\":[\"Pattern distribution\"],\"editor.inspector.group.placement.13lcvts\":[\"Placement\"],\"editor.inspector.group.position.1quewx6\":[\"Position\"],\"editor.inspector.group.profile.1kwlci6\":[\"Profile\"],\"editor.inspector.group.railing.19a5bnr\":[\"Railing\"],\"editor.inspector.group.return.1klrjrz\":[\"Return\"],\"editor.inspector.group.settings.ktdb8o\":[\"Settings\"],\"editor.inspector.group.shaft.mad9cv\":[\"Shaft\"],\"editor.inspector.group.shape.iq9t52\":[\"Shape\"],\"editor.inspector.group.shoulder.1nyfx25\":[\"Shoulder\"],\"editor.inspector.group.size.1a4x3zw\":[\"Size\"],\"editor.inspector.group.structure.gezdra\":[\"Structure\"],\"editor.inspector.group.style.nf3vcm\":[\"Style\"],\"editor.inspector.group.supply.1oy2zwu\":[\"Supply\"],\"editor.inspector.group.surface.wtamqk\":[\"Surface\"],\"editor.inspector.group.terminal.1501knl\":[\"Terminal\"],\"editor.inspector.group.topology.18t8dyc\":[\"Topology\"],\"editor.inspector.group.transform.1c55ayj\":[\"Transform\"],\"editor.inspector.group.trap.1qc7vhe\":[\"Trap\"],\"editor.inspector.group.type.1m2zofh\":[\"Type\"],\"editor.inspector.option.abs.132mz8b\":[\"Abs\"],\"editor.inspector.option.accessPanel.13sptb5\":[\"Access panel\"],\"editor.inspector.option.airHandler.1crnyg3\":[\"Air handler\"],\"editor.inspector.option.alternating.5jashi\":[\"Alternating\"],\"editor.inspector.option.arched.14188w0\":[\"Arched\"],\"editor.inspector.option.auto.540b06\":[\"Auto\"],\"editor.inspector.option.automatic.r122ro\":[\"Automatic\"],\"editor.inspector.option.back.1hzmxtu\":[\"Back\"],\"editor.inspector.option.balusters.1j3w6ng\":[\"Balusters\"],\"editor.inspector.option.band.160umau\":[\"Band\"],\"editor.inspector.option.basePlate.17fcg8k\":[\"Base plate\"],\"editor.inspector.option.boards.u14hig\":[\"Boards\"],\"editor.inspector.option.bookshelf.ls0zqk\":[\"Bookshelf\"],\"editor.inspector.option.both.mkyb42\":[\"Both\"],\"editor.inspector.option.bottom.9mpruy\":[\"Bottom\"],\"editor.inspector.option.box.1nbjcuq\":[\"Box\"],\"editor.inspector.option.break.17spnvc\":[\"Break\"],\"editor.inspector.option.butterfly.pvv0g4\":[\"Butterfly\"],\"editor.inspector.option.cable.fp50zq\":[\"Cable\"],\"editor.inspector.option.castIron.1q2z4qk\":[\"Cast iron\"],\"editor.inspector.option.ceiling.1t2zaqo\":[\"Ceiling\"],\"editor.inspector.option.center.kzdxno\":[\"Center\"],\"editor.inspector.option.centerOpening.bn1rvw\":[\"Center opening\"],\"editor.inspector.option.cleanout.lww8bm\":[\"Cleanout\"],\"editor.inspector.option.concretePad.m1zdij\":[\"Concrete pad\"],\"editor.inspector.option.condenser.a74nps\":[\"Condenser\"],\"editor.inspector.option.corbeled.bovs4v\":[\"Corbeled\"],\"editor.inspector.option.count.1qoi4r8\":[\"Count\"],\"editor.inspector.option.coupling.111aap2\":[\"Coupling\"],\"editor.inspector.option.coveringSpecific.1h9fo8w\":[\"Covering specific\"],\"editor.inspector.option.cross.1elubzv\":[\"Cross\"],\"editor.inspector.option.cubby.ivq4qc\":[\"Cubby\"],\"editor.inspector.option.curved.6noz1s\":[\"Curved\"],\"editor.inspector.option.cylinder.eol6vj\":[\"Cylinder\"],\"editor.inspector.option.damper.wgri80\":[\"Damper\"],\"editor.inspector.option.destination.gfzm1r\":[\"Destination\"],\"editor.inspector.option.diffuser.1igj0jh\":[\"Diffuser\"],\"editor.inspector.option.dogEar.xhtvjt\":[\"Dog ear\"],\"editor.inspector.option.dome.1c87e56\":[\"Dome\"],\"editor.inspector.option.double.13h5354\":[\"Double\"],\"editor.inspector.option.ductBoard.lc3o4t\":[\"Duct board\"],\"editor.inspector.option.dutch.1djx429\":[\"Dutch\"],\"editor.inspector.option.elbow.1flup74\":[\"Elbow\"],\"editor.inspector.option.end.1llf32i\":[\"End\"],\"editor.inspector.option.endCap.1p4v4na\":[\"End cap\"],\"editor.inspector.option.equalFit.11vw52c\":[\"Equal fit\"],\"editor.inspector.option.fixedCount.1o3dznu\":[\"Fixed count\"],\"editor.inspector.option.fixedSpacing.hl4dr4\":[\"Fixed spacing\"],\"editor.inspector.option.flat.ly0bei\":[\"Flat\"],\"editor.inspector.option.flex.ktpamq\":[\"Flex\"],\"editor.inspector.option.floating.1oadpln\":[\"Floating\"],\"editor.inspector.option.floor.q9caf1\":[\"Floor\"],\"editor.inspector.option.flush.olwwu5\":[\"Flush\"],\"editor.inspector.option.front.uhugl4\":[\"Front\"],\"editor.inspector.option.furnace.w0mzpf\":[\"Furnace\"],\"editor.inspector.option.gable.1ekyx6\":[\"Gable\"],\"editor.inspector.option.gambrel.1yo90d9\":[\"Gambrel\"],\"editor.inspector.option.generic.1074oey\":[\"Generic\"],\"editor.inspector.option.glass.163tc5n\":[\"Glass\"],\"editor.inspector.option.glassFrame.jp9s3m\":[\"Glass frame\"],\"editor.inspector.option.globe.1avkqoy\":[\"Globe\"],\"editor.inspector.option.grounded.jwoq73\":[\"Grounded\"],\"editor.inspector.option.guard.1m575se\":[\"Guard\"],\"editor.inspector.option.halfRound.m5hob0\":[\"Half round\"],\"editor.inspector.option.hidden.gp48rd\":[\"Hidden\"],\"editor.inspector.option.hip.r0jnjy\":[\"Hip\"],\"editor.inspector.option.horizontal.tyapah\":[\"Horizontal\"],\"editor.inspector.option.include.1a27vnr\":[\"Include\"],\"editor.inspector.option.independentHighBeam.1tn0zvy\":[\"Independent high beam\"],\"editor.inspector.option.industrial.8sd9u\":[\"Industrial\"],\"editor.inspector.option.inline.1uh05lg\":[\"Inline\"],\"editor.inspector.option.integrated.1xd9lv0\":[\"Integrated\"],\"editor.inspector.option.joined.1x2o8ds\":[\"Joined\"],\"editor.inspector.option.kStyle.m8kfwz\":[\"K style\"],\"editor.inspector.option.kickout.vt8s6p\":[\"Kickout\"],\"editor.inspector.option.knee.186hcui\":[\"Knee\"],\"editor.inspector.option.landing.tyqarg\":[\"Landing\"],\"editor.inspector.option.lantern.1h7o2xb\":[\"Lantern\"],\"editor.inspector.option.leave.1xf0sbk\":[\"Leave\"],\"editor.inspector.option.left.14n06mo\":[\"Left\"],\"editor.inspector.option.level.i4lhtp\":[\"Level\"],\"editor.inspector.option.lowProfile.1h9lgzg\":[\"Low profile\"],\"editor.inspector.option.mansard.dwzck9\":[\"Mansard\"],\"editor.inspector.option.manual.1wu7r43\":[\"Manual\"],\"editor.inspector.option.maximumSpacing.n1fzl4\":[\"Maximum spacing\"],\"editor.inspector.option.metal.1az9fgc\":[\"Metal\"],\"editor.inspector.option.metalPanel.1xdz476\":[\"Metal panel\"],\"editor.inspector.option.minimal.fwmiwg\":[\"Minimal\"],\"editor.inspector.option.mono.oszvd6\":[\"Mono\"],\"editor.inspector.option.none.deku7v\":[\"None\"],\"editor.inspector.option.omit.okcs7w\":[\"Omit\"],\"editor.inspector.option.open.n6hn1l\":[\"Open\"],\"editor.inspector.option.openRack.mvt1x0\":[\"Open rack\"],\"editor.inspector.option.opening.dfet3\":[\"Opening\"],\"editor.inspector.option.oval.1jiqzxx\":[\"Oval\"],\"editor.inspector.option.picket.zyeoy1\":[\"Picket\"],\"editor.inspector.option.pointed.effedk\":[\"Pointed\"],\"editor.inspector.option.postAndRail.lajk2u\":[\"Post and rail\"],\"editor.inspector.option.preserveHighEdge.y6ywf0\":[\"Preserve high edge\"],\"editor.inspector.option.preserveLowEdge.196m5pk\":[\"Preserve low edge\"],\"editor.inspector.option.preservePitch.1uq973r\":[\"Preserve pitch\"],\"editor.inspector.option.privacy.1th4hrb\":[\"Privacy\"],\"editor.inspector.option.purlins.od124c\":[\"Purlins\"],\"editor.inspector.option.pvc.1oc4u2w\":[\"Pvc\"],\"editor.inspector.option.pyramid.17ucsqv\":[\"Pyramid\"],\"editor.inspector.option.rafters.16tzbby\":[\"Rafters\"],\"editor.inspector.option.rail.39zqc9\":[\"Rail\"],\"editor.inspector.option.raised.4kyx9h\":[\"Raised\"],\"editor.inspector.option.rect.tpfvaf\":[\"Rect\"],\"editor.inspector.option.reducer.18byt67\":[\"Reducer\"],\"editor.inspector.option.return.1klrjrz\":[\"Return\"],\"editor.inspector.option.returnGrille.r28ncm\":[\"Return grille\"],\"editor.inspector.option.right.8humpx\":[\"Right\"],\"editor.inspector.option.round.1vx0wyj\":[\"Round\"],\"editor.inspector.option.rounded.199nwpm\":[\"Rounded\"],\"editor.inspector.option.sanitaryTee.oro3d4\":[\"Sanitary tee\"],\"editor.inspector.option.scalloped.1eltba0\":[\"Scalloped\"],\"editor.inspector.option.scoop.qy5zdv\":[\"Scoop\"],\"editor.inspector.option.segmentedPanel.5r3hwl\":[\"Segmented panel\"],\"editor.inspector.option.shed.6t994v\":[\"Shed\"],\"editor.inspector.option.sheetMetal.l164lv\":[\"Sheet metal\"],\"editor.inspector.option.shingle.pfmynh\":[\"Shingle\"],\"editor.inspector.option.shingled.1nm9inf\":[\"Shingled\"],\"editor.inspector.option.simple.12mfu73\":[\"Simple\"],\"editor.inspector.option.single.1uzxurt\":[\"Single\"],\"editor.inspector.option.singleLeft.1atdh02\":[\"Single left\"],\"editor.inspector.option.singleRight.1axbu67\":[\"Single right\"],\"editor.inspector.option.slantBox.1ta99vy\":[\"Slant box\"],\"editor.inspector.option.slat.1p9njbz\":[\"Slat\"],\"editor.inspector.option.sliding.cd0jox\":[\"Sliding\"],\"editor.inspector.option.slope.1bn2qw\":[\"Slope\"],\"editor.inspector.option.sloped.lo4sh0\":[\"Sloped\"],\"editor.inspector.option.solid.o4uy6s\":[\"Solid\"],\"editor.inspector.option.solidPanel.2yaw62\":[\"Solid panel\"],\"editor.inspector.option.spiral.91hcl4\":[\"Spiral\"],\"editor.inspector.option.splash.1uke4cm\":[\"Splash\"],\"editor.inspector.option.spread.1g1zysu\":[\"Spread\"],\"editor.inspector.option.square.1xl1lk6\":[\"Square\"],\"editor.inspector.option.stair.1xf86e\":[\"Stair\"],\"editor.inspector.option.standard.vuco\":[\"Standard\"],\"editor.inspector.option.start.30xvgf\":[\"Start\"],\"editor.inspector.option.step.jtn9kf\":[\"Step\"],\"editor.inspector.option.stepped.naxzh0\":[\"Stepped\"],\"editor.inspector.option.straight.lxqbfr\":[\"Straight\"],\"editor.inspector.option.strap.14q0ps9\":[\"Strap\"],\"editor.inspector.option.supply.1oy2zwu\":[\"Supply\"],\"editor.inspector.option.supplyRegister.1lzdbbn\":[\"Supply register\"],\"editor.inspector.option.tapered.3y5blo\":[\"Tapered\"],\"editor.inspector.option.targetSpacing.14uibc9\":[\"Target spacing\"],\"editor.inspector.option.tee.7d6tjp\":[\"Tee\"],\"editor.inspector.option.tilted.6n0u5j\":[\"Tilted\"],\"editor.inspector.option.top.2nypcs\":[\"Top\"],\"editor.inspector.option.transition.1rziz9e\":[\"Transition\"],\"editor.inspector.option.vent.xda5j2\":[\"Vent\"],\"editor.inspector.option.walkOn.1n5sg9l\":[\"Walk on\"],\"editor.inspector.option.wall.blj585\":[\"Wall\"],\"editor.inspector.option.wallAbutment.lza941\":[\"Wall abutment\"],\"editor.inspector.option.wallLedger.5m8ana\":[\"Wall ledger\"],\"editor.inspector.option.wallShelf.yiozfl\":[\"Wall shelf\"],\"editor.inspector.option.waste.3xrp79\":[\"Waste\"],\"editor.inspector.option.wye.14vupc8\":[\"Wye\"],\"editor.layers.collapse\":[\"Collapse\"],\"editor.layers.defaultName.ceiling\":[\"Ceiling (\",[\"area\"],\")\"],\"editor.layers.defaultName.collection\":[\"Collection\"],\"editor.layers.defaultName.flight\":[\"Flight (\",[\"width\"],\"×\",[\"length\"],\"m)\"],\"editor.layers.defaultName.landing\":[\"Landing (\",[\"width\"],\"×\",[\"length\"],\"m)\"],\"editor.layers.defaultName.node\":[\"Node\"],\"editor.layers.defaultName.roof\":[\"Roof (\",[\"count\",\"plural\",{\"one\":[\"#\",\" segment\"],\"other\":[\"#\",\" segments\"]}],\")\"],\"editor.layers.defaultName.roofSegment\":[[\"roofType\",\"select\",{\"hip\":[\"Hip\"],\"gable\":[\"Gable\"],\"shed\":[\"Shed\"],\"gambrel\":[\"Gambrel\"],\"dutch\":[\"Dutch\"],\"mansard\":[\"Mansard\"],\"flat\":[\"Flat\"],\"conical\":[\"Conical\"],\"barrel\":[\"Barrel\"],\"other\":[\"Roof\"]}],\" (\",[\"width\"],\"×\",[\"depth\"],\"m)\"],\"editor.layers.defaultName.room\":[\"Room (\",[\"area\"],\")\"],\"editor.layers.defaultName.slab\":[\"Slab (\",[\"area\"],\")\"],\"editor.layers.defaultName.staircase\":[\"Staircase (\",[\"count\",\"plural\",{\"one\":[\"#\",\" segment\"],\"other\":[\"#\",\" segments\"]}],\")\"],\"editor.layers.defaultName.zone\":[\"Zone (\",[\"area\"],\")\"],\"editor.layers.expand\":[\"Expand\"],\"editor.layers.levelOptions\":[[\"levelName\"],\" options\"],\"editor.layers.rename\":[\"Rename\"],\"editor.layers.spaceColour\":[[\"role\",\"select\",{\"room\":[\"Room colour\"],\"other\":[\"Zone colour\"]}]],\"editor.layers.unitColour\":[\"Unit colour\"],\"editor.levelDuplicateDialog.cancel\":[\"Cancel\"],\"editor.levelDuplicateDialog.chooseWhatToCopyFromLevel\":[\"Choose what to copy from \",[\"levelName\"],\".\"],\"editor.levelDuplicateDialog.chooseWhatToCopyFromThisLevel\":[\"Choose what to copy from this level.\"],\"editor.levelDuplicateDialog.duplicate\":[\"Duplicate\"],\"editor.levelDuplicateDialog.duplicateLevel\":[\"Duplicate Level\"],\"editor.levelDuplicateDialog.everything\":[\"Everything\"],\"editor.levelDuplicateDialog.structureFinishesAndPlacedItemsWithout\":[\"Structure, finishes, and placed items, without guide references.\"],\"editor.levelDuplicateDialog.structureFurniture\":[\"Structure + furniture\"],\"editor.levelDuplicateDialog.structureMaterials\":[\"Structure + materials\"],\"editor.levelDuplicateDialog.structureMaterialsFurnitureAndReferences\":[\"Structure, materials, furniture, and references.\"],\"editor.levelDuplicateDialog.structureOnly\":[\"Structure only\"],\"editor.levelDuplicateDialog.structureWithTheCurrentMaterialAnd\":[\"Structure with the current material and finish assignments.\"],\"editor.levelDuplicateDialog.wallsSlabsRoofsStairsWindowsAnd\":[\"Walls, slabs, roofs, stairs, windows, and doors without finishes.\"],\"editor.lib.contextualHelp.addOrRemoveObjectsFromThe\":[\"Add or remove objects from the selection\"],\"editor.lib.contextualHelp.adjustOneSideSCornerRadius\":[\"Adjust one side’s corner radius\"],\"editor.lib.contextualHelp.clearTheSelectionOrClickOutside\":[\"Clear the selection (or click outside)\"],\"editor.lib.contextualHelp.clickAHandleDotToShow\":[\"Click a handle dot to show move arrows\"],\"editor.lib.contextualHelp.clickOrDragTheSelectionTo\":[\"Click or drag the selection to move it as one\"],\"editor.lib.contextualHelp.clickTheHandleDotToShow\":[\"Click the handle dot to show move + rotate handles\"],\"editor.lib.contextualHelp.detachTheJointWhileDraggingAn\":[\"Detach the joint while dragging an arrow\"],\"editor.lib.contextualHelp.dragLeftOrRightToRotate\":[\"Drag left or right to rotate selected object\"],\"editor.lib.contextualHelp.dragSelectedMovableObject\":[\"Drag selected movable object\"],\"editor.lib.contextualHelp.groupSelectionSessionOnly\":[\"Group selection (session only)\"],\"editor.lib.contextualHelp.holdToRotateFreely\":[\"Hold to rotate freely\"],\"editor.lib.contextualHelp.rotate45\":[\"Rotate ±45°\"],\"editor.lib.contextualHelp.rotateTheSelection45\":[\"Rotate the selection ±45°\"],\"editor.lib.contextualHelp.rotatingFreely\":[\"Rotating freely (no angle step)\"],\"editor.lib.contextualHelp.switchTheRotationAxisYX\":[\"Switch the rotation axis (Y → X → Z)\"],\"editor.lib.contextualHelp.ungroupSessionSelection\":[\"Ungroup session selection\"],\"editor.lib.continuation.continuous\":[\"Continuous\"],\"editor.lib.continuation.continuousCanopy\":[\"Continuous canopy\"],\"editor.lib.continuation.continuousRun\":[\"Continuous run\"],\"editor.lib.continuation.curvedFence\":[\"Curved fence\"],\"editor.lib.continuation.freehandFence\":[\"Freehand fence\"],\"editor.lib.continuation.placeMultiple\":[\"Place multiple\"],\"editor.lib.continuation.placeOnce\":[\"Place once\"],\"editor.lib.continuation.polygonRoom\":[\"Polygon room\"],\"editor.lib.continuation.rectangleRoom\":[\"Rectangle room\"],\"editor.lib.continuation.singleCabinet\":[\"Single cabinet\"],\"editor.lib.continuation.singleCanopy\":[\"Single canopy\"],\"editor.lib.continuation.singleFence\":[\"Single fence\"],\"editor.lib.continuation.walls\":[\"Walls\"],\"editor.lib.hudTitle.cutOpening\":[\"Cut opening\"],\"editor.lib.hudTitle.divideRoom\":[\"Divide room\"],\"editor.lib.hudTitle.editKind\":[\"Edit \",[\"kind\"]],\"editor.lib.hudTitle.erase\":[\"Erase\"],\"editor.lib.hudTitle.levelTerrain\":[\"Level terrain\"],\"editor.lib.hudTitle.lowerTerrain\":[\"Lower terrain\"],\"editor.lib.hudTitle.mezzanine\":[\"Mezzanine\"],\"editor.lib.hudTitle.moveKind\":[\"Move \",[\"kind\"]],\"editor.lib.hudTitle.moveRoom\":[\"Move room\"],\"editor.lib.hudTitle.moveSelection\":[\"Move selection\"],\"editor.lib.hudTitle.paint\":[\"Paint\"],\"editor.lib.hudTitle.paintARectangle\":[\"Paint a rectangle\"],\"editor.lib.hudTitle.paintAShape\":[\"Paint a shape\"],\"editor.lib.hudTitle.pickMaterial\":[\"Pick material\"],\"editor.lib.hudTitle.raiseTerrain\":[\"Raise terrain\"],\"editor.lib.hudTitle.resize\":[\"Resize\"],\"editor.lib.hudTitle.rotate\":[\"Rotate\"],\"editor.lib.hudTitle.select\":[\"Select\"],\"editor.lib.hudTitle.smartMeasure\":[\"Smart measure\"],\"editor.lib.hudTitle.smoothTerrain\":[\"Smooth terrain\"],\"editor.lib.hudTitle.splitKind\":[\"Split \",[\"kind\"]],\"editor.lib.hudTitle.terrace\":[\"Terrace\"],\"editor.lib.wallDrawVariant.polygonRoom\":[\"Polygon room\"],\"editor.lib.wallDrawVariant.rectangleRoom\":[\"Rectangle room\"],\"editor.lib.wallDrawVariant.walls\":[\"Walls\"],\"editor.mechanismAction\":[[\"action\",\"select\",{\"close\":[\"Close\"],\"open\":[\"Open\"],\"stop\":[\"Stop\"],\"other\":[\"Play\"]}]],\"editor.nodeActionMenu.curve\":[\"Curve\"],\"editor.nodeActionMenu.cutOut\":[\"Cut out\"],\"editor.nodeActionMenu.delete\":[\"Delete\"],\"editor.nodeActionMenu.duplicate\":[\"Duplicate\"],\"editor.nodeActionMenu.editMesh\":[\"Edit mesh\"],\"editor.nodeActionMenu.findInCatalog\":[\"Find in catalog\"],\"editor.nodeActionMenu.groupSelection\":[\"Group selection\"],\"editor.nodeActionMenu.move\":[\"Move\"],\"editor.nodeActionMenu.rotateLeft\":[\"Rotate left\"],\"editor.nodeActionMenu.rotateRight\":[\"Rotate right\"],\"editor.nodeActionMenu.ungroupSelection\":[\"Ungroup selection\"],\"editor.nodeDisplay.ceiling\":[\"Ceiling\"],\"editor.nodeDisplay.column\":[\"Column\"],\"editor.nodeDisplay.door\":[\"Door\"],\"editor.nodeDisplay.elevator\":[\"Elevator\"],\"editor.nodeDisplay.fence\":[\"Fence\"],\"editor.nodeDisplay.guide\":[\"Guide image\"],\"editor.nodeDisplay.item\":[\"Item\"],\"editor.nodeDisplay.roof\":[\"Roof\"],\"editor.nodeDisplay.roofSegment\":[\"Roof segment\"],\"editor.nodeDisplay.room\":[\"Room\"],\"editor.nodeDisplay.scan\":[\"3D Scan\"],\"editor.nodeDisplay.selection\":[\"Selection\"],\"editor.nodeDisplay.slab\":[\"Slab\"],\"editor.nodeDisplay.stair\":[\"Stair\"],\"editor.nodeDisplay.stairSegment\":[\"Stair segment\"],\"editor.nodeDisplay.wall\":[\"Wall\"],\"editor.nodeDisplay.window\":[\"Window\"],\"editor.nodeDisplay.zone\":[\"Zone\"],\"editor.panels.collections.collectionsPopover.cancel\":[\"Cancel\"],\"editor.panels.collections.collectionsPopover.collectionName\":[\"Collection name…\"],\"editor.panels.collections.collectionsPopover.collections\":[\"Collections\"],\"editor.panels.collections.collectionsPopover.delete\":[\"Delete\"],\"editor.panels.collections.collectionsPopover.deleteName\":[\"Delete \\\"\",[\"name\"],\"\\\"?\"],\"editor.panels.collections.collectionsPopover.new\":[\"New\"],\"editor.panels.collections.collectionsPopover.noCollectionsYetCreateOneTo\":[\"No collections yet. Create one to group elements together.\"],\"editor.panels.collections.collectionsPopover.rename\":[\"Rename\"],\"editor.panels.floorFoundationPanel.aThickerFloorGrowsUpwardThe\":[\"A thicker floor grows upward: the rooms below keep their height.\"],\"editor.panels.floorFoundationPanel.edgeFinish\":[\"Edge finish\"],\"editor.panels.floorFoundationPanel.floorPlate\":[\"Floor plate\"],\"editor.panels.floorFoundationPanel.floorPlateThicknesslabelThickRestingOn\":[\"Floor plate \",[\"thicknessLabel\"],\" thick, resting on the walls below\"],\"editor.panels.floorFoundationPanel.floorThickness\":[\"Floor thickness\"],\"editor.panels.floorFoundationPanel.floorTopAbove\":[\"Floor top +\",[\"height\"]],\"editor.panels.floorFoundationPanel.floorTopValue\":[\"Floor top \",[\"height\"]],\"editor.panels.floorFoundationPanel.foundationFinish\":[\"Foundation finish\"],\"editor.panels.floorFoundationPanel.foundationHeight\":[\"Foundation height\"],\"editor.panels.floorFoundationPanel.kicker\":[\"Floor plate\"],\"editor.panels.floorFoundationPanel.kickerLevel\":[\"Floor plate · \",[\"level\"]],\"editor.panels.floorFoundationPanel.kickerRestsOn\":[\"Floor plate · \",[\"level\"],\" · rests on \",[\"below\"]],\"editor.panels.floorFoundationPanel.lowerTogether\":[[\"count\",\"plural\",{\"2\":[\"Lower both\"],\"other\":[\"Lower all \",[\"number\"]]}]],\"editor.panels.floorFoundationPanel.notToScale\":[\"Not to scale\"],\"editor.panels.floorFoundationPanel.onTheGround\":[\"On the ground\"],\"editor.panels.floorFoundationPanel.raiseTogether\":[[\"count\",\"plural\",{\"2\":[\"Raise both\"],\"other\":[\"Raise all \",[\"number\"]]}]],\"editor.panels.floorFoundationPanel.raisedOnAFoundation\":[\"Raised on a foundation\"],\"editor.panels.floorFoundationPanel.section.floorPlate\":[\"Floor plate · \",[\"thickness\"]],\"editor.panels.floorFoundationPanel.section.floorTop\":[\"Floor top\"],\"editor.panels.floorFoundationPanel.section.foundation\":[\"Foundation\"],\"editor.panels.floorFoundationPanel.section.foundationKind\":[\"Foundation · \",[\"foundation\"]],\"editor.panels.floorFoundationPanel.section.ground\":[\"Ground\"],\"editor.panels.floorFoundationPanel.section.slab\":[\"Slab · \",[\"thickness\"]],\"editor.panels.floorFoundationPanel.section.wallsBelow\":[\"Walls below\"],\"editor.panels.floorFoundationPanel.sectionOnGround\":[\"Slab \",[\"thickness\"],\" thick on the ground, floor top \",[\"top\"],\" above the ground\"],\"editor.panels.floorFoundationPanel.sectionRaised\":[\"Slab \",[\"thickness\"],\" thick on a \",[\"foundation\"],\" foundation, floor top \",[\"top\"],\" above the ground\"],\"editor.panels.floorFoundationPanel.slab\":[\"Slab\"],\"editor.panels.floorFoundationPanel.slabThickness\":[\"Slab thickness\"],\"editor.panels.floorFoundationPanel.theFloorSOutsideEdgeAll\":[\"The floor's outside edge, all around the footprint.\"],\"editor.panels.floorFoundationPanel.theFoundationStandsOnTheGround\":[\"The foundation stands on the ground; the slab sits on it.\"],\"editor.panels.floorFoundationPanel.theSlabSitsOnTheFoundation\":[\"The slab sits on the foundation (or the ground): a thicker slab raises the floor top and everything on it.\"],\"editor.panels.floorFoundationPanel.underTheFloor\":[\"Under the floor\"],\"editor.panels.floorOpeningPanel.aHatchInTheMezzanineIt\":[\"A hatch in the mezzanine: it cuts only the mezzanine’s floor.\"],\"editor.panels.floorOpeningPanel.alsoCutTheCeilingBelow\":[\"Also cut the ceiling below\"],\"editor.panels.floorOpeningPanel.alsoCutTheFloorAbove\":[\"Also cut the floor above\"],\"editor.panels.floorOpeningPanel.areaDragCorners\":[[\"area\"],\" · Drag its corners to change the shape.\"],\"editor.panels.floorOpeningPanel.areaOwned\":[[\"area\"],\" · Shape follows its owner.\"],\"editor.panels.floorOpeningPanel.delete\":[\"Delete\"],\"editor.panels.floorOpeningPanel.done\":[\"Done\"],\"editor.panels.floorOpeningPanel.kicker\":[\"Opening\"],\"editor.panels.floorOpeningPanel.kickerLevel\":[\"Opening · \",[\"level\"]],\"editor.panels.floorOpeningPanel.kickerRoom\":[\"Opening · in \",[\"room\"]],\"editor.panels.floorOpeningPanel.kickerRoomLevel\":[\"Opening · in \",[\"room\"],\" · \",[\"level\"]],\"editor.panels.floorOpeningPanel.oneVoidWith\":[\"On \",[\"level\"],\", as one void with this opening.\"],\"editor.panels.floorOpeningPanel.ownedByElevator\":[\"Owned by Elevator\"],\"editor.panels.floorOpeningPanel.ownedByStaircase\":[\"Owned by Staircase\"],\"editor.panels.floorOpeningPanel.room\":[\"Room\"],\"editor.panels.floorOpeningPanel.thereIsNoFloorAboveThis\":[\"There is no floor above this storey.\"],\"editor.panels.floorOpeningPanel.thereIsNoStoreyBelow\":[\"There is no storey below.\"],\"editor.panels.floorOpeningPanel.title\":[[\"source\",\"select\",{\"stair\":[\"Stair opening\"],\"elevator\":[\"Elevator opening\"],\"ceiling\":[\"Ceiling opening\"],\"other\":[\"Floor opening\"]}]],\"editor.panels.mergeRefusal.alreadyJoined\":[\"One of them already wraps another corner. Unwrap it first.\"],\"editor.panels.mergeRefusal.between\":[[\"kind\",\"select\",{\"item\":[\"There is an item between them.\"],\"door\":[\"There is a door between them.\"],\"window\":[\"There is a window between them.\"],\"shelf\":[\"There is a shelf between them.\"],\"other\":[\"There is something between them.\"]}]],\"editor.panels.mergeRefusal.cannotMerge\":[\"These windows cannot be merged.\"],\"editor.panels.mergeRefusal.cornerAngle\":[\"Their walls meet at too sharp or too flat an angle for a corner window.\"],\"editor.panels.mergeRefusal.heightExceedsWall\":[\"The window selected first is taller than the other wall. Select the other one first.\"],\"editor.panels.mergeRefusal.notAdjacent\":[\"They are too far apart. Windows merge with at most \",[\"reach\"],\" between them.\"],\"editor.panels.mergeRefusal.notAtCorner\":[\"One of them is too far from the corner. A window joins one within \",[\"reach\"],\" of it.\"],\"editor.panels.mergeRefusal.notOnWall\":[\"A roof or dormer window cannot join another window.\"],\"editor.panels.mergeRefusal.overlap\":[[\"kind\",\"select\",{\"item\":[\"Sliding them to the corner would overlap an item.\"],\"door\":[\"Sliding them to the corner would overlap a door.\"],\"window\":[\"Sliding them to the corner would overlap a window.\"],\"shelf\":[\"Sliding them to the corner would overlap a shelf.\"],\"other\":[\"Sliding them to the corner would overlap something.\"]}]],\"editor.panels.mergeRefusal.wallsNotMeeting\":[\"Their walls do not meet at a corner.\"],\"editor.panels.mixed\":[\"Mixed\"],\"editor.panels.mobilePanelSheet.close\":[\"Close\"],\"editor.panels.mobileSelectionBar.delete\":[\"Delete\"],\"editor.panels.mobileSelectionBar.duplicate\":[\"Duplicate\"],\"editor.panels.mobileSelectionBar.editProperties\":[\"Edit properties\"],\"editor.panels.mobileSelectionBar.editResolvedlabel\":[\"Edit \",[\"resolvedLabel\"]],\"editor.panels.mobileSelectionBar.move\":[\"Move\"],\"editor.panels.multiHeightMode.currentlyCurrentlabel\":[\"Currently \",[\"currentLabel\"]],\"editor.panels.multiHeightMode.customHeight\":[\"Custom height\"],\"editor.panels.multiHeightMode.followsLevel\":[\"Follows level\"],\"editor.panels.multiHeightMode.height\":[\"Height\"],\"editor.panels.multiHeightMode.top\":[\"Top\"],\"editor.panels.multiParametricInspector.labelSessionOnlyPlainClickReselects\":[[\"label\"],\" (session only). Plain click reselects all members. Not saved with the project.\"],\"editor.panels.multiSelectionPanel.delete\":[\"Delete\"],\"editor.panels.multiSelectionPanel.duplicate\":[\"Duplicate\"],\"editor.panels.multiSelectionPanel.group\":[\"Group\"],\"editor.panels.multiSelectionPanel.groupCtrlCmdG\":[\"Group (Ctrl/Cmd+G)\"],\"editor.panels.multiSelectionPanel.labelSessionOnlyPlainClickReselects\":[[\"label\"],\" (session only). Plain click reselects all members. Not saved with the project.\"],\"editor.panels.multiSelectionPanel.lengthSelected\":[[\"length\"],\" selected\"],\"editor.panels.multiSelectionPanel.mergeWindows\":[\"Merge windows\"],\"editor.panels.multiSelectionPanel.mergeWindowsIntoACornerWindow\":[\"Merge windows into a corner window: both take the height, sill and type of the one you selected first\"],\"editor.panels.multiSelectionPanel.mergeWindowsIntoOneAcrossBoth\":[\"Merge windows into one across both: it keeps the type and style of the one you selected first\"],\"editor.panels.multiSelectionPanel.selectBuilding\":[\"Select building\"],\"editor.panels.multiSelectionPanel.selectTheWholeBuildingToMove\":[\"Select the whole building to move all its levels\"],\"editor.panels.multiSelectionPanel.ungroup\":[\"Ungroup\"],\"editor.panels.multiSelectionPanel.ungroupCtrlCmdShiftG\":[\"Ungroup (Ctrl/Cmd+Shift+G)\"],\"editor.panels.multiSelectionPanel.unwrapTheCorner\":[\"Unwrap the corner\"],\"editor.panels.multiSelectionPanel.unwrapTheCornerBothWindowsStay\":[\"Unwrap the corner: both windows stay, each framed at the corner\"],\"editor.panels.panelManager.selection\":[\"Selection\"],\"editor.panels.panelWrapper.back\":[\"Back\"],\"editor.panels.panelWrapper.close\":[\"Close\"],\"editor.panels.panelWrapper.closeTitle\":[\"Close \",[\"title\"]],\"editor.panels.panelWrapper.collapsePanel\":[\"Collapse panel\"],\"editor.panels.panelWrapper.collections\":[\"Collections\"],\"editor.panels.panelWrapper.expandPanel\":[\"Expand panel\"],\"editor.panels.panelWrapper.manageCollections\":[\"Manage collections…\"],\"editor.panels.panelWrapper.openTitle\":[\"Open \",[\"title\"]],\"editor.panels.panelWrapper.reset\":[\"Reset\"],\"editor.panels.panelWrapper.titleHitAnErrorAndWas\":[\"“\",[\"title\"],\"” hit an error and was unloaded for this session.\"],\"editor.panels.parametricFieldControl.mixed\":[\"Mixed\"],\"editor.panels.parametricInspector.actions\":[\"Actions\"],\"editor.panels.parametricInspector.delete\":[\"Delete\"],\"editor.panels.parametricInspector.deleteWithContents\":[\"Delete with contents\"],\"editor.panels.parametricInspector.move\":[\"Move\"],\"editor.panels.referencePanel.cancel\":[\"Cancel\"],\"editor.panels.referencePanel.capture\":[\"Capture\"],\"editor.panels.referencePanel.center\":[\"Center\"],\"editor.panels.referencePanel.clearScale\":[\"Clear Scale\"],\"editor.panels.referencePanel.clickBothEndsOfAKnown\":[\"Click both ends of a known distance on the plan, then type its real length.\"],\"editor.panels.referencePanel.delete\":[\"Delete\"],\"editor.panels.referencePanel.drawALineOverAKnown\":[\"Draw a line over a known dimension on the plan, then type its real length to scale the image exactly.\"],\"editor.panels.referencePanel.editScale\":[\"Edit Scale\"],\"editor.panels.referencePanel.guideImage\":[\"Guide Image\"],\"editor.panels.referencePanel.hide\":[\"Hide\"],\"editor.panels.referencePanel.hideScale\":[\"Hide Scale\"],\"editor.panels.referencePanel.image\":[\"Image\"],\"editor.panels.referencePanel.lock\":[\"Lock\"],\"editor.panels.referencePanel.move\":[\"Move\"],\"editor.panels.referencePanel.opacity\":[\"Opacity\"],\"editor.panels.referencePanel.overlayImageUnavailableReplaceTheImage\":[\"Overlay image unavailable. Replace the image to restore it.\"],\"editor.panels.referencePanel.pos\":[\"pos\"],\"editor.panels.referencePanel.position\":[\"Position\"],\"editor.panels.referencePanel.quickActions\":[\"Quick Actions\"],\"editor.panels.referencePanel.referenceScale\":[\"Reference Scale\"],\"editor.panels.referencePanel.replace\":[\"Replace\"],\"editor.panels.referencePanel.replacing\":[\"Replacing...\"],\"editor.panels.referencePanel.resetImageScale\":[\"Reset Image Scale\"],\"editor.panels.referencePanel.resetRotation\":[\"Reset Rotation\"],\"editor.panels.referencePanel.rot\":[\"rot\"],\"editor.panels.referencePanel.rotation\":[\"Rotation\"],\"editor.panels.referencePanel.scale\":[\"scale\"],\"editor.panels.referencePanel.scaleOpacity\":[\"Scale & Opacity\"],\"editor.panels.referencePanel.scaled\":[\"Scaled · \",[\"scale\"]],\"editor.panels.referencePanel.scaledHidden\":[\"Scaled (hidden) · \",[\"scale\"]],\"editor.panels.referencePanel.setScale\":[\"Set Scale\"],\"editor.panels.referencePanel.show\":[\"Show\"],\"editor.panels.referencePanel.showScale\":[\"Show Scale\"],\"editor.panels.referencePanel.uncalibrated\":[\"Uncalibrated\"],\"editor.panels.referencePanel.unlock\":[\"Unlock\"],\"editor.panels.referencePanel.xyz\":[\"XYZ\"],\"editor.panels.roomConstructionRows.aDrawnSlabSetItsThickness\":[\"A drawn slab: set its thickness and finishes here. It has no footprint height or foundation.\"],\"editor.panels.roomConstructionRows.addMezzanine\":[\"+ Add mezzanine\"],\"editor.panels.roomConstructionRows.atFloorLevel\":[\"At floor level\"],\"editor.panels.roomConstructionRows.builtOn\":[\"Built on\"],\"editor.panels.roomConstructionRows.builtWith\":[\"Built with\"],\"editor.panels.roomConstructionRows.ceiling\":[\"Ceiling\"],\"editor.panels.roomConstructionRows.ceilingAt\":[\"At \",[\"height\"]],\"editor.panels.roomConstructionRows.closeWithWalls\":[\"Close with walls\"],\"editor.panels.roomConstructionRows.drawnFloor\":[[\"ambiguous\",\"select\",{\"yes\":[\"Floor is several drawn slabs, mostly \",[\"name\"]],\"other\":[\"Floor is a drawn slab: \",[\"name\"]]}],[\"shared\",\"plural\",{\"0\":[],\"one\":[\" (shared with \",[\"sharedCount\"],\" room)\"],\"other\":[\" (shared with \",[\"sharedCount\"],\" rooms)\"]}]],\"editor.panels.roomConstructionRows.drawnFloorSwitchHint\":[\"This floor is a drawn slab: select it to edit or delete it.\"],\"editor.panels.roomConstructionRows.drawnSlab\":[\"Drawn slab\"],\"editor.panels.roomConstructionRows.drawnSlabAt\":[\"Drawn slab at \",[\"height\"]],\"editor.panels.roomConstructionRows.editShape\":[\"Edit shape\"],\"editor.panels.roomConstructionRows.flatAtWallHeight\":[\"Flat, at wall height\"],\"editor.panels.roomConstructionRows.floor\":[\"Floor\"],\"editor.panels.roomConstructionRows.floorDown\":[[\"distance\"],\" down\"],\"editor.panels.roomConstructionRows.floorThickness\":[\"Floor thickness\"],\"editor.panels.roomConstructionRows.floorUp\":[[\"distance\"],\" up\"],\"editor.panels.roomConstructionRows.handDrawnCeiling\":[\"Hand-drawn ceiling\"],\"editor.panels.roomConstructionRows.height\":[\"Height\"],\"editor.panels.roomConstructionRows.includeFloor\":[\"Include floor\"],\"editor.panels.roomConstructionRows.includePart\":[[\"part\",\"select\",{\"floor\":[\"Include floor\"],\"walls\":[\"Include walls\"],\"other\":[\"Include ceiling\"]}]],\"editor.panels.roomConstructionRows.includeWalls\":[\"Include walls\"],\"editor.panels.roomConstructionRows.keepOutsideDimensions\":[\"Keep outside dimensions\"],\"editor.panels.roomConstructionRows.lowered\":[\"Lowered \",[\"lift\"]],\"editor.panels.roomConstructionRows.newFloor\":[\"+ New floor\"],\"editor.panels.roomConstructionRows.noFloor\":[\"No floor\"],\"editor.panels.roomConstructionRows.notIncluded\":[\"Not included\"],\"editor.panels.roomConstructionRows.nothingToChange\":[\"Nothing to change.\"],\"editor.panels.roomConstructionRows.onTheGround\":[\"On the ground\"],\"editor.panels.roomConstructionRows.onTheWallsBelow\":[\"On the walls below\"],\"editor.panels.roomConstructionRows.openSides\":[[\"openSides\",\"plural\",{\"one\":[[\"openSideCount\"],\" open side\"],\"other\":[[\"openSideCount\"],\" open sides\"]}]],\"editor.panels.roomConstructionRows.partialCovered\":[\"Partial · \",[\"coverage\",\"number\",\"percent\"],\" covered\"],\"editor.panels.roomConstructionRows.partialWalls\":[\"Partial · \",[\"walls\",\"plural\",{\"one\":[[\"wallCount\"],\" wall\"],\"other\":[[\"wallCount\"],\" walls\"]}],\", \",[\"openSides\",\"plural\",{\"one\":[[\"openSideCount\"],\" open side\"],\"other\":[[\"openSideCount\"],\" open sides\"]}]],\"editor.panels.roomConstructionRows.raised\":[\"Raised \",[\"lift\"]],\"editor.panels.roomConstructionRows.replace\":[\"Replace\"],\"editor.panels.roomConstructionRows.select\":[\"Select\"],\"editor.panels.roomConstructionRows.shape\":[\"Shape\"],\"editor.panels.roomConstructionRows.sharedWallsNote\":[\"Turning walls off keeps the ones shared with \",[\"rooms\"],\".\"],\"editor.panels.roomConstructionRows.sitsOnPreset\":[\"Sits on: \",[\"name\"],\" · \",[\"preset\"]],\"editor.panels.roomConstructionRows.theNextRoom\":[\"the next room\"],\"editor.panels.roomConstructionRows.useExisting\":[\"Use existing\"],\"editor.panels.roomConstructionRows.wallCount\":[[\"walls\",\"plural\",{\"one\":[[\"wallCount\"],\" wall\"],\"other\":[[\"wallCount\"],\" walls\"]}]],\"editor.panels.roomConstructionRows.walls\":[\"Walls\"],\"editor.panels.roomConstructionRows.wallsThickenInwardSoTheBuilding\":[\"Walls thicken inward, so the building's outer size stays the same.\"],\"editor.panels.roomOpeningsField.cutOpening\":[\"Cut opening\"],\"editor.panels.roomOpeningsField.done\":[\"Done\"],\"editor.panels.roomOpeningsField.editFloor\":[\"Edit floor\"],\"editor.panels.roomOpeningsField.elevatorOpening\":[\"Elevator opening\"],\"editor.panels.roomOpeningsField.noOpeningsYetCutOneFor\":[\"No openings yet. Cut one for a stair void or a hatch.\"],\"editor.panels.roomOpeningsField.openingNumber\":[\"Opening \",[\"number\"]],\"editor.panels.roomOpeningsField.openings\":[[\"count\",\"plural\",{\"0\":[\"No openings\"],\"one\":[[\"number\"],\" opening\"],\"other\":[[\"number\"],\" openings\"]}]],\"editor.panels.roomOpeningsField.stairOpening\":[\"Stair opening\"],\"editor.panels.roomPanel.addStairs\":[\"Add stairs\"],\"editor.panels.roomPanel.addToAUnit\":[\"Add to a unit\"],\"editor.panels.roomPanel.area\":[\"Area\"],\"editor.panels.roomPanel.browse\":[\"Browse\"],\"editor.panels.roomPanel.builtWith\":[\"Built with\"],\"editor.panels.roomPanel.ceiling\":[\"Ceiling\"],\"editor.panels.roomPanel.deleteRoom\":[\"Delete room\"],\"editor.panels.roomPanel.editShape\":[\"Edit shape\"],\"editor.panels.roomPanel.floor\":[\"Floor\"],\"editor.panels.roomPanel.headroom\":[[\"height\"],\" headroom\"],\"editor.panels.roomPanel.height\":[\"Height\"],\"editor.panels.roomPanel.hideCode\":[\"Hide code\"],\"editor.panels.roomPanel.kickerLevel\":[\"Room · \",[\"level\"]],\"editor.panels.roomPanel.kickerMezzanineIn\":[\"Mezzanine · in \",[\"room\"]],\"editor.panels.roomPanel.kickerNotEnclosed\":[\"Room · not enclosed\"],\"editor.panels.roomPanel.loading\":[\"Loading…\"],\"editor.panels.roomPanel.mezzanine\":[\"Mezzanine\"],\"editor.panels.roomPanel.mezzanineName\":[\"Mezzanine name\"],\"editor.panels.roomPanel.mezzanineNames\":[\"Mezzanine names\"],\"editor.panels.roomPanel.newUnit\":[\"New unit\"],\"editor.panels.roomPanel.none\":[\"None\"],\"editor.panels.roomPanel.notEnoughHeadroom\":[\"Not enough headroom\"],\"editor.panels.roomPanel.openRoomArea\":[[\"area\"],\" · Close its walls to build its floor and ceiling.\"],\"editor.panels.roomPanel.openingCounts\":[[\"doors\",\"plural\",{\"one\":[[\"doorCount\"],\" door\"],\"other\":[[\"doorCount\"],\" doors\"]}],\" · \",[\"windows\",\"plural\",{\"one\":[[\"windowCount\"],\" window\"],\"other\":[[\"windowCount\"],\" windows\"]}]],\"editor.panels.roomPanel.overTheMezzanine\":[\"Over the mezzanine\"],\"editor.panels.roomPanel.perimeter\":[\"Perimeter\"],\"editor.panels.roomPanel.pick\":[\"Pick\"],\"editor.panels.roomPanel.pickingItAddsANumber\":[\"Picking it adds a number\"],\"editor.panels.roomPanel.remove\":[\"Remove\"],\"editor.panels.roomPanel.removeFromUnit\":[\"Remove from unit\"],\"editor.panels.roomPanel.removeFromUnitNamed\":[\"Remove from \",[\"unit\"]],\"editor.panels.roomPanel.rename\":[\"Rename\"],\"editor.panels.roomPanel.renameNamed\":[[\"name\"],\" · Rename\"],\"editor.panels.roomPanel.revert\":[\"Revert\"],\"editor.panels.roomPanel.room\":[\"Room\"],\"editor.panels.roomPanel.roomColourUsedInThePlan\":[\"Room colour — used in the plan and labels\"],\"editor.panels.roomPanel.roomName\":[\"Room name\"],\"editor.panels.roomPanel.roomNames\":[\"Room names\"],\"editor.panels.roomPanel.scriptedFinish\":[\"Scripted finish\"],\"editor.panels.roomPanel.shape\":[\"Shape\"],\"editor.panels.roomPanel.showMezzanineNames\":[\"Show mezzanine names\"],\"editor.panels.roomPanel.showRoomNames\":[\"Show room names\"],\"editor.panels.roomPanel.stairs\":[\"Stairs\"],\"editor.panels.roomPanel.unit\":[\"Unit\"],\"editor.panels.roomPanel.use\":[\"Use\"],\"editor.panels.roomPanel.useTyped\":[[\"use\"],\" “\",[\"name\"],\"”\"],\"editor.panels.roomPanel.usedOnThisLevel\":[[\"used\"],\" on this level\"],\"editor.panels.roomPanel.viewCode\":[\"View code\"],\"editor.panels.scriptUnreadable\":[\"The script could not be read.\"],\"editor.panels.shapeChoice.polygon\":[\"Polygon\"],\"editor.panels.shapeChoice.rectangle\":[\"Rectangle\"],\"editor.panels.wallRegionList.deleteRegion\":[\"Delete region\"],\"editor.panels.wallRegionList.paintRegions\":[\"Paint regions\"],\"editor.proceduralItems.inspector.adjustDesign\":[\"Adjust design\"],\"editor.proceduralItems.inspector.back\":[\"Back\"],\"editor.proceduralItems.inspector.editParts\":[\"Edit parts\"],\"editor.proceduralItems.inspector.invalidAttachment\":[\"Invalid attachment\"],\"editor.proceduralItems.inspector.invalidEdit\":[\"Invalid edit\"],\"editor.proceduralItems.inspector.invalidPlacement\":[\"Invalid placement\"],\"editor.proceduralItems.inspector.invalidPosition\":[\"Invalid position\"],\"editor.proceduralItems.inspector.invalidReset\":[\"Invalid reset\"],\"editor.proceduralItems.inspector.pos\":[\"pos\"],\"editor.proceduralItems.inspector.position\":[\"Position\"],\"editor.proceduralItems.inspector.resetThisPart\":[\"Reset this part\"],\"editor.reloadEditor\":[\"Reload editor\"],\"editor.riserDiagramPanel.close\":[\"Close riser diagram\"],\"editor.riserDiagramPanel.dwvPlumbingIsometric\":[\"DWV plumbing isometric\"],\"editor.riserDiagramPanel.dwvRiserDiagram\":[\"DWV riser diagram\"],\"editor.riserDiagramPanel.noDrainWasteOrVentPipes\":[\"No drain, waste, or vent pipes yet. Draw plumbing to see the riser diagram.\"],\"editor.riserDiagramPanel.riserDiagram\":[\"Riser Diagram\"],\"editor.riserDiagramPanel.trap\":[[\"diameter\"],\"\\\" P-trap\"],\"editor.riserDiagramPanel.vent\":[\"Vent\"],\"editor.riserDiagramPanel.ventTermination\":[[\"diameter\"],\"\\\" VTR\"],\"editor.riserDiagramPanel.waste\":[\"Waste\"],\"editor.room.builtOn.above\":[[\"current\"],\" · \",[\"distance\"],\" above \",[\"shared\"]],\"editor.room.builtOn.below\":[[\"current\"],\" · \",[\"distance\"],\" below \",[\"shared\"]],\"editor.room.builtOn.levelWith\":[[\"current\"],\" · level with \",[\"shared\"]],\"editor.roomLabel.room\":[\"Room\"],\"editor.roomLabel.zone\":[\"Zone\"],\"editor.roomName.attic\":[\"Attic\"],\"editor.roomName.balcony\":[\"Balcony\"],\"editor.roomName.basement\":[\"Basement\"],\"editor.roomName.bathroom\":[\"Bathroom\"],\"editor.roomName.bedroom\":[\"Bedroom\"],\"editor.roomName.boilerRoom\":[\"Boiler room\"],\"editor.roomName.carport\":[\"Carport\"],\"editor.roomName.cellar\":[\"Cellar\"],\"editor.roomName.closet\":[\"Closet\"],\"editor.roomName.corridor\":[\"Corridor\"],\"editor.roomName.courtyard\":[\"Courtyard\"],\"editor.roomName.deck\":[\"Deck\"],\"editor.roomName.den\":[\"Den\"],\"editor.roomName.diningRoom\":[\"Dining room\"],\"editor.roomName.dressingRoom\":[\"Dressing room\"],\"editor.roomName.enSuite\":[\"En-suite\"],\"editor.roomName.entrance\":[\"Entrance\"],\"editor.roomName.familyRoom\":[\"Family room\"],\"editor.roomName.gallery\":[\"Gallery\"],\"editor.roomName.gamesRoom\":[\"Games room\"],\"editor.roomName.garage\":[\"Garage\"],\"editor.roomName.garden\":[\"Garden\"],\"editor.roomName.gardenShed\":[\"Garden shed\"],\"editor.roomName.guestRoom\":[\"Guest room\"],\"editor.roomName.gym\":[\"Gym\"],\"editor.roomName.hallway\":[\"Hallway\"],\"editor.roomName.homeCinema\":[\"Home cinema\"],\"editor.roomName.kidsRoom\":[\"Kids' room\"],\"editor.roomName.kitchen\":[\"Kitchen\"],\"editor.roomName.kitchenette\":[\"Kitchenette\"],\"editor.roomName.landing\":[\"Landing\"],\"editor.roomName.laundry\":[\"Laundry\"],\"editor.roomName.library\":[\"Library\"],\"editor.roomName.livingRoom\":[\"Living room\"],\"editor.roomName.loft\":[\"Loft\"],\"editor.roomName.lounge\":[\"Lounge\"],\"editor.roomName.mezzanine\":[\"Mezzanine\"],\"editor.roomName.mudroom\":[\"Mudroom\"],\"editor.roomName.nursery\":[\"Nursery\"],\"editor.roomName.office\":[\"Office\"],\"editor.roomName.pantry\":[\"Pantry\"],\"editor.roomName.patio\":[\"Patio\"],\"editor.roomName.playroom\":[\"Playroom\"],\"editor.roomName.poolArea\":[\"Pool area\"],\"editor.roomName.porch\":[\"Porch\"],\"editor.roomName.powderRoom\":[\"Powder room\"],\"editor.roomName.primaryBedroom\":[\"Primary bedroom\"],\"editor.roomName.readingNook\":[\"Reading nook\"],\"editor.roomName.section.bathrooms\":[\"Bathrooms\"],\"editor.roomName.section.circulation\":[\"Circulation\"],\"editor.roomName.section.living\":[\"Living\"],\"editor.roomName.section.mezzanine\":[\"Mezzanine\"],\"editor.roomName.section.outdoor\":[\"Outdoor\"],\"editor.roomName.section.sleeping\":[\"Sleeping\"],\"editor.roomName.section.utility\":[\"Utility & storage\"],\"editor.roomName.section.work\":[\"Work & hobbies\"],\"editor.roomName.showerRoom\":[\"Shower room\"],\"editor.roomName.stairwell\":[\"Stairwell\"],\"editor.roomName.storage\":[\"Storage\"],\"editor.roomName.studio\":[\"Studio\"],\"editor.roomName.study\":[\"Study\"],\"editor.roomName.sunroom\":[\"Sunroom\"],\"editor.roomName.terrace\":[\"Terrace\"],\"editor.roomName.toilet\":[\"Toilet\"],\"editor.roomName.utilityRoom\":[\"Utility room\"],\"editor.roomName.veranda\":[\"Veranda\"],\"editor.roomName.walkInCloset\":[\"Walk-in closet\"],\"editor.roomName.workshop\":[\"Workshop\"],\"editor.sidebar.iconRail.settings\":[\"Settings\"],\"editor.sidebar.iconRail.site\":[\"Site\"],\"editor.sidebar.panels.itemsPanel.all\":[\"All\"],\"editor.sidebar.panels.itemsPanel.community\":[\"Community\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.all\":[\"All\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.community\":[\"Community\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.library\":[\"Library\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.mine\":[\"Mine\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.noResultsForSearch\":[\"No results for “\",[\"search\"],\"”\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.search\":[\"Search...\"],\"editor.sidebar.panels.itemsPanel.library\":[\"Library\"],\"editor.sidebar.panels.itemsPanel.mine\":[\"Mine\"],\"editor.sidebar.panels.itemsPanel.noResultsForSearch\":[\"No results for “\",[\"search\"],\"”\"],\"editor.sidebar.panels.itemsPanel.search\":[\"Search...\"],\"editor.sidebar.panels.sitePanel.addLevel\":[\"Add level\"],\"editor.sidebar.panels.sitePanel.addPoint\":[\"Add point\"],\"editor.sidebar.panels.sitePanel.area\":[\"Area:\"],\"editor.sidebar.panels.sitePanel.baseElevation\":[\"Base elevation\"],\"editor.sidebar.panels.sitePanel.building\":[\"Building\"],\"editor.sidebar.panels.sitePanel.buildingTreeNode.addNewLevel\":[\"Add new level\"],\"editor.sidebar.panels.sitePanel.buildingTreeNode.building\":[\"Building\"],\"editor.sidebar.panels.sitePanel.cameraSnapshot\":[\"Camera snapshot\"],\"editor.sidebar.panels.sitePanel.capture\":[\"Capture\"],\"editor.sidebar.panels.sitePanel.clearSelection\":[\"Clear selection\"],\"editor.sidebar.panels.sitePanel.clearSnapshot\":[\"Clear snapshot\"],\"editor.sidebar.panels.sitePanel.closeWallsAroundASpaceTo\":[\"Close walls around a space to make a room.\"],\"editor.sidebar.panels.sitePanel.collectionTreeNode.collectionColour\":[\"Collection colour\"],\"editor.sidebar.panels.sitePanel.collectionTreeNode.collections\":[\"Collections\"],\"editor.sidebar.panels.sitePanel.collectionTreeNode.deleteCollection\":[\"Delete collection\"],\"editor.sidebar.panels.sitePanel.delete\":[\"Delete\"],\"editor.sidebar.panels.sitePanel.deleteLevel\":[\"Delete level\"],\"editor.sidebar.panels.sitePanel.drawAZone\":[\"Draw a zone\"],\"editor.sidebar.panels.sitePanel.duplicate\":[\"Duplicate\"],\"editor.sidebar.panels.sitePanel.duplicateLevel\":[\"Duplicate level\"],\"editor.sidebar.panels.sitePanel.duplicateLevelWithOptions\":[\"Duplicate level with options\"],\"editor.sidebar.panels.sitePanel.duplicateWithOptions\":[\"Duplicate with options...\"],\"editor.sidebar.panels.sitePanel.elements\":[\"Elements\"],\"editor.sidebar.panels.sitePanel.guide\":[\"Guide\"],\"editor.sidebar.panels.sitePanel.hide\":[\"Hide\"],\"editor.sidebar.panels.sitePanel.level\":[\"Level\"],\"editor.sidebar.panels.sitePanel.newUnit\":[\"New unit\"],\"editor.sidebar.panels.sitePanel.noBuildingsYet\":[\"No buildings yet\"],\"editor.sidebar.panels.sitePanel.noElementsOnThisLevel\":[\"No elements on this level\"],\"editor.sidebar.panels.sitePanel.noLevelsYet\":[\"No levels yet\"],\"editor.sidebar.panels.sitePanel.objectsSelected\":[[\"count\",\"plural\",{\"one\":[\"#\",\" object selected\"],\"other\":[\"#\",\" objects selected\"]}]],\"editor.sidebar.panels.sitePanel.otherZones\":[\"Other zones\"],\"editor.sidebar.panels.sitePanel.perimeter\":[\"Perimeter:\"],\"editor.sidebar.panels.sitePanel.propertyLine\":[\"Property Line\"],\"editor.sidebar.panels.sitePanel.rooms\":[\"Rooms\"],\"editor.sidebar.panels.sitePanel.selectALevelToViewContent\":[\"Select a level to view content\"],\"editor.sidebar.panels.sitePanel.show\":[\"Show\"],\"editor.sidebar.panels.sitePanel.site\":[\"Site\"],\"editor.sidebar.panels.sitePanel.takeSnapshot\":[\"Take snapshot\"],\"editor.sidebar.panels.sitePanel.theGroundLevelCannotBeDeleted\":[\"The ground level cannot be deleted\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.cameraSnapshot\":[\"Camera snapshot\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.clearSnapshot\":[\"Clear snapshot\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.hide\":[\"Hide\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.show\":[\"Show\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.takeSnapshot\":[\"Take snapshot\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.updateSnapshot\":[\"Update snapshot\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.viewSnapshot\":[\"View snapshot\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.deleteUnit\":[\"Delete unit\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.focused\":[\"Focused\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.removeFromUnit\":[\"Remove from unit\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.room\":[\"Room\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.zone\":[\"Zone\"],\"editor.sidebar.panels.sitePanel.units\":[\"Units\"],\"editor.sidebar.panels.sitePanel.updateSnapshot\":[\"Update snapshot\"],\"editor.sidebar.panels.sitePanel.uploadScanFloorplan\":[\"Upload scan/floorplan\"],\"editor.sidebar.panels.sitePanel.uploadingProgress\":[[\"assetType\",\"select\",{\"guide\":[\"Uploading guide... \",[\"progress\"],\"%\"],\"other\":[\"Uploading scan... \",[\"progress\"],\"%\"]}]],\"editor.sidebar.panels.sitePanel.viewSnapshot\":[\"View snapshot\"],\"editor.sidebar.panels.sitePanel.zoneMembershipCheckbox.inUnitname\":[\"In \",[\"unitName\"]],\"editor.sidebar.panels.zonePanel.actions\":[\"Actions\"],\"editor.sidebar.panels.zonePanel.addOne\":[\"Add one\"],\"editor.sidebar.panels.zonePanel.cameraSnapshot\":[\"Camera snapshot\"],\"editor.sidebar.panels.zonePanel.clearSnapshot\":[\"Clear snapshot\"],\"editor.sidebar.panels.zonePanel.delete\":[\"Delete\"],\"editor.sidebar.panels.zonePanel.deleteWithContents\":[\"Delete with contents\"],\"editor.sidebar.panels.zonePanel.noZonesOnThisLevel\":[\"No zones on this level.\"],\"editor.sidebar.panels.zonePanel.saveToCatalog\":[\"Save to catalog\"],\"editor.sidebar.panels.zonePanel.selectALevelToViewAnd\":[\"Select a level to view and create zones\"],\"editor.sidebar.panels.zonePanel.takeSnapshot\":[\"Take snapshot\"],\"editor.sidebar.panels.zonePanel.updateSnapshot\":[\"Update snapshot\"],\"editor.sidebar.panels.zonePanel.viewSnapshot\":[\"View snapshot\"],\"editor.sidebar.usePluginPanels.labelPluginCrashed\":[\"\\\"\",[\"label\"],\"\\\" plugin crashed\"],\"editor.sidebar.usePluginPanels.loading\":[\"Loading…\"],\"editor.sidebar.usePluginPanels.plugins\":[\"Plugins\"],\"editor.sidebar.usePluginPanels.thisPanelHitAnErrorAnd\":[\"This panel hit an error and was unloaded for this session. The rest of the editor is unaffected — reload to try again.\"],\"editor.snapTarget.ceiling\":[\"Ceiling attachment\"],\"editor.snapTarget.roof\":[\"Roof attachment\"],\"editor.snapTarget.wall\":[\"Wall attachment\"],\"editor.theEditorSceneFailedToRender\":[\"The editor scene failed to render\"],\"editor.toolHint.aCurtainWallTakesNoCorner.1qxjv5i\":[\"A curtain wall takes no corner window\"],\"editor.toolHint.aCurvedWallTakesNoCorner.1vdnaw5\":[\"A curved wall takes no corner window\"],\"editor.toolHint.addACornerClickTheFirst.o4r67t\":[\"Add a corner · click the first to close\"],\"editor.toolHint.anotherOpeningIsInTheWay.11l9dd0\":[\"Another opening is in the way at the corner\"],\"editor.toolHint.autoHangers.10554ka\":[\"Auto hangers\"],\"editor.toolHint.autoHangersClickOrPressH.rwa3ka\":[\"Auto hangers - click or press H to toggle\"],\"editor.toolHint.autoHangersOff.7yx01x\":[\"Auto hangers: Off\"],\"editor.toolHint.autoHangersOn.10b1umh\":[\"Auto hangers: On\"],\"editor.toolHint.bypassSnapping.w5lmdv\":[\"Bypass snapping\"],\"editor.toolHint.cancel.ew9em3\":[\"Cancel\"],\"editor.toolHint.cancelMove.lvp31c\":[\"Cancel move\"],\"editor.toolHint.cancelRunExit.zqjf3h\":[\"Cancel run / exit\"],\"editor.toolHint.cancelStartPoint.1xbq2lh\":[\"Cancel start point\"],\"editor.toolHint.cornerWindow.1avkzpo\":[\"Corner window\"],\"editor.toolHint.cuts.1y0axps\":[\"Cuts\"],\"editor.toolHint.cutsValue.ouzhvb\":[\"Cuts: \",[\"value\"]],\"editor.toolHint.cutsValueEven.1ngsz3\":[\"Cuts: \",[\"value\"],\", even\"],\"editor.toolHint.cycleMonoGableButterfly.1poga3m\":[\"Cycle mono / gable / butterfly\"],\"editor.toolHint.cycleSnappingMode.1ct0gn6\":[\"Cycle snapping mode\"],\"editor.toolHint.doorStyleClickOrPressL.33pe65\":[\"Door style — click or press L to cycle\"],\"editor.toolHint.doorTypeClickOrPressO.1hhh8gt\":[\"Door type — click or press O to cycle\"],\"editor.toolHint.dropDownspoutFromOutlet.1k4h1m4\":[\"Drop downspout from outlet\"],\"editor.toolHint.ductDiameterDownUp.1wdz5vq\":[\"Duct diameter down / up\"],\"editor.toolHint.endRunCancel.59dh2w\":[\"End run / cancel\"],\"editor.toolHint.exit.engmg5\":[\"Exit\"],\"editor.toolHint.exitDrawing.9noxyb\":[\"Exit drawing\"],\"editor.toolHint.finishAndContinue.1gpfsks\":[\"Finish and continue\"],\"editor.toolHint.finishCeiling.1c1lfel\":[\"Finish ceiling\"],\"editor.toolHint.finishGridAxis.1wvrfhr\":[\"Finish grid axis\"],\"editor.toolHint.finishMeasurement.1e4gv16\":[\"Finish measurement\"],\"editor.toolHint.finishMultiPointWitnesses.8wzskz\":[\"Finish multi-point witnesses\"],\"editor.toolHint.finishSlab.xmnm8e\":[\"Finish slab\"],\"editor.toolHint.flipSide.172xku9\":[\"Flip side\"],\"editor.toolHint.followTraceALineset.mgquwe\":[\"Follow: trace a lineset\"],\"editor.toolHint.forcePlace.1hq1nr\":[\"Force place\"],\"editor.toolHint.freePlacement.1nztdac\":[\"Free placement\"],\"editor.toolHint.goVerticalClickToPlace.dg8g6m\":[\"Go vertical ↕, click to place\"],\"editor.toolHint.highlightOutlet.65hoq8\":[\"Highlight outlet\"],\"editor.toolHint.joinAsACornerWindow.jvdp4j\":[\"Join as a corner window\"],\"editor.toolHint.key.altDrag.ai3wn9\":[\"Alt + drag\"],\"editor.toolHint.key.backspace.qy6qx8\":[\"Backspace\"],\"editor.toolHint.key.click.m8sun\":[\"Click\"],\"editor.toolHint.key.clickAgain.190ws9j\":[\"Click again\"],\"editor.toolHint.key.command.1j2mkia\":[\"Command\"],\"editor.toolHint.key.control.10fbl8e\":[\"Control\"],\"editor.toolHint.key.delete.oay2cq\":[\"Delete\"],\"editor.toolHint.key.doubleClick.vlma6o\":[\"Double click\"],\"editor.toolHint.key.drag.8pwtpf\":[\"Drag\"],\"editor.toolHint.key.enter.1ctpui5\":[\"Enter\"],\"editor.toolHint.key.hover.6xw79p\":[\"Hover\"],\"editor.toolHint.key.hoverADuctEnd.19axr3b\":[\"Hover a duct end\"],\"editor.toolHint.key.hoverAPipeEnd.1jbum5f\":[\"Hover a pipe end\"],\"editor.toolHint.key.hoverGutter.1dwcsno\":[\"Hover gutter\"],\"editor.toolHint.key.leftClick.s4gwfc\":[\"Left click\"],\"editor.toolHint.key.middleClick.1jbaan4\":[\"Middle click\"],\"editor.toolHint.key.rShiftR.13bnobh\":[\"R / Shift+R\"],\"editor.toolHint.key.rightClick.1ovld0h\":[\"Right click\"],\"editor.toolHint.key.scroll.ai6wr0\":[\"Scroll\"],\"editor.toolHint.key.scrollWheel.18j0ix7\":[\"Scroll wheel\"],\"editor.toolHint.key.space.1hrh82t\":[\"Space\"],\"editor.toolHint.key.tab.1xsal0s\":[\"Tab\"],\"editor.toolHint.mountFloorCeilingWall.32dxpv\":[\"Mount: floor / ceiling / wall\"],\"editor.toolHint.noRoomForTheMatchingWindow.1755948\":[\"No room for the matching window on the other wall\"],\"editor.toolHint.noWallMeetsHere.19n99yc\":[\"No wall meets here\"],\"editor.toolHint.numberOfCutsScrollOrClick.1kqe84b\":[\"Number of cuts — scroll or click to change\"],\"editor.toolHint.pickWitnessPoint.k3hgh1\":[\"Pick witness point\"],\"editor.toolHint.pipeSizeDownUp.wp04og\":[\"Pipe size down / up\"],\"editor.toolHint.placeAndContinue.qfwkrq\":[\"Place and continue\"],\"editor.toolHint.placeBlock.1aylwrx\":[\"Place block\"],\"editor.toolHint.placeBoxVentOnRoof.kf88e5\":[\"Place box vent on roof\"],\"editor.toolHint.placeCabinet.b0ouyk\":[\"Place cabinet\"],\"editor.toolHint.placeCanopyOrSetTheNext.12l7zf8\":[\"Place canopy or set the next run point\"],\"editor.toolHint.placeChimneyOnRoof.19dbqu\":[\"Place chimney on roof\"],\"editor.toolHint.placeColumn.1w2vq86\":[\"Place column\"],\"editor.toolHint.placeCupolaOnRoof.ofx3bn\":[\"Place cupola on roof\"],\"editor.toolHint.placeDimensionLineWhenNeeded.bjw2cj\":[\"Place dimension line when needed\"],\"editor.toolHint.placeDoorOnWall.1jwadf\":[\"Place door on wall\"],\"editor.toolHint.placeDormerOnRoof.1w518a6\":[\"Place dormer on roof\"],\"editor.toolHint.placeElevator.1f65zva\":[\"Place elevator\"],\"editor.toolHint.placeEyebrowVentOnRoof.1h1tqxn\":[\"Place eyebrow vent on roof\"],\"editor.toolHint.placeFitting.1pmx3vn\":[\"Place fitting\"],\"editor.toolHint.placeGutterOnRoofEave.llwzf9\":[\"Place gutter on roof eave\"],\"editor.toolHint.placeItLockedTo45.16e4csk\":[\"Place it (locked to 45°)\"],\"editor.toolHint.placeItem.teynf\":[\"Place item\"],\"editor.toolHint.placeMeasurementPoint.bsatli\":[\"Place measurement point\"],\"editor.toolHint.placeOnAFence.1dptstr\":[\"Place on a fence\"],\"editor.toolHint.placeRegister.1uebycd\":[\"Place register\"],\"editor.toolHint.placeRidgeVentOnRoof.2tpd8r\":[\"Place ridge vent on roof\"],\"editor.toolHint.placeShelf.y4l3iw\":[\"Place shelf\"],\"editor.toolHint.placeSkylightOnRoof.e215pe\":[\"Place skylight on roof\"],\"editor.toolHint.placeSolarPanelArrayOnRoof.kk11fn\":[\"Place solar panel array on roof\"],\"editor.toolHint.placeSpawnPoint.205o25\":[\"Place spawn point\"],\"editor.toolHint.placeStairs.zwxxu2\":[\"Place stairs\"],\"editor.toolHint.placeTrap.1gxemn3\":[\"Place trap\"],\"editor.toolHint.placeTurbineVentOnRoof.1iqeluf\":[\"Place turbine vent on roof\"],\"editor.toolHint.placeUnit.8zkx4q\":[\"Place unit\"],\"editor.toolHint.placeWindowOnWall.1k3qnfb\":[\"Place window on wall\"],\"editor.toolHint.placeWithoutTheCornerSnap.1nifqew\":[\"Place without the corner snap\"],\"editor.toolHint.placement.13lcvts\":[\"Placement\"],\"editor.toolHint.placementAuto.1caa52d\":[\"Placement: Auto\"],\"editor.toolHint.placementGround.1ruz145\":[\"Placement: Ground\"],\"editor.toolHint.placementRoof.renkw8\":[\"Placement: Roof\"],\"editor.toolHint.placementSurfaceClickOrPressP.w56h19\":[\"Placement surface - click or press P to cycle\"],\"editor.toolHint.placementType.1mdpl60\":[\"Placement type\"],\"editor.toolHint.placementTypeClickOrPressI.10cgxh2\":[\"Placement type — click or press I to toggle\"],\"editor.toolHint.removeLastPoint.2dmdcx\":[\"Remove last point\"],\"editor.toolHint.removeLastWitness.1b6vvzw\":[\"Remove last witness\"],\"editor.toolHint.rotate.1thqa0a\":[\"Rotate\"],\"editor.toolHint.rotate45.9zq68u\":[\"Rotate ±45°\"],\"editor.toolHint.rotate45FloorCeiling.m9t57d\":[\"Rotate ±45° (floor / ceiling)\"],\"editor.toolHint.rotateGhost15.rsa52c\":[\"Rotate ghost ±15°\"],\"editor.toolHint.rotateOrFlipTheRunSide.t5ior7\":[\"Rotate or flip the run side\"],\"editor.toolHint.rotateRoofDirection90.tvbji2\":[\"Rotate roof direction 90°\"],\"editor.toolHint.rotateSpawnPoint.1opcuu7\":[\"Rotate spawn point\"],\"editor.toolHint.roundRectangularOval.e4nh6x\":[\"Round / rectangular / oval\"],\"editor.toolHint.setFenceStartEnd.1phbwsq\":[\"Set fence start / end\"],\"editor.toolHint.setOneCornerThenTheOpposite.8tsl49\":[\"Set one corner, then the opposite\"],\"editor.toolHint.setRoofFootprint.p50n0o\":[\"Set roof footprint\"],\"editor.toolHint.setWallStartEnd.1r8ubcx\":[\"Set wall start / end\"],\"editor.toolHint.slopeLevel.ftqp67\":[\"Slope / level\"],\"editor.toolHint.snapOntoTheRun.86yhmp\":[\"Snap onto the run\"],\"editor.toolHint.splitAtTheMarks.x5tpdd\":[\"Split at the marks\"],\"editor.toolHint.startGridAxis.k92yza\":[\"Start grid axis\"],\"editor.toolHint.startLineset.23q8dh\":[\"Start lineset\"],\"editor.toolHint.startLiquidLine.1rlxsgd\":[\"Start liquid line\"],\"editor.toolHint.startRun.r6fc5u\":[\"Start run\"],\"editor.toolHint.startSegment.rolym6\":[\"Start segment\"],\"editor.toolHint.stepBackOrCancel.zbfdkn\":[\"Step back or cancel\"],\"editor.toolHint.style.nf3vcm\":[\"Style\"],\"editor.toolHint.styleBarn.k9n1x\":[\"Style: Barn\"],\"editor.toolHint.styleCasement.ziklec\":[\"Style: Casement\"],\"editor.toolHint.styleCraftsman.52e6a9\":[\"Style: Craftsman\"],\"editor.toolHint.styleDoubleHung.1lg8pkg\":[\"Style: Double-hung\"],\"editor.toolHint.styleFrench.1ue3j64\":[\"Style: French\"],\"editor.toolHint.styleGlass.qudnb4\":[\"Style: Glass\"],\"editor.toolHint.styleGrid.1vuq4po\":[\"Style: Grid\"],\"editor.toolHint.styleHalfLouvered.13b1few\":[\"Style: Half-louvered\"],\"editor.toolHint.styleHorizontalBands.12ethxk\":[\"Style: Horizontal bands\"],\"editor.toolHint.styleModern.1fh8hhn\":[\"Style: Modern\"],\"editor.toolHint.stylePanel.922jze\":[\"Style: Panel\"],\"editor.toolHint.stylePaneledGlass.17a17en\":[\"Style: Paneled glass\"],\"editor.toolHint.styleShaker.49z17k\":[\"Style: Shaker\"],\"editor.toolHint.styleSingle.6f3cm0\":[\"Style: Single\"],\"editor.toolHint.styleSixPanel.u49laj\":[\"Style: Six-panel\"],\"editor.toolHint.styleSliding.q81s0i\":[\"Style: Sliding\"],\"editor.toolHint.styleTallGrid.1eotg3x\":[\"Style: Tall grid\"],\"editor.toolHint.styleTransom.kb9bh6\":[\"Style: Transom\"],\"editor.toolHint.styleTripleHung.pxnqi3\":[\"Style: Triple-hung\"],\"editor.toolHint.styleWideGrid.12n27et\":[\"Style: Wide grid\"],\"editor.toolHint.switchRotationAxisYXZ.15lohm6\":[\"Switch rotation axis (Y → X → Z)\"],\"editor.toolHint.theWallsMeetAtTooSharp.kh3wi3\":[\"The walls meet at too sharp or too flat an angle\"],\"editor.toolHint.theWindowWaitingThereIsTaller.1tqwez4\":[\"The window waiting there is taller than this wall\"],\"editor.toolHint.threeOrMoreWallsMeetHere.rgifif\":[\"Three or more walls meet here\"],\"editor.toolHint.traceCeilingOutline.1b639wv\":[\"Trace ceiling outline\"],\"editor.toolHint.traceSlabOutline.z0j2lc\":[\"Trace slab outline\"],\"editor.toolHint.type.1m2zofh\":[\"Type\"],\"editor.toolHint.typeAwning.1cj59al\":[\"Type: Awning\"],\"editor.toolHint.typeBarn.sbnygq\":[\"Type: Barn\"],\"editor.toolHint.typeBay.1200hc1\":[\"Type: Bay\"],\"editor.toolHint.typeBow.14s2t9p\":[\"Type: Bow\"],\"editor.toolHint.typeCabinet.1r68je5\":[\"Type: Cabinet\"],\"editor.toolHint.typeCasement.176uo9j\":[\"Type: Casement\"],\"editor.toolHint.typeDouble.af7w4i\":[\"Type: Double\"],\"editor.toolHint.typeDoubleHung.t482fu\":[\"Type: Double Hung\"],\"editor.toolHint.typeFixed.v1cjez\":[\"Type: Fixed\"],\"editor.toolHint.typeFolding.sxxyng\":[\"Type: Folding\"],\"editor.toolHint.typeFrench.1y57z1b\":[\"Type: French\"],\"editor.toolHint.typeHinged.1xrcfju\":[\"Type: Hinged\"],\"editor.toolHint.typeIsland.ufr3ce\":[\"Type: Island\"],\"editor.toolHint.typeLouvered.oxl1cz\":[\"Type: Louvered\"],\"editor.toolHint.typePocket.hc65x9\":[\"Type: Pocket\"],\"editor.toolHint.typeSingleHung.p53pyl\":[\"Type: Single Hung\"],\"editor.toolHint.typeSliding.nwmr3f\":[\"Type: Sliding\"],\"editor.toolHint.verticalStackClickToPlace.ijcn4q\":[\"Vertical stack ↕, click to place\"],\"editor.toolHint.wasteVent.1hvi3vj\":[\"Waste / vent\"],\"editor.toolHint.windowStyleClickOrPressL.ah7qm9\":[\"Window style — click or press L to cycle\"],\"editor.toolHint.windowTypeClickOrPressO.wv4x35\":[\"Window type — click or press O to cycle\"],\"editor.tools.distribution.distributionRunTool.lengthField\":[\"Length: \",[\"field\"],\" m\"],\"editor.tools.distribution.distributionRunTool.tabDirection\":[\"Tab: direction\"],\"editor.tools.distribution.distributionRunTool.typeALength\":[\"type a length\"],\"editor.views.plugins\":[\"Plugins\"],\"editor.views.view2d\":[\"2D\"],\"editor.views.view3d\":[\"3D\"],\"editor.views.viewBar.auto\":[\"Auto\"],\"editor.views.viewBar.browsePlugins\":[\"Browse plugins\"],\"editor.views.viewBar.closeLabel\":[\"Close \",[\"label\"]],\"editor.views.viewBar.closeSplit\":[\"Close split (\\\\)\"],\"editor.views.viewBar.ground\":[\"Ground\"],\"editor.views.viewBar.groundSolid\":[[\"standing\",\"select\",{\"partly\":[\"Partly below grade · ground solid\"],\"below\":[\"Below grade · ground solid\"],\"other\":[\"Ground solid\"]}]],\"editor.views.viewBar.groundVeiled\":[[\"standing\",\"select\",{\"partly\":[\"Partly below grade · ground veiled\"],\"below\":[\"Below grade · ground veiled\"],\"other\":[\"Ground veiled\"]}]],\"editor.views.viewBar.keepTheGroundSolid\":[\"Keep the ground solid\"],\"editor.views.viewBar.moreViews\":[\"More views\"],\"editor.views.viewBar.paneViews\":[\"Pane \",[\"pane\"],\" views\"],\"editor.views.viewBar.pinLabel\":[\"Pin \",[\"label\"]],\"editor.views.viewBar.pinToTheViewBar\":[\"Pin to the view bar\"],\"editor.views.viewBar.solid\":[\"Solid\"],\"editor.views.viewBar.split\":[\"Split (\\\\)\"],\"editor.views.viewBar.split2\":[\"Split\"],\"editor.views.viewBar.swapPanes\":[\"Swap panes\"],\"editor.views.viewBar.unpinFromTheViewBar\":[\"Unpin from the view bar\"],\"editor.views.viewBar.unpinLabel\":[\"Unpin \",[\"label\"]],\"editor.views.viewBar.veilTheGroundOverALevel\":[\"Veil the ground over a level below grade\"],\"editor.views.viewBar.views\":[\"Views\"],\"editor.youCanRetryTheSceneOr\":[\"You can retry the scene or return home without reloading the whole app shell.\"],\"node.block.description\":[\"A topology-backed solid edited directly in the canvas.\"],\"node.block.label\":[\"Block\"],\"node.boxVent.description\":[\"Small louvered exhaust vent that sits on a roof slope.\"],\"node.boxVent.label\":[\"Box Vent\"],\"node.boxVent.panel.actions\":[\"Actions\"],\"node.boxVent.panel.baseFlange\":[\"Base Flange\"],\"node.boxVent.panel.baseHeight\":[\"Base Height\"],\"node.boxVent.panel.baseInset\":[\"Base Inset\"],\"node.boxVent.panel.box\":[\"Box\"],\"node.boxVent.panel.boxVent\":[\"Box Vent\"],\"node.boxVent.panel.cap\":[\"Cap\"],\"node.boxVent.panel.capHeight\":[\"Cap Height\"],\"node.boxVent.panel.cornerBevel\":[\"Corner Bevel\"],\"node.boxVent.panel.delete\":[\"Delete\"],\"node.boxVent.panel.depth\":[\"Depth\"],\"node.boxVent.panel.dimensions\":[\"Dimensions\"],\"node.boxVent.panel.dome\":[\"Dome\"],\"node.boxVent.panel.domeCurvature\":[\"Dome Curvature\"],\"node.boxVent.panel.duplicate\":[\"Duplicate\"],\"node.boxVent.panel.gapHeight\":[\"Gap Height\"],\"node.boxVent.panel.height\":[\"Height\"],\"node.boxVent.panel.hoodOverhang\":[\"Hood Overhang\"],\"node.boxVent.panel.move\":[\"Move\"],\"node.boxVent.panel.position\":[\"Position\"],\"node.boxVent.panel.rotation\":[\"Rotation\"],\"node.boxVent.panel.style\":[\"Style\"],\"node.boxVent.panel.topTaper\":[\"Top Taper\"],\"node.boxVent.panel.width\":[\"Width\"],\"node.building.description\":[\"A building container holding one or more levels.\"],\"node.building.label\":[\"Building\"],\"node.cabinet.compartmentCard.baskets\":[\"Baskets\"],\"node.cabinet.compartmentCard.bottom\":[\"Bottom\"],\"node.cabinet.compartmentCard.bottomFreezer\":[\"Bottom Freezer\"],\"node.cabinet.compartmentCard.bowls\":[\"Bowls\"],\"node.cabinet.compartmentCard.burnersOn\":[\"Burners on\"],\"node.cabinet.compartmentCard.chimney\":[\"Chimney\"],\"node.cabinet.compartmentCard.decrease\":[\"Decrease \",[\"label\"]],\"node.cabinet.compartmentCard.door\":[\"Door\"],\"node.cabinet.compartmentCard.double\":[\"Double\"],\"node.cabinet.compartmentCard.drawer\":[\"Drawer\"],\"node.cabinet.compartmentCard.drawers\":[\"Drawers\"],\"node.cabinet.compartmentCard.flipHinge\":[\"Flip hinge\"],\"node.cabinet.compartmentCard.flipTheDoorHingeToThe\":[\"Flip the door hinge to the opposite side\"],\"node.cabinet.compartmentCard.fridge\":[\"Fridge\"],\"node.cabinet.compartmentCard.gas\":[\"Gas\"],\"node.cabinet.compartmentCard.glass\":[\"Glass\"],\"node.cabinet.compartmentCard.height\":[\"Height\"],\"node.cabinet.compartmentCard.hob\":[\"Hob\"],\"node.cabinet.compartmentCard.increase\":[\"Increase \",[\"label\"]],\"node.cabinet.compartmentCard.induction\":[\"Induction\"],\"node.cabinet.compartmentCard.layout\":[\"Layout\"],\"node.cabinet.compartmentCard.left\":[\"Left\"],\"node.cabinet.compartmentCard.micro\":[\"Micro\"],\"node.cabinet.compartmentCard.moveDown\":[\"Move down\"],\"node.cabinet.compartmentCard.moveUp\":[\"Move up\"],\"node.cabinet.compartmentCard.oven\":[\"Oven\"],\"node.cabinet.compartmentCard.pullout\":[\"Pullout\"],\"node.cabinet.compartmentCard.rack\":[\"Rack\"],\"node.cabinet.compartmentCard.removeCompartment\":[\"Remove compartment\"],\"node.cabinet.compartmentCard.right\":[\"Right\"],\"node.cabinet.compartmentCard.shelf\":[\"Shelf\"],\"node.cabinet.compartmentCard.shelves\":[\"Shelves\"],\"node.cabinet.compartmentCard.shelvesInside\":[\"Shelves inside\"],\"node.cabinet.compartmentCard.single\":[\"Single\"],\"node.cabinet.compartmentCard.sink\":[\"Sink\"],\"node.cabinet.compartmentCard.style\":[\"Style\"],\"node.cabinet.compartmentCard.surface\":[\"Surface\"],\"node.cabinet.compartmentCard.top\":[\"Top\"],\"node.cabinet.compartmentCard.topFreezer\":[\"Top Freezer\"],\"node.cabinet.compartmentCard.topGrate\":[\"Top grate\"],\"node.cabinet.compartmentCard.tray\":[\"Tray\"],\"node.cabinet.compartmentCard.type\":[\"Type\"],\"node.cabinet.compartmentCard.washer\":[\"Washer\"],\"node.cabinet.compartmentCard.wire\":[\"Wire\"],\"node.cabinet.description\":[\"A configurable parametric base cabinet.\"],\"node.cabinet.essentialControls.bottomFreezer\":[\"Bottom freezer\"],\"node.cabinet.essentialControls.cooktopType\":[\"Cooktop type\"],\"node.cabinet.essentialControls.doorDirection\":[\"Door direction\"],\"node.cabinet.essentialControls.double\":[\"Double\"],\"node.cabinet.essentialControls.fridgeType\":[\"Fridge type\"],\"node.cabinet.essentialControls.gas\":[\"Gas\"],\"node.cabinet.essentialControls.glass\":[\"Glass\"],\"node.cabinet.essentialControls.induction\":[\"Induction\"],\"node.cabinet.essentialControls.itemOptions\":[\"Item options\"],\"node.cabinet.essentialControls.leftHinge\":[\"Left hinge\"],\"node.cabinet.essentialControls.rightHinge\":[\"Right hinge\"],\"node.cabinet.essentialControls.single\":[\"Single\"],\"node.cabinet.essentialControls.sinkLayout\":[\"Sink layout\"],\"node.cabinet.essentialControls.topFreezer\":[\"Top freezer\"],\"node.cabinet.kitchenCollection.chooseLabel\":[\"Choose \",[\"label\"]],\"node.cabinet.kitchenCollection.noKitchenItemsMatchTryFridge\":[\"No kitchen items match. Try “fridge”, “sink”, or “cabinet”.\"],\"node.cabinet.kitchenCollection.searchFridgeSinkCabinets\":[\"Search fridge, sink, cabinets…\"],\"node.cabinet.kitchenCollection.searchKitchenItems\":[\"Search kitchen items\"],\"node.cabinet.kitchenGroup.appliances\":[\"Appliances & fixtures\"],\"node.cabinet.kitchenGroup.cabinets\":[\"Cabinets\"],\"node.cabinet.kitchenModuleActions.addBeside\":[\"Add beside\"],\"node.cabinet.kitchenModuleActions.addBesideSelectedItem\":[\"Add beside selected item\"],\"node.cabinet.kitchenModuleActions.addLabel\":[\"Add \",[\"label\"]],\"node.cabinet.kitchenModuleActions.anUpperCabinetAttachedToThis\":[\"An upper cabinet attached to this item will be removed to make room.\"],\"node.cabinet.kitchenModuleActions.cabinet\":[\"Cabinet\"],\"node.cabinet.kitchenModuleActions.cancel\":[\"Cancel\"],\"node.cabinet.kitchenModuleActions.cannotFit\":[\"This \",[\"width\"],\" item cannot fit within the current run and its wall or corner limits. Move an end cabinet or free space, then try again.\"],\"node.cabinet.kitchenModuleActions.insertsBeside\":[[\"side\",\"select\",{\"left\":[\"Inserts on the left of the selected item.\"],\"other\":[\"Inserts on the right of the selected item.\"]}]],\"node.cabinet.kitchenModuleActions.kitchenChanged\":[\"The kitchen changed. Select an item again to refresh the preview.\"],\"node.cabinet.kitchenModuleActions.kitchenRunPreviewHighlightedItemIs\":[\"Kitchen run preview, highlighted item is the proposed change\"],\"node.cabinet.kitchenModuleActions.leftSide\":[\"Left side\"],\"node.cabinet.kitchenModuleActions.moved\":[[\"name\"],\": moves \",[\"distance\"]],\"node.cabinet.kitchenModuleActions.previewItem\":[[\"name\"],\": \",[\"width\"]],\"node.cabinet.kitchenModuleActions.replaceSelectedItem\":[\"Replace selected item\"],\"node.cabinet.kitchenModuleActions.replaceWith\":[\"Replace with…\"],\"node.cabinet.kitchenModuleActions.replaceWithLabel\":[\"Replace with \",[\"label\"]],\"node.cabinet.kitchenModuleActions.replacesOnlyTheSelectedItem\":[\"Replaces only the selected item.\"],\"node.cabinet.kitchenModuleActions.resized\":[[\"name\"],\": \",[\"before\"],\" → \",[\"after\"]],\"node.cabinet.kitchenModuleActions.rightSide\":[\"Right side\"],\"node.cabinet.kitchenModuleActions.unableToUpdateThisKitchen\":[\"Unable to update this kitchen.\"],\"node.cabinet.label\":[\"Modular Cabinet\"],\"node.cabinet.panel.aboveCeiling\":[\"Finished height extends \",[\"overflow\"],\" mm above the ceiling.\"],\"node.cabinet.panel.addChimney\":[\"Add chimney\"],\"node.cabinet.panel.addCompartment\":[\"Add compartment\"],\"node.cabinet.panel.addWallCabinet\":[\"Add wall cabinet\"],\"node.cabinet.panel.advanced\":[\"Advanced\"],\"node.cabinet.panel.appliance\":[\"Appliance\"],\"node.cabinet.panel.applianceFront\":[\"Appliance front\"],\"node.cabinet.panel.auto\":[\"Auto\"],\"node.cabinet.panel.bar\":[\"Bar\"],\"node.cabinet.panel.baseCabinet\":[\"Base Cabinet\"],\"node.cabinet.panel.cabinetConstructionCompartmentsAndOpeningPreview\":[\"Cabinet construction, compartments, and opening preview.\"],\"node.cabinet.panel.cabinetPanel\":[\"Cabinet panel\"],\"node.cabinet.panel.cabinetType\":[\"Cabinet Type\"],\"node.cabinet.panel.center\":[\"Center\"],\"node.cabinet.panel.close\":[\"Close\"],\"node.cabinet.panel.closeCabinet\":[\"Close cabinet\"],\"node.cabinet.panel.commonWallCabinetHeightsUseThe\":[\"Common wall-cabinet heights. Use the slider below for a custom height.\"],\"node.cabinet.panel.compartments\":[\"Compartments\"],\"node.cabinet.panel.cutout\":[\"Cutout\"],\"node.cabinet.panel.depth\":[\"Depth\"],\"node.cabinet.panel.dimensions\":[\"Dimensions\"],\"node.cabinet.panel.editKitchenRun\":[\"Edit kitchen run\"],\"node.cabinet.panel.fillToCeiling\":[\"Fill to ceiling\"],\"node.cabinet.panel.finish\":[\"Finish\"],\"node.cabinet.panel.frontConstruction\":[\"Front construction\"],\"node.cabinet.panel.handles\":[\"Handles\"],\"node.cabinet.panel.height\":[\"Height\"],\"node.cabinet.panel.heightPreset\":[\"Height preset\"],\"node.cabinet.panel.hole\":[\"Hole\"],\"node.cabinet.panel.inset\":[\"Inset\"],\"node.cabinet.panel.kitchen\":[\"Kitchen\"],\"node.cabinet.panel.kitchenRun\":[\"Kitchen run\"],\"node.cabinet.panel.knob\":[\"Knob\"],\"node.cabinet.panel.mounting\":[\"Mounting\"],\"node.cabinet.panel.none\":[\"None\"],\"node.cabinet.panel.open\":[\"Open\"],\"node.cabinet.panel.openAnimation\":[\"Open Animation\"],\"node.cabinet.panel.openCabinet\":[\"Open cabinet\"],\"node.cabinet.panel.overlay\":[\"Overlay\"],\"node.cabinet.panel.panelReady\":[\"Panel-ready\"],\"node.cabinet.panel.planningChecks\":[\"Planning checks\"],\"node.cabinet.panel.play\":[\"Play\"],\"node.cabinet.panel.playAnimation\":[\"Play animation\"],\"node.cabinet.panel.position\":[\"Position\"],\"node.cabinet.panel.raisedArch\":[\"Raised Arch\"],\"node.cabinet.panel.removeWallCabinet\":[\"Remove wall cabinet\"],\"node.cabinet.panel.replaceWith\":[\"Replace with…\"],\"node.cabinet.panel.revealGap\":[\"Reveal gap\"],\"node.cabinet.panel.shaker\":[\"Shaker\"],\"node.cabinet.panel.sharedCountertopPlinthAndFinishes\":[\"Shared countertop, plinth, and finishes\"],\"node.cabinet.panel.slab\":[\"Slab\"],\"node.cabinet.panel.solidMatchingFrontBetweenTheCabinet\":[\"Solid matching front between the cabinet and wall. Countertop and toe-kick continue across this filler.\"],\"node.cabinet.panel.standardWidth\":[\"Standard width\"],\"node.cabinet.panel.stop\":[\"Stop\"],\"node.cabinet.panel.stopAnimation\":[\"Stop animation\"],\"node.cabinet.panel.style\":[\"Style\"],\"node.cabinet.panel.tallCabinet\":[\"Tall Cabinet\"],\"node.cabinet.panel.top\":[\"Top\"],\"node.cabinet.panel.topCabinet\":[\"Top Cabinet\"],\"node.cabinet.panel.topCeiling\":[\"Top / Ceiling\"],\"node.cabinet.panel.topDepth\":[\"Top depth\"],\"node.cabinet.panel.topHeight\":[\"Top height\"],\"node.cabinet.panel.trimSoffit\":[\"Trim / Soffit\"],\"node.cabinet.panel.usesTheCabinetFrontStyleReveal\":[\"Uses the cabinet front style, reveal, handle, and front material settings below.\"],\"node.cabinet.panel.wallFiller\":[\"Wall filler\"],\"node.cabinet.panel.width\":[\"Width\"],\"node.cabinet.preset.baseCabinet\":[\"Base cabinet\"],\"node.cabinet.preset.dishwasher\":[\"Dishwasher\"],\"node.cabinet.preset.drawerCabinet\":[\"Drawer cabinet\"],\"node.cabinet.preset.fridge\":[\"Fridge\"],\"node.cabinet.preset.gasCooktop\":[\"Gas cooktop\"],\"node.cabinet.preset.inductionCooktop\":[\"Induction cooktop\"],\"node.cabinet.preset.ovenTower\":[\"Oven Tower\"],\"node.cabinet.preset.sinkCabinet\":[\"Sink cabinet\"],\"node.cabinet.preset.tallPantry\":[\"Tall Pantry\"],\"node.cabinet.preset.wallCabinet\":[\"Wall cabinet\"],\"node.cabinet.runPanel.addLeft\":[\"Add left\"],\"node.cabinet.runPanel.addRight\":[\"Add right\"],\"node.cabinet.runPanel.alignCabinetsHandles\":[\"Align cabinets & handles\"],\"node.cabinet.runPanel.appliesDepthCarcassPlinthAndCountertop\":[\"Applies depth, carcass, plinth, and countertop thickness to this run.\"],\"node.cabinet.runPanel.arrayCreate\":[[\"count\",\"plural\",{\"one\":[\"Create \",[\"number\"],\" module copy\"],\"other\":[\"Create \",[\"number\"],\" module copies\"]}]],\"node.cabinet.runPanel.arrayCreateNamed\":[[\"count\",\"plural\",{\"one\":[\"Create \",[\"number\"],\" \",[\"name\"],\" copy\"],\"other\":[\"Create \",[\"number\"],\" \",[\"name\"],\" copies\"]}]],\"node.cabinet.runPanel.arrayInvalidOptions\":[\"Choose a copy count from 1 to 20 and spacing from 0 to 2 m\"],\"node.cabinet.runPanel.arrayNoRoom\":[\"There is not enough room in this run for the requested array\"],\"node.cabinet.runPanel.arrayNoSource\":[\"Choose a standard or appliance module as the source\"],\"node.cabinet.runPanel.auto\":[\"Auto\"],\"node.cabinet.runPanel.back\":[\"Back\"],\"node.cabinet.runPanel.balancesStandardBaseCabinetsWhileKeeping\":[\"Balances standard base cabinets while keeping appliance and corner-filler widths fixed.\"],\"node.cabinet.runPanel.bar\":[\"Bar\"],\"node.cabinet.runPanel.barCounter\":[\"Bar counter\"],\"node.cabinet.runPanel.barDepth\":[\"Bar depth\"],\"node.cabinet.runPanel.barHeight\":[\"Bar height\"],\"node.cabinet.runPanel.carcassHeight\":[\"Carcass height\"],\"node.cabinet.runPanel.center\":[\"Center\"],\"node.cabinet.runPanel.commonWallCabinetHeightsUseThe\":[\"Common wall-cabinet heights. Use the slider below for a custom height.\"],\"node.cabinet.runPanel.copies\":[\"Copies\"],\"node.cabinet.runPanel.copiesIncludeTheSourceCabinetStructure\":[\"Copies include the source cabinet structure and any attached wall cabinet. Existing modules stay fixed; the requested array must fit in the available run space.\"],\"node.cabinet.runPanel.cornerFillersCannotBeUsedAs\":[\"Corner fillers cannot be used as array sources\"],\"node.cabinet.runPanel.countertopDepth\":[\"Countertop depth\"],\"node.cabinet.runPanel.countertopHeight\":[\"Countertop height\"],\"node.cabinet.runPanel.createArray\":[\"Create array\"],\"node.cabinet.runPanel.cutout\":[\"Cutout\"],\"node.cabinet.runPanel.deleteModule\":[\"Delete \",[\"name\"]],\"node.cabinet.runPanel.depth\":[\"Depth\"],\"node.cabinet.runPanel.direction\":[\"Direction\"],\"node.cabinet.runPanel.duplicateAlongRun\":[\"Duplicate along run\"],\"node.cabinet.runPanel.equalizeAll\":[\"Equalize all resizeable standard base cabinets in this run\"],\"node.cabinet.runPanel.equalizeAlreadyEqual\":[\"The resizeable cabinet widths are already equal\"],\"node.cabinet.runPanel.equalizeNeedsTwo\":[\"At least two standard base cabinets are required\"],\"node.cabinet.runPanel.equalizeNoFit\":[\"The available run width cannot satisfy the cabinet width limits\"],\"node.cabinet.runPanel.equalizeWidths\":[\"Equalize widths\"],\"node.cabinet.runPanel.fillerPlanSide\":[[\"side\",\"select\",{\"left\":[\"Left: \",[\"width\"],\" mm\"],\"other\":[\"Right: \",[\"width\"],\" mm\"]}]],\"node.cabinet.runPanel.finishAlign\":[\"Finish & align\"],\"node.cabinet.runPanel.finishedBack\":[\"Finished back\"],\"node.cabinet.runPanel.finishedExposedEnds\":[\"Finished exposed ends\"],\"node.cabinet.runPanel.fitWallFillers\":[\"Fit wall fillers\"],\"node.cabinet.runPanel.fits50150MmGapsAt\":[\"Fits 50–150 mm gaps at run ends beside perpendicular walls.\"],\"node.cabinet.runPanel.fronts\":[\"Fronts\"],\"node.cabinet.runPanel.handles\":[\"Handles\"],\"node.cabinet.runPanel.heightPreset\":[\"Height preset\"],\"node.cabinet.runPanel.hole\":[\"Hole\"],\"node.cabinet.runPanel.inset\":[\"Inset\"],\"node.cabinet.runPanel.islandBar\":[\"Island & Bar\"],\"node.cabinet.runPanel.kitchenRun\":[\"Kitchen run\"],\"node.cabinet.runPanel.knob\":[\"Knob\"],\"node.cabinet.runPanel.left\":[\"Left\"],\"node.cabinet.runPanel.matchBaseHeightsBacksRevealsAnd\":[\"Match base heights, backs, reveals and handles. Align upper cabinets; preserve tall appliances and custom compartments.\"],\"node.cabinet.runPanel.metricProfile\":[\"Metric · 600 mm\"],\"node.cabinet.runPanel.moduleNumber\":[\"Module \",[\"number\"]],\"node.cabinet.runPanel.modules\":[\"Modules\"],\"node.cabinet.runPanel.mounting\":[\"Mounting\"],\"node.cabinet.runPanel.noEligibleModule\":[\"No eligible module\"],\"node.cabinet.runPanel.none\":[\"None\"],\"node.cabinet.runPanel.overlay\":[\"Overlay\"],\"node.cabinet.runPanel.plinthHeight\":[\"Plinth height\"],\"node.cabinet.runPanel.position\":[\"Position\"],\"node.cabinet.runPanel.raisedArch\":[\"Raised Arch\"],\"node.cabinet.runPanel.revealGap\":[\"Reveal gap\"],\"node.cabinet.runPanel.right\":[\"Right\"],\"node.cabinet.runPanel.seatingOverhang\":[\"Seating overhang\"],\"node.cabinet.runPanel.shaker\":[\"Shaker\"],\"node.cabinet.runPanel.sharedPlinthCountertop\":[\"Shared Plinth & Countertop\"],\"node.cabinet.runPanel.showCountertop\":[\"Show countertop\"],\"node.cabinet.runPanel.showPlinth\":[\"Show plinth\"],\"node.cabinet.runPanel.slab\":[\"Slab\"],\"node.cabinet.runPanel.sourceModule\":[\"Source module\"],\"node.cabinet.runPanel.spacing\":[\"Spacing\"],\"node.cabinet.runPanel.standardDimensions\":[\"Standard dimensions\"],\"node.cabinet.runPanel.style\":[\"Style\"],\"node.cabinet.runPanel.summaryCompartment\":[[\"type\",\"select\",{\"shelf\":[\"Shelf\"],\"drawer\":[\"Drawer\"],\"door\":[\"Door\"],\"oven\":[\"Oven\"],\"microwave\":[\"Microwave\"],\"dishwasher\":[\"Dishwasher\"],\"sink\":[\"Sink\"],\"cooktop_gas\":[\"Gas cooktop\"],\"cooktop_induction\":[\"Induction cooktop\"],\"pull_out_pantry\":[\"Pull-out pantry\"],\"fridge_single\":[\"Fridge\"],\"fridge_double\":[\"Double fridge\"],\"fridge_top_freezer\":[\"Top-freezer fridge\"],\"fridge_bottom_freezer\":[\"Bottom-freezer fridge\"],\"hood_pyramid\":[\"Pyramid hood\"],\"hood_curved_glass\":[\"Curved glass hood\"],\"other\":[[\"raw\"]]}]],\"node.cabinet.runPanel.summaryCompartments\":[[\"count\",\"plural\",{\"one\":[[\"number\"],\" compartment\"],\"other\":[[\"number\"],\" compartments\"]}]],\"node.cabinet.runPanel.summaryEmpty\":[\"Empty\"],\"node.cabinet.runPanel.summaryTall\":[\"Tall cabinet\"],\"node.cabinet.runPanel.top\":[\"Top\"],\"node.cabinet.runPanel.unableToFinish\":[\"Unable to finish this kitchen run.\"],\"node.cabinet.runPanel.usProfile\":[\"US · 24 in\"],\"node.cabinet.runPanel.useAsArraySource\":[\"Use \",[\"name\"],\" as array source\"],\"node.cabinet.runPanel.useThisModuleAsTheArray\":[\"Use this module as the array source\"],\"node.cabinet.runPanel.waterfallEnds\":[\"Waterfall ends\"],\"node.cabinetModule.description\":[\"An editable module inside a modular cabinet run.\"],\"node.cabinetModule.label\":[\"Cabinet Module\"],\"node.ceiling.description\":[\"A polygon-bounded ceiling surface that hosts ceiling-mounted items.\"],\"node.ceiling.label\":[\"Ceiling\"],\"node.ceiling.panel.addHole\":[\"Add Hole\"],\"node.ceiling.panel.area\":[\"Area\"],\"node.ceiling.panel.auto\":[\"Auto\"],\"node.ceiling.panel.ceiling\":[\"Ceiling\"],\"node.ceiling.panel.customHeight\":[\"Custom height\"],\"node.ceiling.panel.cutOpening\":[\"Cut opening\"],\"node.ceiling.panel.done\":[\"Done\"],\"node.ceiling.panel.followsLevel\":[\"Follows level\"],\"node.ceiling.panel.height\":[\"Height\"],\"node.ceiling.panel.high30m\":[\"High (3.0m)\"],\"node.ceiling.panel.high90\":[\"High (9'0\\\")\"],\"node.ceiling.panel.holes\":[\"Holes\"],\"node.ceiling.panel.info\":[\"Info\"],\"node.ceiling.panel.limitedByLevel\":[\"Limited by the level to \",[\"height\"],\" — raise the level height for a taller ceiling.\"],\"node.ceiling.panel.low24m\":[\"Low (2.4m)\"],\"node.ceiling.panel.low80\":[\"Low (8'0\\\")\"],\"node.ceiling.panel.move\":[\"Move\"],\"node.ceiling.panel.noHoles\":[\"No holes\"],\"node.ceiling.panel.standard25m\":[\"Standard (2.5m)\"],\"node.ceiling.panel.standard86\":[\"Standard (8'6\\\")\"],\"node.ceiling.panel.tallerThanLevel\":[\"Taller than this level (\",[\"available\"],\" available). Raise the level height first.\"],\"node.chimney.description\":[\"Vertical masonry stack on a roof segment.\"],\"node.chimney.label\":[\"Chimney\"],\"node.chimney.panel.aboveRidge\":[\"Above Ridge\"],\"node.chimney.panel.actions\":[\"Actions\"],\"node.chimney.panel.back\":[\"Back\"],\"node.chimney.panel.bands\":[\"Bands\"],\"node.chimney.panel.cap\":[\"Cap\"],\"node.chimney.panel.chimney\":[\"Chimney\"],\"node.chimney.panel.chimneyType\":[\"Chimney Type\"],\"node.chimney.panel.corbeled\":[\"Corbeled\"],\"node.chimney.panel.cornerBevel\":[\"Corner Bevel\"],\"node.chimney.panel.count\":[\"Count\"],\"node.chimney.panel.cricket\":[\"Cricket\"],\"node.chimney.panel.cutoutOffset\":[\"Cutout Offset\"],\"node.chimney.panel.delete\":[\"Delete\"],\"node.chimney.panel.depth\":[\"Depth\"],\"node.chimney.panel.diameter\":[\"Diameter\"],\"node.chimney.panel.double\":[\"Double\"],\"node.chimney.panel.extent\":[\"Extent\"],\"node.chimney.panel.flat\":[\"Flat\"],\"node.chimney.panel.flues\":[\"Flues\"],\"node.chimney.panel.footprint\":[\"Footprint\"],\"node.chimney.panel.front\":[\"Front\"],\"node.chimney.panel.height\":[\"Height\"],\"node.chimney.panel.hollowDepth\":[\"Hollow Depth\"],\"node.chimney.panel.length\":[\"Length\"],\"node.chimney.panel.none\":[\"None\"],\"node.chimney.panel.offset\":[\"Offset\"],\"node.chimney.panel.overhang\":[\"Overhang\"],\"node.chimney.panel.panels\":[\"Panels\"],\"node.chimney.panel.position\":[\"Position\"],\"node.chimney.panel.rectangular\":[\"Rectangular\"],\"node.chimney.panel.rotation\":[\"Rotation\"],\"node.chimney.panel.round\":[\"Round\"],\"node.chimney.panel.shoulder\":[\"Shoulder\"],\"node.chimney.panel.sideMargin\":[\"Side Margin\"],\"node.chimney.panel.simple\":[\"Simple\"],\"node.chimney.panel.single\":[\"Single\"],\"node.chimney.panel.sloped\":[\"Sloped\"],\"node.chimney.panel.spacing\":[\"Spacing\"],\"node.chimney.panel.square\":[\"Square\"],\"node.chimney.panel.stepped\":[\"Stepped\"],\"node.chimney.panel.style\":[\"Style\"],\"node.chimney.panel.tapered\":[\"Tapered\"],\"node.chimney.panel.thickness\":[\"Thickness\"],\"node.chimney.panel.topOffset\":[\"Top Offset\"],\"node.chimney.panel.wallThickness\":[\"Wall Thickness\"],\"node.chimney.panel.width\":[\"Width\"],\"node.chimney.preset.brick\":[\"Brick\"],\"node.chimney.preset.modern\":[\"Modern\"],\"node.chimney.preset.round\":[\"Round\"],\"node.column.description\":[\"A parametric column with configurable cross-section, base, and capital.\"],\"node.column.label\":[\"Column\"],\"node.column.panel.aFrame\":[\"A-Frame\"],\"node.column.panel.actions\":[\"Actions\"],\"node.column.panel.applyPreset\":[\"Apply preset...\"],\"node.column.panel.applyProportion\":[\"Apply proportion...\"],\"node.column.panel.bottomDepth\":[\"Bottom Depth\"],\"node.column.panel.bottomHeight\":[\"Bottom Height\"],\"node.column.panel.bottomSpread\":[\"Bottom Spread\"],\"node.column.panel.bottomStepSpread\":[\"Bottom Step Spread\"],\"node.column.panel.bottomTiers\":[\"Bottom Tiers\"],\"node.column.panel.bottomWidth\":[\"Bottom Width\"],\"node.column.panel.boxFrame\":[\"Box Frame\"],\"node.column.panel.braceDepth\":[\"Brace Depth\"],\"node.column.panel.braceWidth\":[\"Brace Width\"],\"node.column.panel.bulge\":[\"Bulge\"],\"node.column.panel.bulged\":[\"Bulged\"],\"node.column.panel.column\":[\"Column\"],\"node.column.panel.connectorPlates\":[\"Connector Plates\"],\"node.column.panel.delete\":[\"Delete\"],\"node.column.panel.depth\":[\"Depth\"],\"node.column.panel.dimensions\":[\"Dimensions\"],\"node.column.panel.edgeSoftness\":[\"Edge Softness\"],\"node.column.panel.endWidth\":[\"End Width\"],\"node.column.panel.ends\":[\"Ends\"],\"node.column.panel.forkSpread\":[\"Fork Spread\"],\"node.column.panel.heavy\":[\"Heavy\"],\"node.column.panel.height\":[\"Height\"],\"node.column.panel.heightAndFootprintAreControlledBy\":[\"Height and footprint are controlled by the lean-to extension. Rotate or change the support style here; resize from the parent lean-to.\"],\"node.column.panel.hourglass\":[\"Hourglass\"],\"node.column.panel.kBrace\":[\"K Brace\"],\"node.column.panel.move\":[\"Move\"],\"node.column.panel.neckWidth\":[\"Neck Width\"],\"node.column.panel.noBottom\":[\"No Bottom\"],\"node.column.panel.noTop\":[\"No Top\"],\"node.column.panel.plinthThickness\":[\"Plinth Thickness\"],\"node.column.panel.portalFrame\":[\"Portal Frame\"],\"node.column.panel.preset\":[\"Preset\"],\"node.column.panel.rectangular\":[\"Rectangular\"],\"node.column.panel.ringPairs\":[\"Ring Pairs\"],\"node.column.panel.ringSpread\":[\"Ring Spread\"],\"node.column.panel.ringThickness\":[\"Ring Thickness\"],\"node.column.panel.round\":[\"Round\"],\"node.column.panel.roundBandWidth\":[\"Round Band Width\"],\"node.column.panel.roundedBottom\":[\"Rounded Bottom\"],\"node.column.panel.roundedTop\":[\"Rounded Top\"],\"node.column.panel.segmentTwist\":[\"Segment Twist\"],\"node.column.panel.shaft\":[\"Shaft\"],\"node.column.panel.shaftCornerRadius\":[\"Shaft Corner Radius\"],\"node.column.panel.shaftWidth\":[\"Shaft Width\"],\"node.column.panel.shape\":[\"Shape\"],\"node.column.panel.shortStout\":[\"Short / Stout\"],\"node.column.panel.simpleBlockBottom\":[\"Simple Block Bottom\"],\"node.column.panel.simpleTop\":[\"Simple Top\"],\"node.column.panel.singleStrut\":[\"Single Strut\"],\"node.column.panel.slender\":[\"Slender\"],\"node.column.panel.square\":[\"Square\"],\"node.column.panel.squarePlinthBottom\":[\"Square Plinth Bottom\"],\"node.column.panel.standard\":[\"Standard\"],\"node.column.panel.steppedBottom\":[\"Stepped Bottom\"],\"node.column.panel.steppedTop\":[\"Stepped Top\"],\"node.column.panel.straight\":[\"Straight\"],\"node.column.panel.taper\":[\"Taper\"],\"node.column.panel.tapered\":[\"Tapered\"],\"node.column.panel.topDepth\":[\"Top Depth\"],\"node.column.panel.topHeight\":[\"Top Height\"],\"node.column.panel.topSpread\":[\"Top Spread\"],\"node.column.panel.topStepSpread\":[\"Top Step Spread\"],\"node.column.panel.topTiers\":[\"Top Tiers\"],\"node.column.panel.topWidth\":[\"Top Width\"],\"node.column.panel.transform\":[\"Transform\"],\"node.column.panel.trestle\":[\"Trestle\"],\"node.column.panel.tripod\":[\"Tripod\"],\"node.column.panel.twistSegments\":[\"Twist Segments\"],\"node.column.panel.vSupport\":[\"V Support\"],\"node.column.panel.vertical\":[\"Vertical\"],\"node.column.panel.waist\":[\"Waist\"],\"node.column.panel.width\":[\"Width\"],\"node.column.panel.xBrace\":[\"X Brace\"],\"node.column.panel.ySupport\":[\"Y Support\"],\"node.column.panel.yaw\":[\"Yaw\"],\"node.column.preset.aFrameSupport\":[\"A-Frame Support\"],\"node.column.preset.basicPillar\":[\"Straight Round\"],\"node.column.preset.boxFrameSupport\":[\"Box Frame\"],\"node.column.preset.bulgedPillar\":[\"Soft Bulged\"],\"node.column.preset.hourglassPillar\":[\"Hourglass\"],\"node.column.preset.kBraceSupport\":[\"K Brace\"],\"node.column.preset.portalFrameSupport\":[\"Portal Frame\"],\"node.column.preset.singleStrutSupport\":[\"Single Strut\"],\"node.column.preset.squarePillar\":[\"Square Block\"],\"node.column.preset.taperedPillar\":[\"Tapered Round\"],\"node.column.preset.trestleSupport\":[\"Trestle Frame\"],\"node.column.preset.tripodSupport\":[\"Tripod Support\"],\"node.column.preset.vFrameSupport\":[\"V Support\"],\"node.column.preset.xBraceSupport\":[\"X Brace\"],\"node.column.preset.yFrameSupport\":[\"Y Support\"],\"node.constructionDimension.description\":[\"Associative linear, curved, circular, angular, or coordinate plan dimension.\"],\"node.constructionDimension.label\":[\"Construction Dimension\"],\"node.cornerRadius.bottomLeft\":[\"Bottom Left\"],\"node.cornerRadius.bottomRight\":[\"Bottom Right\"],\"node.cornerRadius.topLeft\":[\"Top Left\"],\"node.cornerRadius.topRight\":[\"Top Right\"],\"node.cupola.description\":[\"Louvered roof lantern with a dome or pyramid cap and optional finial.\"],\"node.cupola.label\":[\"Cupola\"],\"node.cupola.panel.actions\":[\"Actions\"],\"node.cupola.panel.cupola\":[\"Cupola\"],\"node.cupola.panel.delete\":[\"Delete\"],\"node.cupola.panel.depth\":[\"Depth\"],\"node.cupola.panel.dimensions\":[\"Dimensions\"],\"node.cupola.panel.dome\":[\"Dome\"],\"node.cupola.panel.duplicate\":[\"Duplicate\"],\"node.cupola.panel.finial\":[\"Finial\"],\"node.cupola.panel.height\":[\"Height\"],\"node.cupola.panel.move\":[\"Move\"],\"node.cupola.panel.noFinial\":[\"No Finial\"],\"node.cupola.panel.position\":[\"Position\"],\"node.cupola.panel.pyramid\":[\"Pyramid\"],\"node.cupola.panel.rotation\":[\"Rotation\"],\"node.cupola.panel.style\":[\"Style\"],\"node.cupola.panel.width\":[\"Width\"],\"node.cutout.autoElevator\":[\"Auto elevator cutout\"],\"node.cutout.autoStair\":[\"Auto stair cutout\"],\"node.cutout.opening\":[\"Opening\"],\"node.cutout.room\":[\"Room cutout\"],\"node.door.description\":[\"A door cut into a wall. Animated open/close state.\"],\"node.door.label\":[\"Door\"],\"node.door.panel.actions\":[\"Actions\"],\"node.door.panel.addSegment\":[\"+ Add Segment\"],\"node.door.panel.all\":[\"All\"],\"node.door.panel.arch\":[\"Arch\"],\"node.door.panel.archHeight\":[\"Arch Height\"],\"node.door.panel.auto\":[\"Auto\"],\"node.door.panel.autoFollowsTheWall\":[\"Auto follows the wall\"],\"node.door.panel.barHeight\":[\"Bar Height\"],\"node.door.panel.columns\":[\"Columns\"],\"node.door.panel.contentPadding\":[\"Content Padding\"],\"node.door.panel.cornerRadius\":[\"Corner Radius\"],\"node.door.panel.customTheSegmentsMatchNoStyle\":[\"Custom: the segments match no style.\"],\"node.door.panel.delete\":[\"Delete\"],\"node.door.panel.depth\":[\"Depth\"],\"node.door.panel.dimensions\":[\"Dimensions\"],\"node.door.panel.direction\":[\"Direction\"],\"node.door.panel.divider\":[\"Divider\"],\"node.door.panel.door\":[\"Door\"],\"node.door.panel.doorCloser\":[\"Door Closer\"],\"node.door.panel.duplicate\":[\"Duplicate\"],\"node.door.panel.empty\":[\"Empty\"],\"node.door.panel.enableHandle\":[\"Enable Handle\"],\"node.door.panel.enableThreshold\":[\"Enable Threshold\"],\"node.door.panel.flipSide\":[\"Flip Side\"],\"node.door.panel.fold\":[\"Fold\"],\"node.door.panel.frame\":[\"Frame\"],\"node.door.panel.frameDepthAuto\":[\"Depth (auto)\"],\"node.door.panel.garage\":[\"Garage\"],\"node.door.panel.glass\":[\"Glass\"],\"node.door.panel.handle\":[\"Handle\"],\"node.door.panel.handleSide\":[\"Handle Side\"],\"node.door.panel.hardware\":[\"Hardware\"],\"node.door.panel.height\":[\"Height\"],\"node.door.panel.hingesSide\":[\"Hinges Side\"],\"node.door.panel.horizontal\":[\"Horizontal\"],\"node.door.panel.individual\":[\"Individual\"],\"node.door.panel.inset\":[\"Inset\"],\"node.door.panel.inward\":[\"Inward\"],\"node.door.panel.left\":[\"Left\"],\"node.door.panel.move\":[\"Move\"],\"node.door.panel.open\":[\"Open\"],\"node.door.panel.opening\":[\"Opening\"],\"node.door.panel.openingShape\":[\"Opening Shape\"],\"node.door.panel.outward\":[\"Outward\"],\"node.door.panel.panel\":[\"Panel\"],\"node.door.panel.panels\":[\"Panels\"],\"node.door.panel.panicBar\":[\"Panic Bar\"],\"node.door.panel.pocket\":[\"Pocket\"],\"node.door.panel.position\":[\"Position\"],\"node.door.panel.rail\":[\"Rail\"],\"node.door.panel.rect\":[\"Rect\"],\"node.door.panel.remove\":[\"- Remove\"],\"node.door.panel.revealRadius\":[\"Reveal Radius\"],\"node.door.panel.right\":[\"Right\"],\"node.door.panel.rounded\":[\"Rounded\"],\"node.door.panel.segments\":[\"Segments\"],\"node.door.panel.sizeIsLimitedToTheWall\":[\"Size is limited to the wall, including clearance for the opening frame.\"],\"node.door.panel.slide\":[\"Slide\"],\"node.door.panel.style\":[\"Style\"],\"node.door.panel.swing\":[\"Swing\"],\"node.door.panel.thickness\":[\"Thickness\"],\"node.door.panel.threshold\":[\"Threshold\"],\"node.door.panel.topShape\":[\"Top Shape\"],\"node.door.panel.type\":[\"Type\"],\"node.door.panel.vertical\":[\"Vertical\"],\"node.door.panel.wall\":[\"wall\"],\"node.door.panel.width\":[\"Width\"],\"node.door.style.barn\":[\"Barn\"],\"node.door.style.craftsman\":[\"Craftsman\"],\"node.door.style.french\":[\"French\"],\"node.door.style.glass\":[\"Glass\"],\"node.door.style.halfLouvered\":[\"Half-louvered\"],\"node.door.style.modern\":[\"Modern\"],\"node.door.style.panel\":[\"Panel\"],\"node.door.style.paneledGlass\":[\"Paneled glass\"],\"node.door.style.shaker\":[\"Shaker\"],\"node.door.style.sixPanel\":[\"Six-panel\"],\"node.door.type.barn\":[\"Barn\"],\"node.door.type.double\":[\"Double\"],\"node.door.type.folding\":[\"Folding\"],\"node.door.type.french\":[\"French\"],\"node.door.type.garageRollup\":[\"Roll-up\"],\"node.door.type.garageSectional\":[\"Sectional\"],\"node.door.type.garageTiltup\":[\"Tilt-up\"],\"node.door.type.hinged\":[\"Hinged\"],\"node.door.type.pocket\":[\"Pocket\"],\"node.door.type.sliding\":[\"Sliding\"],\"node.dormer.description\":[\"House-shaped protrusion on a roof segment.\"],\"node.dormer.label\":[\"Dormer\"],\"node.dormer.panel.depth\":[\"Depth\"],\"node.dormer.panel.dimensions\":[\"Dimensions\"],\"node.dormer.panel.dormer\":[\"Dormer\"],\"node.dormer.panel.dutch\":[\"Dutch\"],\"node.dormer.panel.flat\":[\"Flat\"],\"node.dormer.panel.gable\":[\"Gable\"],\"node.dormer.panel.gambrel\":[\"Gambrel\"],\"node.dormer.panel.hip\":[\"Hip\"],\"node.dormer.panel.mansard\":[\"Mansard\"],\"node.dormer.panel.pitchDirection\":[\"Pitch Direction\"],\"node.dormer.panel.pitchRise\":[\"Pitch Rise\"],\"node.dormer.panel.riseBack\":[\"Rise Back\"],\"node.dormer.panel.riseFront\":[\"Rise Front\"],\"node.dormer.panel.roofHeight\":[\"Roof Height\"],\"node.dormer.panel.roofType\":[\"Roof Type\"],\"node.dormer.panel.section\":[\"Section\"],\"node.dormer.panel.shed\":[\"Shed\"],\"node.dormer.panel.wallHeight\":[\"Wall Height\"],\"node.dormer.panel.width\":[\"Width\"],\"node.dormer.panel.windows\":[\"Windows\"],\"node.dormer.panelActionsSection.actions\":[\"Actions\"],\"node.dormer.panelActionsSection.delete\":[\"Delete\"],\"node.dormer.panelActionsSection.duplicate\":[\"Duplicate\"],\"node.dormer.panelActionsSection.move\":[\"Move\"],\"node.dormer.panelPositionSection.position\":[\"Position\"],\"node.dormer.panelPositionSection.rotation\":[\"Rotation\"],\"node.dormer.panelWindowsSection.addWindow\":[\"Add Window\"],\"node.dormer.panelWindowsSection.editNamed\":[\"Edit \",[\"name\"]],\"node.dormer.panelWindowsSection.editWindow\":[\"Edit window\"],\"node.dormer.panelWindowsSection.increaseTheDormerWidthToAdd\":[\"Increase the dormer width to add another window.\"],\"node.dormer.panelWindowsSection.move\":[\"Move\"],\"node.dormer.panelWindowsSection.moveNamed\":[\"Move \",[\"name\"]],\"node.dormer.panelWindowsSection.moveWindow\":[\"Move window\"],\"node.dormer.panelWindowsSection.noWindows\":[\"No windows\"],\"node.dormer.panelWindowsSection.windowNumber\":[\"Window \",[\"number\"]],\"node.dormer.panelWindowsSection.windowSummary\":[[\"face\",\"select\",{\"back\":[\"Back\"],\"left\":[\"Left\"],\"right\":[\"Right\"],\"other\":[\"Front\"]}],\" · \",[\"width\"],\" × \",[\"height\"],\" m\"],\"node.dormer.panelWindowsSection.windowsLength\":[\"Windows (\",[\"length\"],\")\"],\"node.downspout.description\":[\"Vertical drop pipe from a gutter outlet to the ground.\"],\"node.downspout.inspectorEditors.position\":[\"Position\"],\"node.downspout.label\":[\"Downspout\"],\"node.ductFitting.description\":[\"Elbow, tee, reducer, or square-to-round transition connecting duct runs.\"],\"node.ductFitting.inspectorEditors.swapWH\":[\"Swap W/H\"],\"node.ductFitting.inspectorEditors.swapWidthAndHeight\":[\"Swap width and height\"],\"node.ductFitting.label\":[\"Duct Fitting\"],\"node.ductFitting.tool.axis\":[\"Axis\"],\"node.ductFitting.tool.axis2\":[\"⌥ axis\"],\"node.ductFitting.tool.hoverADuctFaceThatFits\":[\"Hover a duct face that fits the door\"],\"node.ductFitting.tool.placeAccessDoor\":[\"Place access door\"],\"node.ductFitting.tool.rTRotate\":[\"R/T rotate\"],\"node.ductSegment.description\":[\"HVAC duct run — polyline of round, rect, or flat-oval sections.\"],\"node.ductSegment.label\":[\"Duct\"],\"node.ductTerminal.description\":[\"Duct terminal — supply register, ceiling diffuser, or return grille. Duct runs end at its collar.\"],\"node.ductTerminal.label\":[\"Register\"],\"node.ductTerminal.tool.mSurface\":[\"M surface\"],\"node.ductTerminal.tool.mount\":[[\"mount\",\"select\",{\"floor\":[\"Mount Floor\"],\"ceiling\":[\"Mount Ceiling\"],\"wall\":[\"Mount Wall\"],\"other\":[\"Mount \",[\"label\"]]}]],\"node.ductTerminal.tool.rTRotate\":[\"R/T rotate\"],\"node.ductTerminal.tool.snappedToDuct\":[\"Snapped to duct\"],\"node.elevator.description\":[\"A multi-level elevator shaft with configurable openings per level.\"],\"node.elevator.label\":[\"Elevator\"],\"node.elevator.panel.access\":[\"Access\"],\"node.elevator.panel.actions\":[\"Actions\"],\"node.elevator.panel.cab\":[\"Cab\"],\"node.elevator.panel.cabHeight\":[\"Cab Height\"],\"node.elevator.panel.centerOpening\":[\"Center opening\"],\"node.elevator.panel.defaultFloor\":[\"Default Floor\"],\"node.elevator.panel.delete\":[\"Delete\"],\"node.elevator.panel.depth\":[\"Depth\"],\"node.elevator.panel.destination\":[\"Destination\"],\"node.elevator.panel.disabled\":[\"Disabled\"],\"node.elevator.panel.doorHeight\":[\"Door Height\"],\"node.elevator.panel.doorTime\":[\"Door Time\"],\"node.elevator.panel.doorType\":[\"Door Type\"],\"node.elevator.panel.doorWidth\":[\"Door Width\"],\"node.elevator.panel.doors\":[\"Doors\"],\"node.elevator.panel.duplicate\":[\"Duplicate\"],\"node.elevator.panel.dwell\":[\"Dwell\"],\"node.elevator.panel.elevator\":[\"Elevator\"],\"node.elevator.panel.from\":[\"From\"],\"node.elevator.panel.glass\":[\"Glass\"],\"node.elevator.panel.glassFrame\":[\"Glass frame\"],\"node.elevator.panel.motion\":[\"Motion\"],\"node.elevator.panel.move\":[\"Move\"],\"node.elevator.panel.openingStyle\":[\"Opening Style\"],\"node.elevator.panel.position\":[\"Position\"],\"node.elevator.panel.rotation\":[\"Rotation\"],\"node.elevator.panel.segmentedPanel\":[\"Segmented panel\"],\"node.elevator.panel.service\":[\"Service\"],\"node.elevator.panel.shaft\":[\"Shaft\"],\"node.elevator.panel.shaftDepth\":[\"Shaft Depth\"],\"node.elevator.panel.shaftStyle\":[\"Shaft Style\"],\"node.elevator.panel.shaftWidth\":[\"Shaft Width\"],\"node.elevator.panel.singleLeft\":[\"Single left\"],\"node.elevator.panel.singleRight\":[\"Single right\"],\"node.elevator.panel.solid\":[\"Solid\"],\"node.elevator.panel.solidPanel\":[\"Solid panel\"],\"node.elevator.panel.speed\":[\"Speed\"],\"node.elevator.panel.stopStoporder\":[\"Stop \",[\"stopOrder\"]],\"node.elevator.panel.to\":[\"To\"],\"node.elevator.panel.wallThickness\":[\"Wall Thickness\"],\"node.elevator.panel.width\":[\"Width\"],\"node.elevator.panel.yaw\":[\"Yaw\"],\"node.eyebrowVent.description\":[\"Low curved lens-shaped roof vent with a louvered front.\"],\"node.eyebrowVent.label\":[\"Eyebrow Vent\"],\"node.eyebrowVent.panel.actions\":[\"Actions\"],\"node.eyebrowVent.panel.backHeight\":[\"Back height\"],\"node.eyebrowVent.panel.delete\":[\"Delete\"],\"node.eyebrowVent.panel.depth\":[\"Depth\"],\"node.eyebrowVent.panel.dimensions\":[\"Dimensions\"],\"node.eyebrowVent.panel.duplicate\":[\"Duplicate\"],\"node.eyebrowVent.panel.eyebrowVent\":[\"Eyebrow Vent\"],\"node.eyebrowVent.panel.halfRound\":[\"Half-round\"],\"node.eyebrowVent.panel.height\":[\"Height\"],\"node.eyebrowVent.panel.louvers\":[\"Louvers\"],\"node.eyebrowVent.panel.move\":[\"Move\"],\"node.eyebrowVent.panel.position\":[\"Position\"],\"node.eyebrowVent.panel.rotation\":[\"Rotation\"],\"node.eyebrowVent.panel.scoop\":[\"Scoop\"],\"node.eyebrowVent.panel.slantBox\":[\"Slant-box\"],\"node.eyebrowVent.panel.style\":[\"Style\"],\"node.eyebrowVent.panel.width\":[\"Width\"],\"node.fence.description\":[\"A straight or curved fence segment with configurable posts and infill.\"],\"node.fence.inspectorEditors.addPointAfter\":[\"Add point after\"],\"node.fence.inspectorEditors.chooseASlabOrShapedSurface\":[\"Choose a slab or shaped surface on this level.\"],\"node.fence.inspectorEditors.chooseASurface\":[\"Choose a surface\"],\"node.fence.inspectorEditors.corner\":[\"Corner\"],\"node.fence.inspectorEditors.curve\":[\"Curve\"],\"node.fence.inspectorEditors.curved\":[\"Curved\"],\"node.fence.inspectorEditors.distributionInfo\":[[\"style\",\"select\",{\"picket\":[\"Distribution controls pickets in each bay between posts.\"],\"horizontal\":[\"Distribution controls posts along the full fence.\"],\"other\":[\"Distribution controls infill pieces between the two end posts.\"]}],\" Spacing is measured between centers. The available width limits the count so pieces do not overlap.\"],\"node.fence.inspectorEditors.editPath\":[\"Edit path\"],\"node.fence.inspectorEditors.extendPath\":[\"Extend path\"],\"node.fence.inspectorEditors.followHighestSurface\":[\"Follow highest surface\"],\"node.fence.inspectorEditors.followSelectedSurface\":[\"Follow selected surface\"],\"node.fence.inspectorEditors.holdStartingHeight\":[\"Hold starting height\"],\"node.fence.inspectorEditors.join\":[\"Join\"],\"node.fence.inspectorEditors.length\":[\"Length\"],\"node.fence.inspectorEditors.pathSummary\":[[\"count\",\"plural\",{\"one\":[[\"number\"],\" point\"],\"other\":[[\"number\"],\" points\"]}],\" · \",[\"length\"],\" m\"],\"node.fence.inspectorEditors.picketRailProjection\":[\"Picket rail projection\"],\"node.fence.inspectorEditors.point\":[\"Point\"],\"node.fence.inspectorEditors.removePoint\":[\"Remove point\"],\"node.fence.inspectorEditors.setEachSpanToStraightOr\":[\"Set each span to straight or curved, then drag its points and curve handles in either view.\"],\"node.fence.inspectorEditors.smooth\":[\"Smooth\"],\"node.fence.inspectorEditors.spanToPointNumber\":[\"Span to point \",[\"number\"]],\"node.fence.inspectorEditors.straight\":[\"Straight\"],\"node.fence.inspectorEditors.surface\":[\"Surface\"],\"node.fence.inspectorEditors.surfaceBehavior\":[\"Surface behavior\"],\"node.fence.label\":[\"Fence\"],\"node.fence.moveEndpointTool.detachEndpoint\":[\"Detach endpoint\"],\"node.fence.moveEndpointTool.dragEndpoint\":[\"Drag endpoint\"],\"node.fenceFeature.actions.close\":[\"Close\"],\"node.fenceFeature.actions.open\":[\"Open\"],\"node.fenceFeature.inspector.boardWidth\":[\"Board width\"],\"node.fenceFeature.inspector.bracing\":[\"Bracing\"],\"node.fenceFeature.inspector.distanceFromStart\":[\"Distance from start\"],\"node.fenceFeature.inspector.fenceUnavailable\":[\"Fence unavailable.\"],\"node.fenceFeature.inspector.frameWidth\":[\"Frame width\"],\"node.fenceFeature.inspector.gateHeight\":[\"Gate height\"],\"node.fenceFeature.inspector.gateStyle\":[\"Gate style\"],\"node.fenceFeature.inspector.groundClearance\":[\"Ground clearance\"],\"node.fenceFeature.inspector.hingeSide\":[\"Hinge side\"],\"node.fenceFeature.inspector.hingesAndLatch\":[\"Hinges and latch\"],\"node.fenceFeature.inspector.horizontalBoards\":[\"Horizontal boards\"],\"node.fenceFeature.inspector.infillSpacing\":[\"Infill spacing\"],\"node.fenceFeature.inspector.jambPosts\":[\"Jamb posts\"],\"node.fenceFeature.inspector.keepTheOpeningInsideTheFence\":[\"Keep the opening inside the fence and clear of other gates or passages.\"],\"node.fenceFeature.inspector.leafThickness\":[\"Leaf thickness\"],\"node.fenceFeature.inspector.leaves\":[\"Leaves\"],\"node.fenceFeature.inspector.leftLeafProportion\":[\"Left leaf proportion\"],\"node.fenceFeature.inspector.matchFenceHeight\":[\"Match fence height\"],\"node.fenceFeature.inspector.matchFenceStyle\":[\"Match fence style\"],\"node.fenceFeature.inspector.openRails\":[\"Open rails\"],\"node.fenceFeature.inspector.openingAngle\":[\"Opening angle\"],\"node.fenceFeature.inspector.openingWidth\":[\"Opening width\"],\"node.fenceFeature.inspector.option.cross\":[\"Cross\"],\"node.fenceFeature.inspector.option.diagonal\":[\"Diagonal\"],\"node.fenceFeature.inspector.option.doubleGate\":[\"Double gate\"],\"node.fenceFeature.inspector.option.inward\":[\"Inward\"],\"node.fenceFeature.inspector.option.left\":[\"Left\"],\"node.fenceFeature.inspector.option.none\":[\"None\"],\"node.fenceFeature.inspector.option.outward\":[\"Outward\"],\"node.fenceFeature.inspector.option.right\":[\"Right\"],\"node.fenceFeature.inspector.option.singleGate\":[\"Single gate\"],\"node.fenceFeature.inspector.picket\":[\"Picket\"],\"node.fenceFeature.inspector.postHeight\":[\"Post height\"],\"node.fenceFeature.inspector.removeGate\":[\"Remove gate\"],\"node.fenceFeature.inspector.removeOpening\":[\"Remove opening\"],\"node.fenceFeature.inspector.solidPrivacy\":[\"Solid privacy\"],\"node.fenceFeature.inspector.swingDirection\":[\"Swing direction\"],\"node.fenceFeature.inspector.verticalSlats\":[\"Vertical slats\"],\"node.fenceGate.description\":[\"A gate hosted by a fence.\"],\"node.fenceGate.label\":[\"Gate\"],\"node.fenceOpening.description\":[\"An intentional opening in a fence.\"],\"node.fenceOpening.label\":[\"Open Passage\"],\"node.floorOpening.label\":[\"Floor opening\"],\"node.guide.description\":[\"A measurement / reference annotation (linear, area, or arc).\"],\"node.guide.label\":[\"Guide\"],\"node.gutter.description\":[\"Rain-water channel running along the eave of a roof segment.\"],\"node.gutter.downspoutsPanel.addDownspout\":[\"Add Downspout\"],\"node.gutter.downspoutsPanel.downspoutNumber\":[\"Downspout \",[\"number\"]],\"node.gutter.downspoutsPanel.downspouts\":[\"Downspouts\"],\"node.gutter.downspoutsPanel.removeDownspout\":[\"Remove downspout\"],\"node.gutter.label\":[\"Gutter\"],\"node.hole.manual\":[\"Manual\"],\"node.holeEditing\":[\"Hole \",[\"number\"],\" (Editing)\"],\"node.holeNumber\":[\"Hole \",[\"number\"]],\"node.holeSummary\":[[\"area\"],\" m² · \",[\"count\",\"plural\",{\"one\":[[\"points\"],\" pt\"],\"other\":[[\"points\"],\" pts\"]}],\" · \",[\"source\"]],\"node.hvacEquipment.description\":[\"Furnace, air handler, or condenser — duct runs connect to its supply/return collars.\"],\"node.hvacEquipment.label\":[\"HVAC Unit\"],\"node.hvacEquipment.tool.rTRotate\":[\"R/T rotate\"],\"node.importedMesh.description\":[\"Geometry preserved from an imported model when no native Pascal shape exists.\"],\"node.importedMesh.label\":[\"Imported Mesh\"],\"node.item.authoredParams.couldnTRebuildWithTheseValues\":[\"Couldn't rebuild with these values.\"],\"node.item.authoredParams.parameters\":[\"Parameters\"],\"node.item.authoredParams.rebuilding\":[\"Rebuilding…\"],\"node.item.authoredParams.rebuildingInBlender\":[\"Rebuilding in Blender…\"],\"node.item.authoredParams.resetParam\":[\"Reset \",[\"param\"]],\"node.item.authoredParams.resetParameters\":[\"Reset parameters\"],\"node.item.authoredParams.resetToDefault\":[\"Reset to default\"],\"node.item.description\":[\"A catalog-backed item (furniture, fixtures, decorations).\"],\"node.item.label\":[\"Item\"],\"node.item.panel.actions\":[\"Actions\"],\"node.item.panel.delete\":[\"Delete\"],\"node.item.panel.dimensions\":[\"Dimensions\"],\"node.item.panel.duplicate\":[\"Duplicate\"],\"node.item.panel.info\":[\"Info\"],\"node.item.panel.move\":[\"Move\"],\"node.item.panel.pos\":[\"pos\"],\"node.item.panel.position\":[\"Position\"],\"node.item.panel.rot\":[\"rot\"],\"node.item.panel.rotation\":[\"Rotation\"],\"node.item.panel.scale\":[\"Scale\"],\"node.item.panel.scale2\":[\"scale\"],\"node.item.panel.uniformScale\":[\"Uniform Scale\"],\"node.item.panel.xyz\":[\"XYZ\"],\"node.leanToExtension.description\":[\"An attached mono-pitch or freestanding mono, gable, or butterfly canopy with managed structure and drainage.\"],\"node.leanToExtension.label\":[\"Canopy\"],\"node.level.description\":[\"A single floor of a building, holding walls / slabs / ceilings / items.\"],\"node.level.label\":[\"Level\"],\"node.lineset.description\":[\"Refrigerant lineset — copper suction + liquid pair joining a condenser to the indoor coil.\"],\"node.lineset.label\":[\"Lineset\"],\"node.liquidLine.description\":[\"Standalone refrigerant liquid line — a thin bare-copper run; Follow mode traces an existing lineset.\"],\"node.liquidLine.label\":[\"Liquid Line\"],\"node.liquidLine.tool.clickToTraceThisLinesetRun\":[\"Click to trace this lineset run\"],\"node.liquidLine.tool.followHoverALineset\":[\"Follow: hover a lineset\"],\"node.measurement.description\":[\"A persistent distance, angle, area, perimeter, or volume annotation.\"],\"node.measurement.label\":[\"Measurement\"],\"node.numberedName\":[[\"kind\"],\" \",[\"number\"]],\"node.panel.currently\":[\"Currently \",[\"value\"]],\"node.pipeFitting.description\":[\"DWV joint — elbow bend, 45° wye, or sanitary tee.\"],\"node.pipeFitting.label\":[\"Pipe Fitting\"],\"node.pipeFitting.tool.axis\":[\"Axis\"],\"node.pipeFitting.tool.axis2\":[\"⌥ axis\"],\"node.pipeFitting.tool.rTRotate\":[\"R/T rotate\"],\"node.pipeSegment.description\":[\"Drain / waste / vent pipe run — draw level or toggle a ¼″ per foot fall with S.\"],\"node.pipeSegment.label\":[\"DWV Pipe\"],\"node.pipeTrap.description\":[\"DWV P-trap — water seal on the waste line. The trap arm runs to the vent.\"],\"node.pipeTrap.label\":[\"Trap\"],\"node.pipeTrap.tool.diameterTrap\":[[\"diameter\"],\"\\\" Trap\"],\"node.pipeTrap.tool.rTRotate\":[\"R/T rotate\"],\"node.proceduralItem.description\":[\"Experimental editable recipe\"],\"node.proceduralItem.label\":[\"Procedural item\"],\"node.ridgeVent.description\":[\"Ventilation strip running along the ridge of a roof segment.\"],\"node.ridgeVent.label\":[\"Ridge Vent\"],\"node.ridgeVent.panel.actions\":[\"Actions\"],\"node.ridgeVent.panel.delete\":[\"Delete\"],\"node.ridgeVent.panel.dimensions\":[\"Dimensions\"],\"node.ridgeVent.panel.duplicate\":[\"Duplicate\"],\"node.ridgeVent.panel.endCaps\":[\"End Caps\"],\"node.ridgeVent.panel.flanged\":[\"Flanged\"],\"node.ridgeVent.panel.height\":[\"Height\"],\"node.ridgeVent.panel.length\":[\"Length\"],\"node.ridgeVent.panel.move\":[\"Move\"],\"node.ridgeVent.panel.open\":[\"Open\"],\"node.ridgeVent.panel.position\":[\"Position\"],\"node.ridgeVent.panel.ridgeVent\":[\"Ridge Vent\"],\"node.ridgeVent.panel.rotation\":[\"Rotation\"],\"node.ridgeVent.panel.shingled\":[\"Shingled\"],\"node.ridgeVent.panel.standard\":[\"Standard\"],\"node.ridgeVent.panel.style\":[\"Style\"],\"node.ridgeVent.panel.width\":[\"Width\"],\"node.roof.barrelPanel.archBays\":[\"Arch bays\"],\"node.roof.barrelPanel.barrelArch\":[\"Barrel arch\"],\"node.roof.barrelPanel.flatPanesFollowACircularArch\":[\"Flat panes follow a circular arch. Rise is measured from the eaves.\"],\"node.roof.barrelPanel.rise\":[\"Rise\"],\"node.roof.description\":[\"A pitched / hip / gable roof composed of one or more segments.\"],\"node.roof.glazing.face.archBay\":[\"Arch bay \",[\"number\"]],\"node.roof.glazing.face.back\":[\"Back slope\"],\"node.roof.glazing.face.endLeft\":[\"Left end\"],\"node.roof.glazing.face.endRight\":[\"Right end\"],\"node.roof.glazing.face.front\":[\"Front slope\"],\"node.roof.glazing.face.slope\":[\"Shed slope\"],\"node.roof.glazingControls.alignment\":[\"Alignment\"],\"node.roof.glazingControls.center\":[\"Center\"],\"node.roof.glazingControls.chooseALayoutToEditThe\":[\"Choose a layout to edit the grid.\"],\"node.roof.glazingControls.empty\":[\"Empty\"],\"node.roof.glazingControls.end\":[\"End\"],\"node.roof.glazingControls.fixedSpacing\":[\"Fixed spacing\"],\"node.roof.glazingControls.glass\":[\"Glass\"],\"node.roof.glazingControls.layout\":[\"Layout\"],\"node.roof.glazingControls.maxSpacing\":[\"Max spacing\"],\"node.roof.glazingControls.maximumSpacing\":[\"Maximum spacing\"],\"node.roof.glazingControls.mixed\":[\"Mixed\"],\"node.roof.glazingControls.panelCount\":[\"Panel count\"],\"node.roof.glazingControls.panels\":[\"Panels\"],\"node.roof.glazingControls.solid\":[\"Solid\"],\"node.roof.glazingControls.spacing\":[\"Spacing\"],\"node.roof.glazingControls.start\":[\"Start\"],\"node.roof.glazingControls.titleAlignment\":[[\"title\"],\" alignment\"],\"node.roof.glazingPanel.changesApplyToAllLengthRoof\":[\"Changes apply to all \",[\"length\"],\" roof segments.\"],\"node.roof.glazingPanel.chooseOneRoofSystemToEdit\":[\"Choose one roof system to edit settings for all selected segments.\"],\"node.roof.glazingPanel.closeTheRoofEnds\":[\"Close the roof ends\"],\"node.roof.glazingPanel.defaultPanelInfill\":[\"Default panel infill\"],\"node.roof.glazingPanel.dividesEachRoofFaceIntoColumns\":[\"Divides each roof face into columns.\"],\"node.roof.glazingPanel.dividesTheLengthOfEachArch\":[\"Divides the length of each arch bay into columns.\"],\"node.roof.glazingPanel.endInfillFillsTheSpaceAbove\":[\"End infill fills the space above the walls. Edit room walls and ceilings separately.\"],\"node.roof.glazingPanel.frameColor\":[\"Frame color\"],\"node.roof.glazingPanel.frameDepth\":[\"Frame depth\"],\"node.roof.glazingPanel.frameWidth\":[\"Frame width\"],\"node.roof.glazingPanel.framing\":[\"Framing\"],\"node.roof.glazingPanel.glass\":[\"Glass\"],\"node.roof.glazingPanel.glassTint\":[\"Glass tint\"],\"node.roof.glazingPanel.glazed\":[\"Glazed\"],\"node.roof.glazingPanel.glazingIsAvailableForGableStraight\":[\"Glazing is available for gable, straight shed, and barrel roofs.\"],\"node.roof.glazingPanel.gridAcrossTheRoof\":[\"Grid across the roof\"],\"node.roof.glazingPanel.gridAlongTheLength\":[\"Grid along the length\"],\"node.roof.glazingPanel.gridAlongTheSlope\":[\"Grid along the slope\"],\"node.roof.glazingPanel.gridWithinEachArchBay\":[\"Grid within each arch bay\"],\"node.roof.glazingPanel.infill\":[\"Infill\"],\"node.roof.glazingPanel.opacity\":[\"Opacity\"],\"node.roof.glazingPanel.paneThickness\":[\"Pane thickness\"],\"node.roof.glazingPanel.roofSystem\":[\"Roof system\"],\"node.roof.glazingPanel.roughness\":[\"Roughness\"],\"node.roof.glazingPanel.spacingIsMeasuredOnTheSlope\":[\"Spacing is measured on the slope, not its horizontal projection.\"],\"node.roof.glazingPanel.standard\":[\"Standard\"],\"node.roof.glazingPanel.subdividesEachFlatArchBayArch\":[\"Subdivides each flat arch bay. Arch bays controls the divisions around the curve.\"],\"node.roof.glazingPanelEditor.chooseAPanelToOverrideIts\":[\"Choose a panel to override its default infill.\"],\"node.roof.glazingPanelEditor.column2\":[\"Column\"],\"node.roof.glazingPanelEditor.custom\":[\"Custom\"],\"node.roof.glazingPanelEditor.default\":[\"Default\"],\"node.roof.glazingPanelEditor.grid\":[[\"columns\",\"plural\",{\"one\":[[\"columnCount\"],\" column\"],\"other\":[[\"columnCount\"],\" columns\"]}],\" · \",[\"rows\",\"plural\",{\"one\":[[\"rowCount\"],\" row\"],\"other\":[[\"rowCount\"],\" rows\"]}]],\"node.roof.glazingPanelEditor.individualPanels\":[\"Individual panels\"],\"node.roof.glazingPanelEditor.panelInfill\":[\"Panel infill\"],\"node.roof.glazingPanelEditor.resetToDefault\":[\"Reset to default\"],\"node.roof.glazingPanelEditor.roofFace\":[\"Roof face\"],\"node.roof.glazingPanelEditor.row2\":[\"Row\"],\"node.roof.glazingPanelEditor.selectedPanelInfill\":[\"Selected panel infill\"],\"node.roof.label\":[\"Roof\"],\"node.roof.panel.actions\":[\"Actions\"],\"node.roof.panel.addChimney\":[\"Add Chimney\"],\"node.roof.panel.addCupola\":[\"Add Cupola\"],\"node.roof.panel.addDormer\":[\"Add Dormer\"],\"node.roof.panel.addEyebrowVent\":[\"Add Eyebrow Vent\"],\"node.roof.panel.addGutter\":[\"Add Gutter\"],\"node.roof.panel.addSkylight\":[\"Add Skylight\"],\"node.roof.panel.addSolarPanel\":[\"Add Solar Panel\"],\"node.roof.panel.addVent\":[\"Add Vent\"],\"node.roof.panel.box\":[\"Box\"],\"node.roof.panel.boxVent\":[\"box vent\"],\"node.roof.panel.chimney\":[\"chimney\"],\"node.roof.panel.custom\":[\"Custom\"],\"node.roof.panel.delete\":[\"Delete\"],\"node.roof.panel.dormer\":[\"dormer\"],\"node.roof.panel.drawSegment\":[\"Draw Segment\"],\"node.roof.panel.duplicate\":[\"Duplicate\"],\"node.roof.panel.elements\":[\"Elements\"],\"node.roof.panel.followsWalls\":[\"Follows walls\"],\"node.roof.panel.gutter\":[\"gutter\"],\"node.roof.panel.level\":[\"Level\"],\"node.roof.panel.move\":[\"Move\"],\"node.roof.panel.moveToLevel\":[\"Move to \",[\"level\"]],\"node.roof.panel.moveToTheRoofLevel\":[\"Move to the roof level\"],\"node.roof.panel.onStoreyWalls\":[\"On \",[\"storey\"],\" with its walls, so it hides that floor's plan in solo and exploded views.\",[\"roofs\",\"plural\",{\"0\":[],\"1\":[],\"other\":[\" The floor's \",[\"roofCount\"],\" roofs move together.\"]}]],\"node.roof.panel.position\":[\"Position\"],\"node.roof.panel.ridge\":[\"Ridge\"],\"node.roof.panel.ridgeVent\":[\"ridge vent\"],\"node.roof.panel.roof\":[\"Roof\"],\"node.roof.panel.rotation\":[\"Rotation\"],\"node.roof.panel.segmentType\":[[\"roofType\",\"select\",{\"hip\":[\"Hip\"],\"gable\":[\"Gable\"],\"shed\":[\"Shed\"],\"gambrel\":[\"Gambrel\"],\"dutch\":[\"Dutch\"],\"mansard\":[\"Mansard\"],\"flat\":[\"Flat\"],\"conical\":[\"Conical\"],\"barrel\":[\"Barrel\"],\"other\":[\"Roof\"]}]],\"node.roof.panel.segments\":[\"Segments\"],\"node.roof.panel.skylight\":[\"skylight\"],\"node.roof.panel.solarPanel\":[\"solar panel\"],\"node.roof.panel.turbine\":[\"Turbine\"],\"node.roof.panel.turbineVent\":[\"turbine vent\"],\"node.roofSegment.description\":[\"A single pitched plane of a parent roof.\"],\"node.roofSegment.label\":[\"Roof Segment\"],\"node.roofSegment.panel.actions\":[\"Actions\"],\"node.roofSegment.panel.angle\":[\"Angle\"],\"node.roofSegment.panel.arc\":[\"Arc\"],\"node.roofSegment.panel.autoGutters\":[\"Auto gutters\"],\"node.roofSegment.panel.autoRidgeVent\":[\"Auto ridge vent\"],\"node.roofSegment.panel.barrel\":[\"Barrel\"],\"node.roofSegment.panel.clippedVersion\":[\"Clipped version\"],\"node.roofSegment.panel.conical\":[\"Conical\"],\"node.roofSegment.panel.conicalShape\":[\"Conical Shape\"],\"node.roofSegment.panel.deckThick\":[\"Deck Thick.\"],\"node.roofSegment.panel.delete\":[\"Delete\"],\"node.roofSegment.panel.depth\":[\"Depth\"],\"node.roofSegment.panel.diameter\":[\"Diameter\"],\"node.roofSegment.panel.doneEditing\":[\"Done editing\"],\"node.roofSegment.panel.drainage\":[\"Drainage\"],\"node.roofSegment.panel.duplicate\":[\"Duplicate\"],\"node.roofSegment.panel.dutch\":[\"Dutch\"],\"node.roofSegment.panel.eaveOverhang\":[\"Eave overhang\"],\"node.roofSegment.panel.editFootprint\":[\"Edit footprint\"],\"node.roofSegment.panel.endOverhang\":[\"End overhang\"],\"node.roofSegment.panel.fascia\":[\"Fascia\"],\"node.roofSegment.panel.fasciaHeight\":[\"Fascia height\"],\"node.roofSegment.panel.flat\":[\"Flat\"],\"node.roofSegment.panel.footprint\":[\"Footprint\"],\"node.roofSegment.panel.gable\":[\"Gable\"],\"node.roofSegment.panel.gableOverhang\":[\"Gable overhang\"],\"node.roofSegment.panel.gambrel\":[\"Gambrel\"],\"node.roofSegment.panel.hip\":[\"Hip\"],\"node.roofSegment.panel.kinkDepth\":[\"Kink Depth\"],\"node.roofSegment.panel.kinkHeight\":[\"Kink Height\"],\"node.roofSegment.panel.length\":[\"Length\"],\"node.roofSegment.panel.mansard\":[\"Mansard\"],\"node.roofSegment.panel.move\":[\"Move\"],\"node.roofSegment.panel.pitch\":[\"Pitch\"],\"node.roofSegment.panel.position\":[\"Position\"],\"node.roofSegment.panel.reset\":[\"Reset\"],\"node.roofSegment.panel.roofSegment\":[\"Roof Segment\"],\"node.roofSegment.panel.roofType\":[\"Roof Type\"],\"node.roofSegment.panel.rotation\":[\"Rotation\"],\"node.roofSegment.panel.shape\":[\"Shape\"],\"node.roofSegment.panel.shed\":[\"Shed\"],\"node.roofSegment.panel.shingleThick\":[\"Shingle Thick.\"],\"node.roofSegment.panel.span\":[\"Span\"],\"node.roofSegment.panel.startAngle\":[\"Start Angle\"],\"node.roofSegment.panel.structure\":[\"Structure\"],\"node.roofSegment.panel.topRakeLength\":[\"Top Rake Length\"],\"node.roofSegment.panel.topRakeThick\":[\"Top Rake Thick.\"],\"node.roofSegment.panel.trim\":[\"Trim\"],\"node.roofSegment.panel.waistHeight\":[\"Waist Height\"],\"node.roofSegment.panel.waistLength\":[\"Waist Length\"],\"node.roofSegment.panel.waistWidth\":[\"Waist Width\"],\"node.roofSegment.panel.wall\":[\"Wall\"],\"node.roofSegment.panel.wallHeight\":[\"Wall Height\"],\"node.roofSegment.panel.wallThick\":[\"Wall Thick.\"],\"node.roofSegment.panel.width\":[\"Width\"],\"node.scan.description\":[\"A captured session with optional mesh, motion, media, and sensor data.\"],\"node.scan.label\":[\"Capture\"],\"node.segmentNumber\":[\"Segment \",[\"number\"]],\"node.separator.label\":[\"Separator\"],\"node.shared.itemInteractionActions.turnLightOff\":[\"Turn light off\"],\"node.shared.itemInteractionActions.turnLightOn\":[\"Turn light on\"],\"node.shared.runHangerInspector.automaticSupport\":[\"Automatic support\"],\"node.shared.runHangerInspector.hangerOnSegment\":[\"Hanger \",[\"number\"],\" · segment \",[\"segment\"]],\"node.shared.runHangerInspector.individualHangers\":[\"Individual hangers\"],\"node.shared.runHangerInspector.missingSupport\":[\"Missing support\"],\"node.shared.runHangerInspector.noSupportWithinReachMoveThe\":[\"No support within reach. Move the hanger or choose another host.\"],\"node.shared.runHangerInspector.positionLabel\":[\"Hanger \",[\"number\"],\" position in metres\"],\"node.shared.runHangerInspector.positionM\":[\"Position (m)\"],\"node.shared.runHangerInspector.positionsAreMeasuredAlongEachPath\":[\"Positions are measured along each path segment. Changing spacing regenerates the numbered slots.\"],\"node.shared.runHangerInspector.revealSupport\":[\"Reveal support\"],\"node.shared.runHangerInspector.skip\":[\"Skip\"],\"node.shared.runHangerInspector.supportLabel\":[\"Hanger \",[\"number\"],\" support\"],\"node.shared.systemCheckPanel.aboutTheseChecks\":[\"About these checks\"],\"node.shared.systemCheckPanel.allFindings\":[\"All findings\"],\"node.shared.systemCheckPanel.allSystems\":[\"All systems\"],\"node.shared.systemCheckPanel.connections\":[\"Connections\"],\"node.shared.systemCheckPanel.drainage\":[\"Drainage\"],\"node.shared.systemCheckPanel.error\":[\"Error\"],\"node.shared.systemCheckPanel.errors\":[\"Errors\"],\"node.shared.systemCheckPanel.filterSystemChecks\":[\"Filter system checks\"],\"node.shared.systemCheckPanel.hangers\":[\"Hangers\"],\"node.shared.systemCheckPanel.intersections\":[\"Intersections\"],\"node.shared.systemCheckPanel.locate\":[\"Locate \",[\"name\"],\" (\",[\"id\"],\")\"],\"node.shared.systemCheckPanel.missingItem\":[\"Missing item\"],\"node.shared.systemCheckPanel.noFindings\":[\"No findings\"],\"node.shared.systemCheckPanel.noFindingsInThisCategory\":[\"No findings in this category\"],\"node.shared.systemCheckPanel.openEnds\":[\"Open ends\"],\"node.shared.systemCheckPanel.openEndsAndSeparateBranchesMay\":[\"Open ends and separate branches may be intentional. Intersection checks use bounding boxes; inspect openings and clearances.\"],\"node.shared.systemCheckPanel.selectedConnectedSystem\":[\"Selected connected system\"],\"node.shared.systemCheckPanel.selectedRuns\":[\"Selected: \",[\"count\",\"plural\",{\"one\":[[\"number\"],\" run\"],\"other\":[[\"number\"],\" runs\"]}],\" · \",[\"length\"],\" m\"],\"node.shared.systemCheckPanel.separateBranches\":[\"Separate branches\"],\"node.shared.systemCheckPanel.showAllFindings\":[\"Show all findings\"],\"node.shared.systemCheckPanel.systemChecks\":[\"System checks\"],\"node.shared.systemCheckPanel.systemFinding\":[\"System finding\"],\"node.shared.systemCheckPanel.systemFindings\":[\"System findings\"],\"node.shared.systemCheckPanel.warning\":[\"Warning\"],\"node.shared.systemCheckPanel.warnings\":[\"Warnings\"],\"node.shelf.description\":[\"A configurable shelving unit. Items host on each row.\"],\"node.shelf.label\":[\"Shelf\"],\"node.site.description\":[\"The top-level container holding buildings, zones, and the property boundary.\"],\"node.site.label\":[\"Site\"],\"node.site.panel.address\":[\"Address\"],\"node.site.panel.apn\":[\"APN\"],\"node.site.panel.autoMostNorthFacingEdge\":[\"Auto — most north-facing edge\"],\"node.site.panel.contourIntervalSitePlanAnd3d\":[\"Contour interval (site plan and 3D)\"],\"node.site.panel.county\":[\"County\"],\"node.site.panel.eGRs60\":[\"e.g. RS-60\"],\"node.site.panel.eGTampaLdc27156\":[\"e.g. Tampa LDC §27-156\"],\"node.site.panel.every12In\":[\"every 12 in\"],\"node.site.panel.every24In\":[\"every 24 in\"],\"node.site.panel.every6In\":[\"every 6 in\"],\"node.site.panel.findParcel\":[\"Find parcel\"],\"node.site.panel.finding\":[\"Finding…\"],\"node.site.panel.frontStreetEdge\":[\"Front (street) edge\"],\"node.site.panel.lookingUpTheParcel\":[\"Looking up the parcel and the streets around it…\"],\"node.site.panel.lotArea\":[\"Lot area\"],\"node.site.panel.n1200WCassStTampaFl\":[\"1200 W Cass St, Tampa, FL\"],\"node.site.panel.noSurveyedLinesContoursAreDrawn\":[\"No surveyed lines — contours are drawn from the sculpted ground.\"],\"node.site.panel.none\":[\"none\"],\"node.site.panel.northRotation\":[\"North rotation\"],\"node.site.panel.orientation\":[\"Orientation\"],\"node.site.panel.parcel\":[\"Parcel\"],\"node.site.panel.parcelLookupFailed\":[\"Parcel lookup failed.\"],\"node.site.panel.projectLook\":[\"Project look\"],\"node.site.panel.saveCurrentLook\":[\"Save current look\"],\"node.site.panel.saveTheCurrentLightingAndDisplay\":[\"Save the current lighting and display as this project's default. Personal display changes stay in this browser.\"],\"node.site.panel.setbacks\":[\"Setbacks\"],\"node.site.panel.showGround\":[\"Show ground\"],\"node.site.panel.showTheContourLinesIn3d\":[\"Show the contour lines in 3D\"],\"node.site.panel.side\":[\"side\"],\"node.site.panel.site\":[\"Site\"],\"node.site.panel.source\":[\"Source\"],\"node.site.panel.sourceCitation\":[\"Source / citation\"],\"node.site.panel.streetAddress\":[\"Street address\"],\"node.site.panel.survey\":[\"survey\"],\"node.site.panel.surveyedContours\":[[\"count\",\"plural\",{\"one\":[[\"lineCount\"],\" surveyed line\"],\"other\":[[\"lineCount\"],\" surveyed lines\"]}],\" at \",[\"interval\"],\" ft (\",[\"datum\"],\") — \",[\"source\"]],\"node.site.panel.terrain\":[\"Terrain\"],\"node.site.panel.typeAnAddressFirst\":[\"Type an address first.\"],\"node.site.panel.useProjectLook\":[\"Use project look\"],\"node.site.panel.zone\":[\"Zone\"],\"node.site.setback.front\":[\"Front\"],\"node.site.setback.leftOverride\":[\"Left (override)\"],\"node.site.setback.rear\":[\"Rear\"],\"node.site.setback.rightOverride\":[\"Right (override)\"],\"node.site.setback.side\":[\"Side\"],\"node.skylight.description\":[\"Framed glass opening on a roof segment.\"],\"node.skylight.label\":[\"Skylight\"],\"node.skylight.panel.actions\":[\"Actions\"],\"node.skylight.panel.alongX\":[\"Along X\"],\"node.skylight.panel.alongZ\":[\"Along Z\"],\"node.skylight.panel.bottom\":[\"Bottom\"],\"node.skylight.panel.curb\":[\"Curb\"],\"node.skylight.panel.cutoutOffset\":[\"Cutout Offset\"],\"node.skylight.panel.delete\":[\"Delete\"],\"node.skylight.panel.depth\":[\"Depth\"],\"node.skylight.panel.dimensions\":[\"Dimensions\"],\"node.skylight.panel.frame\":[\"Frame\"],\"node.skylight.panel.glassThickness\":[\"Glass Thickness\"],\"node.skylight.panel.height\":[\"Height\"],\"node.skylight.panel.lanternHeight\":[\"Lantern Height\"],\"node.skylight.panel.left\":[\"Left\"],\"node.skylight.panel.motor\":[\"Motor\"],\"node.skylight.panel.motorHousing\":[\"Motor Housing\"],\"node.skylight.panel.no\":[\"No\"],\"node.skylight.panel.noMotor\":[\"No Motor\"],\"node.skylight.panel.open\":[\"Open\"],\"node.skylight.panel.openingAngle\":[\"Opening Angle\"],\"node.skylight.panel.position\":[\"Position\"],\"node.skylight.panel.right\":[\"Right\"],\"node.skylight.panel.rotation\":[\"Rotation\"],\"node.skylight.panel.skylight\":[\"Skylight\"],\"node.skylight.panel.thickness\":[\"Thickness\"],\"node.skylight.panel.top\":[\"Top\"],\"node.skylight.panel.topScale\":[\"Top Scale\"],\"node.skylight.panel.trackWidth\":[\"Track Width\"],\"node.skylight.panel.type\":[\"Type\"],\"node.skylight.panel.width\":[\"Width\"],\"node.skylight.panel.yes\":[\"Yes\"],\"node.skylight.type.flat\":[\"Flat roof skylight\"],\"node.skylight.type.lantern\":[\"Roof lantern\"],\"node.skylight.type.opening\":[\"Opening skylight\"],\"node.skylight.type.sliding\":[\"Sliding skylight\"],\"node.skylight.type.walkOn\":[\"Walk-on rooflight\"],\"node.slab.description\":[\"A polygon-bounded floor surface that hosts items on top.\"],\"node.slab.label\":[\"Slab\"],\"node.slab.panel.addHole\":[\"Add Hole\"],\"node.slab.panel.area\":[\"Area\"],\"node.slab.panel.auto\":[\"Auto\"],\"node.slab.panel.base\":[\"Base\"],\"node.slab.panel.cutHatch\":[\"Cut hatch\"],\"node.slab.panel.cutOpening\":[\"Cut opening\"],\"node.slab.panel.depth\":[\"Depth\"],\"node.slab.panel.done\":[\"Done\"],\"node.slab.panel.elevation\":[\"Elevation\"],\"node.slab.panel.extendsThePerimeterDownToTerrain\":[\"Extends the perimeter down to terrain. The flat surface, base, and thickness stay unchanged.\"],\"node.slab.panel.fixed\":[\"Fixed\"],\"node.slab.panel.floor\":[\"Floor\"],\"node.slab.panel.followsTerrain\":[\"Follows terrain\"],\"node.slab.panel.foundation\":[\"Foundation\"],\"node.slab.panel.holes\":[\"Holes\"],\"node.slab.panel.info\":[\"Info\"],\"node.slab.panel.move\":[\"Move\"],\"node.slab.panel.noHoles\":[\"No holes\"],\"node.slab.panel.rim\":[\"Rim\"],\"node.slab.panel.slab\":[\"Slab\"],\"node.slab.panel.standard2\":[\"Standard (2\\\")\"],\"node.slab.panel.standard5cm\":[\"Standard (5cm)\"],\"node.slab.panel.sunken15cm\":[\"Sunken (15cm)\"],\"node.slab.panel.sunken6\":[\"Sunken (6\\\")\"],\"node.slab.panel.surface\":[\"Surface\"],\"node.slab.panel.thick15cm\":[\"Thick (15cm)\"],\"node.slab.panel.thick6\":[\"Thick (6\\\")\"],\"node.slab.panel.thickness\":[\"Thickness\"],\"node.slab.panel.thin1\":[\"Thin (1\\\")\"],\"node.slab.panel.thin2cm\":[\"Thin (2cm)\"],\"node.solarPanel.description\":[\"Grid of photovoltaic panels mounted on a roof segment.\"],\"node.solarPanel.label\":[\"Solar Panel\"],\"node.solarPanel.panel.actions\":[\"Actions\"],\"node.solarPanel.panel.array\":[\"Array\"],\"node.solarPanel.panel.autoFitToRoof\":[\"Auto-fit to roof\"],\"node.solarPanel.panel.columns\":[\"Columns\"],\"node.solarPanel.panel.customDimensionsDonTMatchAny\":[\"Custom — dimensions don't match any preset\"],\"node.solarPanel.panel.delete\":[\"Delete\"],\"node.solarPanel.panel.flipOrientation\":[\"Flip orientation\"],\"node.solarPanel.panel.flush\":[\"Flush\"],\"node.solarPanel.panel.frameDepth\":[\"Frame depth\"],\"node.solarPanel.panel.frameThickness\":[\"Frame thickness\"],\"node.solarPanel.panel.gapX\":[\"Gap X\"],\"node.solarPanel.panel.gapY\":[\"Gap Y\"],\"node.solarPanel.panel.height\":[\"Height\"],\"node.solarPanel.panel.mounting\":[\"Mounting\"],\"node.solarPanel.panel.panel\":[\"Panel\"],\"node.solarPanel.panel.preset\":[\"Preset\"],\"node.solarPanel.panel.rows\":[\"Rows\"],\"node.solarPanel.panel.setbacksTooLarge\":[\"Setbacks too large to fit a panel.\"],\"node.solarPanel.panel.solarPanel\":[\"Solar Panel\"],\"node.solarPanel.panel.standoff\":[\"Standoff\"],\"node.solarPanel.panel.tiltAngle\":[\"Tilt angle\"],\"node.solarPanel.panel.tilted\":[\"Tilted\"],\"node.solarPanel.panel.width\":[\"Width\"],\"node.solarPanel.preset.compact\":[\"Compact\"],\"node.solarPanel.preset.frameless\":[\"Frameless\"],\"node.solarPanel.preset.residential\":[\"Residential\"],\"node.solarPanel.preset.residentialLarge\":[\"Residential Large\"],\"node.spawn.description\":[\"Player or camera origin within a level. One per level.\"],\"node.spawn.label\":[\"Spawn Point\"],\"node.stair.constructionControls.body\":[\"Body\"],\"node.stair.constructionControls.centerStringer\":[\"Center stringer\"],\"node.stair.constructionControls.closedRisers\":[\"Closed risers\"],\"node.stair.constructionControls.inherit\":[\"Inherit\"],\"node.stair.constructionControls.nosing\":[\"Nosing\"],\"node.stair.constructionControls.open\":[\"Open\"],\"node.stair.constructionControls.original\":[\"Original\"],\"node.stair.constructionControls.riserThickness\":[\"Riser thickness\"],\"node.stair.constructionControls.sideStringers\":[\"Side stringers\"],\"node.stair.constructionControls.solid\":[\"Solid\"],\"node.stair.constructionControls.stringerDepth\":[\"Stringer depth\"],\"node.stair.constructionControls.stringerWidth\":[\"Stringer width\"],\"node.stair.constructionControls.treadFinish\":[\"Tread finish\"],\"node.stair.constructionControls.treadThickness\":[\"Tread thickness\"],\"node.stair.constructionControls.waist\":[\"Waist\"],\"node.stair.constructionControls.waistThickness\":[\"Waist thickness\"],\"node.stair.description\":[\"A stair composed of one or more flights with configurable treads, risers, railings.\"],\"node.stair.diagnostic.arrivalMismatch\":[\"The flight chain does not reach the declared destination.\"],\"node.stair.diagnostic.comfortTarget\":[\"Two risers plus going is outside the 0.60–0.65 m design range.\"],\"node.stair.diagnostic.goingTarget\":[\"Going is below the design target.\"],\"node.stair.diagnostic.headroomTarget\":[\"Overhead surfaces leave less than the target headroom.\"],\"node.stair.diagnostic.headroomUnresolved\":[\"Detailed headroom could not be evaluated: check riser counts and the surface query budget.\"],\"node.stair.diagnostic.invalidFlight\":[\"Flight dimensions and integer riser count must be positive.\"],\"node.stair.diagnostic.invalidRise\":[\"The destination must be above the stair base.\"],\"node.stair.diagnostic.landingOverlap\":[\"Landing depth exceeds a full circle at the walking line; the visible landing is limited to one circle.\"],\"node.stair.diagnostic.narrowWinderEnd\":[\"The narrow end of a winder tread is below 0.10 m; check the intended stair use.\"],\"node.stair.diagnostic.nonuniformRisers\":[\"Flight riser heights differ. Use uniform-riser repair only if this is a proposed design.\"],\"node.stair.diagnostic.raisedLanding\":[\"A landing has a stored rise; inspect its transition before repair.\"],\"node.stair.diagnostic.riserTarget\":[\"Riser height exceeds the design target.\"],\"node.stair.label\":[\"Stair\"],\"node.stair.layout.straight\":[\"Straight\"],\"node.stair.layout.turn\":[[\"layout\"],\" turn\"],\"node.stair.panel.actions\":[\"Actions\"],\"node.stair.panel.addFlight\":[\"Add flight\"],\"node.stair.panel.addLanding\":[\"Add landing\"],\"node.stair.panel.applyLabelLayout\":[\"Apply \",[\"label\"],\" layout\"],\"node.stair.panel.autoCutout\":[\"Auto Cutout\"],\"node.stair.panel.balusters\":[\"Balusters\"],\"node.stair.panel.boards\":[\"Boards\"],\"node.stair.panel.both\":[\"Both\"],\"node.stair.panel.cable\":[\"Cable\"],\"node.stair.panel.centerColumn\":[\"Center Column\"],\"node.stair.panel.clockwise\":[\"Clockwise\"],\"node.stair.panel.connectedTo\":[\"Connected to \",[\"surface\"],\". Move the stair to connect to another edge.\"],\"node.stair.panel.connectedToSurface\":[\"Connected to a surface. Move the stair to connect to another edge.\"],\"node.stair.panel.construction\":[\"Construction\"],\"node.stair.panel.counterclockwise\":[\"Counterclockwise\"],\"node.stair.panel.curved\":[\"Curved\"],\"node.stair.panel.customRise\":[\"Custom rise\"],\"node.stair.panel.deck\":[\"Deck\"],\"node.stair.panel.delete\":[\"Delete\"],\"node.stair.panel.designTargets\":[\"Design targets\"],\"node.stair.panel.destination\":[\"Destination\"],\"node.stair.panel.dragNearADeckPatioConcrete\":[\"Drag near a deck, patio, concrete slab, or landing edge to fit the stair.\"],\"node.stair.panel.duplicate\":[\"Duplicate\"],\"node.stair.panel.equalAngle\":[\"Equal angle\"],\"node.stair.panel.equalGoing\":[\"Equal going\"],\"node.stair.panel.fitRisersAndGoing\":[\"Fit risers and going\"],\"node.stair.panel.fitToFloor\":[\"Fit To Floor\"],\"node.stair.panel.fitUniformRisers\":[\"Fit uniform risers\"],\"node.stair.panel.flightMeasurements\":[\"Flight \",[\"number\"],\": \",[\"count\",\"plural\",{\"one\":[[\"riserCount\"],\" riser\"],\"other\":[[\"riserCount\"],\" risers\"]}],\" · R \",[\"riser\"],\" · T \",[\"going\"],\" · \",[\"slope\"]],\"node.stair.panel.floorsCeilingsAndStairsOnly\":[\"Floors, ceilings and stairs only.\"],\"node.stair.panel.followsDeck\":[\"Follows deck\"],\"node.stair.panel.followsLevel\":[\"Follows level\"],\"node.stair.panel.fromLevel\":[\"From Level\"],\"node.stair.panel.geometry\":[\"Geometry\"],\"node.stair.panel.glass\":[\"Glass\"],\"node.stair.panel.headroom\":[\"Headroom:\"],\"node.stair.panel.height\":[\"Height\"],\"node.stair.panel.innerGap\":[\"Inner gap\"],\"node.stair.panel.innerRadius\":[\"Inner Radius\"],\"node.stair.panel.integrated\":[\"Integrated\"],\"node.stair.panel.landing\":[\"Landing\"],\"node.stair.panel.layout\":[\"Layout\"],\"node.stair.panel.left\":[\"Left\"],\"node.stair.panel.leftTurn\":[\"Left turn\"],\"node.stair.panel.measurements\":[\"Measurements\"],\"node.stair.panel.metal\":[\"Metal\"],\"node.stair.panel.move\":[\"Move\"],\"node.stair.panel.movingThisStairKeepsItsCurrent\":[\"Moving this stair keeps its current rise, steps, and run.\"],\"node.stair.panel.noOverheadSurface\":[\"No overhead surface\"],\"node.stair.panel.none\":[\"None\"],\"node.stair.panel.notEvaluated\":[\"Not evaluated\"],\"node.stair.panel.opening\":[\"Opening\"],\"node.stair.panel.openingOffset\":[\"Opening Offset\"],\"node.stair.panel.position\":[\"Position\"],\"node.stair.panel.postRail\":[\"Post & rail\"],\"node.stair.panel.railing\":[\"Railing\"],\"node.stair.panel.right\":[\"Right\"],\"node.stair.panel.rightTurn\":[\"Right turn\"],\"node.stair.panel.rise\":[\"Rise\"],\"node.stair.panel.rotation\":[\"Rotation\"],\"node.stair.panel.segmentType\":[[\"type\",\"select\",{\"landing\":[\"Landing\"],\"other\":[\"Stair\"]}]],\"node.stair.panel.segments\":[\"Segments\"],\"node.stair.panel.sizing\":[\"Sizing\"],\"node.stair.panel.snapToNearbySurfaces\":[\"Snap to nearby surfaces\"],\"node.stair.panel.spiral\":[\"Spiral\"],\"node.stair.panel.staircase\":[\"Staircase\"],\"node.stair.panel.stepSupports\":[\"Step Supports\"],\"node.stair.panel.steps\":[\"Steps\"],\"node.stair.panel.straight\":[\"Straight\"],\"node.stair.panel.style\":[\"Style\"],\"node.stair.panel.surfaceConnection\":[\"Surface connection\"],\"node.stair.panel.sweep\":[\"Sweep\"],\"node.stair.panel.targetGoing\":[\"Target going\"],\"node.stair.panel.targetHeadroom\":[\"Target headroom\"],\"node.stair.panel.targetMaxRiser\":[\"Target max riser\"],\"node.stair.panel.targetMinimumGoing\":[\"Target minimum going\"],\"node.stair.panel.thickness\":[\"Thickness\"],\"node.stair.panel.to\":[\"To\"],\"node.stair.panel.topLanding\":[\"Top Landing\"],\"node.stair.panel.type\":[\"Type\"],\"node.stair.panel.unavailable\":[\"Unavailable\"],\"node.stair.panel.walkingLineOffset\":[\"Walking line offset\"],\"node.stair.panel.width\":[\"Width\"],\"node.stair.panel.winder\":[\"Winder\"],\"node.stair.railingControls.both\":[\"Both\"],\"node.stair.railingControls.bottomExtension\":[\"Bottom sloped extension\"],\"node.stair.railingControls.continuous\":[\"Continuous\"],\"node.stair.railingControls.floor\":[\"Floor\"],\"node.stair.railingControls.handrailDiameter\":[\"Handrail diameter\"],\"node.stair.railingControls.handrailHeight\":[\"Handrail height\"],\"node.stair.railingControls.handrailInset\":[\"Handrail inset\"],\"node.stair.railingControls.left\":[\"Left\"],\"node.stair.railingControls.noReturn\":[\"No return\"],\"node.stair.railingControls.none\":[\"None\"],\"node.stair.railingControls.originalLayout\":[\"Original layout\"],\"node.stair.railingControls.postFacing\":[\"Post-facing\"],\"node.stair.railingControls.returnLength\":[\"Return length\"],\"node.stair.railingControls.right\":[\"Right\"],\"node.stair.railingControls.separateHandrail\":[\"Separate handrail\"],\"node.stair.railingControls.setTheLengthToReachThe\":[\"Set the length to reach the wall or post.\"],\"node.stair.railingControls.topExtension\":[\"Top horizontal extension\"],\"node.stair.railingControls.wallFacing\":[\"Wall-facing\"],\"node.stairSegment.description\":[\"A single flight of a parent stair.\"],\"node.stairSegment.label\":[\"Stair Segment\"],\"node.stairSegment.panel.actions\":[\"Actions\"],\"node.stairSegment.panel.attachment\":[\"Attachment\"],\"node.stairSegment.panel.delete\":[\"Delete\"],\"node.stairSegment.panel.dimensions\":[\"Dimensions\"],\"node.stairSegment.panel.duplicate\":[\"Duplicate\"],\"node.stairSegment.panel.editingSwitchesTheStairToCustom\":[\"Editing switches the stair to Custom rise\"],\"node.stairSegment.panel.equalAngle\":[\"Equal angle\"],\"node.stairSegment.panel.equalGoing\":[\"Equal going\"],\"node.stairSegment.panel.fillToFloor\":[\"Fill to floor\"],\"node.stairSegment.panel.flight\":[\"Flight\"],\"node.stairSegment.panel.flightShape\":[\"Flight shape\"],\"node.stairSegment.panel.front\":[\"Front\"],\"node.stairSegment.panel.height\":[\"Height\"],\"node.stairSegment.panel.innerGap\":[\"Inner gap\"],\"node.stairSegment.panel.landing\":[\"Landing\"],\"node.stairSegment.panel.left\":[\"Left\"],\"node.stairSegment.panel.leftTurn\":[\"Left turn\"],\"node.stairSegment.panel.length\":[\"Length\"],\"node.stairSegment.panel.move\":[\"Move\"],\"node.stairSegment.panel.position\":[\"Position\"],\"node.stairSegment.panel.right\":[\"Right\"],\"node.stairSegment.panel.rightTurn\":[\"Right turn\"],\"node.stairSegment.panel.rotation\":[\"Rotation\"],\"node.stairSegment.panel.stairSegment\":[\"Stair Segment\"],\"node.stairSegment.panel.steps\":[\"Steps\"],\"node.stairSegment.panel.straight\":[\"Straight\"],\"node.stairSegment.panel.structure\":[\"Structure\"],\"node.stairSegment.panel.thickness\":[\"Thickness\"],\"node.stairSegment.panel.type\":[\"Type\"],\"node.stairSegment.panel.walkingLineOffset\":[\"Walking line offset\"],\"node.stairSegment.panel.width\":[\"Width\"],\"node.stairSegment.panel.winder\":[\"Winder\"],\"node.structuralGrid.description\":[\"Persistent construction grid axis with identification bubbles.\"],\"node.structuralGrid.label\":[\"Structural Grid\"],\"node.turbineVent.description\":[\"Wind-driven spinning whirlybird exhaust vent for a roof slope.\"],\"node.turbineVent.label\":[\"Turbine Vent\"],\"node.turbineVent.panel.actions\":[\"Actions\"],\"node.turbineVent.panel.cylinder\":[\"Cylinder\"],\"node.turbineVent.panel.delete\":[\"Delete\"],\"node.turbineVent.panel.diameter\":[\"Diameter\"],\"node.turbineVent.panel.dimensions\":[\"Dimensions\"],\"node.turbineVent.panel.duplicate\":[\"Duplicate\"],\"node.turbineVent.panel.globe\":[\"Globe\"],\"node.turbineVent.panel.height\":[\"Height\"],\"node.turbineVent.panel.motion\":[\"Motion\"],\"node.turbineVent.panel.move\":[\"Move\"],\"node.turbineVent.panel.neckHeight\":[\"Neck Height\"],\"node.turbineVent.panel.pause\":[\"Pause\"],\"node.turbineVent.panel.play\":[\"Play\"],\"node.turbineVent.panel.position\":[\"Position\"],\"node.turbineVent.panel.rotation\":[\"Rotation\"],\"node.turbineVent.panel.spinSpeed\":[\"Spin Speed\"],\"node.turbineVent.panel.style\":[\"Style\"],\"node.turbineVent.panel.turbineVent\":[\"Turbine Vent\"],\"node.turbineVent.panel.vanes\":[\"Vanes\"],\"node.unit.description\":[\"A named group of zones forming one apartment, hotel room or commercial lot.\"],\"node.unit.kind.apartment\":[\"Apartment\"],\"node.unit.kind.commercial\":[\"Commercial\"],\"node.unit.kind.common\":[\"Common\"],\"node.unit.kind.hotelRoom\":[\"Hotel room\"],\"node.unit.label\":[\"Unit\"],\"node.unit.panel.memberRoom\":[\"Room\"],\"node.unit.panel.memberZone\":[\"Zone\"],\"node.unit.panel.noZonesAssigned\":[\"No zones assigned yet.\"],\"node.unit.panel.nonAdjacentLevels\":[\"Members sit on levels that are not adjacent.\"],\"node.unit.panel.removeMember\":[\"Remove \",[\"name\"],\" from unit\"],\"node.unit.panel.removeZone\":[\"Remove zone from unit\"],\"node.unit.unitPanel.actions\":[\"Actions\"],\"node.unit.unitPanel.color\":[\"Color\"],\"node.unit.unitPanel.delete\":[\"Delete\"],\"node.unit.unitPanel.focus\":[\"Focus\"],\"node.unit.unitPanel.grossArea\":[\"Gross area\"],\"node.unit.unitPanel.kind\":[\"Kind\"],\"node.unit.unitPanel.levels\":[\"Levels\"],\"node.unit.unitPanel.members\":[\"Members\"],\"node.unit.unitPanel.name\":[\"Name\"],\"node.unit.unitPanel.noRoomsYetPickThisUnit\":[\"No rooms yet. Pick this unit from a room's panel, or draw zones while it is focused.\"],\"node.unit.unitPanel.report\":[\"Report\"],\"node.unit.unitPanel.unit\":[\"Unit\"],\"node.wall.actions.mergeWalls\":[\"Merge walls\"],\"node.wall.actions.splitWall\":[\"Split wall\"],\"node.wall.curtain.cell\":[\"Column \",[\"column\"],\", row \",[\"row\"],\": \",[\"type\",\"select\",{\"glass\":[\"glass\"],\"solid\":[\"solid\"],\"other\":[\"empty\"]}]],\"node.wall.curtain.columnSpacing\":[[\"count\",\"plural\",{\"one\":[[\"number\"],\" column\"],\"other\":[[\"number\"],\" columns\"]}],\" · \",[\"spacing\"],\" grid spacing\"],\"node.wall.curtain.noPanels\":[\"No panels\"],\"node.wall.curtain.rowSpacing\":[[\"count\",\"plural\",{\"one\":[[\"number\"],\" row\"],\"other\":[[\"number\"],\" rows\"]}],\" · \",[\"spacing\"],\" grid spacing\"],\"node.wall.curtainWallPanel.applyTint\":[\"Apply tint\"],\"node.wall.curtainWallPanel.borderOpeningFrame\":[\"Border / opening frame\"],\"node.wall.curtainWallPanel.bottom\":[\"Bottom\"],\"node.wall.curtainWallPanel.bottomRow\":[\"Bottom row\"],\"node.wall.curtainWallPanel.cancelTint\":[\"Cancel tint\"],\"node.wall.curtainWallPanel.center\":[\"Center\"],\"node.wall.curtainWallPanel.chooseACellOrEnterIts\":[\"Choose a cell or enter its column and row. Use arrow keys to move between cells. Columns run from the wall start; rows count upward.\"],\"node.wall.curtainWallPanel.clearHiddenOverrides\":[\"Clear hidden overrides\"],\"node.wall.curtainWallPanel.column\":[\"Column\"],\"node.wall.curtainWallPanel.columnLayout\":[\"Column layout\"],\"node.wall.curtainWallPanel.columnRow\":[\"Column \",[\"column\"],\", row \",[\"row\"]],\"node.wall.curtainWallPanel.construction\":[\"Construction\"],\"node.wall.curtainWallPanel.continuousMullionsAndTransomsAssembledAlong\":[\"Continuous mullions and transoms assembled along the wall.\"],\"node.wall.curtainWallPanel.curtainWallPanelSelection\":[\"Curtain wall panel selection\"],\"node.wall.curtainWallPanel.customInfill\":[\"Custom infill\"],\"node.wall.curtainWallPanel.defaultPanel\":[\"Default panel\"],\"node.wall.curtainWallPanel.editIndividualPanels\":[\"Edit individual panels\"],\"node.wall.curtainWallPanel.effectiveThicknessLimited\":[\"Effective thickness: \",[\"thickness\"],\", limited by frame depth.\"],\"node.wall.curtainWallPanel.empty\":[\"Empty\"],\"node.wall.curtainWallPanel.enablePanelEditing\":[\"Enable panel editing\"],\"node.wall.curtainWallPanel.end\":[\"End\"],\"node.wall.curtainWallPanel.fixedSpacing\":[\"Fixed spacing\"],\"node.wall.curtainWallPanel.followingWallDefaults\":[\"Following wall defaults\"],\"node.wall.curtainWallPanel.frameDimensions\":[\"Frame dimensions\"],\"node.wall.curtainWallPanel.framing\":[\"Framing\"],\"node.wall.curtainWallPanel.fullyCapped\":[\"Fully capped\"],\"node.wall.curtainWallPanel.glass\":[\"Glass\"],\"node.wall.curtainWallPanel.glassAppearance\":[\"Glass appearance\"],\"node.wall.curtainWallPanel.glassAppearanceIsControlledByThe\":[\"Glass appearance is controlled by the paint tool.\"],\"node.wall.curtainWallPanel.glassTint\":[\"Glass tint\"],\"node.wall.curtainWallPanel.glazingGap\":[\"Glazing gap\"],\"node.wall.curtainWallPanel.gridLimitedTo32PanelsPer\":[\"Grid limited to 32 panels per axis. Spacing expands to fit this wall.\"],\"node.wall.curtainWallPanel.hiddenCustomPanelCount\":[[\"length\",\"plural\",{\"one\":[[\"number\"],\" custom panel is outside this grid. It returns if the grid expands.\"],\"other\":[[\"number\"],\" custom panels are outside this grid. They return if the grid expands.\"]}]],\"node.wall.curtainWallPanel.horizontalCaps\":[\"Horizontal caps\"],\"node.wall.curtainWallPanel.horizontalFrameWidth\":[\"Horizontal frame width\"],\"node.wall.curtainWallPanel.layout\":[\"Layout\"],\"node.wall.curtainWallPanel.lowRoughnessIsSmoothHighRoughness\":[\"Low roughness is smooth; high roughness gives a matte surface in rendered shading.\"],\"node.wall.curtainWallPanel.maximumSpacing\":[\"Maximum spacing\"],\"node.wall.curtainWallPanel.moduleJointWidth\":[\"Module joint width\"],\"node.wall.curtainWallPanel.none\":[\"None\"],\"node.wall.curtainWallPanel.opacity\":[\"Opacity\"],\"node.wall.curtainWallPanel.opaqueBand\":[\"Opaque band\"],\"node.wall.curtainWallPanel.opaqueBandsReplaceAFullRow\":[\"Opaque bands replace a full row with solid panels. Apply their finish with the paint tool.\"],\"node.wall.curtainWallPanel.panelCount\":[\"Panel count\"],\"node.wall.curtainWallPanel.panelInfill\":[\"Panel infill\"],\"node.wall.curtainWallPanel.panelThickness\":[\"Panel thickness\"],\"node.wall.curtainWallPanel.panels\":[\"Panels\"],\"node.wall.curtainWallPanel.resetThisPanel\":[\"Reset this panel\"],\"node.wall.curtainWallPanel.row2\":[\"Row\"],\"node.wall.curtainWallPanel.rowLayout\":[\"Row layout\"],\"node.wall.curtainWallPanel.separateFramedModulesWithJointsBetween\":[\"Separate framed modules with joints between units.\"],\"node.wall.curtainWallPanel.solid\":[\"Solid\"],\"node.wall.curtainWallPanel.spacing\":[\"Spacing\"],\"node.wall.curtainWallPanel.start\":[\"Start\"],\"node.wall.curtainWallPanel.stickBuilt\":[\"Stick-built\"],\"node.wall.curtainWallPanel.structuralGlazing\":[\"Structural glazing\"],\"node.wall.curtainWallPanel.surfaceRoughness\":[\"Surface roughness\"],\"node.wall.curtainWallPanel.top\":[\"Top\"],\"node.wall.curtainWallPanel.topRow\":[\"Top row\"],\"node.wall.curtainWallPanel.uncappedMembersSitBehindTheGlazing\":[\"Uncapped members sit behind the glazing.\"],\"node.wall.curtainWallPanel.unitized\":[\"Unitized\"],\"node.wall.curtainWallPanel.useGlassSettingsInstead\":[\"Use glass settings instead\"],\"node.wall.curtainWallPanel.useTheDoorOrWindowTool\":[\"Use the Door or Window tool to add an opening through the wall.\"],\"node.wall.curtainWallPanel.verticalCaps\":[\"Vertical caps\"],\"node.wall.curtainWallPanel.verticalFrameWidth\":[\"Vertical frame width\"],\"node.wall.curtainWallPanel.wallSystem\":[\"Wall system\"],\"node.wall.description\":[\"A straight or curved wall segment. Hosts doors, windows, lean-to extensions, and wall-mounted items.\"],\"node.wall.label\":[\"Wall\"],\"node.wall.panel.actions\":[\"Actions\"],\"node.wall.panel.assembly\":[\"Assembly\"],\"node.wall.panel.auto\":[\"Auto\"],\"node.wall.panel.both\":[\"Both\"],\"node.wall.panel.bottom\":[\"Bottom\"],\"node.wall.panel.brickVeneer\":[\"Brick veneer\"],\"node.wall.panel.chairRail\":[\"Chair rail\"],\"node.wall.panel.cmu\":[\"CMU\"],\"node.wall.panel.colonial\":[\"Colonial\"],\"node.wall.panel.cove\":[\"Cove\"],\"node.wall.panel.craft\":[\"Craft\"],\"node.wall.panel.crownMolding\":[\"Crown molding\"],\"node.wall.panel.curtainWall\":[\"Curtain wall\"],\"node.wall.panel.curve\":[\"Curve\"],\"node.wall.panel.custom\":[\"Custom\"],\"node.wall.panel.customHeight\":[\"Custom height\"],\"node.wall.panel.depth\":[\"Depth\"],\"node.wall.panel.dimensions\":[\"Dimensions\"],\"node.wall.panel.drywall\":[\"Drywall\"],\"node.wall.panel.extendsDownwardToMeetTheTerrain\":[\"Extends downward to meet the terrain. Height and top stay unchanged.\"],\"node.wall.panel.exterior\":[\"Exterior\"],\"node.wall.panel.fiberCement\":[\"Fiber cement\"],\"node.wall.panel.fillToTerrain\":[\"Fill to terrain\"],\"node.wall.panel.flat\":[\"Flat\"],\"node.wall.panel.followsLevel\":[\"Follows level\"],\"node.wall.panel.frameDepth\":[\"Frame depth\"],\"node.wall.panel.framing\":[\"Framing\"],\"node.wall.panel.gypsum\":[\"Gypsum\"],\"node.wall.panel.height\":[\"Height\"],\"node.wall.panel.hideCode\":[\"Hide code\"],\"node.wall.panel.icf\":[\"ICF\"],\"node.wall.panel.interior\":[\"Interior\"],\"node.wall.panel.lapSiding\":[\"Lap siding\"],\"node.wall.panel.layerThicknessesFollowThe2021Irc\":[\"Layer thicknesses follow the 2021 IRC assembly data. Drafting aid, not engineering — verify with the authority having jurisdiction.\"],\"node.wall.panel.layered\":[\"Layered\"],\"node.wall.panel.length\":[\"Length\"],\"node.wall.panel.loading\":[\"Loading…\"],\"node.wall.panel.modern\":[\"Modern\"],\"node.wall.panel.none\":[\"None\"],\"node.wall.panel.noneSingleLayer\":[\"None (single layer)\"],\"node.wall.panel.offset\":[\"Offset\"],\"node.wall.panel.ogee\":[\"Ogee\"],\"node.wall.panel.osb\":[\"OSB\"],\"node.wall.panel.partitionTheInteriorFinishIsApplied\":[\"Partition: the interior finish is applied to both faces.\"],\"node.wall.panel.picture\":[\"Picture\"],\"node.wall.panel.plaster\":[\"Plaster\"],\"node.wall.panel.plywood\":[\"Plywood\"],\"node.wall.panel.preset\":[\"Preset\"],\"node.wall.panel.reference\":[\"Reference\"],\"node.wall.panel.remove\":[\"Remove\"],\"node.wall.panel.round\":[\"Round\"],\"node.wall.panel.scriptedFinish\":[\"Scripted finish\"],\"node.wall.panel.sheathing\":[\"Sheathing\"],\"node.wall.panel.shoe\":[\"Shoe\"],\"node.wall.panel.sideA\":[\"Side A\"],\"node.wall.panel.sideB\":[\"Side B\"],\"node.wall.panel.sideFace\":[\"Side \",[\"face\"]],\"node.wall.panel.skirting\":[\"Skirting\"],\"node.wall.panel.standard\":[\"Standard\"],\"node.wall.panel.steelStuds\":[\"Steel studs\"],\"node.wall.panel.step\":[\"Step\"],\"node.wall.panel.stoneVeneer\":[\"Stone veneer\"],\"node.wall.panel.stucco\":[\"Stucco\"],\"node.wall.panel.thickness\":[\"Thickness\"],\"node.wall.panel.thicknessFromAssembly\":[[\"thickness\"],\" · from assembly\"],\"node.wall.panel.top\":[\"Top\"],\"node.wall.panel.totalThickness\":[\"Total thickness\"],\"node.wall.panel.unverifiedPresetnote\":[\"Unverified: \",[\"presetNote\"]],\"node.wall.panel.viewCode\":[\"View code\"],\"node.wall.panel.wall\":[\"Wall\"],\"node.wall.panel.wallType\":[\"Wall type\"],\"node.wall.panel.whichFaceIsOutsideIsUndetermined\":[\"Which face is outside is undetermined (no room detected on either side) — the exterior layers are drawn on side B.\"],\"node.wall.panel.woodStuds\":[\"Wood studs\"],\"node.wall.reference.center\":[\"Center\"],\"node.wall.reference.inside\":[\"Inside face\"],\"node.wall.reference.left\":[\"Left\"],\"node.wall.reference.outside\":[\"Outside face\"],\"node.wall.reference.right\":[\"Right\"],\"node.wall.trim.hide\":[[\"trim\",\"select\",{\"skirting\":[\"Hide skirting\"],\"crown\":[\"Hide crown molding\"],\"other\":[\"Hide chair rail\"]}]],\"node.wall.trim.show\":[[\"trim\",\"select\",{\"skirting\":[\"Show skirting\"],\"crown\":[\"Show crown molding\"],\"other\":[\"Show chair rail\"]}]],\"node.window.description\":[\"A window cut into a wall. Animated open/close for opening windows.\"],\"node.window.label\":[\"Window\"],\"node.window.operation.raise\":[\"Raise\"],\"node.window.operation.slats\":[\"Slats\"],\"node.window.operation.slide\":[\"Slide\"],\"node.window.operation.swing\":[\"Swing\"],\"node.window.operation.tilt\":[\"Tilt\"],\"node.window.panel.actions\":[\"Actions\"],\"node.window.panel.all\":[\"All\"],\"node.window.panel.arch\":[\"Arch\"],\"node.window.panel.archHeight\":[\"Arch Height\"],\"node.window.panel.auto\":[\"Auto\"],\"node.window.panel.autoFollowsTheWall\":[\"Auto follows the wall\"],\"node.window.panel.colWidths\":[\"Col Widths\"],\"node.window.panel.columns\":[\"Columns\"],\"node.window.panel.corner\":[\"Corner\"],\"node.window.panel.cornerPost\":[\"Corner post\"],\"node.window.panel.cornerRadius\":[\"Corner Radius\"],\"node.window.panel.customThePanesMatchNoStyle\":[\"Custom: the panes match no style.\"],\"node.window.panel.delete\":[\"Delete\"],\"node.window.panel.depth\":[\"Depth\"],\"node.window.panel.dimensions\":[\"Dimensions\"],\"node.window.panel.divider\":[\"Divider\"],\"node.window.panel.down\":[\"Down\"],\"node.window.panel.duplicate\":[\"Duplicate\"],\"node.window.panel.enableSill\":[\"Enable Sill\"],\"node.window.panel.flipSide\":[\"Flip Side\"],\"node.window.panel.frame\":[\"Frame\"],\"node.window.panel.frameDepthAuto\":[\"Depth (auto)\"],\"node.window.panel.french\":[\"French\"],\"node.window.panel.fusedGlass\":[\"Fused glass\"],\"node.window.panel.grid\":[\"Grid\"],\"node.window.panel.height\":[\"Height\"],\"node.window.panel.individual\":[\"Individual\"],\"node.window.panel.left\":[\"Left\"],\"node.window.panel.move\":[\"Move\"],\"node.window.panel.opening\":[\"Opening\"],\"node.window.panel.openingShape\":[\"Opening Shape\"],\"node.window.panel.otherSide\":[\"Other side\"],\"node.window.panel.pos\":[\"pos\"],\"node.window.panel.position\":[\"Position\"],\"node.window.panel.rect\":[\"Rect\"],\"node.window.panel.revealRadius\":[\"Reveal Radius\"],\"node.window.panel.right\":[\"Right\"],\"node.window.panel.rounded\":[\"Rounded\"],\"node.window.panel.rowHeights\":[\"Row Heights\"],\"node.window.panel.rows\":[\"Rows\"],\"node.window.panel.sill\":[\"Sill\"],\"node.window.panel.single\":[\"Single\"],\"node.window.panel.sizeIsLimitedToTheWall\":[\"Size is limited to the wall, including clearance for the opening frame.\"],\"node.window.panel.style\":[\"Style\"],\"node.window.panel.thickness\":[\"Thickness\"],\"node.window.panel.thisSide\":[\"This side\"],\"node.window.panel.topShape\":[\"Top Shape\"],\"node.window.panel.type\":[\"Type\"],\"node.window.panel.unwrap\":[\"Unwrap\"],\"node.window.panel.up\":[\"Up\"],\"node.window.panel.width\":[\"Width\"],\"node.window.panel.window\":[\"Window\"],\"node.window.panel.windowType\":[\"Window Type\"],\"node.window.panel.wrapTheCorner\":[\"Wrap the corner\"],\"node.window.panel.wrapsTheCornerWithNamed\":[\"Wraps the corner with \",[\"partner\"]],\"node.window.panel.wrapsTheCornerWithPartner\":[\"Wraps the corner with its partner\"],\"node.window.style.casement\":[\"Casement\"],\"node.window.style.doubleHung\":[\"Double-hung\"],\"node.window.style.grid\":[\"Grid\"],\"node.window.style.horizontalBands\":[\"Horizontal bands\"],\"node.window.style.picture\":[\"Picture\"],\"node.window.style.single\":[\"Single\"],\"node.window.style.sliding\":[\"Sliding\"],\"node.window.style.tallGrid\":[\"Tall grid\"],\"node.window.style.transom\":[\"Transom\"],\"node.window.style.tripleHung\":[\"Triple-hung\"],\"node.window.style.wideGrid\":[\"Wide grid\"],\"node.window.type.awning\":[\"Awning\"],\"node.window.type.bay\":[\"Bay\"],\"node.window.type.bow\":[\"Bow\"],\"node.window.type.casement\":[\"Casement\"],\"node.window.type.doubleHung\":[\"Double Hung\"],\"node.window.type.fixed\":[\"Fixed\"],\"node.window.type.hopper\":[\"Hopper\"],\"node.window.type.louvered\":[\"Louvered\"],\"node.window.type.singleHung\":[\"Single Hung\"],\"node.window.type.sliding\":[\"Sliding\"],\"node.zone.description\":[\"A polygonal site zone (lawn, water, paving) with a TSL gradient material.\"],\"node.zone.label\":[\"Zone\"],\"node.zone.quantitiesPanel.enclosedRoom\":[\"Enclosed room\"],\"node.zone.quantitiesPanel.floorSurface\":[\"Floor surface\"],\"node.zone.quantitiesPanel.footprintOnly\":[\"Footprint only\"],\"node.zone.quantitiesPanel.none\":[\"None\"],\"node.zone.quantitiesPanel.notProven\":[\"Not proven\"],\"node.zone.quantitiesPanel.roomQuantities\":[\"Room quantities\"],\"node.zone.quantitiesPanel.topViewWithZoneEdgeDimensions\":[\"Top view with zone edge dimensions\"],\"node.zone.quantitiesPanel.unit\":[\"Unit\"],\"node.zone.quantitiesPanel.volume\":[\"Volume\"],\"node.zone.quantitiesPanel.wallSurface\":[\"Wall surface\"],\"node.zone.quantitiesPanel.zoneBoundaryUnavailable\":[\"Zone boundary unavailable\"],\"node.zone.quantitiesPanel.zoneQuantities\":[\"Zone quantities\"],\"viewer.camera.orbitLeft\":[\"Orbit left\"],\"viewer.camera.orbitRight\":[\"Orbit right\"],\"viewer.camera.topView\":[\"Top view\"],\"viewer.common.off\":[\"Off\"],\"viewer.common.on\":[\"On\"],\"viewer.display.camera\":[\"Camera\"],\"viewer.display.colored\":[\"Colored\"],\"viewer.display.colors\":[\"Colors\"],\"viewer.display.edges.off\":[\"Off\"],\"viewer.display.edges.offDetail\":[\"No edge lines\"],\"viewer.display.edges.soft\":[\"Soft\"],\"viewer.display.edges.softDetail\":[\"Faint outline of major creases\"],\"viewer.display.edges.strong\":[\"Strong\"],\"viewer.display.edges.strongDetail\":[\"Crisp, opaque edge lines\"],\"viewer.display.edges.title\":[\"Edges\"],\"viewer.display.monochrome\":[\"Monochrome\"],\"viewer.display.orthographic\":[\"Orthographic\"],\"viewer.display.perspective\":[\"Perspective\"],\"viewer.display.render.rendered\":[\"Rendered\"],\"viewer.display.render.renderedDetail\":[\"Full ambient occlusion\"],\"viewer.display.render.solid\":[\"Solid\"],\"viewer.display.render.solidDetail\":[\"Flat and fast — no ambient occlusion\"],\"viewer.display.render.title\":[\"Render\"],\"viewer.display.shadows\":[\"Shadows\"],\"viewer.display.title\":[\"Display settings\"],\"viewer.floorplan.alignNorth\":[\"Align view to north\"],\"viewer.floorplan.empty\":[\"No floor plans are available for this scene.\"],\"viewer.floorplan.fit\":[\"Fit floor plan\"],\"viewer.floorplan.floor\":[\"Floor\"],\"viewer.floorplan.floorPlan\":[\"Floor plan\"],\"viewer.floorplan.viewLabel\":[[\"floor\"],\" 2D view\"],\"viewer.floorplan.zoomIn\":[\"Zoom in\"],\"viewer.floorplan.zoomOut\":[\"Zoom out\"],\"viewer.header.back\":[\"Back\"],\"viewer.header.levels\":[\"Levels\"],\"viewer.header.rooms\":[\"Rooms\"],\"viewer.header.selection\":[\"Selection\"],\"viewer.header.units\":[\"Units\"],\"viewer.header.untitled\":[\"Untitled\"],\"viewer.header.zones\":[\"Zones\"],\"viewer.levels.exploded\":[\"Exploded\"],\"viewer.levels.label\":[\"Levels: \",[\"mode\"]],\"viewer.levels.manual\":[\"Manual\"],\"viewer.levels.solo\":[\"Solo\"],\"viewer.levels.stacked\":[\"Stacked\"],\"viewer.stage.layout\":[\"Viewer layout\"],\"viewer.stage.split\":[\"Split\"],\"viewer.theme.blueprint\":[\"Blueprint\"],\"viewer.theme.mediterranean\":[\"Mediterranean\"],\"viewer.theme.night\":[\"Night\"],\"viewer.theme.overcast\":[\"Overcast\"],\"viewer.theme.paper\":[\"Paper\"],\"viewer.theme.studio\":[\"Studio\"],\"viewer.theme.sunset\":[\"Sunset\"],\"viewer.theme.title\":[\"Scene theme\"],\"viewer.theme.twilight\":[\"Twilight\"],\"viewer.theme.verdant\":[\"Verdant\"],\"viewer.visibility.guides\":[\"Guides\"],\"viewer.visibility.scans\":[\"Scans\"],\"viewer.visibility.title\":[\"Visibility\"],\"viewer.walkthrough.label\":[\"Walkthrough: \",[\"state\"]],\"viewer.walls.cutaway\":[\"Cutaway\"],\"viewer.walls.fullHeight\":[\"Full height\"],\"viewer.walls.label\":[\"Walls: \",[\"mode\"]],\"viewer.walls.low\":[\"Low\"]}")as Messages; \ No newline at end of file +/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"app.appShell.pascalHome\":[\"Pascal home\"],\"app.buildTab.addGate\":[\"Add Gate\"],\"app.buildTab.addOpenPassage\":[\"Add Open Passage\"],\"app.buildTab.addToRooms\":[\"Add to rooms\"],\"app.buildTab.allBuildTools\":[\"← All build tools\"],\"app.buildTab.chooseGateOrOpenPassageThen\":[\"Choose Gate or Open Passage, then click its position on any fence. Find placed gates and openings under their fence in the scene graph.\"],\"app.buildTab.clickALinesetToLayThe\":[\"Click a lineset to lay the line beside it.\"],\"app.buildTab.doubleGate\":[\"Double gate\"],\"app.buildTab.featuresExtensions\":[\"Features & extensions\"],\"app.buildTab.fenceFeatures\":[\"Fence features\"],\"app.buildTab.followLineset\":[\"Follow lineset\"],\"app.buildTab.gate\":[\"Gate\"],\"app.buildTab.gateStyle\":[\"Gate style\"],\"app.buildTab.horizontalBoards\":[\"Horizontal boards\"],\"app.buildTab.hoverAFenceToPreviewClick\":[\"Hover a fence to preview. Click to place. Esc cancels. Leave room between openings.\"],\"app.buildTab.leaves\":[\"Leaves\"],\"app.buildTab.liquidLine\":[\"Liquid Line\"],\"app.buildTab.matchFenceStyle\":[\"Match fence style\"],\"app.buildTab.mep\":[\"MEP\"],\"app.buildTab.off\":[\"Off\"],\"app.buildTab.on\":[\"On\"],\"app.buildTab.openRails\":[\"Open rails\"],\"app.buildTab.opening\":[\"Opening\"],\"app.buildTab.openingWidthM\":[\"Opening width (m)\"],\"app.buildTab.outdoor\":[\"Outdoor\"],\"app.buildTab.picket\":[\"Picket\"],\"app.buildTab.roofType\":[\"Roof type\"],\"app.buildTab.roomsAlreadyCreateTheirFloorAnd\":[\"Rooms already create their floor and ceiling. Use these for platforms and one-off structure.\"],\"app.buildTab.searchBuildToolsAndKitchenItems\":[\"Search build tools and kitchen items\"],\"app.buildTab.searchToolsFridgeSink\":[\"Search tools, fridge, sink…\"],\"app.buildTab.selectACurvedWallToMatch\":[\"Select a curved wall to match its radius and arc.\"],\"app.buildTab.singleGate\":[\"Single gate\"],\"app.buildTab.slabCeilingColumn\":[\"Slab, ceiling, column…\"],\"app.buildTab.solidPrivacy\":[\"Solid privacy\"],\"app.buildTab.traceALineAlongsideAnExisting\":[\"Trace a line alongside an existing lineset (F).\"],\"app.buildTab.verticalSlats\":[\"Vertical slats\"],\"app.editorNavbar.allProjects\":[\"All projects\"],\"app.editorNavbar.preview\":[\"Preview\"],\"app.editorNavbar.projectName\":[\"Project name\"],\"app.editorNavbar.renameProject\":[\"Rename project\"],\"app.editorNavbar.share\":[\"Share\"],\"app.kitchenBrowser.addLabel\":[\"Add \",[\"label\"]],\"app.kitchenBrowser.addToKitchen\":[\"Add to kitchen\"],\"app.kitchenBrowser.chooseAnItemThenClickTo\":[\"Choose an item, then click to place it. Appliances include their cabinetry.\"],\"app.kitchenBrowser.findInThisProjectLength\":[\"Find in this project · \",[\"length\"]],\"app.kitchenBrowser.findName\":[\"Find \",[\"name\"]],\"app.kitchenBrowser.groupAdd\":[\"Kitchen · Add\"],\"app.kitchenBrowser.groupInThisProject\":[\"Kitchen · In this project\"],\"app.kitchenBrowser.kitchenCabinet\":[\"Kitchen cabinet\"],\"app.kitchenBrowser.noMatchingKitchenItemsPlacedYet\":[\"No matching kitchen items placed yet.\"],\"app.kitchenBrowser.selectAndShowInScene\":[\"Select and show in scene\"],\"app.lib.buildPalette.ceiling\":[\"Ceiling\"],\"app.lib.buildPalette.column\":[\"Column\"],\"app.lib.buildPalette.door\":[\"Door\"],\"app.lib.buildPalette.duct\":[\"Duct\"],\"app.lib.buildPalette.dwvPipe\":[\"DWV Pipe\"],\"app.lib.buildPalette.elevator\":[\"Elevator\"],\"app.lib.buildPalette.fence\":[\"Fence\"],\"app.lib.buildPalette.hvacUnit\":[\"HVAC Unit\"],\"app.lib.buildPalette.kitchen\":[\"Kitchen\"],\"app.lib.buildPalette.lineset\":[\"Lineset\"],\"app.lib.buildPalette.liquidLine\":[\"Liquid Line\"],\"app.lib.buildPalette.mep\":[\"MEP\"],\"app.lib.buildPalette.post\":[\"Post\"],\"app.lib.buildPalette.register\":[\"Register\"],\"app.lib.buildPalette.roof\":[\"Roof\"],\"app.lib.buildPalette.shelf\":[\"Shelf\"],\"app.lib.buildPalette.slab\":[\"Slab\"],\"app.lib.buildPalette.spawnPoint\":[\"Spawn point\"],\"app.lib.buildPalette.stairs\":[\"Stairs\"],\"app.lib.buildPalette.terrace\":[\"Terrace\"],\"app.lib.buildPalette.terrain\":[\"Terrain\"],\"app.lib.buildPalette.wall\":[\"Wall\"],\"app.lib.buildPalette.window\":[\"Window\"],\"app.lib.buildPanelModel.addFitting\":[\"Add Fitting\"],\"app.lib.buildPanelModel.addGate\":[\"Add Gate\"],\"app.lib.buildPanelModel.addOpenPassage\":[\"Add Open Passage\"],\"app.lib.buildPanelModel.addTrap\":[\"Add Trap\"],\"app.lib.buildPanelModel.build\":[\"Build\"],\"app.lib.buildPanelModel.createFrom\":[\"Create from\"],\"app.lib.buildPanelModel.drawTheRoofFootprintWithTwo\":[\"Draw the roof footprint with two corner clicks.\"],\"app.lib.buildPanelModel.duct\":[\"Duct\"],\"app.lib.buildPanelModel.dwvPipe\":[\"DWV Pipe\"],\"app.lib.buildPanelModel.featuresExtensions\":[\"Features & extensions\"],\"app.lib.buildPanelModel.fence\":[\"Fence\"],\"app.lib.buildPanelModel.followLineset\":[\"Follow lineset\"],\"app.lib.buildPanelModel.gatesOpenings\":[\"Gates & openings\"],\"app.lib.buildPanelModel.hoverARoomToPreviewIts\":[\"Hover a room to preview its boundary, then click to place.\"],\"app.lib.buildPanelModel.kitchen\":[\"Kitchen\"],\"app.lib.buildPanelModel.mep\":[\"MEP\"],\"app.lib.buildPanelModel.modularCabinet\":[\"Modular Cabinet\"],\"app.lib.buildPanelModel.off\":[\"Off\"],\"app.lib.buildPanelModel.on\":[\"On\"],\"app.lib.buildPanelModel.painting\":[\"Painting\"],\"app.lib.buildPanelModel.roof\":[\"Roof\"],\"app.lib.buildPanelModel.roofType\":[\"Roof type\"],\"app.lib.buildPanelModel.toolCount\":[[\"count\",\"plural\",{\"one\":[\"#\",\" tool\"],\"other\":[\"#\",\" tools\"]}]],\"app.lib.buildTabState.conical\":[\"Conical\"],\"app.lib.buildTabState.draw\":[\"Draw\"],\"app.lib.buildTabState.dutch\":[\"Dutch\"],\"app.lib.buildTabState.flat\":[\"Flat\"],\"app.lib.buildTabState.gable\":[\"Gable\"],\"app.lib.buildTabState.gambrel\":[\"Gambrel\"],\"app.lib.buildTabState.hip\":[\"Hip\"],\"app.lib.buildTabState.mansard\":[\"Mansard\"],\"app.lib.buildTabState.room\":[\"Room\"],\"app.lib.buildTabState.shed\":[\"Shed\"],\"app.lib.buildTabState.wall\":[\"Wall\"],\"app.sceneLoader.anotherSessionSavedFirstRefresh\":[\"Another session saved first — refresh?\"],\"app.sceneLoader.build\":[\"Build\"],\"app.sceneLoader.dismiss\":[\"Dismiss\"],\"app.sceneLoader.items\":[\"Items\"],\"app.sceneLoader.paint\":[\"Paint\"],\"app.sceneLoader.reload\":[\"Reload\"],\"app.sceneLoader.scene\":[\"Scene\"],\"app.sceneLoader.settings\":[\"Settings\"],\"app.sceneLoader.yourChangesHavenTBeenSaved\":[\"Your changes haven't been saved. Reload to pick up the latest version.\"],\"app.sharePanel.anyoneWithTheLinkCanView\":[\"Anyone with the link can view this project. They cannot edit it.\"],\"app.sharePanel.copied\":[\"Copied\"],\"app.sharePanel.copy\":[\"Copy\"],\"app.sharePanel.couldNotReadTheSharingState\":[\"Could not read the sharing state.\"],\"app.sharePanel.couldNotTurnOffThePublic\":[\"Could not turn off the public link.\"],\"app.sharePanel.couldNotTurnOnThePublic\":[\"Could not turn on the public link.\"],\"app.sharePanel.embedCode\":[\"Embed code\"],\"app.sharePanel.embedLink\":[\"Embed link\"],\"app.sharePanel.hideControls\":[\"Hide controls\"],\"app.sharePanel.link\":[\"Link\"],\"app.sharePanel.onlyThe3dViewNoHeader\":[\"Only the 3D view, no header or toolbar.\"],\"app.sharePanel.open\":[\"Open\"],\"app.sharePanel.publicLink\":[\"Public link\"],\"app.sharePanel.shareProject\":[\"Share project\"],\"app.viewerToolbar.above\":[\"Above\"],\"app.viewerToolbar.automaticDimensions\":[\"Automatic dimensions\"],\"app.viewerToolbar.below\":[\"Below\"],\"app.viewerToolbar.both\":[\"Both\"],\"app.viewerToolbar.camera\":[\"Camera\"],\"app.viewerToolbar.ceilings\":[\"Ceilings\"],\"app.viewerToolbar.cleanPlanDimensionsAppearWithSelection\":[\"Clean plan; dimensions appear with selection\"],\"app.viewerToolbar.collapseSidebar\":[\"Collapse sidebar\"],\"app.viewerToolbar.crispOpaqueEdgeLines\":[\"Crisp, opaque edge lines\"],\"app.viewerToolbar.cutaway\":[\"Cutaway\"],\"app.viewerToolbar.default\":[\"Default\"],\"app.viewerToolbar.dimensions\":[\"Dimensions\"],\"app.viewerToolbar.display\":[\"Display\"],\"app.viewerToolbar.displaySettings\":[\"Display settings\"],\"app.viewerToolbar.doorWindowMarks\":[\"Door/window marks\"],\"app.viewerToolbar.edges\":[\"Edges\"],\"app.viewerToolbar.editing\":[\"Editing\"],\"app.viewerToolbar.enterVr\":[\"Enter VR\"],\"app.viewerToolbar.exitVr\":[\"Exit VR\"],\"app.viewerToolbar.expandSidebar\":[\"Expand sidebar\"],\"app.viewerToolbar.expert\":[\"Expert\"],\"app.viewerToolbar.exploded\":[\"Exploded\"],\"app.viewerToolbar.faintOutlineOfMajorCreases\":[\"Faint outline of major creases\"],\"app.viewerToolbar.feetInches\":[\"Feet & inches\"],\"app.viewerToolbar.flatAndFastNoAmbientOcclusion\":[\"Flat and fast — no ambient occlusion\"],\"app.viewerToolbar.floorPlanAnnotations\":[\"Floor plan annotations\"],\"app.viewerToolbar.floorPlanMode\":[\"Floor plan mode\"],\"app.viewerToolbar.fullAmbientOcclusion\":[\"Full ambient occlusion\"],\"app.viewerToolbar.fullDocumentationAndAnnotationControls\":[\"Full documentation and annotation controls\"],\"app.viewerToolbar.fullHeight\":[\"Full height\"],\"app.viewerToolbar.ghostedForReference\":[\"Ghosted for reference\"],\"app.viewerToolbar.grid\":[\"Grid\"],\"app.viewerToolbar.id\":[\"ID\"],\"app.viewerToolbar.idOd\":[\"ID + OD\"],\"app.viewerToolbar.inside\":[\"Inside\"],\"app.viewerToolbar.levelsMode\":[\"Levels: \",[\"mode\"]],\"app.viewerToolbar.low\":[\"Low\"],\"app.viewerToolbar.magneticSnap\":[\"Magnetic snap\"],\"app.viewerToolbar.manual\":[\"Manual\"],\"app.viewerToolbar.manualDimensions\":[\"Manual dimensions\"],\"app.viewerToolbar.measureWalls\":[\"Measure walls\"],\"app.viewerToolbar.measurements\":[\"Measurements\"],\"app.viewerToolbar.meters\":[\"Meters\"],\"app.viewerToolbar.millimeters\":[\"Millimeters\"],\"app.viewerToolbar.n2dOnly\":[\"2D only\"],\"app.viewerToolbar.n3dOnly\":[\"3D only\"],\"app.viewerToolbar.noEdgeLines\":[\"No edge lines\"],\"app.viewerToolbar.od\":[\"OD\"],\"app.viewerToolbar.off\":[\"Off\"],\"app.viewerToolbar.on\":[\"On\"],\"app.viewerToolbar.orthographic\":[\"Orthographic\"],\"app.viewerToolbar.otherLevels\":[\"Other levels\"],\"app.viewerToolbar.outside\":[\"Outside\"],\"app.viewerToolbar.overallSizeOutsideFaceToOutsideFace\":[\"Overall size, outside face to outside face\"],\"app.viewerToolbar.perspective\":[\"Perspective\"],\"app.viewerToolbar.plan\":[\"Plan\"],\"app.viewerToolbar.preview\":[\"Preview\"],\"app.viewerToolbar.previewMode\":[\"Preview mode\"],\"app.viewerToolbar.render\":[\"Render\"],\"app.viewerToolbar.rendered\":[\"Rendered\"],\"app.viewerToolbar.roomLabels\":[\"Room labels\"],\"app.viewerToolbar.roomSizesInsideFaceToInsideFace\":[\"Room sizes, inside face to inside face\"],\"app.viewerToolbar.roomSizesInsideOverallSizeOutside\":[\"Room sizes inside, overall size outside\"],\"app.viewerToolbar.scene\":[\"Scene\"],\"app.viewerToolbar.sceneTheme\":[\"Scene theme\"],\"app.viewerToolbar.shadows\":[\"Shadows\"],\"app.viewerToolbar.sharedBy2dAnd3d\":[\"Shared by 2D and 3D\"],\"app.viewerToolbar.show\":[\"Show\"],\"app.viewerToolbar.soft\":[\"Soft\"],\"app.viewerToolbar.solid\":[\"Solid\"],\"app.viewerToolbar.solo\":[\"Solo\"],\"app.viewerToolbar.stack\":[\"Stack\"],\"app.viewerToolbar.stairAnnotations\":[\"Stair annotations\"],\"app.viewerToolbar.strong\":[\"Strong\"],\"app.viewerToolbar.structuralGridsColumnCenters\":[\"Structural grids & column centers\"],\"app.viewerToolbar.translucent\":[\"Translucent\"],\"app.viewerToolbar.turnOnDimensionsToShowThem\":[\"Turn on Dimensions to show them\"],\"app.viewerToolbar.units\":[\"Units\"],\"app.viewerToolbar.walkthrough\":[\"Walkthrough\"],\"app.viewerToolbar.wallsLabel\":[\"Walls: \",[\"label\"]],\"core.level.basement\":[\"Basement\"],\"core.level.basementNumber\":[\"Basement \",[\"number\"]],\"core.level.floorNumber\":[\"Floor \",[\"number\"]],\"core.level.groundFloor\":[\"Ground floor\"],\"editor.actionMenu.cameraActions.orbitLeft\":[\"Orbit Left\"],\"editor.actionMenu.cameraActions.orbitRight\":[\"Orbit Right\"],\"editor.actionMenu.cameraActions.topView\":[\"Top View\"],\"editor.actionMenu.controlModes.delete\":[\"Delete\"],\"editor.actionMenu.controlModes.select\":[\"Select\"],\"editor.actionMenu.followPascalPill.resumeFollowing\":[\"Resume following\"],\"editor.actionMenu.followPascalToggle.off\":[\"Follow Pascal: Off\"],\"editor.actionMenu.followPascalToggle.on\":[\"Follow Pascal: On\"],\"editor.actionMenu.furnishTools.appliance\":[\"Appliance\"],\"editor.actionMenu.furnishTools.bathroom\":[\"Bathroom\"],\"editor.actionMenu.furnishTools.furniture\":[\"Furniture\"],\"editor.actionMenu.furnishTools.kitchen\":[\"Kitchen\"],\"editor.actionMenu.furnishTools.outdoor\":[\"Outdoor\"],\"editor.actionMenu.measurementControl.angle\":[\"Angle\"],\"editor.actionMenu.measurementControl.angularDimension\":[\"Angular dimension\"],\"editor.actionMenu.measurementControl.arcLength\":[\"Arc length\"],\"editor.actionMenu.measurementControl.area\":[\"Area\"],\"editor.actionMenu.measurementControl.centerMark\":[\"Center mark\"],\"editor.actionMenu.measurementControl.chordDimension\":[\"Chord dimension\"],\"editor.actionMenu.measurementControl.continuousDimension\":[\"Continuous dimension\"],\"editor.actionMenu.measurementControl.coordinateDimensions\":[\"Coordinate dimensions\"],\"editor.actionMenu.measurementControl.diameterDimension\":[\"Diameter dimension\"],\"editor.actionMenu.measurementControl.distance\":[\"Distance\"],\"editor.actionMenu.measurementControl.floorPlan\":[\"Floor plan\"],\"editor.actionMenu.measurementControl.linearDimension\":[\"Linear dimension\"],\"editor.actionMenu.measurementControl.measureSelectedlabel\":[\"Measure: \",[\"selectedLabel\"]],\"editor.actionMenu.measurementControl.measurementOptions\":[\"Measurement options\"],\"editor.actionMenu.measurementControl.measurementType\":[\"Measurement type\"],\"editor.actionMenu.measurementControl.perimeter\":[\"Perimeter\"],\"editor.actionMenu.measurementControl.radiusDimension\":[\"Radius dimension\"],\"editor.actionMenu.measurementControl.smart\":[\"Smart\"],\"editor.actionMenu.measurementControl.volume\":[\"Volume\"],\"editor.actionMenu.pointAskButton.pointAndAsk\":[\"Point and ask\"],\"editor.actionMenu.pointAskButton.pointAndAskC\":[\"Point and ask (C)\"],\"editor.actionMenu.pointAskButton.pointAndAskWorksInThe\":[\"Point and ask works in the 3D view\"],\"editor.actionMenu.structureTools.beam\":[\"Beam\"],\"editor.actionMenu.structureTools.ceiling\":[\"Ceiling\"],\"editor.actionMenu.structureTools.column\":[\"Column\"],\"editor.actionMenu.structureTools.door\":[\"Door\"],\"editor.actionMenu.structureTools.duct\":[\"Duct\"],\"editor.actionMenu.structureTools.ductFitting\":[\"Duct Fitting\"],\"editor.actionMenu.structureTools.dwvPipe\":[\"DWV Pipe\"],\"editor.actionMenu.structureTools.elevator\":[\"Elevator\"],\"editor.actionMenu.structureTools.fence\":[\"Fence\"],\"editor.actionMenu.structureTools.gableRoof\":[\"Gable Roof\"],\"editor.actionMenu.structureTools.hvacUnit\":[\"HVAC Unit\"],\"editor.actionMenu.structureTools.lineset\":[\"Lineset\"],\"editor.actionMenu.structureTools.liquidLine\":[\"Liquid Line\"],\"editor.actionMenu.structureTools.pipeFitting\":[\"Pipe Fitting\"],\"editor.actionMenu.structureTools.register\":[\"Register\"],\"editor.actionMenu.structureTools.shelf\":[\"Shelf\"],\"editor.actionMenu.structureTools.slab\":[\"Slab\"],\"editor.actionMenu.structureTools.spawnPoint\":[\"Spawn Point\"],\"editor.actionMenu.structureTools.stairs\":[\"Stairs\"],\"editor.actionMenu.structureTools.trap\":[\"Trap\"],\"editor.actionMenu.structureTools.wall\":[\"Wall\"],\"editor.actionMenu.structureTools.window\":[\"Window\"],\"editor.actionMenu.structureTools.zone\":[\"Zone\"],\"editor.actionMenu.viewToggles.dashedOutlinesOfTheNeighbouringLevels\":[\"Dashed outlines of the neighbouring levels’ walls, to line walls up and check a roof against the walls under it.\"],\"editor.actionMenu.viewToggles.deleteGuideImage\":[\"Delete guide image\"],\"editor.actionMenu.viewToggles.deleteScan\":[\"Delete scan\"],\"editor.actionMenu.viewToggles.guideCount\":[[\"count\",\"plural\",{\"one\":[\"#\",\" guide image on this level\"],\"other\":[\"#\",\" guide images on this level\"]}]],\"editor.actionMenu.viewToggles.guideImageNumber\":[\"Guide image \",[\"number\"]],\"editor.actionMenu.viewToggles.guideImageSettings\":[\"Guide image settings\"],\"editor.actionMenu.viewToggles.guideImages\":[\"Guide images\"],\"editor.actionMenu.viewToggles.guides\":[\"Guides\"],\"editor.actionMenu.viewToggles.guidesHidden\":[\"Guides: Hidden\"],\"editor.actionMenu.viewToggles.guidesVisible\":[\"Guides: Visible\"],\"editor.actionMenu.viewToggles.hideGuideImages\":[\"Hide guide images\"],\"editor.actionMenu.viewToggles.hideReferenceFloor\":[\"Hide reference floor\"],\"editor.actionMenu.viewToggles.hideScans\":[\"Hide scans\"],\"editor.actionMenu.viewToggles.levelsBelow\":[[\"count\"],\" below\"],\"editor.actionMenu.viewToggles.noLevelAbove\":[\"No level above\"],\"editor.actionMenu.viewToggles.noLevelBelow\":[\"No level below\"],\"editor.actionMenu.viewToggles.noLowerFloorAvailable\":[\"No lower floor available.\"],\"editor.actionMenu.viewToggles.opacity\":[\"Opacity\"],\"editor.actionMenu.viewToggles.referenceFloor\":[\"Reference floor\"],\"editor.actionMenu.viewToggles.referenceFloorSelectedlevelname\":[\"Reference floor: \",[\"selectedLevelName\"]],\"editor.actionMenu.viewToggles.referenceFloorSettings\":[\"Reference floor settings\"],\"editor.actionMenu.viewToggles.referenceSettings\":[\"Reference settings\"],\"editor.actionMenu.viewToggles.references\":[\"References\"],\"editor.actionMenu.viewToggles.referencesEmpty\":[\"Upload GLB meshes as scan references or blueprint images as guide references.\"],\"editor.actionMenu.viewToggles.referencesHidden\":[\"References: Hidden\"],\"editor.actionMenu.viewToggles.referencesVisible\":[\"References: Visible\"],\"editor.actionMenu.viewToggles.riserDiagram\":[\"Riser diagram\"],\"editor.actionMenu.viewToggles.scanCount\":[[\"count\",\"plural\",{\"one\":[\"#\",\" scan on this level\"],\"other\":[\"#\",\" scans on this level\"]}]],\"editor.actionMenu.viewToggles.scanNumber\":[\"Scan \",[\"number\"]],\"editor.actionMenu.viewToggles.scanSettings\":[\"Scan settings\"],\"editor.actionMenu.viewToggles.scans\":[\"Scans\"],\"editor.actionMenu.viewToggles.scansHidden\":[\"Scans: Hidden\"],\"editor.actionMenu.viewToggles.scansVisible\":[\"Scans: Visible\"],\"editor.actionMenu.viewToggles.showGuideImages\":[\"Show guide images\"],\"editor.actionMenu.viewToggles.showReferenceFloor\":[\"Show reference floor\"],\"editor.actionMenu.viewToggles.showScans\":[\"Show scans\"],\"editor.actionMenu.viewToggles.showWallsBelowAndAbove\":[\"Show walls below and above\"],\"editor.actionMenu.viewToggles.uploadScanOrGuideImage\":[\"Upload scan or guide image\"],\"editor.actionMenu.viewToggles.wallsAbove\":[\"Walls above\"],\"editor.actionMenu.viewToggles.wallsBelow\":[\"Walls below\"],\"editor.actionMenu.viewToggles.wallsBelowAndAbove\":[\"Walls below and above\"],\"editor.actionMenu.viewToggles.wallsBelowAndAboveSettings\":[\"Walls below and above settings\"],\"editor.actionMenu.viewToggles.wallsBelowAndAboveShown\":[\"Walls below and above: shown\"],\"editor.backToHome\":[\"Back to home\"],\"editor.buildPanel.advanced\":[\"Advanced\"],\"editor.buildPanel.rooms.hint\":[\"walls · floor · ceiling\"],\"editor.buildPanel.rooms.idle\":[\"Pick a shape to start. Every room brings its own walls, floor and ceiling.\"],\"editor.buildPanel.rooms.polygon.caption\":[[\"lead\"],\" then the first one again to close. For L-shapes and angled rooms.\"],\"editor.buildPanel.rooms.polygon.label\":[\"Polygon\"],\"editor.buildPanel.rooms.polygon.lead\":[\"Click each corner,\"],\"editor.buildPanel.rooms.polygon.title\":[\"Polygon room\"],\"editor.buildPanel.rooms.rectangle.caption\":[[\"lead\"],\" on the grid. Walls, floor and ceiling are created together.\"],\"editor.buildPanel.rooms.rectangle.label\":[\"Rectangle\"],\"editor.buildPanel.rooms.rectangle.lead\":[\"Click two corners\"],\"editor.buildPanel.rooms.rectangle.title\":[\"Rectangle room\"],\"editor.buildPanel.rooms.title\":[\"Rooms\"],\"editor.buildPanel.rooms.wallKinds.invisibleHelp\":[\"Divides a room or closes off a porch without building a wall; rooms close on it. Change any wall later from its controls.\"],\"editor.buildPanel.rooms.wallKinds.label\":[\"Wall kind\"],\"editor.buildPanel.rooms.wallKinds.railingHelp\":[\"A guard for stairs, balconies and mezzanines; rooms close on it. Change any wall later from its controls.\"],\"editor.buildPanel.rooms.wallKinds.standardHelp\":[\"One wall per two clicks. Its sides become exterior or interior from the rooms it bounds. Change any wall later from its controls.\"],\"editor.buildPanel.rooms.walls.label\":[\"Walls\"],\"editor.buildPanel.rooms.walls.title\":[\"Walls\"],\"editor.buildPanel.wallTypeControls.deleteFromThisProject\":[\"Delete from this project\"],\"editor.buildPanel.wallTypeControls.duplicateAsANewType\":[\"Duplicate as a new type…\"],\"editor.buildPanel.wallTypeControls.editLayers\":[\"Edit layers…\"],\"editor.buildPanel.wallTypeControls.editOrDuplicateThisWallType\":[\"Edit or duplicate this wall type\"],\"editor.buildPanel.wallTypeControls.newWallType\":[\"New wall type…\"],\"editor.buildPanel.wallTypeControls.presetsStayAsCitedDuplicateOne\":[\"Presets stay as cited. Duplicate one to change its layers.\"],\"editor.buildPanel.wallTypeEditorDialog.aWallTypeHoldsAtMost\":[\"A wall type holds at most \",[\"limit\",\"plural\",{\"one\":[\"#\",\" layer\"],\"other\":[\"#\",\" layers\"]}],\".\"],\"editor.buildPanel.wallTypeEditorDialog.add\":[\"Add\"],\"editor.buildPanel.wallTypeEditorDialog.airSpace\":[\"Air space\"],\"editor.buildPanel.wallTypeEditorDialog.brickVeneer\":[\"Brick veneer\"],\"editor.buildPanel.wallTypeEditorDialog.cancel\":[\"Cancel\"],\"editor.buildPanel.wallTypeEditorDialog.drywall\":[\"Drywall\"],\"editor.buildPanel.wallTypeEditorDialog.duplicateWallType\":[\"Duplicate wall type\"],\"editor.buildPanel.wallTypeEditorDialog.editWallType\":[\"Edit wall type\"],\"editor.buildPanel.wallTypeEditorDialog.everyWallTypeHasOneFraming\":[\"Every wall type has one framing core\"],\"editor.buildPanel.wallTypeEditorDialog.fiberCement\":[\"Fiber cement\"],\"editor.buildPanel.wallTypeEditorDialog.finish\":[\"Finish\"],\"editor.buildPanel.wallTypeEditorDialog.framingCore\":[\"Framing core\"],\"editor.buildPanel.wallTypeEditorDialog.fullreasonRemoveOneToAddAnother\":[[\"fullReason\"],\" Remove one to add another.\"],\"editor.buildPanel.wallTypeEditorDialog.gypsumSheathing\":[\"Gypsum sheathing\"],\"editor.buildPanel.wallTypeEditorDialog.inside\":[\"Inside\"],\"editor.buildPanel.wallTypeEditorDialog.insulation\":[\"Insulation\"],\"editor.buildPanel.wallTypeEditorDialog.lapSiding\":[\"Lap siding\"],\"editor.buildPanel.wallTypeEditorDialog.layer\":[\"Layer\"],\"editor.buildPanel.wallTypeEditorDialog.layerRole\":[\"Layer role\"],\"editor.buildPanel.wallTypeEditorDialog.lining\":[\"Lining\"],\"editor.buildPanel.wallTypeEditorDialog.material\":[\"Material\"],\"editor.buildPanel.wallTypeEditorDialog.mineralWoolBoard\":[\"Mineral wool board\"],\"editor.buildPanel.wallTypeEditorDialog.moveIn\":[\"Move in\"],\"editor.buildPanel.wallTypeEditorDialog.moveOut\":[\"Move out\"],\"editor.buildPanel.wallTypeEditorDialog.name\":[\"Name\"],\"editor.buildPanel.wallTypeEditorDialog.newWallType\":[\"New wall type\"],\"editor.buildPanel.wallTypeEditorDialog.osb\":[\"OSB\"],\"editor.buildPanel.wallTypeEditorDialog.outside\":[\"Outside\"],\"editor.buildPanel.wallTypeEditorDialog.plaster\":[\"Plaster\"],\"editor.buildPanel.wallTypeEditorDialog.plywood\":[\"Plywood\"],\"editor.buildPanel.wallTypeEditorDialog.removeLayer\":[\"Remove layer\"],\"editor.buildPanel.wallTypeEditorDialog.rigidFoam\":[\"Rigid foam\"],\"editor.buildPanel.wallTypeEditorDialog.saveWallType\":[\"Save wall type\"],\"editor.buildPanel.wallTypeEditorDialog.sheathing\":[\"Sheathing\"],\"editor.buildPanel.wallTypeEditorDialog.stoneVeneer\":[\"Stone veneer\"],\"editor.buildPanel.wallTypeEditorDialog.stucco\":[\"Stucco\"],\"editor.buildPanel.wallTypeEditorDialog.thickness\":[\"Thickness\"],\"editor.buildPanel.wallTypeEditorDialog.totalThickness\":[\"Total \",[\"thickness\"]],\"editor.buildPanel.wallTypeEditorDialog.wallType\":[\"Wall type\"],\"editor.buildPanel.wallTypes.plainWall\":[\"Plain wall\"],\"editor.cameraControlsHint\":[\"Camera controls hint\"],\"editor.cameraHint.pan\":[\"Pan\"],\"editor.cameraHint.rotate\":[\"Rotate\"],\"editor.cameraHint.zoom\":[\"Zoom\"],\"editor.controls.finishSwatch.ariaLabel\":[[\"label\"],\": \",[\"finish\"]],\"editor.controls.finishSwatch.default\":[\"Default\"],\"editor.dismiss\":[\"Dismiss\"],\"editor.dismissCameraControlsHint\":[\"Dismiss camera controls hint\"],\"editor.expandSidebar\":[\"Expand sidebar\"],\"editor.floatingActionMenu.axis\":[\"Axis\"],\"editor.floatingActionMenu.axis2\":[\"⌥ axis\"],\"editor.floatingActionMenu.noEquipment\":[\"⚠ no equipment\"],\"editor.floatingActionMenu.rTRotate\":[\"R/T rotate\"],\"editor.floatingActionMenu.registerCount\":[[\"count\",\"plural\",{\"one\":[\"#\",\" register\"],\"other\":[\"#\",\" registers\"]}]],\"editor.floatingActionMenu.runCount\":[[\"count\",\"plural\",{\"one\":[[\"number\"],\" run\"],\"other\":[[\"number\"],\" runs\"]}]],\"editor.floatingActionMenu.system\":[\"System\"],\"editor.floatingLevelSelector.addAFloorUnderTheRoof\":[\"Add a floor under the roof\"],\"editor.floatingLevelSelector.addLevelAbove\":[\"Add level above\"],\"editor.floatingLevelSelector.addLevelBelow\":[\"Add level below\"],\"editor.floatingLevelSelector.cancel\":[\"Cancel\"],\"editor.floatingLevelSelector.delete\":[\"Delete\"],\"editor.floatingLevelSelector.deleteLevel\":[\"Delete level\"],\"editor.floatingLevelSelector.deleteLevelConfirm\":[\"Are you sure you want to delete \",[\"levelName\"],\"? All walls, floors, and objects on this level will be permanently removed.\"],\"editor.floatingLevelSelector.dragToReorder\":[\"Drag to reorder\"],\"editor.floatingLevelSelector.duplicateLevel\":[\"Duplicate level\"],\"editor.floatingLevelSelector.duplicateWithOptions\":[\"Duplicate with options...\"],\"editor.floatingLevelSelector.exitUnitFocus\":[\"Exit unit focus\"],\"editor.floatingLevelSelector.focusedUnitHasZonesHere\":[\"Focused unit has zones here\"],\"editor.floatingLevelSelector.groundFloorOverGrade\":[\"The ground floor stands \",[\"distance\"],\" over grade. Seat the ground floor 8 in over grade\"],\"editor.floatingLevelSelector.groundFloorUnderGrade\":[\"The ground floor stands \",[\"distance\"],\" under grade. Seat the ground floor 8 in over grade\"],\"editor.floatingLevelSelector.groundLineTheLevelsUnderIt\":[\"Ground line: the levels under it are below grade\"],\"editor.floatingLevelSelector.groundOffset\":[\"Ground · \",[\"offset\"]],\"editor.floatingLevelSelector.insertLevelHere\":[\"Insert level here\"],\"editor.floatingLevelSelector.levelHeight\":[\"Level height\"],\"editor.floatingLevelSelector.pasteCopiedSelection\":[\"Paste copied selection\"],\"editor.floatingLevelSelector.reorderLevelname\":[\"Reorder \",[\"levelName\"]],\"editor.floatingLevelSelector.seatTheBuildingSoThisFloor\":[\"Seat the building so this floor stands at grade; the floors under it are below grade\"],\"editor.floatingLevelSelector.setAsGroundFloor\":[\"Set as ground floor\"],\"editor.floatingLevelSelector.theGroundLevelCannotBeDeleted\":[\"The ground level cannot be deleted\"],\"editor.floatingLevelSelector.thisFloorStandsAtGrade\":[\"This floor stands at grade\"],\"editor.floatingLevelSelector.unit\":[\"Unit\"],\"editor.floorFootprint.area\":[\"Floor area\"],\"editor.floorFootprint.room\":[[\"room\"],\" floor\"],\"editor.floorFootprint.shared\":[\"Shared floor\"],\"editor.helpers.buildingHelper.cancel\":[\"Cancel\"],\"editor.helpers.buildingHelper.placeBuilding\":[\"Place building\"],\"editor.helpers.buildingHelper.rotate\":[\"Rotate\"],\"editor.helpers.contextualHelperPanel.cancelPlacement\":[\"Cancel placement\"],\"editor.helpers.contextualHelperPanel.continuationClickOrPressCTo\":[\"Continuation — click or press C to cycle\"],\"editor.helpers.contextualHelperPanel.continuationLabel\":[\"Continuation: \",[\"label\"]],\"editor.helpers.contextualHelperPanel.dragToDrawFence\":[\"Drag to draw fence\"],\"editor.helpers.contextualHelperPanel.eraseScope\":[\"Erase: \",[\"scope\"]],\"editor.helpers.contextualHelperPanel.eraseScopeClickOrPressShift\":[\"Erase scope — click or press Shift to cycle\"],\"editor.helpers.contextualHelperPanel.eraseScopeLabel\":[\"Erase scope: \",[\"scope\"]],\"editor.helpers.contextualHelperPanel.fenceTypeClickOrPressT\":[\"Fence type — click or press T to switch between straight, curved and freehand\"],\"editor.helpers.contextualHelperPanel.fewerShortcuts\":[\"Fewer shortcuts\"],\"editor.helpers.contextualHelperPanel.finishCurveOrDoubleClick\":[\"Finish curve (or double-click)\"],\"editor.helpers.contextualHelperPanel.gridLength\":[\"Grid: \",[\"length\"]],\"editor.helpers.contextualHelperPanel.gridStepClickOrTapCtrl\":[\"Grid step — click or tap Ctrl to cycle\"],\"editor.helpers.contextualHelperPanel.gridStepLength\":[\"Grid step: \",[\"length\"]],\"editor.helpers.contextualHelperPanel.hoverAPaintedSurfaceToErase\":[\"Hover a painted surface to erase\"],\"editor.helpers.contextualHelperPanel.hoverASurfaceToPaint\":[\"Hover a surface to paint\"],\"editor.helpers.contextualHelperPanel.hoverASurfaceToPickIts\":[\"Hover a surface to pick its material\"],\"editor.helpers.contextualHelperPanel.moreShortcuts\":[\"More shortcuts\"],\"editor.helpers.contextualHelperPanel.paintScope\":[\"Paint: \",[\"scope\"]],\"editor.helpers.contextualHelperPanel.paintScopeClickOrPressShift\":[\"Paint scope — click or press Shift to cycle\"],\"editor.helpers.contextualHelperPanel.paintScopeLabel\":[\"Paint scope: \",[\"scope\"]],\"editor.helpers.contextualHelperPanel.pickScope\":[\"Pick: \",[\"scope\"]],\"editor.helpers.contextualHelperPanel.placeGateOnAFence\":[\"Place gate on a fence\"],\"editor.helpers.contextualHelperPanel.placePassageOnAFence\":[\"Place passage on a fence\"],\"editor.helpers.contextualHelperPanel.selectAMaterialToPaint\":[\"Select a material to paint\"],\"editor.helpers.contextualHelperPanel.snappingAngles\":[\"Snapping: Angles\"],\"editor.helpers.contextualHelperPanel.snappingGrid\":[\"Snapping: Grid\"],\"editor.helpers.contextualHelperPanel.snappingLines\":[\"Snapping: Lines\"],\"editor.helpers.contextualHelperPanel.snappingModeClickOrPressShift\":[\"Snapping mode — click or press Shift to cycle\"],\"editor.helpers.contextualHelperPanel.snappingOff\":[\"Snapping: Off\"],\"editor.helpers.contextualHelperPanel.straightContinuationIsUnavailableForCurved\":[\"Straight continuation is unavailable for curved or freehand fences\"],\"editor.helpers.contextualHelperPanel.straightContinuous\":[\"Straight: Continuous\"],\"editor.helpers.contextualHelperPanel.straightFenceContinuationClickOrPress\":[\"Straight fence continuation — click or press C to toggle\"],\"editor.helpers.contextualHelperPanel.straightSingle\":[\"Straight: Single\"],\"editor.helpers.helperManager.addPoint\":[\"Add point\"],\"editor.helpers.helperManager.addPointClickTheFirstTo\":[\"Add point · click the first to close\"],\"editor.helpers.helperManager.brushSize\":[\"Brush size\"],\"editor.helpers.helperManager.cancel\":[\"Cancel\"],\"editor.helpers.helperManager.cancelPicking\":[\"Cancel picking\"],\"editor.helpers.helperManager.cancelStroke\":[\"Cancel stroke\"],\"editor.helpers.helperManager.done\":[\"Done\"],\"editor.helpers.helperManager.drawTheMezzanine\":[\"Draw the mezzanine\"],\"editor.helpers.helperManager.drawTheOpening\":[\"Draw the opening\"],\"editor.helpers.helperManager.drawTheTerrace\":[\"Draw the terrace\"],\"editor.helpers.helperManager.exitSmartMeasure\":[\"Exit smart measure\"],\"editor.helpers.helperManager.finish\":[\"Finish\"],\"editor.helpers.helperManager.finishAtTheEdge\":[\"Finish at the edge\"],\"editor.helpers.helperManager.freeMove\":[\"Free move\"],\"editor.helpers.helperManager.freeMoveSlideDoorsAndWindows\":[\"Free move · slide doors and windows\"],\"editor.helpers.helperManager.holdToPickAMaterial\":[\"Hold to pick a material\"],\"editor.helpers.helperManager.inspectSurfaceDimensions\":[\"Inspect surface dimensions\"],\"editor.helpers.helperManager.paintWithThisMaterial\":[\"Paint with this material\"],\"editor.helpers.helperManager.pickTargetHeight\":[\"Pick target height\"],\"editor.helpers.helperManager.pinMeasurementLens\":[\"Pin measurement lens\"],\"editor.helpers.helperManager.place\":[\"Place\"],\"editor.helpers.helperManager.placeInsideTheRoom\":[\"Place inside the room\"],\"editor.helpers.helperManager.pressAnywhereDragToTheOpposite\":[\"Press anywhere, drag to the opposite corner\"],\"editor.helpers.helperManager.raiseOrLower\":[\"Raise or lower\"],\"editor.helpers.helperManager.removeAPaintedPartOrReset\":[\"Remove a painted part, or reset a surface\"],\"editor.helpers.helperManager.removeLastPoint\":[\"Remove last point\"],\"editor.helpers.helperManager.resize\":[\"Resize\"],\"editor.helpers.helperManager.rotate45\":[\"Rotate ±45°\"],\"editor.helpers.helperManager.rotateTheSelection45\":[\"Rotate the selection ±45°\"],\"editor.helpers.helperManager.setOneCornerThenTheOpposite\":[\"Set one corner, then the opposite\"],\"editor.helpers.itemHelper.cancel\":[\"Cancel\"],\"editor.helpers.itemHelper.forcePlace\":[\"Force place\"],\"editor.helpers.itemHelper.place\":[\"Place\"],\"editor.helpers.itemHelper.rotate\":[\"Rotate\"],\"editor.helpers.registeredToolHelper.guidedConstraintsBypassed\":[\"Guided constraints bypassed\"],\"editor.inspector.field.angle.g10zaw\":[\"Angle\"],\"editor.inspector.field.armLengthM.1jclqgw\":[\"Arm length m\"],\"editor.inspector.field.attachmentSide.6n9s5v\":[\"Attachment side\"],\"editor.inspector.field.autoHangers.10554ka\":[\"Auto hangers\"],\"editor.inspector.field.autoMiterCorners.zxr5lt\":[\"Auto miter corners\"],\"editor.inspector.field.autoSpan.1gas9r6\":[\"Auto span\"],\"editor.inspector.field.backRatio.1ughd99\":[\"Back ratio\"],\"editor.inspector.field.baseHeight.1hs4zdf\":[\"Base height\"],\"editor.inspector.field.baseStyle.24vty5\":[\"Base style\"],\"editor.inspector.field.beamHeight.1kq0oh1\":[\"Beam height\"],\"editor.inspector.field.beamWidth.1q1mzbe\":[\"Beam width\"],\"editor.inspector.field.bodyShape.arvkuw\":[\"Body shape\"],\"editor.inspector.field.bracketStyle.1vvoptm\":[\"Bracket style\"],\"editor.inspector.field.branchAngle.v56zme\":[\"Branch angle\"],\"editor.inspector.field.cabHeight.1yn34mk\":[\"Cab height\"],\"editor.inspector.field.canopyForm.1czzggp\":[\"Canopy form\"],\"editor.inspector.field.cap.s0thej\":[\"Cap\"],\"editor.inspector.field.capOverhang.kxxz9j\":[\"Cap overhang\"],\"editor.inspector.field.capShape.17mbxhu\":[\"Cap shape\"],\"editor.inspector.field.capThickness.u835q9\":[\"Cap thickness\"],\"editor.inspector.field.carcassHeight.1aks0zy\":[\"Carcass height\"],\"editor.inspector.field.cleanoutStyle.127zz6z\":[\"Cleanout style\"],\"editor.inspector.field.collarDiameter.1d5k28r\":[\"Collar diameter\"],\"editor.inspector.field.collarHeight.1dqwsrf\":[\"Collar height\"],\"editor.inspector.field.collarShape.1gacv11\":[\"Collar shape\"],\"editor.inspector.field.collarWidth.qvc9ik\":[\"Collar width\"],\"editor.inspector.field.columns.1sy73ks\":[\"Columns\"],\"editor.inspector.field.conicalFullCircle.1pgkpz5\":[\"Conical full circle\"],\"editor.inspector.field.connectionMode.1nty478\":[\"Connection mode\"],\"editor.inspector.field.connectionOffset.2m70s8\":[\"Connection offset\"],\"editor.inspector.field.cornerBevel.16iniho\":[\"Corner bevel\"],\"editor.inspector.field.coveringType.95yd3k\":[\"Covering type\"],\"editor.inspector.field.cricketHeight.pok31n\":[\"Cricket height\"],\"editor.inspector.field.cricketLength.i2aht8\":[\"Cricket length\"],\"editor.inspector.field.cricketSide.1xnwil7\":[\"Cricket side\"],\"editor.inspector.field.cricketStyle.10j0lat\":[\"Cricket style\"],\"editor.inspector.field.curb.5xi2ol\":[\"Curb\"],\"editor.inspector.field.curbHeight.1yn97sg\":[\"Curb height\"],\"editor.inspector.field.curveOffset.l4xhvr\":[\"Curve offset\"],\"editor.inspector.field.damperAngle.h5fxn7\":[\"Damper angle\"],\"editor.inspector.field.deckThickness.4jmqze\":[\"Deck thickness\"],\"editor.inspector.field.defaultLevelId.xmrjzp\":[\"Default level id\"],\"editor.inspector.field.depth.1lu11u2\":[\"Depth\"],\"editor.inspector.field.diameter.s3robe\":[\"Diameter\"],\"editor.inspector.field.diameter2.pm6cl4\":[\"Diameter2\"],\"editor.inspector.field.doorDurationMs.13nx909\":[\"Door duration ms\"],\"editor.inspector.field.doorHeight.92r9k4\":[\"Door height\"],\"editor.inspector.field.doorPanelStyle.2qog4q\":[\"Door panel style\"],\"editor.inspector.field.doorStyle.gerpos\":[\"Door style\"],\"editor.inspector.field.doorWidth.sy732l\":[\"Door width\"],\"editor.inspector.field.downspoutEnabled.1gn00nv\":[\"Downspout enabled\"],\"editor.inspector.field.downspoutPosition.fxcsop\":[\"Downspout position\"],\"editor.inspector.field.ductMaterial.i8eonq\":[\"Duct material\"],\"editor.inspector.field.dutchGabletRake.6paydp\":[\"Dutch gablet rake\"],\"editor.inspector.field.dutchHipHeightRatio.1etnwgg\":[\"Dutch hip height ratio\"],\"editor.inspector.field.dutchHipWidthRatio.1dopfvb\":[\"Dutch hip width ratio\"],\"editor.inspector.field.dutchTopRakeThickness.1w9khxt\":[\"Dutch top rake thickness\"],\"editor.inspector.field.dutchWaistLengthRatio.agtoxw\":[\"Dutch waist length ratio\"],\"editor.inspector.field.dwellMs.1lkk0o5\":[\"Dwell ms\"],\"editor.inspector.field.edgeInset.1obeimx\":[\"Edge inset\"],\"editor.inspector.field.elevation.4jbp44\":[\"Elevation\"],\"editor.inspector.field.endCapLeft.19jel4v\":[\"End cap left\"],\"editor.inspector.field.endCapRight.lhse9c\":[\"End cap right\"],\"editor.inspector.field.endCaps.4fsb5b\":[\"End caps\"],\"editor.inspector.field.endPost.1guwsk0\":[\"End post\"],\"editor.inspector.field.equipmentType.1mc2ywt\":[\"Equipment type\"],\"editor.inspector.field.fillToFloor.1oppnkf\":[\"Fill to floor\"],\"editor.inspector.field.finial.1ertf4s\":[\"Finial\"],\"editor.inspector.field.fittingType.18mz17s\":[\"Fitting type\"],\"editor.inspector.field.flashingHeight.3e8nn6\":[\"Flashing height\"],\"editor.inspector.field.flashingProjection.hhf0fk\":[\"Flashing projection\"],\"editor.inspector.field.flueCount.j3t2ci\":[\"Flue count\"],\"editor.inspector.field.flueDiameter.cjhubg\":[\"Flue diameter\"],\"editor.inspector.field.flueHeight.1dhc4y4\":[\"Flue height\"],\"editor.inspector.field.flueShape.1ealiy4\":[\"Flue shape\"],\"editor.inspector.field.flueSpacing.exhzco\":[\"Flue spacing\"],\"editor.inspector.field.footingStyle.e3btg6\":[\"Footing style\"],\"editor.inspector.field.frameDepth.1934a5n\":[\"Frame depth\"],\"editor.inspector.field.frameThickness.1agxzd8\":[\"Frame thickness\"],\"editor.inspector.field.framingStrategy.3jx9qe\":[\"Framing strategy\"],\"editor.inspector.field.fromLevelId.15ieejs\":[\"From level id\"],\"editor.inspector.field.gableOverhang.2z0obw\":[\"Gable overhang\"],\"editor.inspector.field.gambrelLowerHeightRatio.wqq7lg\":[\"Gambrel lower height ratio\"],\"editor.inspector.field.gambrelLowerWidthRatio.uvyb1v\":[\"Gambrel lower width ratio\"],\"editor.inspector.field.gapX.wjxa7\":[\"Gap x\"],\"editor.inspector.field.gapY.mkbl8\":[\"Gap y\"],\"editor.inspector.field.glassThickness.s97b0x\":[\"Glass thickness\"],\"editor.inspector.field.groundClearance.4os7f0\":[\"Ground clearance\"],\"editor.inspector.field.guardInfill.16heiig\":[\"Guard infill\"],\"editor.inspector.field.gutterEnabled.1oxiltf\":[\"Gutter enabled\"],\"editor.inspector.field.gutterProfile.1ngzqi3\":[\"Gutter profile\"],\"editor.inspector.field.gutterSize.jgavtz\":[\"Gutter size\"],\"editor.inspector.field.hangerMaxReach.1869epv\":[\"Hanger max reach\"],\"editor.inspector.field.hangerSpacing.i2b5d7\":[\"Hanger spacing\"],\"editor.inspector.field.hangerStyle.l7v7gb\":[\"Hanger style\"],\"editor.inspector.field.height.7puwki\":[\"Height\"],\"editor.inspector.field.height2.7b3jlc\":[\"Height2\"],\"editor.inspector.field.heightAboveRidge.1k99brk\":[\"Height above ridge\"],\"editor.inspector.field.highEdgeHeight.1s7v90t\":[\"High edge height\"],\"editor.inspector.field.highOverhang.67w55d\":[\"High overhang\"],\"editor.inspector.field.highSideMode.1rc1r5j\":[\"High side mode\"],\"editor.inspector.field.hoodOverhang.1q1hcin\":[\"Hood overhang\"],\"editor.inspector.field.infillPlacement.11dxzpo\":[\"Infill placement\"],\"editor.inspector.field.inletShape.ypayh2\":[\"Inlet shape\"],\"editor.inspector.field.innerRadius.1fkmg0j\":[\"Inner radius\"],\"editor.inspector.field.insulated.iwziey\":[\"Insulated\"],\"editor.inspector.field.insulationR.663ufx\":[\"Insulation r\"],\"editor.inspector.field.lanternHeight.oz7zpm\":[\"Lantern height\"],\"editor.inspector.field.lanternTopScale.hkmpp2\":[\"Lantern top scale\"],\"editor.inspector.field.ledgerDepth.7av8k9\":[\"Ledger depth\"],\"editor.inspector.field.ledgerHeight.zo2oif\":[\"Ledger height\"],\"editor.inspector.field.ledgerVerticalOffset.1athbgt\":[\"Ledger vertical offset\"],\"editor.inspector.field.leftEndCondition.1syqlaw\":[\"Left end condition\"],\"editor.inspector.field.leftOverhang.1ydl9ma\":[\"Left overhang\"],\"editor.inspector.field.length.1kpdcfp\":[\"Length\"],\"editor.inspector.field.liquidDiameter.w3pk7c\":[\"Liquid diameter\"],\"editor.inspector.field.louverCount.lhw2gr\":[\"Louver count\"],\"editor.inspector.field.lowBeamInset.1g7yw5l\":[\"Low beam inset\"],\"editor.inspector.field.lowEdgeHeight.47mae1\":[\"Low edge height\"],\"editor.inspector.field.lowOverhang.t4nz1h\":[\"Low overhang\"],\"editor.inspector.field.mansardSteepHeightRatio.1hbb8rq\":[\"Mansard steep height ratio\"],\"editor.inspector.field.mansardSteepWidthRatio.6xk6vd\":[\"Mansard steep width ratio\"],\"editor.inspector.field.matchHostRoofMaterial.s56zwj\":[\"Match host roof material\"],\"editor.inspector.field.matchHostRoofStructure.bojht3\":[\"Match host roof structure\"],\"editor.inspector.field.mount.h80tay\":[\"Mount\"],\"editor.inspector.field.mountingType.1xvin1e\":[\"Mounting type\"],\"editor.inspector.field.neckHeight.19ym8n1\":[\"Neck height\"],\"editor.inspector.field.opacity.1pmpfd2\":[\"Opacity\"],\"editor.inspector.field.openingAngle.brhi7c\":[\"Opening angle\"],\"editor.inspector.field.openingOffset.wpoqt6\":[\"Opening offset\"],\"editor.inspector.field.openingSide.18l2iwe\":[\"Opening side\"],\"editor.inspector.field.operationState.1lwrz07\":[\"Operation state\"],\"editor.inspector.field.outletShape.lgpqhx\":[\"Outlet shape\"],\"editor.inspector.field.overhang.b5ljpv\":[\"Overhang\"],\"editor.inspector.field.panelHeight.1kf31vk\":[\"Panel height\"],\"editor.inspector.field.panelWidth.946581\":[\"Panel width\"],\"editor.inspector.field.patternAlignment.jd1ht0\":[\"Pattern alignment\"],\"editor.inspector.field.patternCount.1r37pve\":[\"Pattern count\"],\"editor.inspector.field.patternDistribution.fmam51\":[\"Pattern distribution\"],\"editor.inspector.field.patternRemainder.i47p5y\":[\"Pattern remainder\"],\"editor.inspector.field.picketProfile.1xgzuyc\":[\"Picket profile\"],\"editor.inspector.field.picketRailCount.atgt6w\":[\"Picket rail count\"],\"editor.inspector.field.picketSpacing.p8d98w\":[\"Picket spacing\"],\"editor.inspector.field.picketTop.1tskplu\":[\"Picket top\"],\"editor.inspector.field.picketTopClearance.16eq1k0\":[\"Picket top clearance\"],\"editor.inspector.field.picketVariation.f7vl1c\":[\"Picket variation\"],\"editor.inspector.field.picketWidth.3fr3rh\":[\"Picket width\"],\"editor.inspector.field.pipeMaterial.1ggc2wy\":[\"Pipe material\"],\"editor.inspector.field.pitch.xe6ekx\":[\"Pitch\"],\"editor.inspector.field.position.1quewx6\":[\"Position\"],\"editor.inspector.field.postBracing.crq8nn\":[\"Post bracing\"],\"editor.inspector.field.postCap.1xcvxrv\":[\"Post cap\"],\"editor.inspector.field.postCount.22r56c\":[\"Post count\"],\"editor.inspector.field.postDepth.1ko6j1m\":[\"Post depth\"],\"editor.inspector.field.postInset.le36li\":[\"Post inset\"],\"editor.inspector.field.postLayoutMode.16jre62\":[\"Post layout mode\"],\"editor.inspector.field.postSize.1jodxek\":[\"Post size\"],\"editor.inspector.field.postSpacing.voppfi\":[\"Post spacing\"],\"editor.inspector.field.postThrough.1abgu4a\":[\"Post through\"],\"editor.inspector.field.postWidth.rk26fz\":[\"Post width\"],\"editor.inspector.field.profile.1kwlci6\":[\"Profile\"],\"editor.inspector.field.projection.jhtig0\":[\"Projection\"],\"editor.inspector.field.purlinHeight.eo9cjm\":[\"Purlin height\"],\"editor.inspector.field.purlinSpacing.4gbzb2\":[\"Purlin spacing\"],\"editor.inspector.field.purlinWidth.r6tu3j\":[\"Purlin width\"],\"editor.inspector.field.rafterEndInset.14c0wy5\":[\"Rafter end inset\"],\"editor.inspector.field.rafterHeight.1e1n99w\":[\"Rafter height\"],\"editor.inspector.field.rafterSpacing.19subc0\":[\"Rafter spacing\"],\"editor.inspector.field.rafterWidth.eksj4t\":[\"Rafter width\"],\"editor.inspector.field.railingHeight.6wf4bm\":[\"Railing height\"],\"editor.inspector.field.railingMode.ov7xpu\":[\"Railing mode\"],\"editor.inspector.field.railingStyle.1nyd2u\":[\"Railing style\"],\"editor.inspector.field.resizeLock.b2hbr0\":[\"Resize lock\"],\"editor.inspector.field.returnDiameter.166ozhe\":[\"Return diameter\"],\"editor.inspector.field.returnHeight.b9sq6y\":[\"Return height\"],\"editor.inspector.field.returnShape.1e3a27i\":[\"Return shape\"],\"editor.inspector.field.returnWidth.z9r3h3\":[\"Return width\"],\"editor.inspector.field.rightEndCondition.tjlw3l\":[\"Right end condition\"],\"editor.inspector.field.rightOverhang.yqbeft\":[\"Right overhang\"],\"editor.inspector.field.roofHeight.1uhy6qy\":[\"Roof height\"],\"editor.inspector.field.roofStyle.pawqfy\":[\"Roof style\"],\"editor.inspector.field.roofThickness.1xlr3rx\":[\"Roof thickness\"],\"editor.inspector.field.roofType.1m9kv5h\":[\"Roof type\"],\"editor.inspector.field.rotation.ly2rj\":[\"Rotation\"],\"editor.inspector.field.rows.1ba1neg\":[\"Rows\"],\"editor.inspector.field.scale.b6rpxt\":[\"Scale\"],\"editor.inspector.field.seamDetail.197za48\":[\"Seam detail\"],\"editor.inspector.field.segmentType.l667sy\":[\"Segment type\"],\"editor.inspector.field.shaftStyle.1i5ampa\":[\"Shaft style\"],\"editor.inspector.field.shaftWallThickness.bduslr\":[\"Shaft wall thickness\"],\"editor.inspector.field.shape.iq9t52\":[\"Shape\"],\"editor.inspector.field.shape2.fi0nx8\":[\"Shape2\"],\"editor.inspector.field.shedHighSide.bzzddg\":[\"Shed high side\"],\"editor.inspector.field.shingleThickness.1hn5wxr\":[\"Shingle thickness\"],\"editor.inspector.field.shoulderExtent.11j8uiv\":[\"Shoulder extent\"],\"editor.inspector.field.shoulderHeight.xyqn6g\":[\"Shoulder height\"],\"editor.inspector.field.shoulderStyle.1hkcv2w\":[\"Shoulder style\"],\"editor.inspector.field.showCenterColumn.1uggg45\":[\"Show center column\"],\"editor.inspector.field.showInfill.33rv7u\":[\"Show infill\"],\"editor.inspector.field.showStepSupports.1kg8h8m\":[\"Show step supports\"],\"editor.inspector.field.sideFlashing.cv744o\":[\"Side flashing\"],\"editor.inspector.field.size.1a4x3zw\":[\"Size\"],\"editor.inspector.field.skylightType.1a5vj3i\":[\"Skylight type\"],\"editor.inspector.field.slabOpeningMode.g4f730\":[\"Slab opening mode\"],\"editor.inspector.field.slatGap.slmk93\":[\"Slat gap\"],\"editor.inspector.field.slideDirection.1527q13\":[\"Slide direction\"],\"editor.inspector.field.span.1bmmuw1\":[\"Span\"],\"editor.inspector.field.speed.2w2xwg\":[\"Speed\"],\"editor.inspector.field.spinSpeed.1ozx746\":[\"Spin speed\"],\"editor.inspector.field.stairType.1u05e02\":[\"Stair type\"],\"editor.inspector.field.standoff.4wv2g0\":[\"Standoff\"],\"editor.inspector.field.standoffHeight.1qdnff\":[\"Standoff height\"],\"editor.inspector.field.startPost.1ood9kv\":[\"Start post\"],\"editor.inspector.field.stepCount.nzorrw\":[\"Step count\"],\"editor.inspector.field.strapSpacing.1cyt3dc\":[\"Strap spacing\"],\"editor.inspector.field.strapStyle.fh1oy4\":[\"Strap style\"],\"editor.inspector.field.style.nf3vcm\":[\"Style\"],\"editor.inspector.field.suctionDiameter.nutxtj\":[\"Suction diameter\"],\"editor.inspector.field.supplyDiameter.h5ldh5\":[\"Supply diameter\"],\"editor.inspector.field.supplyHeight.zy6ru1\":[\"Supply height\"],\"editor.inspector.field.supplyShape.k39wnb\":[\"Supply shape\"],\"editor.inspector.field.supplyWidth.g66axi\":[\"Supply width\"],\"editor.inspector.field.supportOffset.1w4cocr\":[\"Support offset\"],\"editor.inspector.field.sweepAngle.ucmmlw\":[\"Sweep angle\"],\"editor.inspector.field.system.13qbhrw\":[\"System\"],\"editor.inspector.field.terminal.1501knl\":[\"Terminal\"],\"editor.inspector.field.terminalType.1ne8lgb\":[\"Terminal type\"],\"editor.inspector.field.thickness.1l8hu45\":[\"Thickness\"],\"editor.inspector.field.tiltAngle.1312yw1\":[\"Tilt angle\"],\"editor.inspector.field.toLevelId.8i5qx7\":[\"To level id\"],\"editor.inspector.field.topLandingDepth.ki7gk2\":[\"Top landing depth\"],\"editor.inspector.field.topLandingMode.zk0h7e\":[\"Top landing mode\"],\"editor.inspector.field.topRailHeight.fscisv\":[\"Top rail height\"],\"editor.inspector.field.transitionMode.f3evgt\":[\"Transition mode\"],\"editor.inspector.field.transitionWidth.rtgz3m\":[\"Transition width\"],\"editor.inspector.field.vaneCount.55vtye\":[\"Vane count\"],\"editor.inspector.field.wallHeight.18vmh5c\":[\"Wall height\"],\"editor.inspector.field.wallShell.vqsyhv\":[\"Wall shell\"],\"editor.inspector.field.wallSkirtHeight.1uea2ad\":[\"Wall skirt height\"],\"editor.inspector.field.wallThickness.17wn4iv\":[\"Wall thickness\"],\"editor.inspector.field.width.gfxz9b\":[\"Width\"],\"editor.inspector.field.width2.1nqawvr\":[\"Width2\"],\"editor.inspector.field.withBack.1ay8nus\":[\"With back\"],\"editor.inspector.field.withBottom.1x1z1vo\":[\"With bottom\"],\"editor.inspector.field.withSides.uq066x\":[\"With sides\"],\"editor.inspector.group.advanced.qwfkor\":[\"Advanced\"],\"editor.inspector.group.air.15jotdj\":[\"Air\"],\"editor.inspector.group.appearance.dli9wf\":[\"Appearance\"],\"editor.inspector.group.body.ign4wl\":[\"Body\"],\"editor.inspector.group.cab.o4z1ox\":[\"Cab\"],\"editor.inspector.group.cabinet.rzvymr\":[\"Cabinet\"],\"editor.inspector.group.cap.s0thej\":[\"Cap\"],\"editor.inspector.group.collar.1am2iqo\":[\"Collar\"],\"editor.inspector.group.connection.2r1h4p\":[\"Connection\"],\"editor.inspector.group.connections.ai4w8u\":[\"Connections\"],\"editor.inspector.group.construction.j6p9kc\":[\"Construction\"],\"editor.inspector.group.cricket.6iwg8g\":[\"Cricket\"],\"editor.inspector.group.curb.5xi2ol\":[\"Curb\"],\"editor.inspector.group.curvePoints.ztdcnn\":[\"Curve points\"],\"editor.inspector.group.dimensions.pewa8g\":[\"Dimensions\"],\"editor.inspector.group.doors.18w2kpa\":[\"Doors\"],\"editor.inspector.group.dormer.1fjs5tq\":[\"Dormer\"],\"editor.inspector.group.dormerRoof.u9uy2g\":[\"Dormer roof\"],\"editor.inspector.group.drainage.7easy0\":[\"Drainage\"],\"editor.inspector.group.elevation.4jbp44\":[\"Elevation\"],\"editor.inspector.group.endCaps.4fsb5b\":[\"End caps\"],\"editor.inspector.group.equipment.1xtq0ev\":[\"Equipment\"],\"editor.inspector.group.face.1531fr0\":[\"Face\"],\"editor.inspector.group.fitting.171z1r4\":[\"Fitting\"],\"editor.inspector.group.flues.nq6pye\":[\"Flues\"],\"editor.inspector.group.footprint.g8q2pg\":[\"Footprint\"],\"editor.inspector.group.frame.q7q9fq\":[\"Frame\"],\"editor.inspector.group.geometry.a21os1\":[\"Geometry\"],\"editor.inspector.group.grid.d8gwxd\":[\"Grid\"],\"editor.inspector.group.hangers.agnfzn\":[\"Hangers\"],\"editor.inspector.group.hardware.1nygwm1\":[\"Hardware\"],\"editor.inspector.group.hungWall.1ftr1gz\":[\"Hung wall\"],\"editor.inspector.group.insulation.1kyo5e7\":[\"Insulation\"],\"editor.inspector.group.lantern.1h7o2xb\":[\"Lantern\"],\"editor.inspector.group.levels.1s6yaru\":[\"Levels\"],\"editor.inspector.group.line.166mv5z\":[\"Line\"],\"editor.inspector.group.lines.12bghr0\":[\"Lines\"],\"editor.inspector.group.motion.1be7sjr\":[\"Motion\"],\"editor.inspector.group.mounting.feutd2\":[\"Mounting\"],\"editor.inspector.group.opening.dfet3\":[\"Opening\"],\"editor.inspector.group.panelDimensions.b59qe6\":[\"Panel dimensions\"],\"editor.inspector.group.patternDistribution.fmam51\":[\"Pattern distribution\"],\"editor.inspector.group.placement.13lcvts\":[\"Placement\"],\"editor.inspector.group.position.1quewx6\":[\"Position\"],\"editor.inspector.group.profile.1kwlci6\":[\"Profile\"],\"editor.inspector.group.railing.19a5bnr\":[\"Railing\"],\"editor.inspector.group.return.1klrjrz\":[\"Return\"],\"editor.inspector.group.settings.ktdb8o\":[\"Settings\"],\"editor.inspector.group.shaft.mad9cv\":[\"Shaft\"],\"editor.inspector.group.shape.iq9t52\":[\"Shape\"],\"editor.inspector.group.shoulder.1nyfx25\":[\"Shoulder\"],\"editor.inspector.group.size.1a4x3zw\":[\"Size\"],\"editor.inspector.group.structure.gezdra\":[\"Structure\"],\"editor.inspector.group.style.nf3vcm\":[\"Style\"],\"editor.inspector.group.supply.1oy2zwu\":[\"Supply\"],\"editor.inspector.group.surface.wtamqk\":[\"Surface\"],\"editor.inspector.group.terminal.1501knl\":[\"Terminal\"],\"editor.inspector.group.topology.18t8dyc\":[\"Topology\"],\"editor.inspector.group.transform.1c55ayj\":[\"Transform\"],\"editor.inspector.group.trap.1qc7vhe\":[\"Trap\"],\"editor.inspector.group.type.1m2zofh\":[\"Type\"],\"editor.inspector.option.abs.132mz8b\":[\"Abs\"],\"editor.inspector.option.accessPanel.13sptb5\":[\"Access panel\"],\"editor.inspector.option.airHandler.1crnyg3\":[\"Air handler\"],\"editor.inspector.option.alternating.5jashi\":[\"Alternating\"],\"editor.inspector.option.arched.14188w0\":[\"Arched\"],\"editor.inspector.option.auto.540b06\":[\"Auto\"],\"editor.inspector.option.automatic.r122ro\":[\"Automatic\"],\"editor.inspector.option.back.1hzmxtu\":[\"Back\"],\"editor.inspector.option.balusters.1j3w6ng\":[\"Balusters\"],\"editor.inspector.option.band.160umau\":[\"Band\"],\"editor.inspector.option.basePlate.17fcg8k\":[\"Base plate\"],\"editor.inspector.option.boards.u14hig\":[\"Boards\"],\"editor.inspector.option.bookshelf.ls0zqk\":[\"Bookshelf\"],\"editor.inspector.option.both.mkyb42\":[\"Both\"],\"editor.inspector.option.bottom.9mpruy\":[\"Bottom\"],\"editor.inspector.option.box.1nbjcuq\":[\"Box\"],\"editor.inspector.option.break.17spnvc\":[\"Break\"],\"editor.inspector.option.butterfly.pvv0g4\":[\"Butterfly\"],\"editor.inspector.option.cable.fp50zq\":[\"Cable\"],\"editor.inspector.option.castIron.1q2z4qk\":[\"Cast iron\"],\"editor.inspector.option.ceiling.1t2zaqo\":[\"Ceiling\"],\"editor.inspector.option.center.kzdxno\":[\"Center\"],\"editor.inspector.option.centerOpening.bn1rvw\":[\"Center opening\"],\"editor.inspector.option.cleanout.lww8bm\":[\"Cleanout\"],\"editor.inspector.option.concretePad.m1zdij\":[\"Concrete pad\"],\"editor.inspector.option.condenser.a74nps\":[\"Condenser\"],\"editor.inspector.option.corbeled.bovs4v\":[\"Corbeled\"],\"editor.inspector.option.count.1qoi4r8\":[\"Count\"],\"editor.inspector.option.coupling.111aap2\":[\"Coupling\"],\"editor.inspector.option.coveringSpecific.1h9fo8w\":[\"Covering specific\"],\"editor.inspector.option.cross.1elubzv\":[\"Cross\"],\"editor.inspector.option.cubby.ivq4qc\":[\"Cubby\"],\"editor.inspector.option.curved.6noz1s\":[\"Curved\"],\"editor.inspector.option.cylinder.eol6vj\":[\"Cylinder\"],\"editor.inspector.option.damper.wgri80\":[\"Damper\"],\"editor.inspector.option.destination.gfzm1r\":[\"Destination\"],\"editor.inspector.option.diffuser.1igj0jh\":[\"Diffuser\"],\"editor.inspector.option.dogEar.xhtvjt\":[\"Dog ear\"],\"editor.inspector.option.dome.1c87e56\":[\"Dome\"],\"editor.inspector.option.double.13h5354\":[\"Double\"],\"editor.inspector.option.ductBoard.lc3o4t\":[\"Duct board\"],\"editor.inspector.option.dutch.1djx429\":[\"Dutch\"],\"editor.inspector.option.elbow.1flup74\":[\"Elbow\"],\"editor.inspector.option.end.1llf32i\":[\"End\"],\"editor.inspector.option.endCap.1p4v4na\":[\"End cap\"],\"editor.inspector.option.equalFit.11vw52c\":[\"Equal fit\"],\"editor.inspector.option.fixedCount.1o3dznu\":[\"Fixed count\"],\"editor.inspector.option.fixedSpacing.hl4dr4\":[\"Fixed spacing\"],\"editor.inspector.option.flat.ly0bei\":[\"Flat\"],\"editor.inspector.option.flex.ktpamq\":[\"Flex\"],\"editor.inspector.option.floating.1oadpln\":[\"Floating\"],\"editor.inspector.option.floor.q9caf1\":[\"Floor\"],\"editor.inspector.option.flush.olwwu5\":[\"Flush\"],\"editor.inspector.option.front.uhugl4\":[\"Front\"],\"editor.inspector.option.furnace.w0mzpf\":[\"Furnace\"],\"editor.inspector.option.gable.1ekyx6\":[\"Gable\"],\"editor.inspector.option.gambrel.1yo90d9\":[\"Gambrel\"],\"editor.inspector.option.generic.1074oey\":[\"Generic\"],\"editor.inspector.option.glass.163tc5n\":[\"Glass\"],\"editor.inspector.option.glassFrame.jp9s3m\":[\"Glass frame\"],\"editor.inspector.option.globe.1avkqoy\":[\"Globe\"],\"editor.inspector.option.grounded.jwoq73\":[\"Grounded\"],\"editor.inspector.option.guard.1m575se\":[\"Guard\"],\"editor.inspector.option.halfRound.m5hob0\":[\"Half round\"],\"editor.inspector.option.hidden.gp48rd\":[\"Hidden\"],\"editor.inspector.option.hip.r0jnjy\":[\"Hip\"],\"editor.inspector.option.horizontal.tyapah\":[\"Horizontal\"],\"editor.inspector.option.include.1a27vnr\":[\"Include\"],\"editor.inspector.option.independentHighBeam.1tn0zvy\":[\"Independent high beam\"],\"editor.inspector.option.industrial.8sd9u\":[\"Industrial\"],\"editor.inspector.option.inline.1uh05lg\":[\"Inline\"],\"editor.inspector.option.integrated.1xd9lv0\":[\"Integrated\"],\"editor.inspector.option.joined.1x2o8ds\":[\"Joined\"],\"editor.inspector.option.kStyle.m8kfwz\":[\"K style\"],\"editor.inspector.option.kickout.vt8s6p\":[\"Kickout\"],\"editor.inspector.option.knee.186hcui\":[\"Knee\"],\"editor.inspector.option.landing.tyqarg\":[\"Landing\"],\"editor.inspector.option.lantern.1h7o2xb\":[\"Lantern\"],\"editor.inspector.option.leave.1xf0sbk\":[\"Leave\"],\"editor.inspector.option.left.14n06mo\":[\"Left\"],\"editor.inspector.option.level.i4lhtp\":[\"Level\"],\"editor.inspector.option.lowProfile.1h9lgzg\":[\"Low profile\"],\"editor.inspector.option.mansard.dwzck9\":[\"Mansard\"],\"editor.inspector.option.manual.1wu7r43\":[\"Manual\"],\"editor.inspector.option.maximumSpacing.n1fzl4\":[\"Maximum spacing\"],\"editor.inspector.option.metal.1az9fgc\":[\"Metal\"],\"editor.inspector.option.metalPanel.1xdz476\":[\"Metal panel\"],\"editor.inspector.option.minimal.fwmiwg\":[\"Minimal\"],\"editor.inspector.option.mono.oszvd6\":[\"Mono\"],\"editor.inspector.option.none.deku7v\":[\"None\"],\"editor.inspector.option.omit.okcs7w\":[\"Omit\"],\"editor.inspector.option.open.n6hn1l\":[\"Open\"],\"editor.inspector.option.openRack.mvt1x0\":[\"Open rack\"],\"editor.inspector.option.opening.dfet3\":[\"Opening\"],\"editor.inspector.option.oval.1jiqzxx\":[\"Oval\"],\"editor.inspector.option.picket.zyeoy1\":[\"Picket\"],\"editor.inspector.option.pointed.effedk\":[\"Pointed\"],\"editor.inspector.option.postAndRail.lajk2u\":[\"Post and rail\"],\"editor.inspector.option.preserveHighEdge.y6ywf0\":[\"Preserve high edge\"],\"editor.inspector.option.preserveLowEdge.196m5pk\":[\"Preserve low edge\"],\"editor.inspector.option.preservePitch.1uq973r\":[\"Preserve pitch\"],\"editor.inspector.option.privacy.1th4hrb\":[\"Privacy\"],\"editor.inspector.option.purlins.od124c\":[\"Purlins\"],\"editor.inspector.option.pvc.1oc4u2w\":[\"Pvc\"],\"editor.inspector.option.pyramid.17ucsqv\":[\"Pyramid\"],\"editor.inspector.option.rafters.16tzbby\":[\"Rafters\"],\"editor.inspector.option.rail.39zqc9\":[\"Rail\"],\"editor.inspector.option.raised.4kyx9h\":[\"Raised\"],\"editor.inspector.option.rect.tpfvaf\":[\"Rect\"],\"editor.inspector.option.reducer.18byt67\":[\"Reducer\"],\"editor.inspector.option.return.1klrjrz\":[\"Return\"],\"editor.inspector.option.returnGrille.r28ncm\":[\"Return grille\"],\"editor.inspector.option.right.8humpx\":[\"Right\"],\"editor.inspector.option.round.1vx0wyj\":[\"Round\"],\"editor.inspector.option.rounded.199nwpm\":[\"Rounded\"],\"editor.inspector.option.sanitaryTee.oro3d4\":[\"Sanitary tee\"],\"editor.inspector.option.scalloped.1eltba0\":[\"Scalloped\"],\"editor.inspector.option.scoop.qy5zdv\":[\"Scoop\"],\"editor.inspector.option.segmentedPanel.5r3hwl\":[\"Segmented panel\"],\"editor.inspector.option.shed.6t994v\":[\"Shed\"],\"editor.inspector.option.sheetMetal.l164lv\":[\"Sheet metal\"],\"editor.inspector.option.shingle.pfmynh\":[\"Shingle\"],\"editor.inspector.option.shingled.1nm9inf\":[\"Shingled\"],\"editor.inspector.option.simple.12mfu73\":[\"Simple\"],\"editor.inspector.option.single.1uzxurt\":[\"Single\"],\"editor.inspector.option.singleLeft.1atdh02\":[\"Single left\"],\"editor.inspector.option.singleRight.1axbu67\":[\"Single right\"],\"editor.inspector.option.slantBox.1ta99vy\":[\"Slant box\"],\"editor.inspector.option.slat.1p9njbz\":[\"Slat\"],\"editor.inspector.option.sliding.cd0jox\":[\"Sliding\"],\"editor.inspector.option.slope.1bn2qw\":[\"Slope\"],\"editor.inspector.option.sloped.lo4sh0\":[\"Sloped\"],\"editor.inspector.option.solid.o4uy6s\":[\"Solid\"],\"editor.inspector.option.solidPanel.2yaw62\":[\"Solid panel\"],\"editor.inspector.option.spiral.91hcl4\":[\"Spiral\"],\"editor.inspector.option.splash.1uke4cm\":[\"Splash\"],\"editor.inspector.option.spread.1g1zysu\":[\"Spread\"],\"editor.inspector.option.square.1xl1lk6\":[\"Square\"],\"editor.inspector.option.stair.1xf86e\":[\"Stair\"],\"editor.inspector.option.standard.vuco\":[\"Standard\"],\"editor.inspector.option.start.30xvgf\":[\"Start\"],\"editor.inspector.option.step.jtn9kf\":[\"Step\"],\"editor.inspector.option.stepped.naxzh0\":[\"Stepped\"],\"editor.inspector.option.straight.lxqbfr\":[\"Straight\"],\"editor.inspector.option.strap.14q0ps9\":[\"Strap\"],\"editor.inspector.option.supply.1oy2zwu\":[\"Supply\"],\"editor.inspector.option.supplyRegister.1lzdbbn\":[\"Supply register\"],\"editor.inspector.option.tapered.3y5blo\":[\"Tapered\"],\"editor.inspector.option.targetSpacing.14uibc9\":[\"Target spacing\"],\"editor.inspector.option.tee.7d6tjp\":[\"Tee\"],\"editor.inspector.option.tilted.6n0u5j\":[\"Tilted\"],\"editor.inspector.option.top.2nypcs\":[\"Top\"],\"editor.inspector.option.transition.1rziz9e\":[\"Transition\"],\"editor.inspector.option.vent.xda5j2\":[\"Vent\"],\"editor.inspector.option.walkOn.1n5sg9l\":[\"Walk on\"],\"editor.inspector.option.wall.blj585\":[\"Wall\"],\"editor.inspector.option.wallAbutment.lza941\":[\"Wall abutment\"],\"editor.inspector.option.wallLedger.5m8ana\":[\"Wall ledger\"],\"editor.inspector.option.wallShelf.yiozfl\":[\"Wall shelf\"],\"editor.inspector.option.waste.3xrp79\":[\"Waste\"],\"editor.inspector.option.wye.14vupc8\":[\"Wye\"],\"editor.layers.collapse\":[\"Collapse\"],\"editor.layers.defaultName.ceiling\":[\"Ceiling (\",[\"area\"],\")\"],\"editor.layers.defaultName.collection\":[\"Collection\"],\"editor.layers.defaultName.flight\":[\"Flight (\",[\"width\"],\"×\",[\"length\"],\"m)\"],\"editor.layers.defaultName.landing\":[\"Landing (\",[\"width\"],\"×\",[\"length\"],\"m)\"],\"editor.layers.defaultName.node\":[\"Node\"],\"editor.layers.defaultName.roof\":[\"Roof (\",[\"count\",\"plural\",{\"one\":[\"#\",\" segment\"],\"other\":[\"#\",\" segments\"]}],\")\"],\"editor.layers.defaultName.roofSegment\":[[\"roofType\",\"select\",{\"hip\":[\"Hip\"],\"gable\":[\"Gable\"],\"shed\":[\"Shed\"],\"gambrel\":[\"Gambrel\"],\"dutch\":[\"Dutch\"],\"mansard\":[\"Mansard\"],\"flat\":[\"Flat\"],\"conical\":[\"Conical\"],\"barrel\":[\"Barrel\"],\"other\":[\"Roof\"]}],\" (\",[\"width\"],\"×\",[\"depth\"],\"m)\"],\"editor.layers.defaultName.room\":[\"Room (\",[\"area\"],\")\"],\"editor.layers.defaultName.slab\":[\"Slab (\",[\"area\"],\")\"],\"editor.layers.defaultName.staircase\":[\"Staircase (\",[\"count\",\"plural\",{\"one\":[\"#\",\" segment\"],\"other\":[\"#\",\" segments\"]}],\")\"],\"editor.layers.defaultName.zone\":[\"Zone (\",[\"area\"],\")\"],\"editor.layers.expand\":[\"Expand\"],\"editor.layers.levelOptions\":[[\"levelName\"],\" options\"],\"editor.layers.rename\":[\"Rename\"],\"editor.layers.spaceColour\":[[\"role\",\"select\",{\"room\":[\"Room colour\"],\"other\":[\"Zone colour\"]}]],\"editor.layers.unitColour\":[\"Unit colour\"],\"editor.levelDuplicateDialog.cancel\":[\"Cancel\"],\"editor.levelDuplicateDialog.chooseWhatToCopyFromLevel\":[\"Choose what to copy from \",[\"levelName\"],\".\"],\"editor.levelDuplicateDialog.chooseWhatToCopyFromThisLevel\":[\"Choose what to copy from this level.\"],\"editor.levelDuplicateDialog.duplicate\":[\"Duplicate\"],\"editor.levelDuplicateDialog.duplicateLevel\":[\"Duplicate Level\"],\"editor.levelDuplicateDialog.everything\":[\"Everything\"],\"editor.levelDuplicateDialog.structureFinishesAndPlacedItemsWithout\":[\"Structure, finishes, and placed items, without guide references.\"],\"editor.levelDuplicateDialog.structureFurniture\":[\"Structure + furniture\"],\"editor.levelDuplicateDialog.structureMaterials\":[\"Structure + materials\"],\"editor.levelDuplicateDialog.structureMaterialsFurnitureAndReferences\":[\"Structure, materials, furniture, and references.\"],\"editor.levelDuplicateDialog.structureOnly\":[\"Structure only\"],\"editor.levelDuplicateDialog.structureWithTheCurrentMaterialAnd\":[\"Structure with the current material and finish assignments.\"],\"editor.levelDuplicateDialog.wallsSlabsRoofsStairsWindowsAnd\":[\"Walls, slabs, roofs, stairs, windows, and doors without finishes.\"],\"editor.levelWallCopyPrompt.copy\":[\"Copy\"],\"editor.levelWallCopyPrompt.copyExteriorWallsFromTheLevel\":[\"Copy exterior walls from the level \",[\"direction\"],\"?\"],\"editor.levelWallCopyPrompt.noThanks\":[\"No thanks\"],\"editor.levelWallCopyPrompt.sourcenameSOutsideWallsInPlace\":[[\"sourceName\"],\"’s outside walls, in place, so this level lines up with it.\"],\"editor.lib.contextualHelp.addOrRemoveObjectsFromThe\":[\"Add or remove objects from the selection\"],\"editor.lib.contextualHelp.adjustOneSideSCornerRadius\":[\"Adjust one side’s corner radius\"],\"editor.lib.contextualHelp.clearTheSelectionOrClickOutside\":[\"Clear the selection (or click outside)\"],\"editor.lib.contextualHelp.clickAHandleDotToShow\":[\"Click a handle dot to show move arrows\"],\"editor.lib.contextualHelp.clickOrDragTheSelectionTo\":[\"Click or drag the selection to move it as one\"],\"editor.lib.contextualHelp.clickTheHandleDotToShow\":[\"Click the handle dot to show move + rotate handles\"],\"editor.lib.contextualHelp.detachTheJointWhileDraggingAn\":[\"Detach the joint while dragging an arrow\"],\"editor.lib.contextualHelp.dragLeftOrRightToRotate\":[\"Drag left or right to rotate selected object\"],\"editor.lib.contextualHelp.dragSelectedMovableObject\":[\"Drag selected movable object\"],\"editor.lib.contextualHelp.groupSelectionSessionOnly\":[\"Group selection (session only)\"],\"editor.lib.contextualHelp.holdToRotateFreely\":[\"Hold to rotate freely\"],\"editor.lib.contextualHelp.rotate45\":[\"Rotate ±45°\"],\"editor.lib.contextualHelp.rotateTheSelection45\":[\"Rotate the selection ±45°\"],\"editor.lib.contextualHelp.rotatingFreely\":[\"Rotating freely (no angle step)\"],\"editor.lib.contextualHelp.switchTheRotationAxisYX\":[\"Switch the rotation axis (Y → X → Z)\"],\"editor.lib.contextualHelp.ungroupSessionSelection\":[\"Ungroup session selection\"],\"editor.lib.continuation.continuous\":[\"Continuous\"],\"editor.lib.continuation.continuousCanopy\":[\"Continuous canopy\"],\"editor.lib.continuation.continuousRun\":[\"Continuous run\"],\"editor.lib.continuation.curvedFence\":[\"Curved fence\"],\"editor.lib.continuation.freehandFence\":[\"Freehand fence\"],\"editor.lib.continuation.placeMultiple\":[\"Place multiple\"],\"editor.lib.continuation.placeOnce\":[\"Place once\"],\"editor.lib.continuation.polygonRoom\":[\"Polygon room\"],\"editor.lib.continuation.rectangleRoom\":[\"Rectangle room\"],\"editor.lib.continuation.singleCabinet\":[\"Single cabinet\"],\"editor.lib.continuation.singleCanopy\":[\"Single canopy\"],\"editor.lib.continuation.singleFence\":[\"Single fence\"],\"editor.lib.continuation.walls\":[\"Walls\"],\"editor.lib.hudTitle.cutOpening\":[\"Cut opening\"],\"editor.lib.hudTitle.divideRoom\":[\"Divide room\"],\"editor.lib.hudTitle.editKind\":[\"Edit \",[\"kind\"]],\"editor.lib.hudTitle.erase\":[\"Erase\"],\"editor.lib.hudTitle.levelTerrain\":[\"Level terrain\"],\"editor.lib.hudTitle.lowerTerrain\":[\"Lower terrain\"],\"editor.lib.hudTitle.mezzanine\":[\"Mezzanine\"],\"editor.lib.hudTitle.moveKind\":[\"Move \",[\"kind\"]],\"editor.lib.hudTitle.moveRoom\":[\"Move room\"],\"editor.lib.hudTitle.moveSelection\":[\"Move selection\"],\"editor.lib.hudTitle.paint\":[\"Paint\"],\"editor.lib.hudTitle.paintARectangle\":[\"Paint a rectangle\"],\"editor.lib.hudTitle.paintAShape\":[\"Paint a shape\"],\"editor.lib.hudTitle.pickMaterial\":[\"Pick material\"],\"editor.lib.hudTitle.raiseTerrain\":[\"Raise terrain\"],\"editor.lib.hudTitle.resize\":[\"Resize\"],\"editor.lib.hudTitle.rotate\":[\"Rotate\"],\"editor.lib.hudTitle.select\":[\"Select\"],\"editor.lib.hudTitle.smartMeasure\":[\"Smart measure\"],\"editor.lib.hudTitle.smoothTerrain\":[\"Smooth terrain\"],\"editor.lib.hudTitle.splitKind\":[\"Split \",[\"kind\"]],\"editor.lib.hudTitle.terrace\":[\"Terrace\"],\"editor.lib.wallDrawVariant.kind.invisible\":[\"Invisible\"],\"editor.lib.wallDrawVariant.kind.railing\":[\"Railing\"],\"editor.lib.wallDrawVariant.kind.standard\":[\"Standard\"],\"editor.lib.wallDrawVariant.polygonRoom\":[\"Polygon room\"],\"editor.lib.wallDrawVariant.rectangleRoom\":[\"Rectangle room\"],\"editor.lib.wallDrawVariant.walls\":[\"Walls\"],\"editor.mechanismAction\":[[\"action\",\"select\",{\"close\":[\"Close\"],\"open\":[\"Open\"],\"stop\":[\"Stop\"],\"other\":[\"Play\"]}]],\"editor.nodeActionMenu.curve\":[\"Curve\"],\"editor.nodeActionMenu.cutOut\":[\"Cut out\"],\"editor.nodeActionMenu.delete\":[\"Delete\"],\"editor.nodeActionMenu.duplicate\":[\"Duplicate\"],\"editor.nodeActionMenu.editMesh\":[\"Edit mesh\"],\"editor.nodeActionMenu.findInCatalog\":[\"Find in catalog\"],\"editor.nodeActionMenu.groupSelection\":[\"Group selection\"],\"editor.nodeActionMenu.move\":[\"Move\"],\"editor.nodeActionMenu.rotateLeft\":[\"Rotate left\"],\"editor.nodeActionMenu.rotateRight\":[\"Rotate right\"],\"editor.nodeActionMenu.ungroupSelection\":[\"Ungroup selection\"],\"editor.nodeDisplay.ceiling\":[\"Ceiling\"],\"editor.nodeDisplay.column\":[\"Column\"],\"editor.nodeDisplay.door\":[\"Door\"],\"editor.nodeDisplay.elevator\":[\"Elevator\"],\"editor.nodeDisplay.fence\":[\"Fence\"],\"editor.nodeDisplay.guide\":[\"Guide image\"],\"editor.nodeDisplay.item\":[\"Item\"],\"editor.nodeDisplay.roof\":[\"Roof\"],\"editor.nodeDisplay.roofSegment\":[\"Roof segment\"],\"editor.nodeDisplay.room\":[\"Room\"],\"editor.nodeDisplay.scan\":[\"3D Scan\"],\"editor.nodeDisplay.selection\":[\"Selection\"],\"editor.nodeDisplay.slab\":[\"Slab\"],\"editor.nodeDisplay.stair\":[\"Stair\"],\"editor.nodeDisplay.stairSegment\":[\"Stair segment\"],\"editor.nodeDisplay.wall\":[\"Wall\"],\"editor.nodeDisplay.window\":[\"Window\"],\"editor.nodeDisplay.zone\":[\"Zone\"],\"editor.panels.collections.collectionsPopover.cancel\":[\"Cancel\"],\"editor.panels.collections.collectionsPopover.collectionName\":[\"Collection name…\"],\"editor.panels.collections.collectionsPopover.collections\":[\"Collections\"],\"editor.panels.collections.collectionsPopover.delete\":[\"Delete\"],\"editor.panels.collections.collectionsPopover.deleteName\":[\"Delete \\\"\",[\"name\"],\"\\\"?\"],\"editor.panels.collections.collectionsPopover.new\":[\"New\"],\"editor.panels.collections.collectionsPopover.noCollectionsYetCreateOneTo\":[\"No collections yet. Create one to group elements together.\"],\"editor.panels.collections.collectionsPopover.rename\":[\"Rename\"],\"editor.panels.deckBoardsFields.alongHouse\":[\"Along house\"],\"editor.panels.deckBoardsFields.boards\":[\"Boards\"],\"editor.panels.deckBoardsFields.boardsSummary\":[[\"label\"],\" boards \",[\"thickness\"],\" × \",[\"width\"],\" in, \",[\"gap\"],\" in apart, \",[\"direction\",\"select\",{\"parallel\":[\"along the house, on joists square to it\"],\"diagonal\":[\"at 45° to the house\"],\"other\":[\"out from the house, on joists along it, carried by beams square to the house\"]}],\"; joists \",[\"spacing\"],\" in on centre.\"],\"editor.panels.deckBoardsFields.deckBoards\":[\"Deck boards\"],\"editor.panels.deckBoardsFields.diagonal\":[\"Diagonal\"],\"editor.panels.deckBoardsFields.gap\":[\"Gap\"],\"editor.panels.deckBoardsFields.outFromHouse\":[\"Out from house\"],\"editor.panels.deckBoardsFields.run\":[\"Run\"],\"editor.panels.floorFoundationPanel.aThickerFloorGrowsUpwardThe\":[\"A thicker floor grows upward: the rooms below keep their height.\"],\"editor.panels.floorFoundationPanel.edgeFinish\":[\"Edge finish\"],\"editor.panels.floorFoundationPanel.floorPlate\":[\"Floor plate\"],\"editor.panels.floorFoundationPanel.floorPlateThicknesslabelThickRestingOn\":[\"Floor plate \",[\"thicknessLabel\"],\" thick, resting on the walls below\"],\"editor.panels.floorFoundationPanel.floorThickness\":[\"Floor thickness\"],\"editor.panels.floorFoundationPanel.floorTopAbove\":[\"Floor top +\",[\"height\"]],\"editor.panels.floorFoundationPanel.floorTopValue\":[\"Floor top \",[\"height\"]],\"editor.panels.floorFoundationPanel.foundationFinish\":[\"Foundation finish\"],\"editor.panels.floorFoundationPanel.foundationHeight\":[\"Foundation height\"],\"editor.panels.floorFoundationPanel.kicker\":[\"Floor plate\"],\"editor.panels.floorFoundationPanel.kickerLevel\":[\"Floor plate · \",[\"level\"]],\"editor.panels.floorFoundationPanel.kickerRestsOn\":[\"Floor plate · \",[\"level\"],\" · rests on \",[\"below\"]],\"editor.panels.floorFoundationPanel.lowerTogether\":[[\"count\",\"plural\",{\"2\":[\"Lower both\"],\"other\":[\"Lower all \",[\"number\"]]}]],\"editor.panels.floorFoundationPanel.notToScale\":[\"Not to scale\"],\"editor.panels.floorFoundationPanel.onTheGround\":[\"On the ground\"],\"editor.panels.floorFoundationPanel.raiseTogether\":[[\"count\",\"plural\",{\"2\":[\"Raise both\"],\"other\":[\"Raise all \",[\"number\"]]}]],\"editor.panels.floorFoundationPanel.raisedOnAFoundation\":[\"Raised on a foundation\"],\"editor.panels.floorFoundationPanel.section.floorPlate\":[\"Floor plate · \",[\"thickness\"]],\"editor.panels.floorFoundationPanel.section.floorTop\":[\"Floor top\"],\"editor.panels.floorFoundationPanel.section.foundation\":[\"Foundation\"],\"editor.panels.floorFoundationPanel.section.foundationKind\":[\"Foundation · \",[\"foundation\"]],\"editor.panels.floorFoundationPanel.section.ground\":[\"Ground\"],\"editor.panels.floorFoundationPanel.section.slab\":[\"Slab · \",[\"thickness\"]],\"editor.panels.floorFoundationPanel.section.wallsBelow\":[\"Walls below\"],\"editor.panels.floorFoundationPanel.sectionOnGround\":[\"Slab \",[\"thickness\"],\" thick on the ground, floor top \",[\"top\"],\" above the ground\"],\"editor.panels.floorFoundationPanel.sectionRaised\":[\"Slab \",[\"thickness\"],\" thick on a \",[\"foundation\"],\" foundation, floor top \",[\"top\"],\" above the ground\"],\"editor.panels.floorFoundationPanel.slab\":[\"Slab\"],\"editor.panels.floorFoundationPanel.slabThickness\":[\"Slab thickness\"],\"editor.panels.floorFoundationPanel.theFloorSOutsideEdgeAll\":[\"The floor's outside edge, all around the footprint.\"],\"editor.panels.floorFoundationPanel.theFoundationStandsOnTheGround\":[\"The foundation stands on the ground; the slab sits on it.\"],\"editor.panels.floorFoundationPanel.theSlabSitsOnTheFoundation\":[\"The slab sits on the foundation (or the ground): a thicker slab raises the floor top and everything on it.\"],\"editor.panels.floorFoundationPanel.underTheFloor\":[\"Under the floor\"],\"editor.panels.floorOpeningPanel.aHatchInTheMezzanineIt\":[\"A hatch in the mezzanine: it cuts only the mezzanine’s floor.\"],\"editor.panels.floorOpeningPanel.alsoCutTheCeilingBelow\":[\"Also cut the ceiling below\"],\"editor.panels.floorOpeningPanel.alsoCutTheFloorAbove\":[\"Also cut the floor above\"],\"editor.panels.floorOpeningPanel.areaDragCorners\":[[\"area\"],\" · Drag its corners to change the shape.\"],\"editor.panels.floorOpeningPanel.areaOwned\":[[\"area\"],\" · Shape follows its owner.\"],\"editor.panels.floorOpeningPanel.areaStairResize\":[[\"area\"],\" · Drag its sides or corners to resize it; it moves with the stair.\"],\"editor.panels.floorOpeningPanel.delete\":[\"Delete\"],\"editor.panels.floorOpeningPanel.done\":[\"Done\"],\"editor.panels.floorOpeningPanel.kicker\":[\"Opening\"],\"editor.panels.floorOpeningPanel.kickerLevel\":[\"Opening · \",[\"level\"]],\"editor.panels.floorOpeningPanel.kickerRoom\":[\"Opening · in \",[\"room\"]],\"editor.panels.floorOpeningPanel.kickerRoomLevel\":[\"Opening · in \",[\"room\"],\" · \",[\"level\"]],\"editor.panels.floorOpeningPanel.oneVoidWith\":[\"On \",[\"level\"],\", as one void with this opening.\"],\"editor.panels.floorOpeningPanel.ownedByElevator\":[\"Owned by Elevator\"],\"editor.panels.floorOpeningPanel.ownedByStaircase\":[\"Owned by Staircase\"],\"editor.panels.floorOpeningPanel.room\":[\"Room\"],\"editor.panels.floorOpeningPanel.thereIsNoFloorAboveThis\":[\"There is no floor above this storey.\"],\"editor.panels.floorOpeningPanel.thereIsNoStoreyBelow\":[\"There is no storey below.\"],\"editor.panels.floorOpeningPanel.title\":[[\"source\",\"select\",{\"stair\":[\"Stair opening\"],\"elevator\":[\"Elevator opening\"],\"ceiling\":[\"Ceiling opening\"],\"other\":[\"Floor opening\"]}]],\"editor.panels.mergeRefusal.alreadyJoined\":[\"One of them already wraps another corner. Unwrap it first.\"],\"editor.panels.mergeRefusal.between\":[[\"kind\",\"select\",{\"item\":[\"There is an item between them.\"],\"door\":[\"There is a door between them.\"],\"window\":[\"There is a window between them.\"],\"shelf\":[\"There is a shelf between them.\"],\"other\":[\"There is something between them.\"]}]],\"editor.panels.mergeRefusal.cannotMerge\":[\"These windows cannot be merged.\"],\"editor.panels.mergeRefusal.cornerAngle\":[\"Their walls meet at too sharp or too flat an angle for a corner window.\"],\"editor.panels.mergeRefusal.heightExceedsWall\":[\"The window selected first is taller than the other wall. Select the other one first.\"],\"editor.panels.mergeRefusal.notAdjacent\":[\"They are too far apart. Windows merge with at most \",[\"reach\"],\" between them.\"],\"editor.panels.mergeRefusal.notAtCorner\":[\"One of them is too far from the corner. A window joins one within \",[\"reach\"],\" of it.\"],\"editor.panels.mergeRefusal.notOnWall\":[\"A roof or dormer window cannot join another window.\"],\"editor.panels.mergeRefusal.overlap\":[[\"kind\",\"select\",{\"item\":[\"Sliding them to the corner would overlap an item.\"],\"door\":[\"Sliding them to the corner would overlap a door.\"],\"window\":[\"Sliding them to the corner would overlap a window.\"],\"shelf\":[\"Sliding them to the corner would overlap a shelf.\"],\"other\":[\"Sliding them to the corner would overlap something.\"]}]],\"editor.panels.mergeRefusal.wallsNotMeeting\":[\"Their walls do not meet at a corner.\"],\"editor.panels.mixed\":[\"Mixed\"],\"editor.panels.mobilePanelSheet.close\":[\"Close\"],\"editor.panels.mobileSelectionBar.delete\":[\"Delete\"],\"editor.panels.mobileSelectionBar.duplicate\":[\"Duplicate\"],\"editor.panels.mobileSelectionBar.editProperties\":[\"Edit properties\"],\"editor.panels.mobileSelectionBar.editResolvedlabel\":[\"Edit \",[\"resolvedLabel\"]],\"editor.panels.mobileSelectionBar.move\":[\"Move\"],\"editor.panels.multiHeightMode.currentlyCurrentlabel\":[\"Currently \",[\"currentLabel\"]],\"editor.panels.multiHeightMode.customHeight\":[\"Custom height\"],\"editor.panels.multiHeightMode.followsLevel\":[\"Follows level\"],\"editor.panels.multiHeightMode.height\":[\"Height\"],\"editor.panels.multiHeightMode.top\":[\"Top\"],\"editor.panels.multiParametricInspector.labelSessionOnlyPlainClickReselects\":[[\"label\"],\" (session only). Plain click reselects all members. Not saved with the project.\"],\"editor.panels.multiSelectionPanel.delete\":[\"Delete\"],\"editor.panels.multiSelectionPanel.duplicate\":[\"Duplicate\"],\"editor.panels.multiSelectionPanel.group\":[\"Group\"],\"editor.panels.multiSelectionPanel.groupCtrlCmdG\":[\"Group (Ctrl/Cmd+G)\"],\"editor.panels.multiSelectionPanel.labelSessionOnlyPlainClickReselects\":[[\"label\"],\" (session only). Plain click reselects all members. Not saved with the project.\"],\"editor.panels.multiSelectionPanel.lengthSelected\":[[\"length\"],\" selected\"],\"editor.panels.multiSelectionPanel.mergeWindows\":[\"Merge windows\"],\"editor.panels.multiSelectionPanel.mergeWindowsIntoACornerWindow\":[\"Merge windows into a corner window: both take the height, sill and type of the one you selected first\"],\"editor.panels.multiSelectionPanel.mergeWindowsIntoOneAcrossBoth\":[\"Merge windows into one across both: it keeps the type and style of the one you selected first\"],\"editor.panels.multiSelectionPanel.selectBuilding\":[\"Select building\"],\"editor.panels.multiSelectionPanel.selectTheWholeBuildingToMove\":[\"Select the whole building to move all its levels\"],\"editor.panels.multiSelectionPanel.ungroup\":[\"Ungroup\"],\"editor.panels.multiSelectionPanel.ungroupCtrlCmdShiftG\":[\"Ungroup (Ctrl/Cmd+Shift+G)\"],\"editor.panels.multiSelectionPanel.unwrapTheCorner\":[\"Unwrap the corner\"],\"editor.panels.multiSelectionPanel.unwrapTheCornerBothWindowsStay\":[\"Unwrap the corner: both windows stay, each framed at the corner\"],\"editor.panels.panelManager.selection\":[\"Selection\"],\"editor.panels.panelWrapper.back\":[\"Back\"],\"editor.panels.panelWrapper.close\":[\"Close\"],\"editor.panels.panelWrapper.collapsePanel\":[\"Collapse panel\"],\"editor.panels.panelWrapper.collections\":[\"Collections\"],\"editor.panels.panelWrapper.expandPanel\":[\"Expand panel\"],\"editor.panels.panelWrapper.manageCollections\":[\"Manage collections…\"],\"editor.panels.panelWrapper.reset\":[\"Reset\"],\"editor.panels.panelWrapper.titleHitAnErrorAndWas\":[\"“\",[\"title\"],\"” hit an error and was unloaded for this session.\"],\"editor.panels.parametricFieldControl.mixed\":[\"Mixed\"],\"editor.panels.parametricInspector.actions\":[\"Actions\"],\"editor.panels.parametricInspector.delete\":[\"Delete\"],\"editor.panels.parametricInspector.deleteWithContents\":[\"Delete with contents\"],\"editor.panels.parametricInspector.move\":[\"Move\"],\"editor.panels.referencePanel.cancel\":[\"Cancel\"],\"editor.panels.referencePanel.capture\":[\"Capture\"],\"editor.panels.referencePanel.center\":[\"Center\"],\"editor.panels.referencePanel.clearScale\":[\"Clear Scale\"],\"editor.panels.referencePanel.clickBothEndsOfAKnown\":[\"Click both ends of a known distance on the plan, then type its real length.\"],\"editor.panels.referencePanel.delete\":[\"Delete\"],\"editor.panels.referencePanel.drawALineOverAKnown\":[\"Draw a line over a known dimension on the plan, then type its real length to scale the image exactly.\"],\"editor.panels.referencePanel.editScale\":[\"Edit Scale\"],\"editor.panels.referencePanel.guideImage\":[\"Guide Image\"],\"editor.panels.referencePanel.hide\":[\"Hide\"],\"editor.panels.referencePanel.hideScale\":[\"Hide Scale\"],\"editor.panels.referencePanel.image\":[\"Image\"],\"editor.panels.referencePanel.lock\":[\"Lock\"],\"editor.panels.referencePanel.move\":[\"Move\"],\"editor.panels.referencePanel.opacity\":[\"Opacity\"],\"editor.panels.referencePanel.overlayImageUnavailableReplaceTheImage\":[\"Overlay image unavailable. Replace the image to restore it.\"],\"editor.panels.referencePanel.pos\":[\"pos\"],\"editor.panels.referencePanel.position\":[\"Position\"],\"editor.panels.referencePanel.quickActions\":[\"Quick Actions\"],\"editor.panels.referencePanel.referenceScale\":[\"Reference Scale\"],\"editor.panels.referencePanel.replace\":[\"Replace\"],\"editor.panels.referencePanel.replacing\":[\"Replacing...\"],\"editor.panels.referencePanel.resetImageScale\":[\"Reset Image Scale\"],\"editor.panels.referencePanel.resetRotation\":[\"Reset Rotation\"],\"editor.panels.referencePanel.rot\":[\"rot\"],\"editor.panels.referencePanel.rotation\":[\"Rotation\"],\"editor.panels.referencePanel.scale\":[\"scale\"],\"editor.panels.referencePanel.scaleOpacity\":[\"Scale & Opacity\"],\"editor.panels.referencePanel.scaled\":[\"Scaled · \",[\"scale\"]],\"editor.panels.referencePanel.scaledHidden\":[\"Scaled (hidden) · \",[\"scale\"]],\"editor.panels.referencePanel.setScale\":[\"Set Scale\"],\"editor.panels.referencePanel.show\":[\"Show\"],\"editor.panels.referencePanel.showScale\":[\"Show Scale\"],\"editor.panels.referencePanel.uncalibrated\":[\"Uncalibrated\"],\"editor.panels.referencePanel.unlock\":[\"Unlock\"],\"editor.panels.referencePanel.xyz\":[\"XYZ\"],\"editor.panels.roomConstructionRows.aDrawnSlabSetItsThickness\":[\"A drawn slab: set its thickness and finishes here. It has no footprint height or foundation.\"],\"editor.panels.roomConstructionRows.addMezzanine\":[\"+ Add mezzanine\"],\"editor.panels.roomConstructionRows.atFloorLevel\":[\"At floor level\"],\"editor.panels.roomConstructionRows.beam\":[\"Beam\"],\"editor.panels.roomConstructionRows.beamSize\":[\"Beam size\"],\"editor.panels.roomConstructionRows.builtOn\":[\"Built on\"],\"editor.panels.roomConstructionRows.builtWith\":[\"Built with\"],\"editor.panels.roomConstructionRows.ceiling\":[\"Ceiling\"],\"editor.panels.roomConstructionRows.ceilingAt\":[\"At \",[\"height\"]],\"editor.panels.roomConstructionRows.closeWithWalls\":[\"Close with walls\"],\"editor.panels.roomConstructionRows.drawnFloor\":[[\"ambiguous\",\"select\",{\"yes\":[\"Floor is several drawn slabs, mostly \",[\"name\"]],\"other\":[\"Floor is a drawn slab: \",[\"name\"]]}],[\"shared\",\"plural\",{\"0\":[],\"one\":[\" (shared with \",[\"sharedCount\"],\" room)\"],\"other\":[\" (shared with \",[\"sharedCount\"],\" rooms)\"]}]],\"editor.panels.roomConstructionRows.drawnFloorSwitchHint\":[\"This floor is a drawn slab: select it to edit or delete it.\"],\"editor.panels.roomConstructionRows.drawnSlab\":[\"Drawn slab\"],\"editor.panels.roomConstructionRows.drawnSlabAt\":[\"Drawn slab at \",[\"height\"]],\"editor.panels.roomConstructionRows.editShape\":[\"Edit shape\"],\"editor.panels.roomConstructionRows.flatAtWallHeight\":[\"Flat, at wall height\"],\"editor.panels.roomConstructionRows.floor\":[\"Floor\"],\"editor.panels.roomConstructionRows.floorDown\":[[\"distance\"],\" down\"],\"editor.panels.roomConstructionRows.floorThickness\":[\"Floor thickness\"],\"editor.panels.roomConstructionRows.floorUp\":[[\"distance\"],\" up\"],\"editor.panels.roomConstructionRows.framingAutoHint\":[[\"posts\",\"plural\",{\"one\":[[\"postCount\"],\" post\"],\"other\":[[\"postCount\"],\" posts\"]}],\" and \",[\"beams\",\"plural\",{\"one\":[[\"beamCount\"],\" beam\"],\"other\":[[\"beamCount\"],\" beams\"]}],\", a post on each outside corner, kept with \",[\"room\",\"select\",{\"deck\":[\"the deck\"],\"patio\":[\"the patio\"],\"other\":[\"the porch\"]}],\".\"],\"editor.panels.roomConstructionRows.framingAutomatic\":[\"Automatic\"],\"editor.panels.roomConstructionRows.framingManual\":[\"Manual\"],\"editor.panels.roomConstructionRows.framingManualHint\":[\"Kept as you edited them. Automatic rebuilds them from these settings.\"],\"editor.panels.roomConstructionRows.framingOff\":[\"Off\"],\"editor.panels.roomConstructionRows.framingOffHint\":[\"None. Automatic puts a post on each outside corner and a beam on them, to carry a roof over \",[\"room\",\"select\",{\"deck\":[\"the deck\"],\"patio\":[\"the patio\"],\"other\":[\"the porch\"]}],\".\"],\"editor.panels.roomConstructionRows.handDrawnCeiling\":[\"Hand-drawn ceiling\"],\"editor.panels.roomConstructionRows.height\":[\"Height\"],\"editor.panels.roomConstructionRows.includeFloor\":[\"Include floor\"],\"editor.panels.roomConstructionRows.includePart\":[[\"part\",\"select\",{\"floor\":[\"Include floor\"],\"walls\":[\"Include walls\"],\"other\":[\"Include ceiling\"]}]],\"editor.panels.roomConstructionRows.includeWalls\":[\"Include walls\"],\"editor.panels.roomConstructionRows.keepOutsideDimensions\":[\"Keep outside dimensions\"],\"editor.panels.roomConstructionRows.lowered\":[\"Lowered \",[\"lift\"]],\"editor.panels.roomConstructionRows.newFloor\":[\"+ New floor\"],\"editor.panels.roomConstructionRows.noFloor\":[\"No floor\"],\"editor.panels.roomConstructionRows.notIncluded\":[\"Not included\"],\"editor.panels.roomConstructionRows.nothingToChange\":[\"Nothing to change.\"],\"editor.panels.roomConstructionRows.onTheGround\":[\"On the ground\"],\"editor.panels.roomConstructionRows.onTheWallsBelow\":[\"On the walls below\"],\"editor.panels.roomConstructionRows.openSides\":[[\"openSides\",\"plural\",{\"one\":[[\"openSideCount\"],\" open side\"],\"other\":[[\"openSideCount\"],\" open sides\"]}]],\"editor.panels.roomConstructionRows.partialCovered\":[\"Partial · \",[\"coverage\",\"number\",\"percent\"],\" covered\"],\"editor.panels.roomConstructionRows.partialWalls\":[\"Partial · \",[\"walls\",\"plural\",{\"one\":[[\"wallCount\"],\" wall\"],\"other\":[[\"wallCount\"],\" walls\"]}],\", \",[\"openSides\",\"plural\",{\"one\":[[\"openSideCount\"],\" open side\"],\"other\":[[\"openSideCount\"],\" open sides\"]}]],\"editor.panels.roomConstructionRows.postSize\":[\"Post size\"],\"editor.panels.roomConstructionRows.postSpacingMax\":[\"Post spacing (max)\"],\"editor.panels.roomConstructionRows.postsAndBeam\":[\"Posts and beam\"],\"editor.panels.roomConstructionRows.raised\":[\"Raised \",[\"lift\"]],\"editor.panels.roomConstructionRows.replace\":[\"Replace\"],\"editor.panels.roomConstructionRows.roomType\":[\"Room type\"],\"editor.panels.roomConstructionRows.roomTypeDeck\":[\"Deck\"],\"editor.panels.roomConstructionRows.roomTypeDeckHint\":[\"Outdoors: deck boards on a wood frame and posts, 1 in down from the house; no ceiling.\"],\"editor.panels.roomConstructionRows.roomTypePatio\":[\"Patio\"],\"editor.panels.roomConstructionRows.roomTypePatioHint\":[\"Outdoors and open: a concrete slab 1½ in down from the house, no ceiling.\"],\"editor.panels.roomConstructionRows.roomTypePorch\":[\"Porch\"],\"editor.panels.roomConstructionRows.roomTypePorchHint\":[\"Outdoors under a ceiling: a concrete slab 1½ in down from the house, ceiling at the house’s.\"],\"editor.panels.roomConstructionRows.roomTypeRoom\":[\"Room\"],\"editor.panels.roomConstructionRows.roomTypeRoomHint\":[\"An ordinary room inside the house.\"],\"editor.panels.roomConstructionRows.select\":[\"Select\"],\"editor.panels.roomConstructionRows.shape\":[\"Shape\"],\"editor.panels.roomConstructionRows.sharedWallsNote\":[\"Turning walls off keeps the ones shared with \",[\"rooms\"],\".\"],\"editor.panels.roomConstructionRows.sitsOnPreset\":[\"Sits on: \",[\"name\"],\" · \",[\"preset\"]],\"editor.panels.roomConstructionRows.theNextRoom\":[\"the next room\"],\"editor.panels.roomConstructionRows.useExisting\":[\"Use existing\"],\"editor.panels.roomConstructionRows.wallCount\":[[\"walls\",\"plural\",{\"one\":[[\"wallCount\"],\" wall\"],\"other\":[[\"wallCount\"],\" walls\"]}]],\"editor.panels.roomConstructionRows.walls\":[\"Walls\"],\"editor.panels.roomConstructionRows.wallsThickenInwardSoTheBuilding\":[\"Walls thicken inward, so the building's outer size stays the same.\"],\"editor.panels.roomOpeningsField.cutOpening\":[\"Cut opening\"],\"editor.panels.roomOpeningsField.done\":[\"Done\"],\"editor.panels.roomOpeningsField.editFloor\":[\"Edit floor\"],\"editor.panels.roomOpeningsField.elevatorOpening\":[\"Elevator opening\"],\"editor.panels.roomOpeningsField.noOpeningsYetCutOneFor\":[\"No openings yet. Cut one for a stair void or a hatch.\"],\"editor.panels.roomOpeningsField.openingNumber\":[\"Opening \",[\"number\"]],\"editor.panels.roomOpeningsField.openings\":[[\"count\",\"plural\",{\"0\":[\"No openings\"],\"one\":[[\"number\"],\" opening\"],\"other\":[[\"number\"],\" openings\"]}]],\"editor.panels.roomOpeningsField.stairOpening\":[\"Stair opening\"],\"editor.panels.roomPanel.addStairs\":[\"Add stairs\"],\"editor.panels.roomPanel.addToAUnit\":[\"Add to a unit\"],\"editor.panels.roomPanel.area\":[\"Area\"],\"editor.panels.roomPanel.browse\":[\"Browse\"],\"editor.panels.roomPanel.builtWith\":[\"Built with\"],\"editor.panels.roomPanel.ceiling\":[\"Ceiling\"],\"editor.panels.roomPanel.deleteRoom\":[\"Delete room\"],\"editor.panels.roomPanel.editShape\":[\"Edit shape\"],\"editor.panels.roomPanel.floor\":[\"Floor\"],\"editor.panels.roomPanel.headroom\":[[\"height\"],\" headroom\"],\"editor.panels.roomPanel.height\":[\"Height\"],\"editor.panels.roomPanel.hideCode\":[\"Hide code\"],\"editor.panels.roomPanel.kickerLevel\":[\"Room · \",[\"level\"]],\"editor.panels.roomPanel.kickerMezzanineIn\":[\"Mezzanine · in \",[\"room\"]],\"editor.panels.roomPanel.kickerNotEnclosed\":[\"Room · not enclosed\"],\"editor.panels.roomPanel.loading\":[\"Loading…\"],\"editor.panels.roomPanel.mezzanine\":[\"Mezzanine\"],\"editor.panels.roomPanel.mezzanineName\":[\"Mezzanine name\"],\"editor.panels.roomPanel.mezzanineNames\":[\"Mezzanine names\"],\"editor.panels.roomPanel.newUnit\":[\"New unit\"],\"editor.panels.roomPanel.none\":[\"None\"],\"editor.panels.roomPanel.notEnoughHeadroom\":[\"Not enough headroom\"],\"editor.panels.roomPanel.openRoomArea\":[[\"area\"],\" · Close its walls to build its floor and ceiling.\"],\"editor.panels.roomPanel.openingCounts\":[[\"doors\",\"plural\",{\"one\":[[\"doorCount\"],\" door\"],\"other\":[[\"doorCount\"],\" doors\"]}],\" · \",[\"windows\",\"plural\",{\"one\":[[\"windowCount\"],\" window\"],\"other\":[[\"windowCount\"],\" windows\"]}]],\"editor.panels.roomPanel.overTheMezzanine\":[\"Over the mezzanine\"],\"editor.panels.roomPanel.perimeter\":[\"Perimeter\"],\"editor.panels.roomPanel.pick\":[\"Pick\"],\"editor.panels.roomPanel.pickingItAddsANumber\":[\"Picking it adds a number\"],\"editor.panels.roomPanel.remove\":[\"Remove\"],\"editor.panels.roomPanel.removeFromUnit\":[\"Remove from unit\"],\"editor.panels.roomPanel.removeFromUnitNamed\":[\"Remove from \",[\"unit\"]],\"editor.panels.roomPanel.rename\":[\"Rename\"],\"editor.panels.roomPanel.renameNamed\":[[\"name\"],\" · Rename\"],\"editor.panels.roomPanel.revert\":[\"Revert\"],\"editor.panels.roomPanel.room\":[\"Room\"],\"editor.panels.roomPanel.roomColourUsedInThePlan\":[\"Room colour — used in the plan and labels\"],\"editor.panels.roomPanel.roomName\":[\"Room name\"],\"editor.panels.roomPanel.roomNames\":[\"Room names\"],\"editor.panels.roomPanel.scriptedFinish\":[\"Scripted finish\"],\"editor.panels.roomPanel.shape\":[\"Shape\"],\"editor.panels.roomPanel.showMezzanineNames\":[\"Show mezzanine names\"],\"editor.panels.roomPanel.showRoomNames\":[\"Show room names\"],\"editor.panels.roomPanel.stairs\":[\"Stairs\"],\"editor.panels.roomPanel.unit\":[\"Unit\"],\"editor.panels.roomPanel.use\":[\"Use\"],\"editor.panels.roomPanel.useTyped\":[[\"use\"],\" “\",[\"name\"],\"”\"],\"editor.panels.roomPanel.usedOnThisLevel\":[[\"used\"],\" on this level\"],\"editor.panels.roomPanel.viewCode\":[\"View code\"],\"editor.panels.scriptUnreadable\":[\"The script could not be read.\"],\"editor.panels.shapeChoice.polygon\":[\"Polygon\"],\"editor.panels.shapeChoice.rectangle\":[\"Rectangle\"],\"editor.panels.wallRegionList.deleteRegion\":[\"Delete region\"],\"editor.panels.wallRegionList.paintRegions\":[\"Paint regions\"],\"editor.proceduralItems.inspector.adjustDesign\":[\"Adjust design\"],\"editor.proceduralItems.inspector.back\":[\"Back\"],\"editor.proceduralItems.inspector.editParts\":[\"Edit parts\"],\"editor.proceduralItems.inspector.invalidAttachment\":[\"Invalid attachment\"],\"editor.proceduralItems.inspector.invalidEdit\":[\"Invalid edit\"],\"editor.proceduralItems.inspector.invalidPlacement\":[\"Invalid placement\"],\"editor.proceduralItems.inspector.invalidPosition\":[\"Invalid position\"],\"editor.proceduralItems.inspector.invalidReset\":[\"Invalid reset\"],\"editor.proceduralItems.inspector.pos\":[\"pos\"],\"editor.proceduralItems.inspector.position\":[\"Position\"],\"editor.proceduralItems.inspector.resetThisPart\":[\"Reset this part\"],\"editor.reloadEditor\":[\"Reload editor\"],\"editor.riserDiagramPanel.close\":[\"Close riser diagram\"],\"editor.riserDiagramPanel.dwvPlumbingIsometric\":[\"DWV plumbing isometric\"],\"editor.riserDiagramPanel.dwvRiserDiagram\":[\"DWV riser diagram\"],\"editor.riserDiagramPanel.noDrainWasteOrVentPipes\":[\"No drain, waste, or vent pipes yet. Draw plumbing to see the riser diagram.\"],\"editor.riserDiagramPanel.riserDiagram\":[\"Riser Diagram\"],\"editor.riserDiagramPanel.trap\":[[\"diameter\"],\"\\\" P-trap\"],\"editor.riserDiagramPanel.vent\":[\"Vent\"],\"editor.riserDiagramPanel.ventTermination\":[[\"diameter\"],\"\\\" VTR\"],\"editor.riserDiagramPanel.waste\":[\"Waste\"],\"editor.room.builtOn.above\":[[\"current\"],\" · \",[\"distance\"],\" above \",[\"shared\"]],\"editor.room.builtOn.below\":[[\"current\"],\" · \",[\"distance\"],\" below \",[\"shared\"]],\"editor.room.builtOn.levelWith\":[[\"current\"],\" · level with \",[\"shared\"]],\"editor.roomHandles.cannotReadInput\":[\"Cannot read \\\"\",[\"input\"],\"\\\"\"],\"editor.roomHandles.dimensionValue\":[\"Dimension value\"],\"editor.roomHandles.floor\":[\"Floor\"],\"editor.roomHandles.typeASizeToMoveThe\":[\"Type a size to move the wall\"],\"editor.roomLabel.room\":[\"Room\"],\"editor.roomLabel.zone\":[\"Zone\"],\"editor.roomName.attic\":[\"Attic\"],\"editor.roomName.balcony\":[\"Balcony\"],\"editor.roomName.basement\":[\"Basement\"],\"editor.roomName.bathroom\":[\"Bathroom\"],\"editor.roomName.bedroom\":[\"Bedroom\"],\"editor.roomName.boilerRoom\":[\"Boiler room\"],\"editor.roomName.carport\":[\"Carport\"],\"editor.roomName.cellar\":[\"Cellar\"],\"editor.roomName.closet\":[\"Closet\"],\"editor.roomName.corridor\":[\"Corridor\"],\"editor.roomName.courtyard\":[\"Courtyard\"],\"editor.roomName.deck\":[\"Deck\"],\"editor.roomName.den\":[\"Den\"],\"editor.roomName.diningRoom\":[\"Dining room\"],\"editor.roomName.dressingRoom\":[\"Dressing room\"],\"editor.roomName.enSuite\":[\"En-suite\"],\"editor.roomName.entrance\":[\"Entrance\"],\"editor.roomName.familyRoom\":[\"Family room\"],\"editor.roomName.gallery\":[\"Gallery\"],\"editor.roomName.gamesRoom\":[\"Games room\"],\"editor.roomName.garage\":[\"Garage\"],\"editor.roomName.garden\":[\"Garden\"],\"editor.roomName.gardenShed\":[\"Garden shed\"],\"editor.roomName.guestRoom\":[\"Guest room\"],\"editor.roomName.gym\":[\"Gym\"],\"editor.roomName.hallway\":[\"Hallway\"],\"editor.roomName.homeCinema\":[\"Home cinema\"],\"editor.roomName.kidsRoom\":[\"Kids' room\"],\"editor.roomName.kitchen\":[\"Kitchen\"],\"editor.roomName.kitchenette\":[\"Kitchenette\"],\"editor.roomName.landing\":[\"Landing\"],\"editor.roomName.laundry\":[\"Laundry\"],\"editor.roomName.library\":[\"Library\"],\"editor.roomName.livingRoom\":[\"Living room\"],\"editor.roomName.loft\":[\"Loft\"],\"editor.roomName.lounge\":[\"Lounge\"],\"editor.roomName.mezzanine\":[\"Mezzanine\"],\"editor.roomName.mudroom\":[\"Mudroom\"],\"editor.roomName.nursery\":[\"Nursery\"],\"editor.roomName.office\":[\"Office\"],\"editor.roomName.pantry\":[\"Pantry\"],\"editor.roomName.patio\":[\"Patio\"],\"editor.roomName.playroom\":[\"Playroom\"],\"editor.roomName.poolArea\":[\"Pool area\"],\"editor.roomName.porch\":[\"Porch\"],\"editor.roomName.powderRoom\":[\"Powder room\"],\"editor.roomName.primaryBedroom\":[\"Primary bedroom\"],\"editor.roomName.readingNook\":[\"Reading nook\"],\"editor.roomName.section.bathrooms\":[\"Bathrooms\"],\"editor.roomName.section.circulation\":[\"Circulation\"],\"editor.roomName.section.living\":[\"Living\"],\"editor.roomName.section.mezzanine\":[\"Mezzanine\"],\"editor.roomName.section.outdoor\":[\"Outdoor\"],\"editor.roomName.section.sleeping\":[\"Sleeping\"],\"editor.roomName.section.utility\":[\"Utility & storage\"],\"editor.roomName.section.work\":[\"Work & hobbies\"],\"editor.roomName.showerRoom\":[\"Shower room\"],\"editor.roomName.stairwell\":[\"Stairwell\"],\"editor.roomName.storage\":[\"Storage\"],\"editor.roomName.studio\":[\"Studio\"],\"editor.roomName.study\":[\"Study\"],\"editor.roomName.sunroom\":[\"Sunroom\"],\"editor.roomName.terrace\":[\"Terrace\"],\"editor.roomName.toilet\":[\"Toilet\"],\"editor.roomName.utilityRoom\":[\"Utility room\"],\"editor.roomName.veranda\":[\"Veranda\"],\"editor.roomName.walkInCloset\":[\"Walk-in closet\"],\"editor.roomName.workshop\":[\"Workshop\"],\"editor.sidebar.iconRail.settings\":[\"Settings\"],\"editor.sidebar.iconRail.site\":[\"Site\"],\"editor.sidebar.panels.itemsPanel.all\":[\"All\"],\"editor.sidebar.panels.itemsPanel.community\":[\"Community\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.all\":[\"All\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.community\":[\"Community\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.library\":[\"Library\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.mine\":[\"Mine\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.noResultsForSearch\":[\"No results for “\",[\"search\"],\"”\"],\"editor.sidebar.panels.itemsPanel.functionTreePanel.search\":[\"Search...\"],\"editor.sidebar.panels.itemsPanel.library\":[\"Library\"],\"editor.sidebar.panels.itemsPanel.mine\":[\"Mine\"],\"editor.sidebar.panels.itemsPanel.noResultsForSearch\":[\"No results for “\",[\"search\"],\"”\"],\"editor.sidebar.panels.itemsPanel.search\":[\"Search...\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.buildTools\":[\"Build Tools\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.camera\":[\"Camera\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.directManipulation\":[\"Direct Manipulation\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.drawingTools\":[\"Drawing Tools\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.editorNavigation\":[\"Editor Navigation\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.itemPlacement\":[\"Item Placement\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.keyboardShortcuts\":[\"Keyboard shortcuts\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.modesHistory\":[\"Modes & History\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.selection\":[\"Selection\"],\"editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.shortcutsAreContextAwareGuidedConstraints\":[\"Shortcuts are context-aware. Snapping is a visible mode: tap Shift to cycle it, hold Alt during a gesture to place freely.\"],\"editor.sidebar.panels.sitePanel.addLevel\":[\"Add level\"],\"editor.sidebar.panels.sitePanel.addPoint\":[\"Add point\"],\"editor.sidebar.panels.sitePanel.area\":[\"Area:\"],\"editor.sidebar.panels.sitePanel.baseElevation\":[\"Base elevation\"],\"editor.sidebar.panels.sitePanel.building\":[\"Building\"],\"editor.sidebar.panels.sitePanel.buildingTreeNode.addNewLevel\":[\"Add new level\"],\"editor.sidebar.panels.sitePanel.buildingTreeNode.building\":[\"Building\"],\"editor.sidebar.panels.sitePanel.cameraSnapshot\":[\"Camera snapshot\"],\"editor.sidebar.panels.sitePanel.capture\":[\"Capture\"],\"editor.sidebar.panels.sitePanel.clearSelection\":[\"Clear selection\"],\"editor.sidebar.panels.sitePanel.clearSnapshot\":[\"Clear snapshot\"],\"editor.sidebar.panels.sitePanel.closeWallsAroundASpaceTo\":[\"Close walls around a space to make a room.\"],\"editor.sidebar.panels.sitePanel.collectionTreeNode.collectionColour\":[\"Collection colour\"],\"editor.sidebar.panels.sitePanel.collectionTreeNode.collections\":[\"Collections\"],\"editor.sidebar.panels.sitePanel.collectionTreeNode.deleteCollection\":[\"Delete collection\"],\"editor.sidebar.panels.sitePanel.delete\":[\"Delete\"],\"editor.sidebar.panels.sitePanel.deleteLevel\":[\"Delete level\"],\"editor.sidebar.panels.sitePanel.drawAZone\":[\"Draw a zone\"],\"editor.sidebar.panels.sitePanel.duplicate\":[\"Duplicate\"],\"editor.sidebar.panels.sitePanel.duplicateLevel\":[\"Duplicate level\"],\"editor.sidebar.panels.sitePanel.duplicateLevelWithOptions\":[\"Duplicate level with options\"],\"editor.sidebar.panels.sitePanel.duplicateWithOptions\":[\"Duplicate with options...\"],\"editor.sidebar.panels.sitePanel.elements\":[\"Elements\"],\"editor.sidebar.panels.sitePanel.guide\":[\"Guide\"],\"editor.sidebar.panels.sitePanel.hide\":[\"Hide\"],\"editor.sidebar.panels.sitePanel.level\":[\"Level\"],\"editor.sidebar.panels.sitePanel.newUnit\":[\"New unit\"],\"editor.sidebar.panels.sitePanel.noBuildingsYet\":[\"No buildings yet\"],\"editor.sidebar.panels.sitePanel.noElementsOnThisLevel\":[\"No elements on this level\"],\"editor.sidebar.panels.sitePanel.noLevelsYet\":[\"No levels yet\"],\"editor.sidebar.panels.sitePanel.objectsSelected\":[[\"count\",\"plural\",{\"one\":[\"#\",\" object selected\"],\"other\":[\"#\",\" objects selected\"]}]],\"editor.sidebar.panels.sitePanel.otherZones\":[\"Other zones\"],\"editor.sidebar.panels.sitePanel.perimeter\":[\"Perimeter:\"],\"editor.sidebar.panels.sitePanel.propertyLine\":[\"Property Line\"],\"editor.sidebar.panels.sitePanel.rooms\":[\"Rooms\"],\"editor.sidebar.panels.sitePanel.selectALevelToViewContent\":[\"Select a level to view content\"],\"editor.sidebar.panels.sitePanel.show\":[\"Show\"],\"editor.sidebar.panels.sitePanel.site\":[\"Site\"],\"editor.sidebar.panels.sitePanel.takeSnapshot\":[\"Take snapshot\"],\"editor.sidebar.panels.sitePanel.theGroundLevelCannotBeDeleted\":[\"The ground level cannot be deleted\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.cameraSnapshot\":[\"Camera snapshot\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.clearSnapshot\":[\"Clear snapshot\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.hide\":[\"Hide\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.show\":[\"Show\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.takeSnapshot\":[\"Take snapshot\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.updateSnapshot\":[\"Update snapshot\"],\"editor.sidebar.panels.sitePanel.treeNodeActions.viewSnapshot\":[\"View snapshot\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.deleteUnit\":[\"Delete unit\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.focused\":[\"Focused\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.removeFromUnit\":[\"Remove from unit\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.room\":[\"Room\"],\"editor.sidebar.panels.sitePanel.unitTreeNode.zone\":[\"Zone\"],\"editor.sidebar.panels.sitePanel.units\":[\"Units\"],\"editor.sidebar.panels.sitePanel.updateSnapshot\":[\"Update snapshot\"],\"editor.sidebar.panels.sitePanel.uploadScanFloorplan\":[\"Upload scan/floorplan\"],\"editor.sidebar.panels.sitePanel.uploadingProgress\":[[\"assetType\",\"select\",{\"guide\":[\"Uploading guide... \",[\"progress\"],\"%\"],\"other\":[\"Uploading scan... \",[\"progress\"],\"%\"]}]],\"editor.sidebar.panels.sitePanel.viewSnapshot\":[\"View snapshot\"],\"editor.sidebar.panels.sitePanel.zoneMembershipCheckbox.inUnitname\":[\"In \",[\"unitName\"]],\"editor.sidebar.panels.zonePanel.actions\":[\"Actions\"],\"editor.sidebar.panels.zonePanel.addOne\":[\"Add one\"],\"editor.sidebar.panels.zonePanel.cameraSnapshot\":[\"Camera snapshot\"],\"editor.sidebar.panels.zonePanel.clearSnapshot\":[\"Clear snapshot\"],\"editor.sidebar.panels.zonePanel.delete\":[\"Delete\"],\"editor.sidebar.panels.zonePanel.deleteWithContents\":[\"Delete with contents\"],\"editor.sidebar.panels.zonePanel.noZonesOnThisLevel\":[\"No zones on this level.\"],\"editor.sidebar.panels.zonePanel.saveToCatalog\":[\"Save to catalog\"],\"editor.sidebar.panels.zonePanel.selectALevelToViewAnd\":[\"Select a level to view and create zones\"],\"editor.sidebar.panels.zonePanel.takeSnapshot\":[\"Take snapshot\"],\"editor.sidebar.panels.zonePanel.updateSnapshot\":[\"Update snapshot\"],\"editor.sidebar.panels.zonePanel.viewSnapshot\":[\"View snapshot\"],\"editor.sidebar.usePluginPanels.labelPluginCrashed\":[\"\\\"\",[\"label\"],\"\\\" plugin crashed\"],\"editor.sidebar.usePluginPanels.loading\":[\"Loading…\"],\"editor.sidebar.usePluginPanels.plugins\":[\"Plugins\"],\"editor.sidebar.usePluginPanels.thisPanelHitAnErrorAnd\":[\"This panel hit an error and was unloaded for this session. The rest of the editor is unaffected — reload to try again.\"],\"editor.snapTarget.ceiling\":[\"Ceiling attachment\"],\"editor.snapTarget.roof\":[\"Roof attachment\"],\"editor.snapTarget.wall\":[\"Wall attachment\"],\"editor.theEditorSceneFailedToRender\":[\"The editor scene failed to render\"],\"editor.toolHint.aCurtainWallTakesNoCorner.1qxjv5i\":[\"A curtain wall takes no corner window\"],\"editor.toolHint.aCurvedWallTakesNoCorner.1vdnaw5\":[\"A curved wall takes no corner window\"],\"editor.toolHint.addACornerClickTheFirst.o4r67t\":[\"Add a corner · click the first to close\"],\"editor.toolHint.anotherOpeningIsInTheWay.11l9dd0\":[\"Another opening is in the way at the corner\"],\"editor.toolHint.autoHangers.10554ka\":[\"Auto hangers\"],\"editor.toolHint.autoHangersClickOrPressH.rwa3ka\":[\"Auto hangers - click or press H to toggle\"],\"editor.toolHint.autoHangersOff.7yx01x\":[\"Auto hangers: Off\"],\"editor.toolHint.autoHangersOn.10b1umh\":[\"Auto hangers: On\"],\"editor.toolHint.bypassSnapping.w5lmdv\":[\"Bypass snapping\"],\"editor.toolHint.cancel.ew9em3\":[\"Cancel\"],\"editor.toolHint.cancelMove.lvp31c\":[\"Cancel move\"],\"editor.toolHint.cancelRunExit.zqjf3h\":[\"Cancel run / exit\"],\"editor.toolHint.cancelStartPoint.1xbq2lh\":[\"Cancel start point\"],\"editor.toolHint.cornerWindow.1avkzpo\":[\"Corner window\"],\"editor.toolHint.cuts.1y0axps\":[\"Cuts\"],\"editor.toolHint.cutsValue.ouzhvb\":[\"Cuts: \",[\"value\"]],\"editor.toolHint.cutsValueEven.1ngsz3\":[\"Cuts: \",[\"value\"],\", even\"],\"editor.toolHint.cycleMonoGableButterfly.1poga3m\":[\"Cycle mono / gable / butterfly\"],\"editor.toolHint.cycleSnappingMode.1ct0gn6\":[\"Cycle snapping mode\"],\"editor.toolHint.doorStyleClickOrPressL.33pe65\":[\"Door style — click or press L to cycle\"],\"editor.toolHint.doorTypeClickOrPressO.1hhh8gt\":[\"Door type — click or press O to cycle\"],\"editor.toolHint.dropDownspoutFromOutlet.1k4h1m4\":[\"Drop downspout from outlet\"],\"editor.toolHint.ductDiameterDownUp.1wdz5vq\":[\"Duct diameter down / up\"],\"editor.toolHint.endRunCancel.59dh2w\":[\"End run / cancel\"],\"editor.toolHint.endTheRun.1c1raig\":[\"End the run\"],\"editor.toolHint.exit.engmg5\":[\"Exit\"],\"editor.toolHint.exitDrawing.9noxyb\":[\"Exit drawing\"],\"editor.toolHint.finishAndContinue.1gpfsks\":[\"Finish and continue\"],\"editor.toolHint.finishCeiling.1c1lfel\":[\"Finish ceiling\"],\"editor.toolHint.finishGridAxis.1wvrfhr\":[\"Finish grid axis\"],\"editor.toolHint.finishMeasurement.1e4gv16\":[\"Finish measurement\"],\"editor.toolHint.finishMultiPointWitnesses.8wzskz\":[\"Finish multi-point witnesses\"],\"editor.toolHint.finishSlab.xmnm8e\":[\"Finish slab\"],\"editor.toolHint.flipSide.172xku9\":[\"Flip side\"],\"editor.toolHint.followTraceALineset.mgquwe\":[\"Follow: trace a lineset\"],\"editor.toolHint.forcePlace.1hq1nr\":[\"Force place\"],\"editor.toolHint.freeAngle.1ptblho\":[\"Free angle\"],\"editor.toolHint.freePlace.1s1uusw\":[\"Free place\"],\"editor.toolHint.freePlacement.1nztdac\":[\"Free placement\"],\"editor.toolHint.goVerticalClickToPlace.dg8g6m\":[\"Go vertical ↕, click to place\"],\"editor.toolHint.highlightOutlet.65hoq8\":[\"Highlight outlet\"],\"editor.toolHint.joinAsACornerWindow.jvdp4j\":[\"Join as a corner window\"],\"editor.toolHint.key.altDrag.ai3wn9\":[\"Alt + drag\"],\"editor.toolHint.key.backspace.qy6qx8\":[\"Backspace\"],\"editor.toolHint.key.click.m8sun\":[\"Click\"],\"editor.toolHint.key.clickAgain.190ws9j\":[\"Click again\"],\"editor.toolHint.key.command.1j2mkia\":[\"Command\"],\"editor.toolHint.key.control.10fbl8e\":[\"Control\"],\"editor.toolHint.key.delete.oay2cq\":[\"Delete\"],\"editor.toolHint.key.doubleClick.vlma6o\":[\"Double click\"],\"editor.toolHint.key.drag.8pwtpf\":[\"Drag\"],\"editor.toolHint.key.enter.1ctpui5\":[\"Enter\"],\"editor.toolHint.key.hover.6xw79p\":[\"Hover\"],\"editor.toolHint.key.hoverADuctEnd.19axr3b\":[\"Hover a duct end\"],\"editor.toolHint.key.hoverAPipeEnd.1jbum5f\":[\"Hover a pipe end\"],\"editor.toolHint.key.hoverGutter.1dwcsno\":[\"Hover gutter\"],\"editor.toolHint.key.leftClick.s4gwfc\":[\"Left click\"],\"editor.toolHint.key.middleClick.1jbaan4\":[\"Middle click\"],\"editor.toolHint.key.rShiftR.13bnobh\":[\"R / Shift+R\"],\"editor.toolHint.key.rightClick.1ovld0h\":[\"Right click\"],\"editor.toolHint.key.room.1f3jkpm\":[\"Room\"],\"editor.toolHint.key.scroll.ai6wr0\":[\"Scroll\"],\"editor.toolHint.key.scrollWheel.18j0ix7\":[\"Scroll wheel\"],\"editor.toolHint.key.space.1hrh82t\":[\"Space\"],\"editor.toolHint.key.tab.1xsal0s\":[\"Tab\"],\"editor.toolHint.mountFloorCeilingWall.32dxpv\":[\"Mount: floor / ceiling / wall\"],\"editor.toolHint.noRoomForTheMatchingWindow.1755948\":[\"No room for the matching window on the other wall\"],\"editor.toolHint.noWallMeetsHere.19n99yc\":[\"No wall meets here\"],\"editor.toolHint.notARectangleDrawThisRoof.100pa5g\":[\"Not a rectangle: draw this roof instead\"],\"editor.toolHint.numberOfCutsScrollOrClick.1kqe84b\":[\"Number of cuts — scroll or click to change\"],\"editor.toolHint.pickWitnessPoint.k3hgh1\":[\"Pick witness point\"],\"editor.toolHint.pipeSizeDownUp.wp04og\":[\"Pipe size down / up\"],\"editor.toolHint.placeAndContinue.qfwkrq\":[\"Place and continue\"],\"editor.toolHint.placeBlock.1aylwrx\":[\"Place block\"],\"editor.toolHint.placeBoxVentOnRoof.kf88e5\":[\"Place box vent on roof\"],\"editor.toolHint.placeCabinet.b0ouyk\":[\"Place cabinet\"],\"editor.toolHint.placeCanopyOrSetTheNext.12l7zf8\":[\"Place canopy or set the next run point\"],\"editor.toolHint.placeChimneyOnRoof.19dbqu\":[\"Place chimney on roof\"],\"editor.toolHint.placeColumn.1w2vq86\":[\"Place column\"],\"editor.toolHint.placeCupolaOnRoof.ofx3bn\":[\"Place cupola on roof\"],\"editor.toolHint.placeDimensionLineWhenNeeded.bjw2cj\":[\"Place dimension line when needed\"],\"editor.toolHint.placeDoorOnWall.1jwadf\":[\"Place door on wall\"],\"editor.toolHint.placeDormerOnRoof.1w518a6\":[\"Place dormer on roof\"],\"editor.toolHint.placeElevator.1f65zva\":[\"Place elevator\"],\"editor.toolHint.placeEyebrowVentOnRoof.1h1tqxn\":[\"Place eyebrow vent on roof\"],\"editor.toolHint.placeFitting.1pmx3vn\":[\"Place fitting\"],\"editor.toolHint.placeGutterOnRoofEave.llwzf9\":[\"Place gutter on roof eave\"],\"editor.toolHint.placeItLockedTo45.16e4csk\":[\"Place it (locked to 45°)\"],\"editor.toolHint.placeItem.teynf\":[\"Place item\"],\"editor.toolHint.placeMeasurementPoint.bsatli\":[\"Place measurement point\"],\"editor.toolHint.placeOnAFence.1dptstr\":[\"Place on a fence\"],\"editor.toolHint.placeRegister.1uebycd\":[\"Place register\"],\"editor.toolHint.placeRidgeVentOnRoof.2tpd8r\":[\"Place ridge vent on roof\"],\"editor.toolHint.placeShelf.y4l3iw\":[\"Place shelf\"],\"editor.toolHint.placeSkylightOnRoof.e215pe\":[\"Place skylight on roof\"],\"editor.toolHint.placeSolarPanelArrayOnRoof.kk11fn\":[\"Place solar panel array on roof\"],\"editor.toolHint.placeSpawnPoint.205o25\":[\"Place spawn point\"],\"editor.toolHint.placeStairs.zwxxu2\":[\"Place stairs\"],\"editor.toolHint.placeTrap.1gxemn3\":[\"Place trap\"],\"editor.toolHint.placeTurbineVentOnRoof.1iqeluf\":[\"Place turbine vent on roof\"],\"editor.toolHint.placeUnit.8zkx4q\":[\"Place unit\"],\"editor.toolHint.placeWindowOnWall.1k3qnfb\":[\"Place window on wall\"],\"editor.toolHint.placeWithoutTheCornerSnap.1nifqew\":[\"Place without the corner snap\"],\"editor.toolHint.placement.13lcvts\":[\"Placement\"],\"editor.toolHint.placementAuto.1caa52d\":[\"Placement: Auto\"],\"editor.toolHint.placementGround.1ruz145\":[\"Placement: Ground\"],\"editor.toolHint.placementRoof.renkw8\":[\"Placement: Roof\"],\"editor.toolHint.placementSurfaceClickOrPressP.w56h19\":[\"Placement surface - click or press P to cycle\"],\"editor.toolHint.placementType.1mdpl60\":[\"Placement type\"],\"editor.toolHint.placementTypeClickOrPressI.10cgxh2\":[\"Placement type — click or press I to toggle\"],\"editor.toolHint.pointInsideARoomPorchOr.58w64l\":[\"Point inside a room, porch or deck\"],\"editor.toolHint.removeLastPoint.2dmdcx\":[\"Remove last point\"],\"editor.toolHint.removeLastWitness.1b6vvzw\":[\"Remove last witness\"],\"editor.toolHint.ridgeDirection.5m1369\":[\"Ridge direction\"],\"editor.toolHint.ridgeDirectionClickOrPressR.1t14dyk\":[\"Ridge direction - click or press R to turn it 90°\"],\"editor.toolHint.ridgeLongSide.ew0euv\":[\"Ridge: Long side\"],\"editor.toolHint.ridgeShortSide.gye8pb\":[\"Ridge: Short side\"],\"editor.toolHint.rotate.1thqa0a\":[\"Rotate\"],\"editor.toolHint.rotate45.9zq68u\":[\"Rotate ±45°\"],\"editor.toolHint.rotate45FloorCeiling.m9t57d\":[\"Rotate ±45° (floor / ceiling)\"],\"editor.toolHint.rotateGhost15.rsa52c\":[\"Rotate ghost ±15°\"],\"editor.toolHint.rotateOrFlipTheRunSide.t5ior7\":[\"Rotate or flip the run side\"],\"editor.toolHint.rotateSpawnPoint.1opcuu7\":[\"Rotate spawn point\"],\"editor.toolHint.roundRectangularOval.e4nh6x\":[\"Round / rectangular / oval\"],\"editor.toolHint.setBeamStartEndTheNext.di3bzj\":[\"Set beam start / end; the next beam starts there\"],\"editor.toolHint.setFenceStartEnd.1phbwsq\":[\"Set fence start / end\"],\"editor.toolHint.setOneCornerThenTheOpposite.8tsl49\":[\"Set one corner, then the opposite\"],\"editor.toolHint.setRoofFootprint.p50n0o\":[\"Set roof footprint\"],\"editor.toolHint.setWallStartEnd.1r8ubcx\":[\"Set wall start / end\"],\"editor.toolHint.slopeLevel.ftqp67\":[\"Slope / level\"],\"editor.toolHint.snapOntoTheRun.86yhmp\":[\"Snap onto the run\"],\"editor.toolHint.splitAtTheMarks.x5tpdd\":[\"Split at the marks\"],\"editor.toolHint.startGridAxis.k92yza\":[\"Start grid axis\"],\"editor.toolHint.startLineset.23q8dh\":[\"Start lineset\"],\"editor.toolHint.startLiquidLine.1rlxsgd\":[\"Start liquid line\"],\"editor.toolHint.startRun.r6fc5u\":[\"Start run\"],\"editor.toolHint.startSegment.rolym6\":[\"Start segment\"],\"editor.toolHint.stepBackOrCancel.zbfdkn\":[\"Step back or cancel\"],\"editor.toolHint.style.nf3vcm\":[\"Style\"],\"editor.toolHint.styleBarn.k9n1x\":[\"Style: Barn\"],\"editor.toolHint.styleCasement.ziklec\":[\"Style: Casement\"],\"editor.toolHint.styleCraftsman.52e6a9\":[\"Style: Craftsman\"],\"editor.toolHint.styleDoubleHung.1lg8pkg\":[\"Style: Double-hung\"],\"editor.toolHint.styleFrench.1ue3j64\":[\"Style: French\"],\"editor.toolHint.styleGlass.qudnb4\":[\"Style: Glass\"],\"editor.toolHint.styleGrid.1vuq4po\":[\"Style: Grid\"],\"editor.toolHint.styleHalfLouvered.13b1few\":[\"Style: Half-louvered\"],\"editor.toolHint.styleHorizontalBands.12ethxk\":[\"Style: Horizontal bands\"],\"editor.toolHint.styleModern.1fh8hhn\":[\"Style: Modern\"],\"editor.toolHint.stylePanel.922jze\":[\"Style: Panel\"],\"editor.toolHint.stylePaneledGlass.17a17en\":[\"Style: Paneled glass\"],\"editor.toolHint.styleShaker.49z17k\":[\"Style: Shaker\"],\"editor.toolHint.styleSingle.6f3cm0\":[\"Style: Single\"],\"editor.toolHint.styleSixPanel.u49laj\":[\"Style: Six-panel\"],\"editor.toolHint.styleSliding.q81s0i\":[\"Style: Sliding\"],\"editor.toolHint.styleTallGrid.1eotg3x\":[\"Style: Tall grid\"],\"editor.toolHint.styleTransom.kb9bh6\":[\"Style: Transom\"],\"editor.toolHint.styleTripleHung.pxnqi3\":[\"Style: Triple-hung\"],\"editor.toolHint.styleWideGrid.12n27et\":[\"Style: Wide grid\"],\"editor.toolHint.switchRotationAxisYXZ.15lohm6\":[\"Switch rotation axis (Y → X → Z)\"],\"editor.toolHint.theWallsMeetAtTooSharp.kh3wi3\":[\"The walls meet at too sharp or too flat an angle\"],\"editor.toolHint.theWindowWaitingThereIsTaller.1tqwez4\":[\"The window waiting there is taller than this wall\"],\"editor.toolHint.threeOrMoreWallsMeetHere.rgifif\":[\"Three or more walls meet here\"],\"editor.toolHint.traceCeilingOutline.1b639wv\":[\"Trace ceiling outline\"],\"editor.toolHint.traceSlabOutline.z0j2lc\":[\"Trace slab outline\"],\"editor.toolHint.type.1m2zofh\":[\"Type\"],\"editor.toolHint.typeAwning.1cj59al\":[\"Type: Awning\"],\"editor.toolHint.typeBarn.sbnygq\":[\"Type: Barn\"],\"editor.toolHint.typeBay.1200hc1\":[\"Type: Bay\"],\"editor.toolHint.typeBow.14s2t9p\":[\"Type: Bow\"],\"editor.toolHint.typeCabinet.1r68je5\":[\"Type: Cabinet\"],\"editor.toolHint.typeCasement.176uo9j\":[\"Type: Casement\"],\"editor.toolHint.typeDouble.af7w4i\":[\"Type: Double\"],\"editor.toolHint.typeDoubleHung.t482fu\":[\"Type: Double Hung\"],\"editor.toolHint.typeFixed.v1cjez\":[\"Type: Fixed\"],\"editor.toolHint.typeFolding.sxxyng\":[\"Type: Folding\"],\"editor.toolHint.typeFrench.1y57z1b\":[\"Type: French\"],\"editor.toolHint.typeHinged.1xrcfju\":[\"Type: Hinged\"],\"editor.toolHint.typeIsland.ufr3ce\":[\"Type: Island\"],\"editor.toolHint.typeLouvered.oxl1cz\":[\"Type: Louvered\"],\"editor.toolHint.typePocket.hc65x9\":[\"Type: Pocket\"],\"editor.toolHint.typeSingleHung.p53pyl\":[\"Type: Single Hung\"],\"editor.toolHint.typeSliding.nwmr3f\":[\"Type: Sliding\"],\"editor.toolHint.verticalStackClickToPlace.ijcn4q\":[\"Vertical stack ↕, click to place\"],\"editor.toolHint.wasteVent.1hvi3vj\":[\"Waste / vent\"],\"editor.toolHint.windowStyleClickOrPressL.ah7qm9\":[\"Window style — click or press L to cycle\"],\"editor.toolHint.windowTypeClickOrPressO.wv4x35\":[\"Window type — click or press O to cycle\"],\"editor.tools.distribution.distributionRunTool.lengthField\":[\"Length: \",[\"field\"],\" m\"],\"editor.tools.distribution.distributionRunTool.tabDirection\":[\"Tab: direction\"],\"editor.tools.distribution.distributionRunTool.typeALength\":[\"type a length\"],\"editor.views.plugins\":[\"Plugins\"],\"editor.views.view2d\":[\"2D\"],\"editor.views.view3d\":[\"3D\"],\"editor.views.viewBar.auto\":[\"Auto\"],\"editor.views.viewBar.browsePlugins\":[\"Browse plugins\"],\"editor.views.viewBar.closeLabel\":[\"Close \",[\"label\"]],\"editor.views.viewBar.closeSplit\":[\"Close split (\\\\)\"],\"editor.views.viewBar.ground\":[\"Ground\"],\"editor.views.viewBar.groundSolid\":[[\"standing\",\"select\",{\"partly\":[\"Partly below grade · ground solid\"],\"below\":[\"Below grade · ground solid\"],\"other\":[\"Ground solid\"]}]],\"editor.views.viewBar.groundVeiled\":[[\"standing\",\"select\",{\"partly\":[\"Partly below grade · ground veiled\"],\"below\":[\"Below grade · ground veiled\"],\"other\":[\"Ground veiled\"]}]],\"editor.views.viewBar.keepTheGroundSolid\":[\"Keep the ground solid\"],\"editor.views.viewBar.moreViews\":[\"More views\"],\"editor.views.viewBar.paneViews\":[\"Pane \",[\"pane\"],\" views\"],\"editor.views.viewBar.pinLabel\":[\"Pin \",[\"label\"]],\"editor.views.viewBar.pinToTheViewBar\":[\"Pin to the view bar\"],\"editor.views.viewBar.solid\":[\"Solid\"],\"editor.views.viewBar.split\":[\"Split (\\\\)\"],\"editor.views.viewBar.split2\":[\"Split\"],\"editor.views.viewBar.swapPanes\":[\"Swap panes\"],\"editor.views.viewBar.unpinFromTheViewBar\":[\"Unpin from the view bar\"],\"editor.views.viewBar.unpinLabel\":[\"Unpin \",[\"label\"]],\"editor.views.viewBar.veilTheGroundOverALevel\":[\"Veil the ground over a level below grade\"],\"editor.views.viewBar.views\":[\"Views\"],\"editor.wallTypeEditorDialog.listTheLayersAppliedToThisWall\":[\"List the layers from the outside in, around one framing core. The type is saved with the project and applied to this wall; other walls keep their layers.\"],\"editor.wallTypeMenu.custom\":[\"Custom\"],\"editor.wallTypeMenu.wallTypesOf\":[\"Wall types: new, edit or duplicate \",[\"label\"]],\"editor.youCanRetryTheSceneOr\":[\"You can retry the scene or return home without reloading the whole app shell.\"],\"node.beam.description\":[\"A framing beam drawn end to end: a porch header, a deck beam, a girder.\"],\"node.beam.label\":[\"Beam\"],\"node.beam.panel.actions\":[\"Actions\"],\"node.beam.panel.addPosts\":[\"Add posts\"],\"node.beam.panel.beam\":[\"Beam\"],\"node.beam.panel.beamSize\":[\"Beam \",[\"size\"]],\"node.beam.panel.delete\":[\"Delete\"],\"node.beam.panel.depth\":[\"Depth\"],\"node.beam.panel.dropped\":[\"Dropped\"],\"node.beam.panel.flush\":[\"Flush\"],\"node.beam.panel.followTheCeilingPlane\":[\"Follow the ceiling plane\"],\"node.beam.panel.lengthLongItsUnderside\":[[\"length\"],\" long; its underside \",[\"underside\"],\" over the floor, the ceiling plane \",[\"plane\"],\".\"],\"node.beam.panel.material\":[\"Material\"],\"node.beam.panel.move\":[\"Move\"],\"node.beam.panel.n1Ply\":[\"1 ply\"],\"node.beam.panel.placement\":[\"Placement\"],\"node.beam.panel.pliesPlies\":[[\"plies\"],\" plies\"],\"node.beam.panel.size\":[\"Size\"],\"node.beam.panel.top\":[\"Top\"],\"node.beam.panel.topElevation\":[\"Top elevation\"],\"node.beam.panel.width\":[\"Width\"],\"node.block.description\":[\"A topology-backed solid edited directly in the canvas.\"],\"node.block.label\":[\"Block\"],\"node.boxVent.description\":[\"Small louvered exhaust vent that sits on a roof slope.\"],\"node.boxVent.label\":[\"Box Vent\"],\"node.boxVent.panel.actions\":[\"Actions\"],\"node.boxVent.panel.baseFlange\":[\"Base Flange\"],\"node.boxVent.panel.baseHeight\":[\"Base Height\"],\"node.boxVent.panel.baseInset\":[\"Base Inset\"],\"node.boxVent.panel.box\":[\"Box\"],\"node.boxVent.panel.boxVent\":[\"Box Vent\"],\"node.boxVent.panel.cap\":[\"Cap\"],\"node.boxVent.panel.capHeight\":[\"Cap Height\"],\"node.boxVent.panel.cornerBevel\":[\"Corner Bevel\"],\"node.boxVent.panel.delete\":[\"Delete\"],\"node.boxVent.panel.depth\":[\"Depth\"],\"node.boxVent.panel.dimensions\":[\"Dimensions\"],\"node.boxVent.panel.dome\":[\"Dome\"],\"node.boxVent.panel.domeCurvature\":[\"Dome Curvature\"],\"node.boxVent.panel.duplicate\":[\"Duplicate\"],\"node.boxVent.panel.gapHeight\":[\"Gap Height\"],\"node.boxVent.panel.height\":[\"Height\"],\"node.boxVent.panel.hoodOverhang\":[\"Hood Overhang\"],\"node.boxVent.panel.move\":[\"Move\"],\"node.boxVent.panel.position\":[\"Position\"],\"node.boxVent.panel.rotation\":[\"Rotation\"],\"node.boxVent.panel.style\":[\"Style\"],\"node.boxVent.panel.topTaper\":[\"Top Taper\"],\"node.boxVent.panel.width\":[\"Width\"],\"node.building.description\":[\"A building container holding one or more levels.\"],\"node.building.label\":[\"Building\"],\"node.cabinet.compartmentCard.baskets\":[\"Baskets\"],\"node.cabinet.compartmentCard.bottom\":[\"Bottom\"],\"node.cabinet.compartmentCard.bottomFreezer\":[\"Bottom Freezer\"],\"node.cabinet.compartmentCard.bowls\":[\"Bowls\"],\"node.cabinet.compartmentCard.burnersOn\":[\"Burners on\"],\"node.cabinet.compartmentCard.chimney\":[\"Chimney\"],\"node.cabinet.compartmentCard.decrease\":[\"Decrease \",[\"label\"]],\"node.cabinet.compartmentCard.door\":[\"Door\"],\"node.cabinet.compartmentCard.double\":[\"Double\"],\"node.cabinet.compartmentCard.drawer\":[\"Drawer\"],\"node.cabinet.compartmentCard.drawers\":[\"Drawers\"],\"node.cabinet.compartmentCard.flipHinge\":[\"Flip hinge\"],\"node.cabinet.compartmentCard.flipTheDoorHingeToThe\":[\"Flip the door hinge to the opposite side\"],\"node.cabinet.compartmentCard.fridge\":[\"Fridge\"],\"node.cabinet.compartmentCard.gas\":[\"Gas\"],\"node.cabinet.compartmentCard.glass\":[\"Glass\"],\"node.cabinet.compartmentCard.height\":[\"Height\"],\"node.cabinet.compartmentCard.hob\":[\"Hob\"],\"node.cabinet.compartmentCard.increase\":[\"Increase \",[\"label\"]],\"node.cabinet.compartmentCard.induction\":[\"Induction\"],\"node.cabinet.compartmentCard.layout\":[\"Layout\"],\"node.cabinet.compartmentCard.left\":[\"Left\"],\"node.cabinet.compartmentCard.micro\":[\"Micro\"],\"node.cabinet.compartmentCard.moveDown\":[\"Move down\"],\"node.cabinet.compartmentCard.moveUp\":[\"Move up\"],\"node.cabinet.compartmentCard.oven\":[\"Oven\"],\"node.cabinet.compartmentCard.pullout\":[\"Pullout\"],\"node.cabinet.compartmentCard.rack\":[\"Rack\"],\"node.cabinet.compartmentCard.removeCompartment\":[\"Remove compartment\"],\"node.cabinet.compartmentCard.right\":[\"Right\"],\"node.cabinet.compartmentCard.shelf\":[\"Shelf\"],\"node.cabinet.compartmentCard.shelves\":[\"Shelves\"],\"node.cabinet.compartmentCard.shelvesInside\":[\"Shelves inside\"],\"node.cabinet.compartmentCard.single\":[\"Single\"],\"node.cabinet.compartmentCard.sink\":[\"Sink\"],\"node.cabinet.compartmentCard.style\":[\"Style\"],\"node.cabinet.compartmentCard.surface\":[\"Surface\"],\"node.cabinet.compartmentCard.top\":[\"Top\"],\"node.cabinet.compartmentCard.topFreezer\":[\"Top Freezer\"],\"node.cabinet.compartmentCard.topGrate\":[\"Top grate\"],\"node.cabinet.compartmentCard.tray\":[\"Tray\"],\"node.cabinet.compartmentCard.type\":[\"Type\"],\"node.cabinet.compartmentCard.washer\":[\"Washer\"],\"node.cabinet.compartmentCard.wire\":[\"Wire\"],\"node.cabinet.description\":[\"A configurable parametric base cabinet.\"],\"node.cabinet.essentialControls.bottomFreezer\":[\"Bottom freezer\"],\"node.cabinet.essentialControls.cooktopType\":[\"Cooktop type\"],\"node.cabinet.essentialControls.doorDirection\":[\"Door direction\"],\"node.cabinet.essentialControls.double\":[\"Double\"],\"node.cabinet.essentialControls.fridgeType\":[\"Fridge type\"],\"node.cabinet.essentialControls.gas\":[\"Gas\"],\"node.cabinet.essentialControls.glass\":[\"Glass\"],\"node.cabinet.essentialControls.induction\":[\"Induction\"],\"node.cabinet.essentialControls.itemOptions\":[\"Item options\"],\"node.cabinet.essentialControls.leftHinge\":[\"Left hinge\"],\"node.cabinet.essentialControls.rightHinge\":[\"Right hinge\"],\"node.cabinet.essentialControls.single\":[\"Single\"],\"node.cabinet.essentialControls.sinkLayout\":[\"Sink layout\"],\"node.cabinet.essentialControls.topFreezer\":[\"Top freezer\"],\"node.cabinet.kitchenCollection.chooseLabel\":[\"Choose \",[\"label\"]],\"node.cabinet.kitchenCollection.noKitchenItemsMatchTryFridge\":[\"No kitchen items match. Try “fridge”, “sink”, or “cabinet”.\"],\"node.cabinet.kitchenCollection.searchFridgeSinkCabinets\":[\"Search fridge, sink, cabinets…\"],\"node.cabinet.kitchenCollection.searchKitchenItems\":[\"Search kitchen items\"],\"node.cabinet.kitchenGroup.appliances\":[\"Appliances & fixtures\"],\"node.cabinet.kitchenGroup.cabinets\":[\"Cabinets\"],\"node.cabinet.kitchenModuleActions.addBeside\":[\"Add beside\"],\"node.cabinet.kitchenModuleActions.addBesideSelectedItem\":[\"Add beside selected item\"],\"node.cabinet.kitchenModuleActions.addLabel\":[\"Add \",[\"label\"]],\"node.cabinet.kitchenModuleActions.anUpperCabinetAttachedToThis\":[\"An upper cabinet attached to this item will be removed to make room.\"],\"node.cabinet.kitchenModuleActions.cabinet\":[\"Cabinet\"],\"node.cabinet.kitchenModuleActions.cancel\":[\"Cancel\"],\"node.cabinet.kitchenModuleActions.cannotFit\":[\"This \",[\"width\"],\" item cannot fit within the current run and its wall or corner limits. Move an end cabinet or free space, then try again.\"],\"node.cabinet.kitchenModuleActions.insertsBeside\":[[\"side\",\"select\",{\"left\":[\"Inserts on the left of the selected item.\"],\"other\":[\"Inserts on the right of the selected item.\"]}]],\"node.cabinet.kitchenModuleActions.kitchenChanged\":[\"The kitchen changed. Select an item again to refresh the preview.\"],\"node.cabinet.kitchenModuleActions.kitchenRunPreviewHighlightedItemIs\":[\"Kitchen run preview, highlighted item is the proposed change\"],\"node.cabinet.kitchenModuleActions.leftSide\":[\"Left side\"],\"node.cabinet.kitchenModuleActions.moved\":[[\"name\"],\": moves \",[\"distance\"]],\"node.cabinet.kitchenModuleActions.previewItem\":[[\"name\"],\": \",[\"width\"]],\"node.cabinet.kitchenModuleActions.replaceSelectedItem\":[\"Replace selected item\"],\"node.cabinet.kitchenModuleActions.replaceWith\":[\"Replace with…\"],\"node.cabinet.kitchenModuleActions.replaceWithLabel\":[\"Replace with \",[\"label\"]],\"node.cabinet.kitchenModuleActions.replacesOnlyTheSelectedItem\":[\"Replaces only the selected item.\"],\"node.cabinet.kitchenModuleActions.resized\":[[\"name\"],\": \",[\"before\"],\" → \",[\"after\"]],\"node.cabinet.kitchenModuleActions.rightSide\":[\"Right side\"],\"node.cabinet.kitchenModuleActions.unableToUpdateThisKitchen\":[\"Unable to update this kitchen.\"],\"node.cabinet.label\":[\"Modular Cabinet\"],\"node.cabinet.panel.aboveCeiling\":[\"Finished height extends \",[\"overflow\"],\" mm above the ceiling.\"],\"node.cabinet.panel.addChimney\":[\"Add chimney\"],\"node.cabinet.panel.addCompartment\":[\"Add compartment\"],\"node.cabinet.panel.addWallCabinet\":[\"Add wall cabinet\"],\"node.cabinet.panel.advanced\":[\"Advanced\"],\"node.cabinet.panel.appliance\":[\"Appliance\"],\"node.cabinet.panel.applianceFront\":[\"Appliance front\"],\"node.cabinet.panel.auto\":[\"Auto\"],\"node.cabinet.panel.bar\":[\"Bar\"],\"node.cabinet.panel.baseCabinet\":[\"Base Cabinet\"],\"node.cabinet.panel.cabinetConstructionCompartmentsAndOpeningPreview\":[\"Cabinet construction, compartments, and opening preview.\"],\"node.cabinet.panel.cabinetPanel\":[\"Cabinet panel\"],\"node.cabinet.panel.cabinetType\":[\"Cabinet Type\"],\"node.cabinet.panel.center\":[\"Center\"],\"node.cabinet.panel.close\":[\"Close\"],\"node.cabinet.panel.closeCabinet\":[\"Close cabinet\"],\"node.cabinet.panel.commonWallCabinetHeightsUseThe\":[\"Common wall-cabinet heights. Use the slider below for a custom height.\"],\"node.cabinet.panel.compartments\":[\"Compartments\"],\"node.cabinet.panel.cutout\":[\"Cutout\"],\"node.cabinet.panel.depth\":[\"Depth\"],\"node.cabinet.panel.dimensions\":[\"Dimensions\"],\"node.cabinet.panel.editKitchenRun\":[\"Edit kitchen run\"],\"node.cabinet.panel.fillToCeiling\":[\"Fill to ceiling\"],\"node.cabinet.panel.finish\":[\"Finish\"],\"node.cabinet.panel.frontConstruction\":[\"Front construction\"],\"node.cabinet.panel.handles\":[\"Handles\"],\"node.cabinet.panel.height\":[\"Height\"],\"node.cabinet.panel.heightPreset\":[\"Height preset\"],\"node.cabinet.panel.hole\":[\"Hole\"],\"node.cabinet.panel.inset\":[\"Inset\"],\"node.cabinet.panel.kitchen\":[\"Kitchen\"],\"node.cabinet.panel.kitchenRun\":[\"Kitchen run\"],\"node.cabinet.panel.knob\":[\"Knob\"],\"node.cabinet.panel.mounting\":[\"Mounting\"],\"node.cabinet.panel.none\":[\"None\"],\"node.cabinet.panel.open\":[\"Open\"],\"node.cabinet.panel.openAnimation\":[\"Open Animation\"],\"node.cabinet.panel.openCabinet\":[\"Open cabinet\"],\"node.cabinet.panel.overlay\":[\"Overlay\"],\"node.cabinet.panel.panelReady\":[\"Panel-ready\"],\"node.cabinet.panel.planningChecks\":[\"Planning checks\"],\"node.cabinet.panel.play\":[\"Play\"],\"node.cabinet.panel.playAnimation\":[\"Play animation\"],\"node.cabinet.panel.position\":[\"Position\"],\"node.cabinet.panel.raisedArch\":[\"Raised Arch\"],\"node.cabinet.panel.removeWallCabinet\":[\"Remove wall cabinet\"],\"node.cabinet.panel.replaceWith\":[\"Replace with…\"],\"node.cabinet.panel.revealGap\":[\"Reveal gap\"],\"node.cabinet.panel.shaker\":[\"Shaker\"],\"node.cabinet.panel.sharedCountertopPlinthAndFinishes\":[\"Shared countertop, plinth, and finishes\"],\"node.cabinet.panel.slab\":[\"Slab\"],\"node.cabinet.panel.solidMatchingFrontBetweenTheCabinet\":[\"Solid matching front between the cabinet and wall. Countertop and toe-kick continue across this filler.\"],\"node.cabinet.panel.standardWidth\":[\"Standard width\"],\"node.cabinet.panel.stop\":[\"Stop\"],\"node.cabinet.panel.stopAnimation\":[\"Stop animation\"],\"node.cabinet.panel.style\":[\"Style\"],\"node.cabinet.panel.tallCabinet\":[\"Tall Cabinet\"],\"node.cabinet.panel.top\":[\"Top\"],\"node.cabinet.panel.topCabinet\":[\"Top Cabinet\"],\"node.cabinet.panel.topCeiling\":[\"Top / Ceiling\"],\"node.cabinet.panel.topDepth\":[\"Top depth\"],\"node.cabinet.panel.topHeight\":[\"Top height\"],\"node.cabinet.panel.trimSoffit\":[\"Trim / Soffit\"],\"node.cabinet.panel.usesTheCabinetFrontStyleReveal\":[\"Uses the cabinet front style, reveal, handle, and front material settings below.\"],\"node.cabinet.panel.wallFiller\":[\"Wall filler\"],\"node.cabinet.panel.width\":[\"Width\"],\"node.cabinet.preset.baseCabinet\":[\"Base cabinet\"],\"node.cabinet.preset.dishwasher\":[\"Dishwasher\"],\"node.cabinet.preset.drawerCabinet\":[\"Drawer cabinet\"],\"node.cabinet.preset.fridge\":[\"Fridge\"],\"node.cabinet.preset.gasCooktop\":[\"Gas cooktop\"],\"node.cabinet.preset.inductionCooktop\":[\"Induction cooktop\"],\"node.cabinet.preset.ovenTower\":[\"Oven Tower\"],\"node.cabinet.preset.sinkCabinet\":[\"Sink cabinet\"],\"node.cabinet.preset.tallPantry\":[\"Tall Pantry\"],\"node.cabinet.preset.wallCabinet\":[\"Wall cabinet\"],\"node.cabinet.runPanel.addLeft\":[\"Add left\"],\"node.cabinet.runPanel.addRight\":[\"Add right\"],\"node.cabinet.runPanel.alignCabinetsHandles\":[\"Align cabinets & handles\"],\"node.cabinet.runPanel.appliesDepthCarcassPlinthAndCountertop\":[\"Applies depth, carcass, plinth, and countertop thickness to this run.\"],\"node.cabinet.runPanel.arrayCreate\":[[\"count\",\"plural\",{\"one\":[\"Create \",[\"number\"],\" module copy\"],\"other\":[\"Create \",[\"number\"],\" module copies\"]}]],\"node.cabinet.runPanel.arrayCreateNamed\":[[\"count\",\"plural\",{\"one\":[\"Create \",[\"number\"],\" \",[\"name\"],\" copy\"],\"other\":[\"Create \",[\"number\"],\" \",[\"name\"],\" copies\"]}]],\"node.cabinet.runPanel.arrayInvalidOptions\":[\"Choose a copy count from 1 to 20 and spacing from 0 to 2 m\"],\"node.cabinet.runPanel.arrayNoRoom\":[\"There is not enough room in this run for the requested array\"],\"node.cabinet.runPanel.arrayNoSource\":[\"Choose a standard or appliance module as the source\"],\"node.cabinet.runPanel.auto\":[\"Auto\"],\"node.cabinet.runPanel.back\":[\"Back\"],\"node.cabinet.runPanel.balancesStandardBaseCabinetsWhileKeeping\":[\"Balances standard base cabinets while keeping appliance and corner-filler widths fixed.\"],\"node.cabinet.runPanel.bar\":[\"Bar\"],\"node.cabinet.runPanel.barCounter\":[\"Bar counter\"],\"node.cabinet.runPanel.barDepth\":[\"Bar depth\"],\"node.cabinet.runPanel.barHeight\":[\"Bar height\"],\"node.cabinet.runPanel.carcassHeight\":[\"Carcass height\"],\"node.cabinet.runPanel.center\":[\"Center\"],\"node.cabinet.runPanel.commonWallCabinetHeightsUseThe\":[\"Common wall-cabinet heights. Use the slider below for a custom height.\"],\"node.cabinet.runPanel.copies\":[\"Copies\"],\"node.cabinet.runPanel.copiesIncludeTheSourceCabinetStructure\":[\"Copies include the source cabinet structure and any attached wall cabinet. Existing modules stay fixed; the requested array must fit in the available run space.\"],\"node.cabinet.runPanel.cornerFillersCannotBeUsedAs\":[\"Corner fillers cannot be used as array sources\"],\"node.cabinet.runPanel.countertopDepth\":[\"Countertop depth\"],\"node.cabinet.runPanel.countertopHeight\":[\"Countertop height\"],\"node.cabinet.runPanel.createArray\":[\"Create array\"],\"node.cabinet.runPanel.cutout\":[\"Cutout\"],\"node.cabinet.runPanel.deleteModule\":[\"Delete \",[\"name\"]],\"node.cabinet.runPanel.depth\":[\"Depth\"],\"node.cabinet.runPanel.direction\":[\"Direction\"],\"node.cabinet.runPanel.duplicateAlongRun\":[\"Duplicate along run\"],\"node.cabinet.runPanel.equalizeAll\":[\"Equalize all resizeable standard base cabinets in this run\"],\"node.cabinet.runPanel.equalizeAlreadyEqual\":[\"The resizeable cabinet widths are already equal\"],\"node.cabinet.runPanel.equalizeNeedsTwo\":[\"At least two standard base cabinets are required\"],\"node.cabinet.runPanel.equalizeNoFit\":[\"The available run width cannot satisfy the cabinet width limits\"],\"node.cabinet.runPanel.equalizeWidths\":[\"Equalize widths\"],\"node.cabinet.runPanel.fillerPlanSide\":[[\"side\",\"select\",{\"left\":[\"Left: \",[\"width\"],\" mm\"],\"other\":[\"Right: \",[\"width\"],\" mm\"]}]],\"node.cabinet.runPanel.finishAlign\":[\"Finish & align\"],\"node.cabinet.runPanel.finishedBack\":[\"Finished back\"],\"node.cabinet.runPanel.finishedExposedEnds\":[\"Finished exposed ends\"],\"node.cabinet.runPanel.fitWallFillers\":[\"Fit wall fillers\"],\"node.cabinet.runPanel.fits50150MmGapsAt\":[\"Fits 50–150 mm gaps at run ends beside perpendicular walls.\"],\"node.cabinet.runPanel.fronts\":[\"Fronts\"],\"node.cabinet.runPanel.handles\":[\"Handles\"],\"node.cabinet.runPanel.heightPreset\":[\"Height preset\"],\"node.cabinet.runPanel.hole\":[\"Hole\"],\"node.cabinet.runPanel.inset\":[\"Inset\"],\"node.cabinet.runPanel.islandBar\":[\"Island & Bar\"],\"node.cabinet.runPanel.kitchenRun\":[\"Kitchen run\"],\"node.cabinet.runPanel.knob\":[\"Knob\"],\"node.cabinet.runPanel.left\":[\"Left\"],\"node.cabinet.runPanel.matchBaseHeightsBacksRevealsAnd\":[\"Match base heights, backs, reveals and handles. Align upper cabinets; preserve tall appliances and custom compartments.\"],\"node.cabinet.runPanel.metricProfile\":[\"Metric · 600 mm\"],\"node.cabinet.runPanel.moduleNumber\":[\"Module \",[\"number\"]],\"node.cabinet.runPanel.modules\":[\"Modules\"],\"node.cabinet.runPanel.mounting\":[\"Mounting\"],\"node.cabinet.runPanel.noEligibleModule\":[\"No eligible module\"],\"node.cabinet.runPanel.none\":[\"None\"],\"node.cabinet.runPanel.overlay\":[\"Overlay\"],\"node.cabinet.runPanel.plinthHeight\":[\"Plinth height\"],\"node.cabinet.runPanel.position\":[\"Position\"],\"node.cabinet.runPanel.raisedArch\":[\"Raised Arch\"],\"node.cabinet.runPanel.revealGap\":[\"Reveal gap\"],\"node.cabinet.runPanel.right\":[\"Right\"],\"node.cabinet.runPanel.seatingOverhang\":[\"Seating overhang\"],\"node.cabinet.runPanel.shaker\":[\"Shaker\"],\"node.cabinet.runPanel.sharedPlinthCountertop\":[\"Shared Plinth & Countertop\"],\"node.cabinet.runPanel.showCountertop\":[\"Show countertop\"],\"node.cabinet.runPanel.showPlinth\":[\"Show plinth\"],\"node.cabinet.runPanel.slab\":[\"Slab\"],\"node.cabinet.runPanel.sourceModule\":[\"Source module\"],\"node.cabinet.runPanel.spacing\":[\"Spacing\"],\"node.cabinet.runPanel.standardDimensions\":[\"Standard dimensions\"],\"node.cabinet.runPanel.style\":[\"Style\"],\"node.cabinet.runPanel.summaryCompartment\":[[\"type\",\"select\",{\"shelf\":[\"Shelf\"],\"drawer\":[\"Drawer\"],\"door\":[\"Door\"],\"oven\":[\"Oven\"],\"microwave\":[\"Microwave\"],\"dishwasher\":[\"Dishwasher\"],\"sink\":[\"Sink\"],\"cooktop_gas\":[\"Gas cooktop\"],\"cooktop_induction\":[\"Induction cooktop\"],\"pull_out_pantry\":[\"Pull-out pantry\"],\"fridge_single\":[\"Fridge\"],\"fridge_double\":[\"Double fridge\"],\"fridge_top_freezer\":[\"Top-freezer fridge\"],\"fridge_bottom_freezer\":[\"Bottom-freezer fridge\"],\"hood_pyramid\":[\"Pyramid hood\"],\"hood_curved_glass\":[\"Curved glass hood\"],\"other\":[[\"raw\"]]}]],\"node.cabinet.runPanel.summaryCompartments\":[[\"count\",\"plural\",{\"one\":[[\"number\"],\" compartment\"],\"other\":[[\"number\"],\" compartments\"]}]],\"node.cabinet.runPanel.summaryEmpty\":[\"Empty\"],\"node.cabinet.runPanel.summaryTall\":[\"Tall cabinet\"],\"node.cabinet.runPanel.top\":[\"Top\"],\"node.cabinet.runPanel.unableToFinish\":[\"Unable to finish this kitchen run.\"],\"node.cabinet.runPanel.usProfile\":[\"US · 24 in\"],\"node.cabinet.runPanel.useAsArraySource\":[\"Use \",[\"name\"],\" as array source\"],\"node.cabinet.runPanel.useThisModuleAsTheArray\":[\"Use this module as the array source\"],\"node.cabinet.runPanel.waterfallEnds\":[\"Waterfall ends\"],\"node.cabinetModule.description\":[\"An editable module inside a modular cabinet run.\"],\"node.cabinetModule.label\":[\"Cabinet Module\"],\"node.ceiling.buildUpSection.bottomChord\":[\"Bottom chord\"],\"node.ceiling.buildUpSection.ceilingJoists\":[\"Ceiling joists\"],\"node.ceiling.buildUpSection.decking\":[\"Decking\"],\"node.ceiling.buildUpSection.finish\":[\"Finish\"],\"node.ceiling.buildUpSection.framing\":[\"Framing\"],\"node.ceiling.buildUpSection.joists\":[\"Joists\"],\"node.ceiling.buildUpSection.layers\":[\"Layers\"],\"node.ceiling.buildUpSection.none\":[\"None\"],\"node.ceiling.buildUpSection.preset\":[\"Preset\"],\"node.ceiling.buildUpSection.theHeightIsTheFinishedUnderside\":[\"The height is the finished underside; the layers rise from it.\"],\"node.ceiling.buildUpSection.thickness\":[\"Thickness\"],\"node.ceiling.buildUpSection.trussBottomChords\":[\"Truss bottom chords\"],\"node.ceiling.description\":[\"A polygon-bounded ceiling surface that hosts ceiling-mounted items.\"],\"node.ceiling.label\":[\"Ceiling\"],\"node.ceiling.panel.addHole\":[\"Add Hole\"],\"node.ceiling.panel.area\":[\"Area\"],\"node.ceiling.panel.auto\":[\"Auto\"],\"node.ceiling.panel.ceiling\":[\"Ceiling\"],\"node.ceiling.panel.customHeight\":[\"Custom height\"],\"node.ceiling.panel.cutOpening\":[\"Cut opening\"],\"node.ceiling.panel.done\":[\"Done\"],\"node.ceiling.panel.followsLevel\":[\"Follows level\"],\"node.ceiling.panel.height\":[\"Height\"],\"node.ceiling.panel.high30m\":[\"High (3.0m)\"],\"node.ceiling.panel.high90\":[\"High (9'0\\\")\"],\"node.ceiling.panel.holes\":[\"Holes\"],\"node.ceiling.panel.info\":[\"Info\"],\"node.ceiling.panel.limitedByLevel\":[\"Limited by the level to \",[\"height\"],\" — raise the level height for a taller ceiling.\"],\"node.ceiling.panel.low24m\":[\"Low (2.4m)\"],\"node.ceiling.panel.low80\":[\"Low (8'0\\\")\"],\"node.ceiling.panel.move\":[\"Move\"],\"node.ceiling.panel.noHoles\":[\"No holes\"],\"node.ceiling.panel.standard25m\":[\"Standard (2.5m)\"],\"node.ceiling.panel.standard86\":[\"Standard (8'6\\\")\"],\"node.ceiling.panel.tallerThanLevel\":[\"Taller than this level (\",[\"available\"],\" available). Raise the level height first.\"],\"node.chimney.description\":[\"Vertical masonry stack on a roof segment.\"],\"node.chimney.label\":[\"Chimney\"],\"node.chimney.panel.aboveRidge\":[\"Above Ridge\"],\"node.chimney.panel.actions\":[\"Actions\"],\"node.chimney.panel.back\":[\"Back\"],\"node.chimney.panel.bands\":[\"Bands\"],\"node.chimney.panel.cap\":[\"Cap\"],\"node.chimney.panel.chimney\":[\"Chimney\"],\"node.chimney.panel.chimneyType\":[\"Chimney Type\"],\"node.chimney.panel.corbeled\":[\"Corbeled\"],\"node.chimney.panel.cornerBevel\":[\"Corner Bevel\"],\"node.chimney.panel.count\":[\"Count\"],\"node.chimney.panel.cricket\":[\"Cricket\"],\"node.chimney.panel.cutoutOffset\":[\"Cutout Offset\"],\"node.chimney.panel.delete\":[\"Delete\"],\"node.chimney.panel.depth\":[\"Depth\"],\"node.chimney.panel.diameter\":[\"Diameter\"],\"node.chimney.panel.double\":[\"Double\"],\"node.chimney.panel.extent\":[\"Extent\"],\"node.chimney.panel.flat\":[\"Flat\"],\"node.chimney.panel.flues\":[\"Flues\"],\"node.chimney.panel.footprint\":[\"Footprint\"],\"node.chimney.panel.front\":[\"Front\"],\"node.chimney.panel.height\":[\"Height\"],\"node.chimney.panel.hollowDepth\":[\"Hollow Depth\"],\"node.chimney.panel.length\":[\"Length\"],\"node.chimney.panel.none\":[\"None\"],\"node.chimney.panel.offset\":[\"Offset\"],\"node.chimney.panel.overhang\":[\"Overhang\"],\"node.chimney.panel.panels\":[\"Panels\"],\"node.chimney.panel.position\":[\"Position\"],\"node.chimney.panel.rectangular\":[\"Rectangular\"],\"node.chimney.panel.rotation\":[\"Rotation\"],\"node.chimney.panel.round\":[\"Round\"],\"node.chimney.panel.shoulder\":[\"Shoulder\"],\"node.chimney.panel.sideMargin\":[\"Side Margin\"],\"node.chimney.panel.simple\":[\"Simple\"],\"node.chimney.panel.single\":[\"Single\"],\"node.chimney.panel.sloped\":[\"Sloped\"],\"node.chimney.panel.spacing\":[\"Spacing\"],\"node.chimney.panel.square\":[\"Square\"],\"node.chimney.panel.stepped\":[\"Stepped\"],\"node.chimney.panel.style\":[\"Style\"],\"node.chimney.panel.tapered\":[\"Tapered\"],\"node.chimney.panel.thickness\":[\"Thickness\"],\"node.chimney.panel.topOffset\":[\"Top Offset\"],\"node.chimney.panel.wallThickness\":[\"Wall Thickness\"],\"node.chimney.panel.width\":[\"Width\"],\"node.chimney.preset.brick\":[\"Brick\"],\"node.chimney.preset.modern\":[\"Modern\"],\"node.chimney.preset.round\":[\"Round\"],\"node.column.description\":[\"A parametric column with configurable cross-section, base, and capital.\"],\"node.column.label\":[\"Column\"],\"node.column.panel.aFrame\":[\"A-Frame\"],\"node.column.panel.actions\":[\"Actions\"],\"node.column.panel.applyPreset\":[\"Apply preset...\"],\"node.column.panel.applyProportion\":[\"Apply proportion...\"],\"node.column.panel.bottomDepth\":[\"Bottom Depth\"],\"node.column.panel.bottomHeight\":[\"Bottom Height\"],\"node.column.panel.bottomSpread\":[\"Bottom Spread\"],\"node.column.panel.bottomStepSpread\":[\"Bottom Step Spread\"],\"node.column.panel.bottomTiers\":[\"Bottom Tiers\"],\"node.column.panel.bottomWidth\":[\"Bottom Width\"],\"node.column.panel.boxFrame\":[\"Box Frame\"],\"node.column.panel.braceDepth\":[\"Brace Depth\"],\"node.column.panel.braceWidth\":[\"Brace Width\"],\"node.column.panel.bulge\":[\"Bulge\"],\"node.column.panel.bulged\":[\"Bulged\"],\"node.column.panel.column\":[\"Column\"],\"node.column.panel.connectorPlates\":[\"Connector Plates\"],\"node.column.panel.delete\":[\"Delete\"],\"node.column.panel.depth\":[\"Depth\"],\"node.column.panel.dimensions\":[\"Dimensions\"],\"node.column.panel.edgeSoftness\":[\"Edge Softness\"],\"node.column.panel.endWidth\":[\"End Width\"],\"node.column.panel.ends\":[\"Ends\"],\"node.column.panel.forkSpread\":[\"Fork Spread\"],\"node.column.panel.heavy\":[\"Heavy\"],\"node.column.panel.height\":[\"Height\"],\"node.column.panel.heightAndFootprintAreControlledBy\":[\"Height and footprint are controlled by the lean-to extension. Rotate or change the support style here; resize from the parent lean-to.\"],\"node.column.panel.hourglass\":[\"Hourglass\"],\"node.column.panel.kBrace\":[\"K Brace\"],\"node.column.panel.move\":[\"Move\"],\"node.column.panel.neckWidth\":[\"Neck Width\"],\"node.column.panel.noBottom\":[\"No Bottom\"],\"node.column.panel.noTop\":[\"No Top\"],\"node.column.panel.plinthThickness\":[\"Plinth Thickness\"],\"node.column.panel.portalFrame\":[\"Portal Frame\"],\"node.column.panel.preset\":[\"Preset\"],\"node.column.panel.rectangular\":[\"Rectangular\"],\"node.column.panel.ringPairs\":[\"Ring Pairs\"],\"node.column.panel.ringSpread\":[\"Ring Spread\"],\"node.column.panel.ringThickness\":[\"Ring Thickness\"],\"node.column.panel.round\":[\"Round\"],\"node.column.panel.roundBandWidth\":[\"Round Band Width\"],\"node.column.panel.roundedBottom\":[\"Rounded Bottom\"],\"node.column.panel.roundedTop\":[\"Rounded Top\"],\"node.column.panel.segmentTwist\":[\"Segment Twist\"],\"node.column.panel.shaft\":[\"Shaft\"],\"node.column.panel.shaftCornerRadius\":[\"Shaft Corner Radius\"],\"node.column.panel.shaftWidth\":[\"Shaft Width\"],\"node.column.panel.shape\":[\"Shape\"],\"node.column.panel.shortStout\":[\"Short / Stout\"],\"node.column.panel.simpleBlockBottom\":[\"Simple Block Bottom\"],\"node.column.panel.simpleTop\":[\"Simple Top\"],\"node.column.panel.singleStrut\":[\"Single Strut\"],\"node.column.panel.slender\":[\"Slender\"],\"node.column.panel.square\":[\"Square\"],\"node.column.panel.squarePlinthBottom\":[\"Square Plinth Bottom\"],\"node.column.panel.standard\":[\"Standard\"],\"node.column.panel.steppedBottom\":[\"Stepped Bottom\"],\"node.column.panel.steppedTop\":[\"Stepped Top\"],\"node.column.panel.straight\":[\"Straight\"],\"node.column.panel.taper\":[\"Taper\"],\"node.column.panel.tapered\":[\"Tapered\"],\"node.column.panel.topDepth\":[\"Top Depth\"],\"node.column.panel.topHeight\":[\"Top Height\"],\"node.column.panel.topSpread\":[\"Top Spread\"],\"node.column.panel.topStepSpread\":[\"Top Step Spread\"],\"node.column.panel.topTiers\":[\"Top Tiers\"],\"node.column.panel.topWidth\":[\"Top Width\"],\"node.column.panel.transform\":[\"Transform\"],\"node.column.panel.trestle\":[\"Trestle\"],\"node.column.panel.tripod\":[\"Tripod\"],\"node.column.panel.twistSegments\":[\"Twist Segments\"],\"node.column.panel.vSupport\":[\"V Support\"],\"node.column.panel.vertical\":[\"Vertical\"],\"node.column.panel.waist\":[\"Waist\"],\"node.column.panel.width\":[\"Width\"],\"node.column.panel.xBrace\":[\"X Brace\"],\"node.column.panel.ySupport\":[\"Y Support\"],\"node.column.panel.yaw\":[\"Yaw\"],\"node.column.postSection.aSizeDeckPostStandsNo\":[\"A \",[\"size\"],\" deck post stands no taller than \",[\"limit\"],\" (IRC Table R507.4, by species and the area it carries): check it, or use the next size up.\"],\"node.column.postSection.custom\":[\"Custom\"],\"node.column.postSection.fitToTheBeamOverIt\":[\"Fit to the beam over it (\",[\"height\"],\")\"],\"node.column.postSection.fitToTheCeilingPlane\":[\"Fit to the ceiling plane (\",[\"height\"],\")\"],\"node.column.postSection.height\":[\"Height\"],\"node.column.postSection.keepItsShapeAndStyleIt\":[\"Keep its shape and style it as a column\"],\"node.column.postSection.makeItAColumn\":[\"Make it a column\"],\"node.column.postSection.post\":[\"Post\"],\"node.column.postSection.treated\":[\"Treated\"],\"node.column.postSection.untreated\":[\"Untreated\"],\"node.column.preset.aFrameSupport\":[\"A-Frame Support\"],\"node.column.preset.basicPillar\":[\"Straight Round\"],\"node.column.preset.boxFrameSupport\":[\"Box Frame\"],\"node.column.preset.bulgedPillar\":[\"Soft Bulged\"],\"node.column.preset.hourglassPillar\":[\"Hourglass\"],\"node.column.preset.kBraceSupport\":[\"K Brace\"],\"node.column.preset.portalFrameSupport\":[\"Portal Frame\"],\"node.column.preset.singleStrutSupport\":[\"Single Strut\"],\"node.column.preset.squarePillar\":[\"Square Block\"],\"node.column.preset.taperedPillar\":[\"Tapered Round\"],\"node.column.preset.trestleSupport\":[\"Trestle Frame\"],\"node.column.preset.tripodSupport\":[\"Tripod Support\"],\"node.column.preset.vFrameSupport\":[\"V Support\"],\"node.column.preset.xBraceSupport\":[\"X Brace\"],\"node.column.preset.yFrameSupport\":[\"Y Support\"],\"node.constructionDimension.description\":[\"Associative linear, curved, circular, angular, or coordinate plan dimension.\"],\"node.constructionDimension.label\":[\"Construction Dimension\"],\"node.cornerRadius.bottomLeft\":[\"Bottom Left\"],\"node.cornerRadius.bottomRight\":[\"Bottom Right\"],\"node.cornerRadius.topLeft\":[\"Top Left\"],\"node.cornerRadius.topRight\":[\"Top Right\"],\"node.cupola.description\":[\"Louvered roof lantern with a dome or pyramid cap and optional finial.\"],\"node.cupola.label\":[\"Cupola\"],\"node.cupola.panel.actions\":[\"Actions\"],\"node.cupola.panel.cupola\":[\"Cupola\"],\"node.cupola.panel.delete\":[\"Delete\"],\"node.cupola.panel.depth\":[\"Depth\"],\"node.cupola.panel.dimensions\":[\"Dimensions\"],\"node.cupola.panel.dome\":[\"Dome\"],\"node.cupola.panel.duplicate\":[\"Duplicate\"],\"node.cupola.panel.finial\":[\"Finial\"],\"node.cupola.panel.height\":[\"Height\"],\"node.cupola.panel.move\":[\"Move\"],\"node.cupola.panel.noFinial\":[\"No Finial\"],\"node.cupola.panel.position\":[\"Position\"],\"node.cupola.panel.pyramid\":[\"Pyramid\"],\"node.cupola.panel.rotation\":[\"Rotation\"],\"node.cupola.panel.style\":[\"Style\"],\"node.cupola.panel.width\":[\"Width\"],\"node.cutout.autoElevator\":[\"Auto elevator cutout\"],\"node.cutout.autoStair\":[\"Auto stair cutout\"],\"node.cutout.opening\":[\"Opening\"],\"node.cutout.room\":[\"Room cutout\"],\"node.door.actions.swapHingeSide\":[\"Swap hinge side\"],\"node.door.actions.swapSwingSide\":[\"Swap swing side\"],\"node.door.description\":[\"A door cut into a wall. Animated open/close state.\"],\"node.door.label\":[\"Door\"],\"node.door.panel.actions\":[\"Actions\"],\"node.door.panel.addSegment\":[\"+ Add Segment\"],\"node.door.panel.all\":[\"All\"],\"node.door.panel.arch\":[\"Arch\"],\"node.door.panel.archHeight\":[\"Arch Height\"],\"node.door.panel.auto\":[\"Auto\"],\"node.door.panel.autoFollowsTheWall\":[\"Auto follows the wall\"],\"node.door.panel.barHeight\":[\"Bar Height\"],\"node.door.panel.columns\":[\"Columns\"],\"node.door.panel.contentPadding\":[\"Content Padding\"],\"node.door.panel.cornerRadius\":[\"Corner Radius\"],\"node.door.panel.customTheSegmentsMatchNoStyle\":[\"Custom: the segments match no style.\"],\"node.door.panel.delete\":[\"Delete\"],\"node.door.panel.depth\":[\"Depth\"],\"node.door.panel.dimensions\":[\"Dimensions\"],\"node.door.panel.direction\":[\"Direction\"],\"node.door.panel.divider\":[\"Divider\"],\"node.door.panel.door\":[\"Door\"],\"node.door.panel.doorCloser\":[\"Door Closer\"],\"node.door.panel.duplicate\":[\"Duplicate\"],\"node.door.panel.empty\":[\"Empty\"],\"node.door.panel.enableHandle\":[\"Enable Handle\"],\"node.door.panel.enableThreshold\":[\"Enable Threshold\"],\"node.door.panel.flipSide\":[\"Flip Side\"],\"node.door.panel.fold\":[\"Fold\"],\"node.door.panel.frame\":[\"Frame\"],\"node.door.panel.frameDepthAuto\":[\"Depth (auto)\"],\"node.door.panel.garage\":[\"Garage\"],\"node.door.panel.glass\":[\"Glass\"],\"node.door.panel.handle\":[\"Handle\"],\"node.door.panel.handleSide\":[\"Handle Side\"],\"node.door.panel.hardware\":[\"Hardware\"],\"node.door.panel.height\":[\"Height\"],\"node.door.panel.hingesSide\":[\"Hinges Side\"],\"node.door.panel.horizontal\":[\"Horizontal\"],\"node.door.panel.individual\":[\"Individual\"],\"node.door.panel.inset\":[\"Inset\"],\"node.door.panel.inward\":[\"Inward\"],\"node.door.panel.left\":[\"Left\"],\"node.door.panel.move\":[\"Move\"],\"node.door.panel.open\":[\"Open\"],\"node.door.panel.opening\":[\"Opening\"],\"node.door.panel.openingShape\":[\"Opening Shape\"],\"node.door.panel.outward\":[\"Outward\"],\"node.door.panel.panel\":[\"Panel\"],\"node.door.panel.panels\":[\"Panels\"],\"node.door.panel.panicBar\":[\"Panic Bar\"],\"node.door.panel.pocket\":[\"Pocket\"],\"node.door.panel.position\":[\"Position\"],\"node.door.panel.rail\":[\"Rail\"],\"node.door.panel.rect\":[\"Rect\"],\"node.door.panel.remove\":[\"- Remove\"],\"node.door.panel.revealRadius\":[\"Reveal Radius\"],\"node.door.panel.right\":[\"Right\"],\"node.door.panel.rounded\":[\"Rounded\"],\"node.door.panel.segments\":[\"Segments\"],\"node.door.panel.sizeIsLimitedToTheWall\":[\"Size is limited to the wall, including clearance for the opening frame.\"],\"node.door.panel.slide\":[\"Slide\"],\"node.door.panel.style\":[\"Style\"],\"node.door.panel.swing\":[\"Swing\"],\"node.door.panel.thickness\":[\"Thickness\"],\"node.door.panel.threshold\":[\"Threshold\"],\"node.door.panel.topShape\":[\"Top Shape\"],\"node.door.panel.type\":[\"Type\"],\"node.door.panel.vertical\":[\"Vertical\"],\"node.door.panel.wall\":[\"wall\"],\"node.door.panel.width\":[\"Width\"],\"node.door.style.barn\":[\"Barn\"],\"node.door.style.craftsman\":[\"Craftsman\"],\"node.door.style.french\":[\"French\"],\"node.door.style.glass\":[\"Glass\"],\"node.door.style.halfLouvered\":[\"Half-louvered\"],\"node.door.style.modern\":[\"Modern\"],\"node.door.style.panel\":[\"Panel\"],\"node.door.style.paneledGlass\":[\"Paneled glass\"],\"node.door.style.shaker\":[\"Shaker\"],\"node.door.style.sixPanel\":[\"Six-panel\"],\"node.door.type.barn\":[\"Barn\"],\"node.door.type.double\":[\"Double\"],\"node.door.type.folding\":[\"Folding\"],\"node.door.type.french\":[\"French\"],\"node.door.type.garageRollup\":[\"Roll-up\"],\"node.door.type.garageSectional\":[\"Sectional\"],\"node.door.type.garageTiltup\":[\"Tilt-up\"],\"node.door.type.hinged\":[\"Hinged\"],\"node.door.type.pocket\":[\"Pocket\"],\"node.door.type.sliding\":[\"Sliding\"],\"node.dormer.description\":[\"House-shaped protrusion on a roof segment.\"],\"node.dormer.label\":[\"Dormer\"],\"node.dormer.panel.depth\":[\"Depth\"],\"node.dormer.panel.dimensions\":[\"Dimensions\"],\"node.dormer.panel.dormer\":[\"Dormer\"],\"node.dormer.panel.dutch\":[\"Dutch\"],\"node.dormer.panel.flat\":[\"Flat\"],\"node.dormer.panel.gable\":[\"Gable\"],\"node.dormer.panel.gambrel\":[\"Gambrel\"],\"node.dormer.panel.hip\":[\"Hip\"],\"node.dormer.panel.mansard\":[\"Mansard\"],\"node.dormer.panel.pitchDirection\":[\"Pitch Direction\"],\"node.dormer.panel.pitchRise\":[\"Pitch Rise\"],\"node.dormer.panel.riseBack\":[\"Rise Back\"],\"node.dormer.panel.riseFront\":[\"Rise Front\"],\"node.dormer.panel.roofHeight\":[\"Roof Height\"],\"node.dormer.panel.roofType\":[\"Roof Type\"],\"node.dormer.panel.section\":[\"Section\"],\"node.dormer.panel.shed\":[\"Shed\"],\"node.dormer.panel.wallHeight\":[\"Wall Height\"],\"node.dormer.panel.width\":[\"Width\"],\"node.dormer.panel.windows\":[\"Windows\"],\"node.dormer.panelActionsSection.actions\":[\"Actions\"],\"node.dormer.panelActionsSection.delete\":[\"Delete\"],\"node.dormer.panelActionsSection.duplicate\":[\"Duplicate\"],\"node.dormer.panelActionsSection.move\":[\"Move\"],\"node.dormer.panelPositionSection.position\":[\"Position\"],\"node.dormer.panelPositionSection.rotation\":[\"Rotation\"],\"node.dormer.panelWindowsSection.addWindow\":[\"Add Window\"],\"node.dormer.panelWindowsSection.editNamed\":[\"Edit \",[\"name\"]],\"node.dormer.panelWindowsSection.editWindow\":[\"Edit window\"],\"node.dormer.panelWindowsSection.increaseTheDormerWidthToAdd\":[\"Increase the dormer width to add another window.\"],\"node.dormer.panelWindowsSection.move\":[\"Move\"],\"node.dormer.panelWindowsSection.moveNamed\":[\"Move \",[\"name\"]],\"node.dormer.panelWindowsSection.moveWindow\":[\"Move window\"],\"node.dormer.panelWindowsSection.noWindows\":[\"No windows\"],\"node.dormer.panelWindowsSection.windowNumber\":[\"Window \",[\"number\"]],\"node.dormer.panelWindowsSection.windowSummary\":[[\"face\",\"select\",{\"back\":[\"Back\"],\"left\":[\"Left\"],\"right\":[\"Right\"],\"other\":[\"Front\"]}],\" · \",[\"width\"],\" × \",[\"height\"],\" m\"],\"node.dormer.panelWindowsSection.windowsLength\":[\"Windows (\",[\"length\"],\")\"],\"node.downspout.description\":[\"Vertical drop pipe from a gutter outlet to the ground.\"],\"node.downspout.inspectorEditors.position\":[\"Position\"],\"node.downspout.label\":[\"Downspout\"],\"node.ductFitting.description\":[\"Elbow, tee, reducer, or square-to-round transition connecting duct runs.\"],\"node.ductFitting.inspectorEditors.swapWH\":[\"Swap W/H\"],\"node.ductFitting.inspectorEditors.swapWidthAndHeight\":[\"Swap width and height\"],\"node.ductFitting.label\":[\"Duct Fitting\"],\"node.ductFitting.tool.axis\":[\"Axis\"],\"node.ductFitting.tool.axis2\":[\"⌥ axis\"],\"node.ductFitting.tool.hoverADuctFaceThatFits\":[\"Hover a duct face that fits the door\"],\"node.ductFitting.tool.placeAccessDoor\":[\"Place access door\"],\"node.ductFitting.tool.rTRotate\":[\"R/T rotate\"],\"node.ductSegment.description\":[\"HVAC duct run — polyline of round, rect, or flat-oval sections.\"],\"node.ductSegment.label\":[\"Duct\"],\"node.ductTerminal.description\":[\"Duct terminal — supply register, ceiling diffuser, or return grille. Duct runs end at its collar.\"],\"node.ductTerminal.label\":[\"Register\"],\"node.ductTerminal.tool.mSurface\":[\"M surface\"],\"node.ductTerminal.tool.mount\":[[\"mount\",\"select\",{\"floor\":[\"Mount Floor\"],\"ceiling\":[\"Mount Ceiling\"],\"wall\":[\"Mount Wall\"],\"other\":[\"Mount \",[\"label\"]]}]],\"node.ductTerminal.tool.rTRotate\":[\"R/T rotate\"],\"node.ductTerminal.tool.snappedToDuct\":[\"Snapped to duct\"],\"node.elevator.description\":[\"A multi-level elevator shaft with configurable openings per level.\"],\"node.elevator.label\":[\"Elevator\"],\"node.elevator.panel.access\":[\"Access\"],\"node.elevator.panel.actions\":[\"Actions\"],\"node.elevator.panel.cab\":[\"Cab\"],\"node.elevator.panel.cabHeight\":[\"Cab Height\"],\"node.elevator.panel.centerOpening\":[\"Center opening\"],\"node.elevator.panel.defaultFloor\":[\"Default Floor\"],\"node.elevator.panel.delete\":[\"Delete\"],\"node.elevator.panel.depth\":[\"Depth\"],\"node.elevator.panel.destination\":[\"Destination\"],\"node.elevator.panel.disabled\":[\"Disabled\"],\"node.elevator.panel.doorHeight\":[\"Door Height\"],\"node.elevator.panel.doorTime\":[\"Door Time\"],\"node.elevator.panel.doorType\":[\"Door Type\"],\"node.elevator.panel.doorWidth\":[\"Door Width\"],\"node.elevator.panel.doors\":[\"Doors\"],\"node.elevator.panel.duplicate\":[\"Duplicate\"],\"node.elevator.panel.dwell\":[\"Dwell\"],\"node.elevator.panel.elevator\":[\"Elevator\"],\"node.elevator.panel.from\":[\"From\"],\"node.elevator.panel.glass\":[\"Glass\"],\"node.elevator.panel.glassFrame\":[\"Glass frame\"],\"node.elevator.panel.motion\":[\"Motion\"],\"node.elevator.panel.move\":[\"Move\"],\"node.elevator.panel.openingStyle\":[\"Opening Style\"],\"node.elevator.panel.position\":[\"Position\"],\"node.elevator.panel.rotation\":[\"Rotation\"],\"node.elevator.panel.segmentedPanel\":[\"Segmented panel\"],\"node.elevator.panel.service\":[\"Service\"],\"node.elevator.panel.shaft\":[\"Shaft\"],\"node.elevator.panel.shaftDepth\":[\"Shaft Depth\"],\"node.elevator.panel.shaftStyle\":[\"Shaft Style\"],\"node.elevator.panel.shaftWidth\":[\"Shaft Width\"],\"node.elevator.panel.singleLeft\":[\"Single left\"],\"node.elevator.panel.singleRight\":[\"Single right\"],\"node.elevator.panel.solid\":[\"Solid\"],\"node.elevator.panel.solidPanel\":[\"Solid panel\"],\"node.elevator.panel.speed\":[\"Speed\"],\"node.elevator.panel.stopStoporder\":[\"Stop \",[\"stopOrder\"]],\"node.elevator.panel.to\":[\"To\"],\"node.elevator.panel.wallThickness\":[\"Wall Thickness\"],\"node.elevator.panel.width\":[\"Width\"],\"node.elevator.panel.yaw\":[\"Yaw\"],\"node.eyebrowVent.description\":[\"Low curved lens-shaped roof vent with a louvered front.\"],\"node.eyebrowVent.label\":[\"Eyebrow Vent\"],\"node.eyebrowVent.panel.actions\":[\"Actions\"],\"node.eyebrowVent.panel.backHeight\":[\"Back height\"],\"node.eyebrowVent.panel.delete\":[\"Delete\"],\"node.eyebrowVent.panel.depth\":[\"Depth\"],\"node.eyebrowVent.panel.dimensions\":[\"Dimensions\"],\"node.eyebrowVent.panel.duplicate\":[\"Duplicate\"],\"node.eyebrowVent.panel.eyebrowVent\":[\"Eyebrow Vent\"],\"node.eyebrowVent.panel.halfRound\":[\"Half-round\"],\"node.eyebrowVent.panel.height\":[\"Height\"],\"node.eyebrowVent.panel.louvers\":[\"Louvers\"],\"node.eyebrowVent.panel.move\":[\"Move\"],\"node.eyebrowVent.panel.position\":[\"Position\"],\"node.eyebrowVent.panel.rotation\":[\"Rotation\"],\"node.eyebrowVent.panel.scoop\":[\"Scoop\"],\"node.eyebrowVent.panel.slantBox\":[\"Slant-box\"],\"node.eyebrowVent.panel.style\":[\"Style\"],\"node.eyebrowVent.panel.width\":[\"Width\"],\"node.fence.description\":[\"A straight or curved fence segment with configurable posts and infill.\"],\"node.fence.inspectorEditors.addPointAfter\":[\"Add point after\"],\"node.fence.inspectorEditors.chooseASlabOrShapedSurface\":[\"Choose a slab or shaped surface on this level.\"],\"node.fence.inspectorEditors.chooseASurface\":[\"Choose a surface\"],\"node.fence.inspectorEditors.corner\":[\"Corner\"],\"node.fence.inspectorEditors.curve\":[\"Curve\"],\"node.fence.inspectorEditors.curved\":[\"Curved\"],\"node.fence.inspectorEditors.distributionInfo\":[[\"style\",\"select\",{\"picket\":[\"Distribution controls pickets in each bay between posts.\"],\"horizontal\":[\"Distribution controls posts along the full fence.\"],\"other\":[\"Distribution controls infill pieces between the two end posts.\"]}],\" Spacing is measured between centers. The available width limits the count so pieces do not overlap.\"],\"node.fence.inspectorEditors.editPath\":[\"Edit path\"],\"node.fence.inspectorEditors.extendPath\":[\"Extend path\"],\"node.fence.inspectorEditors.followHighestSurface\":[\"Follow highest surface\"],\"node.fence.inspectorEditors.followSelectedSurface\":[\"Follow selected surface\"],\"node.fence.inspectorEditors.holdStartingHeight\":[\"Hold starting height\"],\"node.fence.inspectorEditors.join\":[\"Join\"],\"node.fence.inspectorEditors.length\":[\"Length\"],\"node.fence.inspectorEditors.pathSummary\":[[\"count\",\"plural\",{\"one\":[[\"number\"],\" point\"],\"other\":[[\"number\"],\" points\"]}],\" · \",[\"length\"],\" m\"],\"node.fence.inspectorEditors.picketRailProjection\":[\"Picket rail projection\"],\"node.fence.inspectorEditors.point\":[\"Point\"],\"node.fence.inspectorEditors.removePoint\":[\"Remove point\"],\"node.fence.inspectorEditors.setEachSpanToStraightOr\":[\"Set each span to straight or curved, then drag its points and curve handles in either view.\"],\"node.fence.inspectorEditors.smooth\":[\"Smooth\"],\"node.fence.inspectorEditors.spanToPointNumber\":[\"Span to point \",[\"number\"]],\"node.fence.inspectorEditors.straight\":[\"Straight\"],\"node.fence.inspectorEditors.surface\":[\"Surface\"],\"node.fence.inspectorEditors.surfaceBehavior\":[\"Surface behavior\"],\"node.fence.label\":[\"Fence\"],\"node.fence.moveEndpointTool.detachEndpoint\":[\"Detach endpoint\"],\"node.fence.moveEndpointTool.dragEndpoint\":[\"Drag endpoint\"],\"node.fenceFeature.actions.close\":[\"Close\"],\"node.fenceFeature.actions.open\":[\"Open\"],\"node.fenceFeature.inspector.boardWidth\":[\"Board width\"],\"node.fenceFeature.inspector.bracing\":[\"Bracing\"],\"node.fenceFeature.inspector.distanceFromStart\":[\"Distance from start\"],\"node.fenceFeature.inspector.fenceUnavailable\":[\"Fence unavailable.\"],\"node.fenceFeature.inspector.frameWidth\":[\"Frame width\"],\"node.fenceFeature.inspector.gateHeight\":[\"Gate height\"],\"node.fenceFeature.inspector.gateStyle\":[\"Gate style\"],\"node.fenceFeature.inspector.groundClearance\":[\"Ground clearance\"],\"node.fenceFeature.inspector.hingeSide\":[\"Hinge side\"],\"node.fenceFeature.inspector.hingesAndLatch\":[\"Hinges and latch\"],\"node.fenceFeature.inspector.horizontalBoards\":[\"Horizontal boards\"],\"node.fenceFeature.inspector.infillSpacing\":[\"Infill spacing\"],\"node.fenceFeature.inspector.jambPosts\":[\"Jamb posts\"],\"node.fenceFeature.inspector.keepTheOpeningInsideTheFence\":[\"Keep the opening inside the fence and clear of other gates or passages.\"],\"node.fenceFeature.inspector.leafThickness\":[\"Leaf thickness\"],\"node.fenceFeature.inspector.leaves\":[\"Leaves\"],\"node.fenceFeature.inspector.leftLeafProportion\":[\"Left leaf proportion\"],\"node.fenceFeature.inspector.matchFenceHeight\":[\"Match fence height\"],\"node.fenceFeature.inspector.matchFenceStyle\":[\"Match fence style\"],\"node.fenceFeature.inspector.openRails\":[\"Open rails\"],\"node.fenceFeature.inspector.openingAngle\":[\"Opening angle\"],\"node.fenceFeature.inspector.openingWidth\":[\"Opening width\"],\"node.fenceFeature.inspector.option.cross\":[\"Cross\"],\"node.fenceFeature.inspector.option.diagonal\":[\"Diagonal\"],\"node.fenceFeature.inspector.option.doubleGate\":[\"Double gate\"],\"node.fenceFeature.inspector.option.inward\":[\"Inward\"],\"node.fenceFeature.inspector.option.left\":[\"Left\"],\"node.fenceFeature.inspector.option.none\":[\"None\"],\"node.fenceFeature.inspector.option.outward\":[\"Outward\"],\"node.fenceFeature.inspector.option.right\":[\"Right\"],\"node.fenceFeature.inspector.option.singleGate\":[\"Single gate\"],\"node.fenceFeature.inspector.picket\":[\"Picket\"],\"node.fenceFeature.inspector.postHeight\":[\"Post height\"],\"node.fenceFeature.inspector.removeGate\":[\"Remove gate\"],\"node.fenceFeature.inspector.removeOpening\":[\"Remove opening\"],\"node.fenceFeature.inspector.solidPrivacy\":[\"Solid privacy\"],\"node.fenceFeature.inspector.swingDirection\":[\"Swing direction\"],\"node.fenceFeature.inspector.verticalSlats\":[\"Vertical slats\"],\"node.fenceGate.description\":[\"A gate hosted by a fence.\"],\"node.fenceGate.label\":[\"Gate\"],\"node.fenceOpening.description\":[\"An intentional opening in a fence.\"],\"node.fenceOpening.label\":[\"Open Passage\"],\"node.floorOpening.label\":[\"Floor opening\"],\"node.guide.description\":[\"A measurement / reference annotation (linear, area, or arc).\"],\"node.guide.label\":[\"Guide\"],\"node.gutter.description\":[\"Rain-water channel running along the eave of a roof segment.\"],\"node.gutter.downspoutsPanel.addDownspout\":[\"Add Downspout\"],\"node.gutter.downspoutsPanel.downspoutNumber\":[\"Downspout \",[\"number\"]],\"node.gutter.downspoutsPanel.downspouts\":[\"Downspouts\"],\"node.gutter.downspoutsPanel.removeDownspout\":[\"Remove downspout\"],\"node.gutter.label\":[\"Gutter\"],\"node.hole.manual\":[\"Manual\"],\"node.holeEditing\":[\"Hole \",[\"number\"],\" (Editing)\"],\"node.holeNumber\":[\"Hole \",[\"number\"]],\"node.holeSummary\":[[\"area\"],\" \",[\"unit\"],\" · \",[\"count\",\"plural\",{\"one\":[[\"points\"],\" pt\"],\"other\":[[\"points\"],\" pts\"]}],\" · \",[\"source\"]],\"node.hvacEquipment.description\":[\"Furnace, air handler, or condenser — duct runs connect to its supply/return collars.\"],\"node.hvacEquipment.label\":[\"HVAC Unit\"],\"node.hvacEquipment.tool.rTRotate\":[\"R/T rotate\"],\"node.importedMesh.description\":[\"Geometry preserved from an imported model when no native Pascal shape exists.\"],\"node.importedMesh.label\":[\"Imported Mesh\"],\"node.item.authoredParams.couldnTRebuildWithTheseValues\":[\"Couldn't rebuild with these values.\"],\"node.item.authoredParams.parameters\":[\"Parameters\"],\"node.item.authoredParams.rebuilding\":[\"Rebuilding…\"],\"node.item.authoredParams.rebuildingInBlender\":[\"Rebuilding in Blender…\"],\"node.item.authoredParams.resetParam\":[\"Reset \",[\"param\"]],\"node.item.authoredParams.resetParameters\":[\"Reset parameters\"],\"node.item.authoredParams.resetToDefault\":[\"Reset to default\"],\"node.item.description\":[\"A catalog-backed item (furniture, fixtures, decorations).\"],\"node.item.label\":[\"Item\"],\"node.item.panel.actions\":[\"Actions\"],\"node.item.panel.delete\":[\"Delete\"],\"node.item.panel.dimensions\":[\"Dimensions\"],\"node.item.panel.duplicate\":[\"Duplicate\"],\"node.item.panel.info\":[\"Info\"],\"node.item.panel.move\":[\"Move\"],\"node.item.panel.pos\":[\"pos\"],\"node.item.panel.position\":[\"Position\"],\"node.item.panel.rot\":[\"rot\"],\"node.item.panel.rotation\":[\"Rotation\"],\"node.item.panel.scale\":[\"Scale\"],\"node.item.panel.scale2\":[\"scale\"],\"node.item.panel.uniformScale\":[\"Uniform Scale\"],\"node.item.panel.xyz\":[\"XYZ\"],\"node.leanToExtension.description\":[\"An attached mono-pitch or freestanding mono, gable, or butterfly canopy with managed structure and drainage.\"],\"node.leanToExtension.label\":[\"Canopy\"],\"node.level.description\":[\"A single floor of a building, holding walls / slabs / ceilings / items.\"],\"node.level.label\":[\"Level\"],\"node.lineset.description\":[\"Refrigerant lineset — copper suction + liquid pair joining a condenser to the indoor coil.\"],\"node.lineset.label\":[\"Lineset\"],\"node.liquidLine.description\":[\"Standalone refrigerant liquid line — a thin bare-copper run; Follow mode traces an existing lineset.\"],\"node.liquidLine.label\":[\"Liquid Line\"],\"node.liquidLine.tool.clickToTraceThisLinesetRun\":[\"Click to trace this lineset run\"],\"node.liquidLine.tool.followHoverALineset\":[\"Follow: hover a lineset\"],\"node.measurement.description\":[\"A persistent distance, angle, area, perimeter, or volume annotation.\"],\"node.measurement.label\":[\"Measurement\"],\"node.numberedName\":[[\"kind\"],\" \",[\"number\"]],\"node.panel.currently\":[\"Currently \",[\"value\"]],\"node.pipeFitting.description\":[\"DWV joint — elbow bend, 45° wye, or sanitary tee.\"],\"node.pipeFitting.label\":[\"Pipe Fitting\"],\"node.pipeFitting.tool.axis\":[\"Axis\"],\"node.pipeFitting.tool.axis2\":[\"⌥ axis\"],\"node.pipeFitting.tool.rTRotate\":[\"R/T rotate\"],\"node.pipeSegment.description\":[\"Drain / waste / vent pipe run — draw level or toggle a ¼″ per foot fall with S.\"],\"node.pipeSegment.label\":[\"DWV Pipe\"],\"node.pipeTrap.description\":[\"DWV P-trap — water seal on the waste line. The trap arm runs to the vent.\"],\"node.pipeTrap.label\":[\"Trap\"],\"node.pipeTrap.tool.diameterTrap\":[[\"diameter\"],\"\\\" Trap\"],\"node.pipeTrap.tool.rTRotate\":[\"R/T rotate\"],\"node.proceduralItem.description\":[\"Experimental editable recipe\"],\"node.proceduralItem.label\":[\"Procedural item\"],\"node.ridgeVent.description\":[\"Ventilation strip running along the ridge of a roof segment.\"],\"node.ridgeVent.label\":[\"Ridge Vent\"],\"node.ridgeVent.panel.actions\":[\"Actions\"],\"node.ridgeVent.panel.delete\":[\"Delete\"],\"node.ridgeVent.panel.dimensions\":[\"Dimensions\"],\"node.ridgeVent.panel.duplicate\":[\"Duplicate\"],\"node.ridgeVent.panel.endCaps\":[\"End Caps\"],\"node.ridgeVent.panel.flanged\":[\"Flanged\"],\"node.ridgeVent.panel.height\":[\"Height\"],\"node.ridgeVent.panel.length\":[\"Length\"],\"node.ridgeVent.panel.move\":[\"Move\"],\"node.ridgeVent.panel.open\":[\"Open\"],\"node.ridgeVent.panel.position\":[\"Position\"],\"node.ridgeVent.panel.ridgeVent\":[\"Ridge Vent\"],\"node.ridgeVent.panel.rotation\":[\"Rotation\"],\"node.ridgeVent.panel.shingled\":[\"Shingled\"],\"node.ridgeVent.panel.standard\":[\"Standard\"],\"node.ridgeVent.panel.style\":[\"Style\"],\"node.ridgeVent.panel.width\":[\"Width\"],\"node.roof.barrelPanel.archBays\":[\"Arch bays\"],\"node.roof.barrelPanel.barrelArch\":[\"Barrel arch\"],\"node.roof.barrelPanel.flatPanesFollowACircularArch\":[\"Flat panes follow a circular arch. Rise is measured from the eaves.\"],\"node.roof.barrelPanel.rise\":[\"Rise\"],\"node.roof.description\":[\"A pitched / hip / gable roof composed of one or more segments.\"],\"node.roof.glazing.face.archBay\":[\"Arch bay \",[\"number\"]],\"node.roof.glazing.face.back\":[\"Back slope\"],\"node.roof.glazing.face.endLeft\":[\"Left end\"],\"node.roof.glazing.face.endRight\":[\"Right end\"],\"node.roof.glazing.face.front\":[\"Front slope\"],\"node.roof.glazing.face.slope\":[\"Shed slope\"],\"node.roof.glazingControls.alignment\":[\"Alignment\"],\"node.roof.glazingControls.center\":[\"Center\"],\"node.roof.glazingControls.chooseALayoutToEditThe\":[\"Choose a layout to edit the grid.\"],\"node.roof.glazingControls.empty\":[\"Empty\"],\"node.roof.glazingControls.end\":[\"End\"],\"node.roof.glazingControls.fixedSpacing\":[\"Fixed spacing\"],\"node.roof.glazingControls.glass\":[\"Glass\"],\"node.roof.glazingControls.layout\":[\"Layout\"],\"node.roof.glazingControls.maxSpacing\":[\"Max spacing\"],\"node.roof.glazingControls.maximumSpacing\":[\"Maximum spacing\"],\"node.roof.glazingControls.mixed\":[\"Mixed\"],\"node.roof.glazingControls.panelCount\":[\"Panel count\"],\"node.roof.glazingControls.panels\":[\"Panels\"],\"node.roof.glazingControls.solid\":[\"Solid\"],\"node.roof.glazingControls.spacing\":[\"Spacing\"],\"node.roof.glazingControls.start\":[\"Start\"],\"node.roof.glazingControls.titleAlignment\":[[\"title\"],\" alignment\"],\"node.roof.glazingPanel.changesApplyToAllLengthRoof\":[\"Changes apply to all \",[\"length\"],\" roof segments.\"],\"node.roof.glazingPanel.chooseOneRoofSystemToEdit\":[\"Choose one roof system to edit settings for all selected segments.\"],\"node.roof.glazingPanel.closeTheRoofEnds\":[\"Close the roof ends\"],\"node.roof.glazingPanel.defaultPanelInfill\":[\"Default panel infill\"],\"node.roof.glazingPanel.dividesEachRoofFaceIntoColumns\":[\"Divides each roof face into columns.\"],\"node.roof.glazingPanel.dividesTheLengthOfEachArch\":[\"Divides the length of each arch bay into columns.\"],\"node.roof.glazingPanel.endInfillFillsTheSpaceAbove\":[\"End infill fills the space above the walls. Edit room walls and ceilings separately.\"],\"node.roof.glazingPanel.frameColor\":[\"Frame color\"],\"node.roof.glazingPanel.frameDepth\":[\"Frame depth\"],\"node.roof.glazingPanel.frameWidth\":[\"Frame width\"],\"node.roof.glazingPanel.framing\":[\"Framing\"],\"node.roof.glazingPanel.glass\":[\"Glass\"],\"node.roof.glazingPanel.glassTint\":[\"Glass tint\"],\"node.roof.glazingPanel.glazed\":[\"Glazed\"],\"node.roof.glazingPanel.glazingIsAvailableForGableStraight\":[\"Glazing is available for gable, straight shed, and barrel roofs.\"],\"node.roof.glazingPanel.gridAcrossTheRoof\":[\"Grid across the roof\"],\"node.roof.glazingPanel.gridAlongTheLength\":[\"Grid along the length\"],\"node.roof.glazingPanel.gridAlongTheSlope\":[\"Grid along the slope\"],\"node.roof.glazingPanel.gridWithinEachArchBay\":[\"Grid within each arch bay\"],\"node.roof.glazingPanel.infill\":[\"Infill\"],\"node.roof.glazingPanel.opacity\":[\"Opacity\"],\"node.roof.glazingPanel.paneThickness\":[\"Pane thickness\"],\"node.roof.glazingPanel.roofSystem\":[\"Roof system\"],\"node.roof.glazingPanel.roughness\":[\"Roughness\"],\"node.roof.glazingPanel.spacingIsMeasuredOnTheSlope\":[\"Spacing is measured on the slope, not its horizontal projection.\"],\"node.roof.glazingPanel.standard\":[\"Standard\"],\"node.roof.glazingPanel.subdividesEachFlatArchBayArch\":[\"Subdivides each flat arch bay. Arch bays controls the divisions around the curve.\"],\"node.roof.glazingPanelEditor.chooseAPanelToOverrideIts\":[\"Choose a panel to override its default infill.\"],\"node.roof.glazingPanelEditor.column2\":[\"Column\"],\"node.roof.glazingPanelEditor.custom\":[\"Custom\"],\"node.roof.glazingPanelEditor.default\":[\"Default\"],\"node.roof.glazingPanelEditor.grid\":[[\"columns\",\"plural\",{\"one\":[[\"columnCount\"],\" column\"],\"other\":[[\"columnCount\"],\" columns\"]}],\" · \",[\"rows\",\"plural\",{\"one\":[[\"rowCount\"],\" row\"],\"other\":[[\"rowCount\"],\" rows\"]}]],\"node.roof.glazingPanelEditor.individualPanels\":[\"Individual panels\"],\"node.roof.glazingPanelEditor.panelInfill\":[\"Panel infill\"],\"node.roof.glazingPanelEditor.resetToDefault\":[\"Reset to default\"],\"node.roof.glazingPanelEditor.roofFace\":[\"Roof face\"],\"node.roof.glazingPanelEditor.row2\":[\"Row\"],\"node.roof.glazingPanelEditor.selectedPanelInfill\":[\"Selected panel infill\"],\"node.roof.label\":[\"Roof\"],\"node.roof.panel.actions\":[\"Actions\"],\"node.roof.panel.addChimney\":[\"Add Chimney\"],\"node.roof.panel.addCupola\":[\"Add Cupola\"],\"node.roof.panel.addDormer\":[\"Add Dormer\"],\"node.roof.panel.addEyebrowVent\":[\"Add Eyebrow Vent\"],\"node.roof.panel.addGutter\":[\"Add Gutter\"],\"node.roof.panel.addSkylight\":[\"Add Skylight\"],\"node.roof.panel.addSolarPanel\":[\"Add Solar Panel\"],\"node.roof.panel.addVent\":[\"Add Vent\"],\"node.roof.panel.box\":[\"Box\"],\"node.roof.panel.boxVent\":[\"box vent\"],\"node.roof.panel.chimney\":[\"chimney\"],\"node.roof.panel.custom\":[\"Custom\"],\"node.roof.panel.delete\":[\"Delete\"],\"node.roof.panel.dormer\":[\"dormer\"],\"node.roof.panel.drawSegment\":[\"Draw Segment\"],\"node.roof.panel.duplicate\":[\"Duplicate\"],\"node.roof.panel.eaveOverhang\":[\"Eave overhang\"],\"node.roof.panel.eaves\":[\"Eaves\"],\"node.roof.panel.elements\":[\"Elements\"],\"node.roof.panel.followsWalls\":[\"Follows walls\"],\"node.roof.panel.gableOverhang\":[\"Gable overhang\"],\"node.roof.panel.gutter\":[\"gutter\"],\"node.roof.panel.level\":[\"Level\"],\"node.roof.panel.move\":[\"Move\"],\"node.roof.panel.moveToLevel\":[\"Move to \",[\"level\"]],\"node.roof.panel.moveToTheRoofLevel\":[\"Move to the roof level\"],\"node.roof.panel.onStoreyWalls\":[\"On \",[\"storey\"],\" with its walls, so it hides that floor's plan in solo and exploded views.\",[\"roofs\",\"plural\",{\"0\":[],\"1\":[],\"other\":[\" The floor's \",[\"roofCount\"],\" roofs move together.\"]}]],\"node.roof.panel.position\":[\"Position\"],\"node.roof.panel.ridge\":[\"Ridge\"],\"node.roof.panel.ridgeVent\":[\"ridge vent\"],\"node.roof.panel.roof\":[\"Roof\"],\"node.roof.panel.rotation\":[\"Rotation\"],\"node.roof.panel.segmentType\":[[\"roofType\",\"select\",{\"hip\":[\"Hip\"],\"gable\":[\"Gable\"],\"shed\":[\"Shed\"],\"gambrel\":[\"Gambrel\"],\"dutch\":[\"Dutch\"],\"mansard\":[\"Mansard\"],\"flat\":[\"Flat\"],\"conical\":[\"Conical\"],\"barrel\":[\"Barrel\"],\"other\":[\"Roof\"]}]],\"node.roof.panel.segments\":[\"Segments\"],\"node.roof.panel.skylight\":[\"skylight\"],\"node.roof.panel.solarPanel\":[\"solar panel\"],\"node.roof.panel.turbine\":[\"Turbine\"],\"node.roof.panel.turbineVent\":[\"turbine vent\"],\"node.roofSegment.buildUpSection.applyToAllPlanesOfThis\":[\"Apply to all planes of this roof\"],\"node.roofSegment.buildUpSection.architecturalShingle\":[\"Architectural shingle\"],\"node.roofSegment.buildUpSection.asphalt3Tab\":[\"Asphalt 3-tab\"],\"node.roofSegment.buildUpSection.clayTile\":[\"Clay tile\"],\"node.roofSegment.buildUpSection.concreteTile\":[\"Concrete tile\"],\"node.roofSegment.buildUpSection.covering\":[\"Covering\"],\"node.roofSegment.buildUpSection.deck\":[\"Deck\"],\"node.roofSegment.buildUpSection.editLayers\":[\"Edit layers\"],\"node.roofSegment.buildUpSection.finishName\":[\"Finish name\"],\"node.roofSegment.buildUpSection.iceAndWaterShield\":[\"Ice and water shield\"],\"node.roofSegment.buildUpSection.insulationName\":[\"Insulation name\"],\"node.roofSegment.buildUpSection.interiorFinish\":[\"Interior finish\"],\"node.roofSegment.buildUpSection.layers\":[\"Layers\"],\"node.roofSegment.buildUpSection.n15Felt\":[\"#15 felt\"],\"node.roofSegment.buildUpSection.n30Felt\":[\"#30 felt\"],\"node.roofSegment.buildUpSection.none\":[\"None\"],\"node.roofSegment.buildUpSection.preset\":[\"Preset\"],\"node.roofSegment.buildUpSection.rafters\":[\"Rafters\"],\"node.roofSegment.buildUpSection.roofing\":[\"Roofing\"],\"node.roofSegment.buildUpSection.roofingName\":[\"Roofing name\"],\"node.roofSegment.buildUpSection.sheathing\":[\"Sheathing\"],\"node.roofSegment.buildUpSection.sheathingName\":[\"Sheathing name\"],\"node.roofSegment.buildUpSection.slate\":[\"Slate\"],\"node.roofSegment.buildUpSection.standingSeamMetal\":[\"Standing-seam metal\"],\"node.roofSegment.buildUpSection.synthetic\":[\"Synthetic\"],\"node.roofSegment.buildUpSection.topChord\":[\"Top chord\"],\"node.roofSegment.buildUpSection.trusses\":[\"Trusses\"],\"node.roofSegment.buildUpSection.underlayment\":[\"Underlayment\"],\"node.roofSegment.buildUpSection.underlaymentName\":[\"Underlayment name\"],\"node.roofSegment.buildUpSection.woodShake\":[\"Wood shake\"],\"node.roofSegment.description\":[\"A single pitched plane of a parent roof.\"],\"node.roofSegment.label\":[\"Roof Segment\"],\"node.roofSegment.panel.actions\":[\"Actions\"],\"node.roofSegment.panel.angle\":[\"Angle\"],\"node.roofSegment.panel.arc\":[\"Arc\"],\"node.roofSegment.panel.autoGutters\":[\"Auto gutters\"],\"node.roofSegment.panel.autoRidgeVent\":[\"Auto ridge vent\"],\"node.roofSegment.panel.barrel\":[\"Barrel\"],\"node.roofSegment.panel.clippedVersion\":[\"Clipped version\"],\"node.roofSegment.panel.conical\":[\"Conical\"],\"node.roofSegment.panel.conicalShape\":[\"Conical Shape\"],\"node.roofSegment.panel.deckThick\":[\"Deck Thick.\"],\"node.roofSegment.panel.delete\":[\"Delete\"],\"node.roofSegment.panel.depth\":[\"Depth\"],\"node.roofSegment.panel.diameter\":[\"Diameter\"],\"node.roofSegment.panel.doneEditing\":[\"Done editing\"],\"node.roofSegment.panel.drainage\":[\"Drainage\"],\"node.roofSegment.panel.duplicate\":[\"Duplicate\"],\"node.roofSegment.panel.dutch\":[\"Dutch\"],\"node.roofSegment.panel.eaveCut\":[\"Eave cut\"],\"node.roofSegment.panel.eaveOverhang\":[\"Eave overhang\"],\"node.roofSegment.panel.editFootprint\":[\"Edit footprint\"],\"node.roofSegment.panel.endOverhang\":[\"End overhang\"],\"node.roofSegment.panel.fascia\":[\"Fascia\"],\"node.roofSegment.panel.fasciaHeight\":[\"Fascia height\"],\"node.roofSegment.panel.flat\":[\"Flat\"],\"node.roofSegment.panel.footprint\":[\"Footprint\"],\"node.roofSegment.panel.gable\":[\"Gable\"],\"node.roofSegment.panel.gableOverhang\":[\"Gable overhang\"],\"node.roofSegment.panel.gambrel\":[\"Gambrel\"],\"node.roofSegment.panel.hip\":[\"Hip\"],\"node.roofSegment.panel.kinkDepth\":[\"Kink Depth\"],\"node.roofSegment.panel.kinkHeight\":[\"Kink Height\"],\"node.roofSegment.panel.length\":[\"Length\"],\"node.roofSegment.panel.mansard\":[\"Mansard\"],\"node.roofSegment.panel.move\":[\"Move\"],\"node.roofSegment.panel.pitch\":[\"Pitch\"],\"node.roofSegment.panel.plumb\":[\"Plumb\"],\"node.roofSegment.panel.plumbLevel\":[\"Plumb + level\"],\"node.roofSegment.panel.position\":[\"Position\"],\"node.roofSegment.panel.reset\":[\"Reset\"],\"node.roofSegment.panel.roofSegment\":[\"Roof Segment\"],\"node.roofSegment.panel.roofType\":[\"Roof Type\"],\"node.roofSegment.panel.rotation\":[\"Rotation\"],\"node.roofSegment.panel.shape\":[\"Shape\"],\"node.roofSegment.panel.shed\":[\"Shed\"],\"node.roofSegment.panel.shingleThick\":[\"Shingle Thick.\"],\"node.roofSegment.panel.span\":[\"Span\"],\"node.roofSegment.panel.square\":[\"Square\"],\"node.roofSegment.panel.startAngle\":[\"Start Angle\"],\"node.roofSegment.panel.structure\":[\"Structure\"],\"node.roofSegment.panel.topRakeLength\":[\"Top Rake Length\"],\"node.roofSegment.panel.topRakeThick\":[\"Top Rake Thick.\"],\"node.roofSegment.panel.trim\":[\"Trim\"],\"node.roofSegment.panel.waistHeight\":[\"Waist Height\"],\"node.roofSegment.panel.waistLength\":[\"Waist Length\"],\"node.roofSegment.panel.waistWidth\":[\"Waist Width\"],\"node.roofSegment.panel.wall\":[\"Wall\"],\"node.roofSegment.panel.wallHeight\":[\"Wall Height\"],\"node.roofSegment.panel.wallThick\":[\"Wall Thick.\"],\"node.roofSegment.panel.width\":[\"Width\"],\"node.scan.description\":[\"A captured session with optional mesh, motion, media, and sensor data.\"],\"node.scan.label\":[\"Capture\"],\"node.segmentNumber\":[\"Segment \",[\"number\"]],\"node.separator.label\":[\"Separator\"],\"node.shared.buildUpControls.batt\":[\"Batt\"],\"node.shared.buildUpControls.blown\":[\"Blown\"],\"node.shared.buildUpControls.drywall\":[\"Drywall\"],\"node.shared.buildUpControls.drywallThickness\":[\"Drywall thickness\"],\"node.shared.buildUpControls.insulation\":[\"Insulation\"],\"node.shared.buildUpControls.insulationThickness\":[\"Insulation thickness\"],\"node.shared.buildUpControls.labelThickness\":[[\"label\"],\" thickness\"],\"node.shared.buildUpControls.none\":[\"None\"],\"node.shared.buildUpControls.osb\":[\"OSB\"],\"node.shared.buildUpControls.plaster\":[\"Plaster\"],\"node.shared.buildUpControls.plywood\":[\"Plywood\"],\"node.shared.buildUpControls.rigidBoard\":[\"Rigid board\"],\"node.shared.buildUpControls.spacing\":[\"Spacing\"],\"node.shared.buildUpControls.spacingOC\":[[\"spacing\"],\" o.c.\"],\"node.shared.buildUpControls.woodPlank\":[\"Wood plank\"],\"node.shared.itemInteractionActions.turnLightOff\":[\"Turn light off\"],\"node.shared.itemInteractionActions.turnLightOn\":[\"Turn light on\"],\"node.shared.openingCasingSection.casing\":[\"Casing\"],\"node.shared.openingCasingSection.width\":[\"Width\"],\"node.shared.runHangerInspector.automaticSupport\":[\"Automatic support\"],\"node.shared.runHangerInspector.hangerOnSegment\":[\"Hanger \",[\"number\"],\" · segment \",[\"segment\"]],\"node.shared.runHangerInspector.individualHangers\":[\"Individual hangers\"],\"node.shared.runHangerInspector.missingSupport\":[\"Missing support\"],\"node.shared.runHangerInspector.noSupportWithinReachMoveThe\":[\"No support within reach. Move the hanger or choose another host.\"],\"node.shared.runHangerInspector.positionLabel\":[\"Hanger \",[\"number\"],\" position in metres\"],\"node.shared.runHangerInspector.positionM\":[\"Position (m)\"],\"node.shared.runHangerInspector.positionsAreMeasuredAlongEachPath\":[\"Positions are measured along each path segment. Changing spacing regenerates the numbered slots.\"],\"node.shared.runHangerInspector.revealSupport\":[\"Reveal support\"],\"node.shared.runHangerInspector.skip\":[\"Skip\"],\"node.shared.runHangerInspector.supportLabel\":[\"Hanger \",[\"number\"],\" support\"],\"node.shared.systemCheckPanel.aboutTheseChecks\":[\"About these checks\"],\"node.shared.systemCheckPanel.allFindings\":[\"All findings\"],\"node.shared.systemCheckPanel.allSystems\":[\"All systems\"],\"node.shared.systemCheckPanel.connections\":[\"Connections\"],\"node.shared.systemCheckPanel.drainage\":[\"Drainage\"],\"node.shared.systemCheckPanel.error\":[\"Error\"],\"node.shared.systemCheckPanel.errors\":[\"Errors\"],\"node.shared.systemCheckPanel.filterSystemChecks\":[\"Filter system checks\"],\"node.shared.systemCheckPanel.hangers\":[\"Hangers\"],\"node.shared.systemCheckPanel.intersections\":[\"Intersections\"],\"node.shared.systemCheckPanel.locate\":[\"Locate \",[\"name\"],\" (\",[\"id\"],\")\"],\"node.shared.systemCheckPanel.missingItem\":[\"Missing item\"],\"node.shared.systemCheckPanel.noFindings\":[\"No findings\"],\"node.shared.systemCheckPanel.noFindingsInThisCategory\":[\"No findings in this category\"],\"node.shared.systemCheckPanel.openEnds\":[\"Open ends\"],\"node.shared.systemCheckPanel.openEndsAndSeparateBranchesMay\":[\"Open ends and separate branches may be intentional. Intersection checks use bounding boxes; inspect openings and clearances.\"],\"node.shared.systemCheckPanel.selectedConnectedSystem\":[\"Selected connected system\"],\"node.shared.systemCheckPanel.selectedRuns\":[\"Selected: \",[\"count\",\"plural\",{\"one\":[[\"number\"],\" run\"],\"other\":[[\"number\"],\" runs\"]}],\" · \",[\"length\"],\" m\"],\"node.shared.systemCheckPanel.separateBranches\":[\"Separate branches\"],\"node.shared.systemCheckPanel.showAllFindings\":[\"Show all findings\"],\"node.shared.systemCheckPanel.systemChecks\":[\"System checks\"],\"node.shared.systemCheckPanel.systemFinding\":[\"System finding\"],\"node.shared.systemCheckPanel.systemFindings\":[\"System findings\"],\"node.shared.systemCheckPanel.warning\":[\"Warning\"],\"node.shared.systemCheckPanel.warnings\":[\"Warnings\"],\"node.shelf.description\":[\"A configurable shelving unit. Items host on each row.\"],\"node.shelf.label\":[\"Shelf\"],\"node.site.description\":[\"The top-level container holding buildings, zones, and the property boundary.\"],\"node.site.label\":[\"Site\"],\"node.site.panel.address\":[\"Address\"],\"node.site.panel.apn\":[\"APN\"],\"node.site.panel.autoMostNorthFacingEdge\":[\"Auto — most north-facing edge\"],\"node.site.panel.contourIntervalSitePlanAnd3d\":[\"Contour interval (site plan and 3D)\"],\"node.site.panel.county\":[\"County\"],\"node.site.panel.eGRs60\":[\"e.g. RS-60\"],\"node.site.panel.eGTampaLdc27156\":[\"e.g. Tampa LDC §27-156\"],\"node.site.panel.every12In\":[\"every 12 in\"],\"node.site.panel.every24In\":[\"every 24 in\"],\"node.site.panel.every6In\":[\"every 6 in\"],\"node.site.panel.findParcel\":[\"Find parcel\"],\"node.site.panel.finding\":[\"Finding…\"],\"node.site.panel.frontStreetEdge\":[\"Front (street) edge\"],\"node.site.panel.lookingUpTheParcel\":[\"Looking up the parcel and the streets around it…\"],\"node.site.panel.lotArea\":[\"Lot area\"],\"node.site.panel.n1200WCassStTampaFl\":[\"1200 W Cass St, Tampa, FL\"],\"node.site.panel.noSurveyedLinesContoursAreDrawn\":[\"No surveyed lines — contours are drawn from the sculpted ground.\"],\"node.site.panel.none\":[\"none\"],\"node.site.panel.northRotation\":[\"North rotation\"],\"node.site.panel.orientation\":[\"Orientation\"],\"node.site.panel.parcel\":[\"Parcel\"],\"node.site.panel.parcelLookupFailed\":[\"Parcel lookup failed.\"],\"node.site.panel.projectLook\":[\"Project look\"],\"node.site.panel.saveCurrentLook\":[\"Save current look\"],\"node.site.panel.saveTheCurrentLightingAndDisplay\":[\"Save the current lighting and display as this project's default. Personal display changes stay in this browser.\"],\"node.site.panel.setbacks\":[\"Setbacks\"],\"node.site.panel.showGround\":[\"Show ground\"],\"node.site.panel.showTheContourLinesIn3d\":[\"Show the contour lines in 3D\"],\"node.site.panel.side\":[\"side\"],\"node.site.panel.site\":[\"Site\"],\"node.site.panel.source\":[\"Source\"],\"node.site.panel.sourceCitation\":[\"Source / citation\"],\"node.site.panel.streetAddress\":[\"Street address\"],\"node.site.panel.survey\":[\"survey\"],\"node.site.panel.surveyedContours\":[[\"count\",\"plural\",{\"one\":[[\"lineCount\"],\" surveyed line\"],\"other\":[[\"lineCount\"],\" surveyed lines\"]}],\" at \",[\"interval\"],\" ft (\",[\"datum\"],\") — \",[\"source\"]],\"node.site.panel.terrain\":[\"Terrain\"],\"node.site.panel.typeAnAddressFirst\":[\"Type an address first.\"],\"node.site.panel.useProjectLook\":[\"Use project look\"],\"node.site.panel.zone\":[\"Zone\"],\"node.site.setback.front\":[\"Front\"],\"node.site.setback.leftOverride\":[\"Left (override)\"],\"node.site.setback.rear\":[\"Rear\"],\"node.site.setback.rightOverride\":[\"Right (override)\"],\"node.site.setback.side\":[\"Side\"],\"node.skylight.description\":[\"Framed glass opening on a roof segment.\"],\"node.skylight.label\":[\"Skylight\"],\"node.skylight.panel.actions\":[\"Actions\"],\"node.skylight.panel.alongX\":[\"Along X\"],\"node.skylight.panel.alongZ\":[\"Along Z\"],\"node.skylight.panel.bottom\":[\"Bottom\"],\"node.skylight.panel.curb\":[\"Curb\"],\"node.skylight.panel.cutoutOffset\":[\"Cutout Offset\"],\"node.skylight.panel.delete\":[\"Delete\"],\"node.skylight.panel.depth\":[\"Depth\"],\"node.skylight.panel.dimensions\":[\"Dimensions\"],\"node.skylight.panel.frame\":[\"Frame\"],\"node.skylight.panel.glassThickness\":[\"Glass Thickness\"],\"node.skylight.panel.height\":[\"Height\"],\"node.skylight.panel.lanternHeight\":[\"Lantern Height\"],\"node.skylight.panel.left\":[\"Left\"],\"node.skylight.panel.motor\":[\"Motor\"],\"node.skylight.panel.motorHousing\":[\"Motor Housing\"],\"node.skylight.panel.no\":[\"No\"],\"node.skylight.panel.noMotor\":[\"No Motor\"],\"node.skylight.panel.open\":[\"Open\"],\"node.skylight.panel.openingAngle\":[\"Opening Angle\"],\"node.skylight.panel.position\":[\"Position\"],\"node.skylight.panel.right\":[\"Right\"],\"node.skylight.panel.rotation\":[\"Rotation\"],\"node.skylight.panel.skylight\":[\"Skylight\"],\"node.skylight.panel.thickness\":[\"Thickness\"],\"node.skylight.panel.top\":[\"Top\"],\"node.skylight.panel.topScale\":[\"Top Scale\"],\"node.skylight.panel.trackWidth\":[\"Track Width\"],\"node.skylight.panel.type\":[\"Type\"],\"node.skylight.panel.width\":[\"Width\"],\"node.skylight.panel.yes\":[\"Yes\"],\"node.skylight.type.flat\":[\"Flat roof skylight\"],\"node.skylight.type.lantern\":[\"Roof lantern\"],\"node.skylight.type.opening\":[\"Opening skylight\"],\"node.skylight.type.sliding\":[\"Sliding skylight\"],\"node.skylight.type.walkOn\":[\"Walk-on rooflight\"],\"node.slab.description\":[\"A polygon-bounded floor surface that hosts items on top.\"],\"node.slab.label\":[\"Slab\"],\"node.slab.panel.addHole\":[\"Add Hole\"],\"node.slab.panel.area\":[\"Area\"],\"node.slab.panel.auto\":[\"Auto\"],\"node.slab.panel.base\":[\"Base\"],\"node.slab.panel.cutHatch\":[\"Cut hatch\"],\"node.slab.panel.cutOpening\":[\"Cut opening\"],\"node.slab.panel.depth\":[\"Depth\"],\"node.slab.panel.done\":[\"Done\"],\"node.slab.panel.elevation\":[\"Elevation\"],\"node.slab.panel.extendsThePerimeterDownToTerrain\":[\"Extends the perimeter down to terrain. The flat surface, base, and thickness stay unchanged.\"],\"node.slab.panel.fixed\":[\"Fixed\"],\"node.slab.panel.floor\":[\"Floor\"],\"node.slab.panel.followsTerrain\":[\"Follows terrain\"],\"node.slab.panel.foundation\":[\"Foundation\"],\"node.slab.panel.holes\":[\"Holes\"],\"node.slab.panel.info\":[\"Info\"],\"node.slab.panel.move\":[\"Move\"],\"node.slab.panel.noHoles\":[\"No holes\"],\"node.slab.panel.rim\":[\"Rim\"],\"node.slab.panel.slab\":[\"Slab\"],\"node.slab.panel.standard2\":[\"Standard (2\\\")\"],\"node.slab.panel.standard5cm\":[\"Standard (5cm)\"],\"node.slab.panel.sunken15cm\":[\"Sunken (15cm)\"],\"node.slab.panel.sunken6\":[\"Sunken (6\\\")\"],\"node.slab.panel.surface\":[\"Surface\"],\"node.slab.panel.thick15cm\":[\"Thick (15cm)\"],\"node.slab.panel.thick6\":[\"Thick (6\\\")\"],\"node.slab.panel.thickness\":[\"Thickness\"],\"node.slab.panel.thin1\":[\"Thin (1\\\")\"],\"node.slab.panel.thin2cm\":[\"Thin (2cm)\"],\"node.solarPanel.description\":[\"Grid of photovoltaic panels mounted on a roof segment.\"],\"node.solarPanel.label\":[\"Solar Panel\"],\"node.solarPanel.panel.actions\":[\"Actions\"],\"node.solarPanel.panel.array\":[\"Array\"],\"node.solarPanel.panel.autoFitToRoof\":[\"Auto-fit to roof\"],\"node.solarPanel.panel.columns\":[\"Columns\"],\"node.solarPanel.panel.customDimensionsDonTMatchAny\":[\"Custom — dimensions don't match any preset\"],\"node.solarPanel.panel.delete\":[\"Delete\"],\"node.solarPanel.panel.flipOrientation\":[\"Flip orientation\"],\"node.solarPanel.panel.flush\":[\"Flush\"],\"node.solarPanel.panel.frameDepth\":[\"Frame depth\"],\"node.solarPanel.panel.frameThickness\":[\"Frame thickness\"],\"node.solarPanel.panel.gapX\":[\"Gap X\"],\"node.solarPanel.panel.gapY\":[\"Gap Y\"],\"node.solarPanel.panel.height\":[\"Height\"],\"node.solarPanel.panel.mounting\":[\"Mounting\"],\"node.solarPanel.panel.panel\":[\"Panel\"],\"node.solarPanel.panel.preset\":[\"Preset\"],\"node.solarPanel.panel.rows\":[\"Rows\"],\"node.solarPanel.panel.setbacksTooLarge\":[\"Setbacks too large to fit a panel.\"],\"node.solarPanel.panel.solarPanel\":[\"Solar Panel\"],\"node.solarPanel.panel.standoff\":[\"Standoff\"],\"node.solarPanel.panel.tiltAngle\":[\"Tilt angle\"],\"node.solarPanel.panel.tilted\":[\"Tilted\"],\"node.solarPanel.panel.width\":[\"Width\"],\"node.solarPanel.preset.compact\":[\"Compact\"],\"node.solarPanel.preset.frameless\":[\"Frameless\"],\"node.solarPanel.preset.residential\":[\"Residential\"],\"node.solarPanel.preset.residentialLarge\":[\"Residential Large\"],\"node.spawn.description\":[\"Player or camera origin within a level. One per level.\"],\"node.spawn.label\":[\"Spawn Point\"],\"node.stair.constructionControls.body\":[\"Body\"],\"node.stair.constructionControls.centerStringer\":[\"Center stringer\"],\"node.stair.constructionControls.closedRisers\":[\"Closed risers\"],\"node.stair.constructionControls.fromStructure\":[\"From structure\"],\"node.stair.constructionControls.inherit\":[\"Inherit\"],\"node.stair.constructionControls.nosing\":[\"Nosing\"],\"node.stair.constructionControls.open\":[\"Open\"],\"node.stair.constructionControls.original\":[\"Original\"],\"node.stair.constructionControls.riserThickness\":[\"Riser thickness\"],\"node.stair.constructionControls.sideStringers\":[\"Side stringers\"],\"node.stair.constructionControls.solid\":[\"Solid\"],\"node.stair.constructionControls.stringerDepth\":[\"Stringer depth\"],\"node.stair.constructionControls.stringerWidth\":[\"Stringer width\"],\"node.stair.constructionControls.treadFinish\":[\"Tread finish\"],\"node.stair.constructionControls.treadThickness\":[\"Tread thickness\"],\"node.stair.constructionControls.waist\":[\"Waist\"],\"node.stair.constructionControls.waistThickness\":[\"Waist thickness\"],\"node.stair.description\":[\"A stair composed of one or more flights with configurable treads, risers, railings.\"],\"node.stair.diagnostic.arrivalMismatch\":[\"The flight chain does not reach the declared destination.\"],\"node.stair.diagnostic.comfortTarget\":[\"Two risers plus going is outside the 0.60–0.65 m design range.\"],\"node.stair.diagnostic.goingTarget\":[\"Going is below the design target.\"],\"node.stair.diagnostic.headroomTarget\":[\"Overhead surfaces leave less than the target headroom.\"],\"node.stair.diagnostic.headroomUnresolved\":[\"Detailed headroom could not be evaluated: check riser counts and the surface query budget.\"],\"node.stair.diagnostic.invalidFlight\":[\"Flight dimensions and integer riser count must be positive.\"],\"node.stair.diagnostic.invalidRise\":[\"The destination must be above the stair base.\"],\"node.stair.diagnostic.landingOverlap\":[\"Landing depth exceeds a full circle at the walking line; the visible landing is limited to one circle.\"],\"node.stair.diagnostic.narrowWinderEnd\":[\"The narrow end of a winder tread is below 0.10 m; check the intended stair use.\"],\"node.stair.diagnostic.nonuniformRisers\":[\"Flight riser heights differ. Use uniform-riser repair only if this is a proposed design.\"],\"node.stair.diagnostic.raisedLanding\":[\"A landing has a stored rise; inspect its transition before repair.\"],\"node.stair.diagnostic.riserTarget\":[\"Riser height exceeds the design target.\"],\"node.stair.label\":[\"Stair\"],\"node.stair.layout.straight\":[\"Straight\"],\"node.stair.layout.turn\":[[\"layout\"],\" turn\"],\"node.stair.panel.actions\":[\"Actions\"],\"node.stair.panel.addFlight\":[\"Add flight\"],\"node.stair.panel.addLanding\":[\"Add landing\"],\"node.stair.panel.applyLabelLayout\":[\"Apply \",[\"label\"],\" layout\"],\"node.stair.panel.autoCutout\":[\"Auto Cutout\"],\"node.stair.panel.balusters\":[\"Balusters\"],\"node.stair.panel.boards\":[\"Boards\"],\"node.stair.panel.both\":[\"Both\"],\"node.stair.panel.cable\":[\"Cable\"],\"node.stair.panel.centerColumn\":[\"Center Column\"],\"node.stair.panel.clockwise\":[\"Clockwise\"],\"node.stair.panel.connectedTo\":[\"Connected to \",[\"surface\"],\". Move the stair to connect to another edge.\"],\"node.stair.panel.connectedToSurface\":[\"Connected to a surface. Move the stair to connect to another edge.\"],\"node.stair.panel.construction\":[\"Construction\"],\"node.stair.panel.counterclockwise\":[\"Counterclockwise\"],\"node.stair.panel.curved\":[\"Curved\"],\"node.stair.panel.customRise\":[\"Custom rise\"],\"node.stair.panel.deck\":[\"Deck\"],\"node.stair.panel.delete\":[\"Delete\"],\"node.stair.panel.designTargets\":[\"Design targets\"],\"node.stair.panel.destination\":[\"Destination\"],\"node.stair.panel.dragNearADeckPatioConcrete\":[\"Drag near a deck, patio, concrete slab, or landing edge to fit the stair.\"],\"node.stair.panel.duplicate\":[\"Duplicate\"],\"node.stair.panel.equalAngle\":[\"Equal angle\"],\"node.stair.panel.equalGoing\":[\"Equal going\"],\"node.stair.panel.fitRisersAndGoing\":[\"Fit risers and going\"],\"node.stair.panel.fitToFloor\":[\"Fit To Floor\"],\"node.stair.panel.fitUniformRisers\":[\"Fit uniform risers\"],\"node.stair.panel.flightMeasurements\":[\"Flight \",[\"number\"],\": \",[\"count\",\"plural\",{\"one\":[[\"riserCount\"],\" riser\"],\"other\":[[\"riserCount\"],\" risers\"]}],\" · R \",[\"riser\"],\" · T \",[\"going\"],\" · \",[\"slope\"]],\"node.stair.panel.floorsCeilingsAndStairsOnly\":[\"Floors, ceilings and stairs only.\"],\"node.stair.panel.followsDeck\":[\"Follows deck\"],\"node.stair.panel.followsLevel\":[\"Follows level\"],\"node.stair.panel.fromLevel\":[\"From Level\"],\"node.stair.panel.geometry\":[\"Geometry\"],\"node.stair.panel.glass\":[\"Glass\"],\"node.stair.panel.headroom\":[\"Headroom:\"],\"node.stair.panel.height\":[\"Height\"],\"node.stair.panel.innerGap\":[\"Inner gap\"],\"node.stair.panel.innerRadius\":[\"Inner Radius\"],\"node.stair.panel.integrated\":[\"Integrated\"],\"node.stair.panel.landing\":[\"Landing\"],\"node.stair.panel.layout\":[\"Layout\"],\"node.stair.panel.left\":[\"Left\"],\"node.stair.panel.leftTurn\":[\"Left turn\"],\"node.stair.panel.measurements\":[\"Measurements\"],\"node.stair.panel.metal\":[\"Metal\"],\"node.stair.panel.move\":[\"Move\"],\"node.stair.panel.movingThisStairKeepsItsCurrent\":[\"Moving this stair keeps its current rise, steps, and run.\"],\"node.stair.panel.noOverheadSurface\":[\"No overhead surface\"],\"node.stair.panel.none\":[\"None\"],\"node.stair.panel.notEvaluated\":[\"Not evaluated\"],\"node.stair.panel.opening\":[\"Opening\"],\"node.stair.panel.openingOffset\":[\"Opening Offset\"],\"node.stair.panel.position\":[\"Position\"],\"node.stair.panel.postRail\":[\"Post & rail\"],\"node.stair.panel.railing\":[\"Railing\"],\"node.stair.panel.right\":[\"Right\"],\"node.stair.panel.rightTurn\":[\"Right turn\"],\"node.stair.panel.rise\":[\"Rise\"],\"node.stair.panel.rotation\":[\"Rotation\"],\"node.stair.panel.segmentType\":[[\"type\",\"select\",{\"landing\":[\"Landing\"],\"other\":[\"Stair\"]}]],\"node.stair.panel.segments\":[\"Segments\"],\"node.stair.panel.sizing\":[\"Sizing\"],\"node.stair.panel.snapToNearbySurfaces\":[\"Snap to nearby surfaces\"],\"node.stair.panel.spiral\":[\"Spiral\"],\"node.stair.panel.staircase\":[\"Staircase\"],\"node.stair.panel.stepSupports\":[\"Step Supports\"],\"node.stair.panel.steps\":[\"Steps\"],\"node.stair.panel.straight\":[\"Straight\"],\"node.stair.panel.style\":[\"Style\"],\"node.stair.panel.surfaceConnection\":[\"Surface connection\"],\"node.stair.panel.sweep\":[\"Sweep\"],\"node.stair.panel.targetGoing\":[\"Target going\"],\"node.stair.panel.targetHeadroom\":[\"Target headroom\"],\"node.stair.panel.targetMaxRiser\":[\"Target max riser\"],\"node.stair.panel.targetMinimumGoing\":[\"Target minimum going\"],\"node.stair.panel.thickness\":[\"Thickness\"],\"node.stair.panel.to\":[\"To\"],\"node.stair.panel.topLanding\":[\"Top Landing\"],\"node.stair.panel.type\":[\"Type\"],\"node.stair.panel.unavailable\":[\"Unavailable\"],\"node.stair.panel.walkingLineOffset\":[\"Walking line offset\"],\"node.stair.panel.width\":[\"Width\"],\"node.stair.panel.winder\":[\"Winder\"],\"node.stair.railingControls.both\":[\"Both\"],\"node.stair.railingControls.bottomExtension\":[\"Bottom sloped extension\"],\"node.stair.railingControls.continuous\":[\"Continuous\"],\"node.stair.railingControls.floor\":[\"Floor\"],\"node.stair.railingControls.handrailDiameter\":[\"Handrail diameter\"],\"node.stair.railingControls.handrailHeight\":[\"Handrail height\"],\"node.stair.railingControls.handrailInset\":[\"Handrail inset\"],\"node.stair.railingControls.left\":[\"Left\"],\"node.stair.railingControls.noReturn\":[\"No return\"],\"node.stair.railingControls.none\":[\"None\"],\"node.stair.railingControls.originalLayout\":[\"Original layout\"],\"node.stair.railingControls.postFacing\":[\"Post-facing\"],\"node.stair.railingControls.returnLength\":[\"Return length\"],\"node.stair.railingControls.right\":[\"Right\"],\"node.stair.railingControls.separateHandrail\":[\"Separate handrail\"],\"node.stair.railingControls.setTheLengthToReachThe\":[\"Set the length to reach the wall or post.\"],\"node.stair.railingControls.topExtension\":[\"Top horizontal extension\"],\"node.stair.railingControls.wallFacing\":[\"Wall-facing\"],\"node.stair.structureControls.aSolidPouredFlightOnA\":[\"A solid poured flight on a footing; risers closed, no stringers.\"],\"node.stair.structureControls.autoAutocount\":[\"Auto (\",[\"autoCount\"],\")\"],\"node.stair.structureControls.autoClosed\":[\"Auto (closed)\"],\"node.stair.structureControls.autoOpen\":[\"Auto (open)\"],\"node.stair.structureControls.autoPressureTreated\":[\"Auto (pressure-treated)\"],\"node.stair.structureControls.autoTreads\":[\"Auto (\",[\"treads\"],\")\"],\"node.stair.structureControls.autoUntreated\":[\"Auto (untreated)\"],\"node.stair.structureControls.closed1x8Boards\":[\"Closed (1x8 boards)\"],\"node.stair.structureControls.concrete\":[\"Concrete\"],\"node.stair.structureControls.countSteelChannels\":[[\"count\",\"plural\",{\"one\":[\"#\",\" steel channel\"],\"other\":[\"#\",\" steel channels\"]}]],\"node.stair.structureControls.countSteelChannelsAtSpacing\":[[\"count\",\"plural\",{\"one\":[\"#\",\" steel channel at \",[\"spacing\"],\" o.c.\"],\"other\":[\"#\",\" steel channels at \",[\"spacing\"],\" o.c.\"]}]],\"node.stair.structureControls.countStringers\":[[\"count\",\"plural\",{\"one\":[\"#\",\" stringer\"],\"other\":[\"#\",\" stringers\"]}]],\"node.stair.structureControls.countStringersAtSpacing\":[[\"count\",\"plural\",{\"one\":[\"#\",\" stringer at \",[\"spacing\"],\" o.c.\"],\"other\":[\"#\",\" stringers at \",[\"spacing\"],\" o.c.\"]}]],\"node.stair.structureControls.cut\":[\"Cut\"],\"node.stair.structureControls.flightLayout\":[\"Flight \",[\"number\"],\": \",[\"layout\"]],\"node.stair.structureControls.housedSides\":[\"Housed sides\"],\"node.stair.structureControls.inchesInOC\":[[\"inches\"],\" in o.c.\"],\"node.stair.structureControls.layoutAuto\":[[\"layout\"],\" (auto)\"],\"node.stair.structureControls.lumber\":[\"Lumber\"],\"node.stair.structureControls.maxSpacing\":[\"Max spacing\"],\"node.stair.structureControls.nosing\":[\"Nosing\"],\"node.stair.structureControls.oneStock\":[\"One \",[\"stock\"]],\"node.stair.structureControls.open\":[\"Open\"],\"node.stair.structureControls.originalBody\":[\"Original body\"],\"node.stair.structureControls.plywoodFinish\":[\"Plywood + finish\"],\"node.stair.structureControls.pressureTreated\":[\"Pressure-treated\"],\"node.stair.structureControls.risers\":[\"Risers\"],\"node.stair.structureControls.steelStringers\":[\"Steel stringers\"],\"node.stair.structureControls.stringerCount\":[\"Stringer count\"],\"node.stair.structureControls.stringerType\":[\"Stringer type\"],\"node.stair.structureControls.stringers\":[\"Stringers\"],\"node.stair.structureControls.structure\":[\"Structure\"],\"node.stair.structureControls.treads\":[\"Treads\"],\"node.stair.structureControls.twoStock\":[\"Two \",[\"stock\"]],\"node.stair.structureControls.untreated\":[\"Untreated\"],\"node.stair.structureControls.woodStringers\":[\"Wood stringers\"],\"node.stairSegment.description\":[\"A single flight of a parent stair.\"],\"node.stairSegment.label\":[\"Stair Segment\"],\"node.stairSegment.panel.actions\":[\"Actions\"],\"node.stairSegment.panel.attachment\":[\"Attachment\"],\"node.stairSegment.panel.delete\":[\"Delete\"],\"node.stairSegment.panel.dimensions\":[\"Dimensions\"],\"node.stairSegment.panel.duplicate\":[\"Duplicate\"],\"node.stairSegment.panel.editingSwitchesTheStairToCustom\":[\"Editing switches the stair to Custom rise\"],\"node.stairSegment.panel.equalAngle\":[\"Equal angle\"],\"node.stairSegment.panel.equalGoing\":[\"Equal going\"],\"node.stairSegment.panel.fillToFloor\":[\"Fill to floor\"],\"node.stairSegment.panel.flight\":[\"Flight\"],\"node.stairSegment.panel.flightShape\":[\"Flight shape\"],\"node.stairSegment.panel.front\":[\"Front\"],\"node.stairSegment.panel.height\":[\"Height\"],\"node.stairSegment.panel.innerGap\":[\"Inner gap\"],\"node.stairSegment.panel.landing\":[\"Landing\"],\"node.stairSegment.panel.left\":[\"Left\"],\"node.stairSegment.panel.leftTurn\":[\"Left turn\"],\"node.stairSegment.panel.length\":[\"Length\"],\"node.stairSegment.panel.move\":[\"Move\"],\"node.stairSegment.panel.position\":[\"Position\"],\"node.stairSegment.panel.right\":[\"Right\"],\"node.stairSegment.panel.rightTurn\":[\"Right turn\"],\"node.stairSegment.panel.rotation\":[\"Rotation\"],\"node.stairSegment.panel.stairSegment\":[\"Stair Segment\"],\"node.stairSegment.panel.steps\":[\"Steps\"],\"node.stairSegment.panel.straight\":[\"Straight\"],\"node.stairSegment.panel.structure\":[\"Structure\"],\"node.stairSegment.panel.thickness\":[\"Thickness\"],\"node.stairSegment.panel.type\":[\"Type\"],\"node.stairSegment.panel.walkingLineOffset\":[\"Walking line offset\"],\"node.stairSegment.panel.width\":[\"Width\"],\"node.stairSegment.panel.winder\":[\"Winder\"],\"node.structuralGrid.description\":[\"Persistent construction grid axis with identification bubbles.\"],\"node.structuralGrid.label\":[\"Structural Grid\"],\"node.turbineVent.description\":[\"Wind-driven spinning whirlybird exhaust vent for a roof slope.\"],\"node.turbineVent.label\":[\"Turbine Vent\"],\"node.turbineVent.panel.actions\":[\"Actions\"],\"node.turbineVent.panel.cylinder\":[\"Cylinder\"],\"node.turbineVent.panel.delete\":[\"Delete\"],\"node.turbineVent.panel.diameter\":[\"Diameter\"],\"node.turbineVent.panel.dimensions\":[\"Dimensions\"],\"node.turbineVent.panel.duplicate\":[\"Duplicate\"],\"node.turbineVent.panel.globe\":[\"Globe\"],\"node.turbineVent.panel.height\":[\"Height\"],\"node.turbineVent.panel.motion\":[\"Motion\"],\"node.turbineVent.panel.move\":[\"Move\"],\"node.turbineVent.panel.neckHeight\":[\"Neck Height\"],\"node.turbineVent.panel.pause\":[\"Pause\"],\"node.turbineVent.panel.play\":[\"Play\"],\"node.turbineVent.panel.position\":[\"Position\"],\"node.turbineVent.panel.rotation\":[\"Rotation\"],\"node.turbineVent.panel.spinSpeed\":[\"Spin Speed\"],\"node.turbineVent.panel.style\":[\"Style\"],\"node.turbineVent.panel.turbineVent\":[\"Turbine Vent\"],\"node.turbineVent.panel.vanes\":[\"Vanes\"],\"node.unit.description\":[\"A named group of zones forming one apartment, hotel room or commercial lot.\"],\"node.unit.kind.apartment\":[\"Apartment\"],\"node.unit.kind.commercial\":[\"Commercial\"],\"node.unit.kind.common\":[\"Common\"],\"node.unit.kind.hotelRoom\":[\"Hotel room\"],\"node.unit.label\":[\"Unit\"],\"node.unit.panel.memberRoom\":[\"Room\"],\"node.unit.panel.memberZone\":[\"Zone\"],\"node.unit.panel.noZonesAssigned\":[\"No zones assigned yet.\"],\"node.unit.panel.nonAdjacentLevels\":[\"Members sit on levels that are not adjacent.\"],\"node.unit.panel.removeMember\":[\"Remove \",[\"name\"],\" from unit\"],\"node.unit.panel.removeZone\":[\"Remove zone from unit\"],\"node.unit.unitPanel.actions\":[\"Actions\"],\"node.unit.unitPanel.color\":[\"Color\"],\"node.unit.unitPanel.delete\":[\"Delete\"],\"node.unit.unitPanel.focus\":[\"Focus\"],\"node.unit.unitPanel.grossArea\":[\"Gross area\"],\"node.unit.unitPanel.kind\":[\"Kind\"],\"node.unit.unitPanel.levels\":[\"Levels\"],\"node.unit.unitPanel.members\":[\"Members\"],\"node.unit.unitPanel.name\":[\"Name\"],\"node.unit.unitPanel.noRoomsYetPickThisUnit\":[\"No rooms yet. Pick this unit from a room's panel, or draw zones while it is focused.\"],\"node.unit.unitPanel.report\":[\"Report\"],\"node.unit.unitPanel.unit\":[\"Unit\"],\"node.wall.actions.mergeWalls\":[\"Merge walls\"],\"node.wall.actions.splitWall\":[\"Split wall\"],\"node.wall.actions.theseWallsCannotBeMerged\":[\"These walls cannot be merged.\"],\"node.wall.curtain.cell\":[\"Column \",[\"column\"],\", row \",[\"row\"],\": \",[\"type\",\"select\",{\"glass\":[\"glass\"],\"solid\":[\"solid\"],\"other\":[\"empty\"]}]],\"node.wall.curtain.columnSpacing\":[[\"count\",\"plural\",{\"one\":[[\"number\"],\" column\"],\"other\":[[\"number\"],\" columns\"]}],\" · \",[\"spacing\"],\" grid spacing\"],\"node.wall.curtain.noPanels\":[\"No panels\"],\"node.wall.curtain.rowSpacing\":[[\"count\",\"plural\",{\"one\":[[\"number\"],\" row\"],\"other\":[[\"number\"],\" rows\"]}],\" · \",[\"spacing\"],\" grid spacing\"],\"node.wall.curtainWallPanel.applyTint\":[\"Apply tint\"],\"node.wall.curtainWallPanel.borderOpeningFrame\":[\"Border / opening frame\"],\"node.wall.curtainWallPanel.bottom\":[\"Bottom\"],\"node.wall.curtainWallPanel.bottomRow\":[\"Bottom row\"],\"node.wall.curtainWallPanel.cancelTint\":[\"Cancel tint\"],\"node.wall.curtainWallPanel.center\":[\"Center\"],\"node.wall.curtainWallPanel.chooseACellOrEnterIts\":[\"Choose a cell or enter its column and row. Use arrow keys to move between cells. Columns run from the wall start; rows count upward.\"],\"node.wall.curtainWallPanel.clearHiddenOverrides\":[\"Clear hidden overrides\"],\"node.wall.curtainWallPanel.column\":[\"Column\"],\"node.wall.curtainWallPanel.columnLayout\":[\"Column layout\"],\"node.wall.curtainWallPanel.columnRow\":[\"Column \",[\"column\"],\", row \",[\"row\"]],\"node.wall.curtainWallPanel.construction\":[\"Construction\"],\"node.wall.curtainWallPanel.continuousMullionsAndTransomsAssembledAlong\":[\"Continuous mullions and transoms assembled along the wall.\"],\"node.wall.curtainWallPanel.curtainWallPanelSelection\":[\"Curtain wall panel selection\"],\"node.wall.curtainWallPanel.customInfill\":[\"Custom infill\"],\"node.wall.curtainWallPanel.defaultPanel\":[\"Default panel\"],\"node.wall.curtainWallPanel.editIndividualPanels\":[\"Edit individual panels\"],\"node.wall.curtainWallPanel.effectiveThicknessLimited\":[\"Effective thickness: \",[\"thickness\"],\", limited by frame depth.\"],\"node.wall.curtainWallPanel.empty\":[\"Empty\"],\"node.wall.curtainWallPanel.enablePanelEditing\":[\"Enable panel editing\"],\"node.wall.curtainWallPanel.end\":[\"End\"],\"node.wall.curtainWallPanel.fixedSpacing\":[\"Fixed spacing\"],\"node.wall.curtainWallPanel.followingWallDefaults\":[\"Following wall defaults\"],\"node.wall.curtainWallPanel.frameDimensions\":[\"Frame dimensions\"],\"node.wall.curtainWallPanel.framing\":[\"Framing\"],\"node.wall.curtainWallPanel.fullyCapped\":[\"Fully capped\"],\"node.wall.curtainWallPanel.glass\":[\"Glass\"],\"node.wall.curtainWallPanel.glassAppearance\":[\"Glass appearance\"],\"node.wall.curtainWallPanel.glassAppearanceIsControlledByThe\":[\"Glass appearance is controlled by the paint tool.\"],\"node.wall.curtainWallPanel.glassTint\":[\"Glass tint\"],\"node.wall.curtainWallPanel.glazingGap\":[\"Glazing gap\"],\"node.wall.curtainWallPanel.gridLimitedTo32PanelsPer\":[\"Grid limited to 32 panels per axis. Spacing expands to fit this wall.\"],\"node.wall.curtainWallPanel.hiddenCustomPanelCount\":[[\"length\",\"plural\",{\"one\":[[\"number\"],\" custom panel is outside this grid. It returns if the grid expands.\"],\"other\":[[\"number\"],\" custom panels are outside this grid. They return if the grid expands.\"]}]],\"node.wall.curtainWallPanel.horizontalCaps\":[\"Horizontal caps\"],\"node.wall.curtainWallPanel.horizontalFrameWidth\":[\"Horizontal frame width\"],\"node.wall.curtainWallPanel.layout\":[\"Layout\"],\"node.wall.curtainWallPanel.lowRoughnessIsSmoothHighRoughness\":[\"Low roughness is smooth; high roughness gives a matte surface in rendered shading.\"],\"node.wall.curtainWallPanel.maximumSpacing\":[\"Maximum spacing\"],\"node.wall.curtainWallPanel.moduleJointWidth\":[\"Module joint width\"],\"node.wall.curtainWallPanel.none\":[\"None\"],\"node.wall.curtainWallPanel.opacity\":[\"Opacity\"],\"node.wall.curtainWallPanel.opaqueBand\":[\"Opaque band\"],\"node.wall.curtainWallPanel.opaqueBandsReplaceAFullRow\":[\"Opaque bands replace a full row with solid panels. Apply their finish with the paint tool.\"],\"node.wall.curtainWallPanel.panelCount\":[\"Panel count\"],\"node.wall.curtainWallPanel.panelInfill\":[\"Panel infill\"],\"node.wall.curtainWallPanel.panelThickness\":[\"Panel thickness\"],\"node.wall.curtainWallPanel.panels\":[\"Panels\"],\"node.wall.curtainWallPanel.resetThisPanel\":[\"Reset this panel\"],\"node.wall.curtainWallPanel.row2\":[\"Row\"],\"node.wall.curtainWallPanel.rowLayout\":[\"Row layout\"],\"node.wall.curtainWallPanel.separateFramedModulesWithJointsBetween\":[\"Separate framed modules with joints between units.\"],\"node.wall.curtainWallPanel.solid\":[\"Solid\"],\"node.wall.curtainWallPanel.spacing\":[\"Spacing\"],\"node.wall.curtainWallPanel.start\":[\"Start\"],\"node.wall.curtainWallPanel.stickBuilt\":[\"Stick-built\"],\"node.wall.curtainWallPanel.structuralGlazing\":[\"Structural glazing\"],\"node.wall.curtainWallPanel.surfaceRoughness\":[\"Surface roughness\"],\"node.wall.curtainWallPanel.top\":[\"Top\"],\"node.wall.curtainWallPanel.topRow\":[\"Top row\"],\"node.wall.curtainWallPanel.uncappedMembersSitBehindTheGlazing\":[\"Uncapped members sit behind the glazing.\"],\"node.wall.curtainWallPanel.unitized\":[\"Unitized\"],\"node.wall.curtainWallPanel.useGlassSettingsInstead\":[\"Use glass settings instead\"],\"node.wall.curtainWallPanel.useTheDoorOrWindowTool\":[\"Use the Door or Window tool to add an opening through the wall.\"],\"node.wall.curtainWallPanel.verticalCaps\":[\"Vertical caps\"],\"node.wall.curtainWallPanel.verticalFrameWidth\":[\"Vertical frame width\"],\"node.wall.curtainWallPanel.wallSystem\":[\"Wall system\"],\"node.wall.description\":[\"A straight or curved wall segment. Hosts doors, windows, lean-to extensions, and wall-mounted items.\"],\"node.wall.label\":[\"Wall\"],\"node.wall.panel.actions\":[\"Actions\"],\"node.wall.panel.assembly\":[\"Assembly\"],\"node.wall.panel.auto\":[\"Auto\"],\"node.wall.panel.both\":[\"Both\"],\"node.wall.panel.bottom\":[\"Bottom\"],\"node.wall.panel.brickVeneer\":[\"Brick veneer\"],\"node.wall.panel.chairRail\":[\"Chair rail\"],\"node.wall.panel.cmu\":[\"CMU\"],\"node.wall.panel.colonial\":[\"Colonial\"],\"node.wall.panel.cove\":[\"Cove\"],\"node.wall.panel.craft\":[\"Craft\"],\"node.wall.panel.crownMolding\":[\"Crown molding\"],\"node.wall.panel.curtainWall\":[\"Curtain wall\"],\"node.wall.panel.curve\":[\"Curve\"],\"node.wall.panel.custom\":[\"Custom\"],\"node.wall.panel.customHeight\":[\"Custom height\"],\"node.wall.panel.depth\":[\"Depth\"],\"node.wall.panel.dimensions\":[\"Dimensions\"],\"node.wall.panel.drywall\":[\"Drywall\"],\"node.wall.panel.extendsDownwardToMeetTheTerrain\":[\"Extends downward to meet the terrain. Height and top stay unchanged.\"],\"node.wall.panel.exterior\":[\"Exterior\"],\"node.wall.panel.fiberCement\":[\"Fiber cement\"],\"node.wall.panel.fillToTerrain\":[\"Fill to terrain\"],\"node.wall.panel.flat\":[\"Flat\"],\"node.wall.panel.followsLevel\":[\"Follows level\"],\"node.wall.panel.frameDepth\":[\"Frame depth\"],\"node.wall.panel.framersDefault\":[\"Framer's default\"],\"node.wall.panel.framing\":[\"Framing\"],\"node.wall.panel.gypsum\":[\"Gypsum\"],\"node.wall.panel.height\":[\"Height\"],\"node.wall.panel.hideCode\":[\"Hide code\"],\"node.wall.panel.icf\":[\"ICF\"],\"node.wall.panel.interior\":[\"Interior\"],\"node.wall.panel.lapSiding\":[\"Lap siding\"],\"node.wall.panel.layerThicknessesFollowThe2021Irc\":[\"Layer thicknesses follow the 2021 IRC assembly data. Drafting aid, not engineering — verify with the authority having jurisdiction.\"],\"node.wall.panel.layered\":[\"Layered\"],\"node.wall.panel.length\":[\"Length\"],\"node.wall.panel.loading\":[\"Loading…\"],\"node.wall.panel.modern\":[\"Modern\"],\"node.wall.panel.none\":[\"None\"],\"node.wall.panel.noneSingleLayer\":[\"None (single layer)\"],\"node.wall.panel.offset\":[\"Offset\"],\"node.wall.panel.ogee\":[\"Ogee\"],\"node.wall.panel.osb\":[\"OSB\"],\"node.wall.panel.partitionTheInteriorFinishIsApplied\":[\"Partition: the interior finish is applied to both faces.\"],\"node.wall.panel.picture\":[\"Picture\"],\"node.wall.panel.plaster\":[\"Plaster\"],\"node.wall.panel.plywood\":[\"Plywood\"],\"node.wall.panel.preset\":[\"Preset\"],\"node.wall.panel.railing\":[\"Railing\"],\"node.wall.panel.reference\":[\"Reference\"],\"node.wall.panel.remove\":[\"Remove\"],\"node.wall.panel.round\":[\"Round\"],\"node.wall.panel.scriptedFinish\":[\"Scripted finish\"],\"node.wall.panel.sheathing\":[\"Sheathing\"],\"node.wall.panel.shoe\":[\"Shoe\"],\"node.wall.panel.sideA\":[\"Side A\"],\"node.wall.panel.sideB\":[\"Side B\"],\"node.wall.panel.sideFace\":[\"Side \",[\"face\"]],\"node.wall.panel.skirting\":[\"Skirting\"],\"node.wall.panel.standard\":[\"Standard\"],\"node.wall.panel.steelStuds\":[\"Steel studs\"],\"node.wall.panel.step\":[\"Step\"],\"node.wall.panel.stoneVeneer\":[\"Stone veneer\"],\"node.wall.panel.stucco\":[\"Stucco\"],\"node.wall.panel.studs\":[\"Studs\"],\"node.wall.panel.thickness\":[\"Thickness\"],\"node.wall.panel.thicknessFromAssembly\":[[\"thickness\"],\" · from assembly\"],\"node.wall.panel.thisProject\":[\"This project\"],\"node.wall.panel.top\":[\"Top\"],\"node.wall.panel.totalThickness\":[\"Total thickness\"],\"node.wall.panel.unverifiedPresetnote\":[\"Unverified: \",[\"presetNote\"]],\"node.wall.panel.viewCode\":[\"View code\"],\"node.wall.panel.wall\":[\"Wall\"],\"node.wall.panel.wallType\":[\"Wall type\"],\"node.wall.panel.whichFaceIsOutsideIsUndetermined\":[\"Which face is outside is undetermined (no room detected on either side) — the exterior layers are drawn on side B.\"],\"node.wall.panel.woodStuds\":[\"Wood studs\"],\"node.wall.railingWallPanel.aGuardSOpeningsMustNot\":[\"A guard's openings must not pass a 4 in sphere (IRC R312.1.3).\"],\"node.wall.railingWallPanel.height\":[\"Height\"],\"node.wall.railingWallPanel.infill\":[\"Infill\"],\"node.wall.railingWallPanel.n2x6Cap\":[\"2x6 cap\"],\"node.wall.railingWallPanel.n36In\":[\"36 in\"],\"node.wall.railingWallPanel.n42In\":[\"42 in\"],\"node.wall.railingWallPanel.posts\":[\"Posts\"],\"node.wall.railingWallPanel.railing\":[\"Railing\"],\"node.wall.railingWallPanel.style\":[\"Style\"],\"node.wall.reference.center\":[\"Center\"],\"node.wall.reference.inside\":[\"Inside face\"],\"node.wall.reference.left\":[\"Left\"],\"node.wall.reference.outside\":[\"Outside face\"],\"node.wall.reference.right\":[\"Right\"],\"node.wall.trim.hide\":[[\"trim\",\"select\",{\"skirting\":[\"Hide skirting\"],\"crown\":[\"Hide crown molding\"],\"other\":[\"Hide chair rail\"]}]],\"node.wall.trim.show\":[[\"trim\",\"select\",{\"skirting\":[\"Show skirting\"],\"crown\":[\"Show crown molding\"],\"other\":[\"Show chair rail\"]}]],\"node.window.actions.swapHingeSide\":[\"Swap hinge side\"],\"node.window.description\":[\"A window cut into a wall. Animated open/close for opening windows.\"],\"node.window.label\":[\"Window\"],\"node.window.operation.raise\":[\"Raise\"],\"node.window.operation.slats\":[\"Slats\"],\"node.window.operation.slide\":[\"Slide\"],\"node.window.operation.swing\":[\"Swing\"],\"node.window.operation.tilt\":[\"Tilt\"],\"node.window.panel.actions\":[\"Actions\"],\"node.window.panel.all\":[\"All\"],\"node.window.panel.arch\":[\"Arch\"],\"node.window.panel.archHeight\":[\"Arch Height\"],\"node.window.panel.auto\":[\"Auto\"],\"node.window.panel.autoFollowsTheWall\":[\"Auto follows the wall\"],\"node.window.panel.colWidths\":[\"Col Widths\"],\"node.window.panel.columns\":[\"Columns\"],\"node.window.panel.corner\":[\"Corner\"],\"node.window.panel.cornerPost\":[\"Corner post\"],\"node.window.panel.cornerRadius\":[\"Corner Radius\"],\"node.window.panel.customThePanesMatchNoStyle\":[\"Custom: the panes match no style.\"],\"node.window.panel.delete\":[\"Delete\"],\"node.window.panel.depth\":[\"Depth\"],\"node.window.panel.dimensions\":[\"Dimensions\"],\"node.window.panel.divider\":[\"Divider\"],\"node.window.panel.down\":[\"Down\"],\"node.window.panel.duplicate\":[\"Duplicate\"],\"node.window.panel.enableSill\":[\"Enable Sill\"],\"node.window.panel.flipSide\":[\"Flip Side\"],\"node.window.panel.frame\":[\"Frame\"],\"node.window.panel.frameDepthAuto\":[\"Depth (auto)\"],\"node.window.panel.french\":[\"French\"],\"node.window.panel.fusedGlass\":[\"Fused glass\"],\"node.window.panel.grid\":[\"Grid\"],\"node.window.panel.height\":[\"Height\"],\"node.window.panel.individual\":[\"Individual\"],\"node.window.panel.left\":[\"Left\"],\"node.window.panel.move\":[\"Move\"],\"node.window.panel.opening\":[\"Opening\"],\"node.window.panel.openingShape\":[\"Opening Shape\"],\"node.window.panel.otherSide\":[\"Other side\"],\"node.window.panel.pos\":[\"pos\"],\"node.window.panel.position\":[\"Position\"],\"node.window.panel.rect\":[\"Rect\"],\"node.window.panel.revealRadius\":[\"Reveal Radius\"],\"node.window.panel.right\":[\"Right\"],\"node.window.panel.rounded\":[\"Rounded\"],\"node.window.panel.rowHeights\":[\"Row Heights\"],\"node.window.panel.rows\":[\"Rows\"],\"node.window.panel.sill\":[\"Sill\"],\"node.window.panel.single\":[\"Single\"],\"node.window.panel.sizeIsLimitedToTheWall\":[\"Size is limited to the wall, including clearance for the opening frame.\"],\"node.window.panel.style\":[\"Style\"],\"node.window.panel.thickness\":[\"Thickness\"],\"node.window.panel.thisSide\":[\"This side\"],\"node.window.panel.topShape\":[\"Top Shape\"],\"node.window.panel.type\":[\"Type\"],\"node.window.panel.unwrap\":[\"Unwrap\"],\"node.window.panel.up\":[\"Up\"],\"node.window.panel.width\":[\"Width\"],\"node.window.panel.window\":[\"Window\"],\"node.window.panel.windowType\":[\"Window Type\"],\"node.window.panel.wrapTheCorner\":[\"Wrap the corner\"],\"node.window.panel.wrapsTheCornerWithNamed\":[\"Wraps the corner with \",[\"partner\"]],\"node.window.panel.wrapsTheCornerWithPartner\":[\"Wraps the corner with its partner\"],\"node.window.style.casement\":[\"Casement\"],\"node.window.style.doubleHung\":[\"Double-hung\"],\"node.window.style.grid\":[\"Grid\"],\"node.window.style.horizontalBands\":[\"Horizontal bands\"],\"node.window.style.picture\":[\"Picture\"],\"node.window.style.single\":[\"Single\"],\"node.window.style.sliding\":[\"Sliding\"],\"node.window.style.tallGrid\":[\"Tall grid\"],\"node.window.style.transom\":[\"Transom\"],\"node.window.style.tripleHung\":[\"Triple-hung\"],\"node.window.style.wideGrid\":[\"Wide grid\"],\"node.window.type.awning\":[\"Awning\"],\"node.window.type.bay\":[\"Bay\"],\"node.window.type.bow\":[\"Bow\"],\"node.window.type.casement\":[\"Casement\"],\"node.window.type.doubleHung\":[\"Double Hung\"],\"node.window.type.fixed\":[\"Fixed\"],\"node.window.type.hopper\":[\"Hopper\"],\"node.window.type.louvered\":[\"Louvered\"],\"node.window.type.singleHung\":[\"Single Hung\"],\"node.window.type.sliding\":[\"Sliding\"],\"node.zone.description\":[\"A polygonal site zone (lawn, water, paving) with a TSL gradient material.\"],\"node.zone.label\":[\"Zone\"],\"node.zone.quantitiesPanel.enclosedRoom\":[\"Enclosed room\"],\"node.zone.quantitiesPanel.floorSurface\":[\"Floor surface\"],\"node.zone.quantitiesPanel.footprintOnly\":[\"Footprint only\"],\"node.zone.quantitiesPanel.none\":[\"None\"],\"node.zone.quantitiesPanel.notProven\":[\"Not proven\"],\"node.zone.quantitiesPanel.roomQuantities\":[\"Room quantities\"],\"node.zone.quantitiesPanel.topViewWithZoneEdgeDimensions\":[\"Top view with zone edge dimensions\"],\"node.zone.quantitiesPanel.unit\":[\"Unit\"],\"node.zone.quantitiesPanel.volume\":[\"Volume\"],\"node.zone.quantitiesPanel.wallSurface\":[\"Wall surface\"],\"node.zone.quantitiesPanel.zoneBoundaryUnavailable\":[\"Zone boundary unavailable\"],\"node.zone.quantitiesPanel.zoneQuantities\":[\"Zone quantities\"],\"viewer.camera.orbitLeft\":[\"Orbit left\"],\"viewer.camera.orbitRight\":[\"Orbit right\"],\"viewer.camera.topView\":[\"Top view\"],\"viewer.common.off\":[\"Off\"],\"viewer.common.on\":[\"On\"],\"viewer.display.camera\":[\"Camera\"],\"viewer.display.colored\":[\"Colored\"],\"viewer.display.colors\":[\"Colors\"],\"viewer.display.edges.off\":[\"Off\"],\"viewer.display.edges.offDetail\":[\"No edge lines\"],\"viewer.display.edges.soft\":[\"Soft\"],\"viewer.display.edges.softDetail\":[\"Faint outline of major creases\"],\"viewer.display.edges.strong\":[\"Strong\"],\"viewer.display.edges.strongDetail\":[\"Crisp, opaque edge lines\"],\"viewer.display.edges.title\":[\"Edges\"],\"viewer.display.monochrome\":[\"Monochrome\"],\"viewer.display.orthographic\":[\"Orthographic\"],\"viewer.display.perspective\":[\"Perspective\"],\"viewer.display.render.rendered\":[\"Rendered\"],\"viewer.display.render.renderedDetail\":[\"Full ambient occlusion\"],\"viewer.display.render.solid\":[\"Solid\"],\"viewer.display.render.solidDetail\":[\"Flat and fast — no ambient occlusion\"],\"viewer.display.render.title\":[\"Render\"],\"viewer.display.shadows\":[\"Shadows\"],\"viewer.display.title\":[\"Display settings\"],\"viewer.floorplan.alignNorth\":[\"Align view to north\"],\"viewer.floorplan.empty\":[\"No floor plans are available for this scene.\"],\"viewer.floorplan.fit\":[\"Fit floor plan\"],\"viewer.floorplan.floor\":[\"Floor\"],\"viewer.floorplan.floorPlan\":[\"Floor plan\"],\"viewer.floorplan.viewLabel\":[[\"floor\"],\" 2D view\"],\"viewer.floorplan.zoomIn\":[\"Zoom in\"],\"viewer.floorplan.zoomOut\":[\"Zoom out\"],\"viewer.header.back\":[\"Back\"],\"viewer.header.levels\":[\"Levels\"],\"viewer.header.rooms\":[\"Rooms\"],\"viewer.header.selection\":[\"Selection\"],\"viewer.header.units\":[\"Units\"],\"viewer.header.untitled\":[\"Untitled\"],\"viewer.header.zones\":[\"Zones\"],\"viewer.levels.exploded\":[\"Exploded\"],\"viewer.levels.label\":[\"Levels: \",[\"mode\"]],\"viewer.levels.manual\":[\"Manual\"],\"viewer.levels.solo\":[\"Solo\"],\"viewer.levels.stacked\":[\"Stacked\"],\"viewer.stage.layout\":[\"Viewer layout\"],\"viewer.stage.split\":[\"Split\"],\"viewer.theme.blueprint\":[\"Blueprint\"],\"viewer.theme.mediterranean\":[\"Mediterranean\"],\"viewer.theme.night\":[\"Night\"],\"viewer.theme.overcast\":[\"Overcast\"],\"viewer.theme.paper\":[\"Paper\"],\"viewer.theme.studio\":[\"Studio\"],\"viewer.theme.sunset\":[\"Sunset\"],\"viewer.theme.title\":[\"Scene theme\"],\"viewer.theme.twilight\":[\"Twilight\"],\"viewer.theme.verdant\":[\"Verdant\"],\"viewer.visibility.guides\":[\"Guides\"],\"viewer.visibility.scans\":[\"Scans\"],\"viewer.visibility.title\":[\"Visibility\"],\"viewer.walkthrough.label\":[\"Walkthrough: \",[\"state\"]],\"viewer.walls.cutaway\":[\"Cutaway\"],\"viewer.walls.fullHeight\":[\"Full height\"],\"viewer.walls.label\":[\"Walls: \",[\"mode\"]],\"viewer.walls.low\":[\"Low\"]}")as Messages; \ No newline at end of file diff --git a/packages/editor/src/i18n/locales/es/messages.po b/packages/editor/src/i18n/locales/es/messages.po index ae396c5438..155eefb216 100644 --- a/packages/editor/src/i18n/locales/es/messages.po +++ b/packages/editor/src/i18n/locales/es/messages.po @@ -15,8 +15,8 @@ msgstr "" # Source-Hash: 8ffb1c5066e53a8d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Pascal home" #: apps/editor/components/app-home-link.tsx #, fuzzy @@ -25,8 +25,8 @@ msgstr "Inicio de Pascal" # Source-Hash: 534540df302975a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Gate" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -35,8 +35,8 @@ msgstr "Añadir puerta de valla" # Source-Hash: 8b9110c4e72f2db2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Open Passage" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -45,8 +45,8 @@ msgstr "Añadir paso abierto" # Source-Hash: 9a4d56454dc89966 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add to rooms" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -55,8 +55,8 @@ msgstr "Añadir a las estancias" # Source-Hash: a17210912addc85f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "← All build tools" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -65,8 +65,8 @@ msgstr "← Todas las herramientas de construcción" # Source-Hash: 6b63404967e1d5b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Choose Gate or Open Passage, then click its position on any fence. Find placed gates and openings under their fence in the scene graph." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -75,8 +75,8 @@ msgstr "Elige Puerta de valla o Paso abierto y haz clic en su posición en cualq # Source-Hash: 8fd051e1e1a6c1a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Click a lineset to lay the line beside it." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -85,8 +85,8 @@ msgstr "Haz clic en una línea frigorífica para tender la línea junto a ella." # Source-Hash: 7308869944020839 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Double gate" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -95,8 +95,8 @@ msgstr "Puerta doble" # Source-Hash: 281d63a4b3e2de4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Features & extensions" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -105,8 +105,8 @@ msgstr "Elementos y ampliaciones" # Source-Hash: b18788f1d889c1d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fence features" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -115,8 +115,8 @@ msgstr "Elementos de valla" # Source-Hash: 62803100bd6e7cc2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follow lineset" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -125,8 +125,8 @@ msgstr "Seguir la línea frigorífica" # Source-Hash: 4a479aa23542d766 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gate" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -135,8 +135,8 @@ msgstr "Puerta de valla" # Source-Hash: 54098b5ee574737a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gate style" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -145,8 +145,8 @@ msgstr "Estilo de puerta de valla" # Source-Hash: 8fec7e969045a8e7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Horizontal boards" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -155,8 +155,8 @@ msgstr "Tablas horizontales" # Source-Hash: 09197c4fea516277 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hover a fence to preview. Click to place. Esc cancels. Leave room between openings." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -165,8 +165,8 @@ msgstr "Pasa el cursor por una valla para previsualizar. Haz clic para colocar. # Source-Hash: c390ba248e629b9e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Leaves" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -175,8 +175,8 @@ msgstr "Hojas" # Source-Hash: c34c9b36492c6e21 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Liquid Line" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -185,8 +185,8 @@ msgstr "Línea de líquido" # Source-Hash: c15c1af69ec5c1eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Match fence style" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -195,8 +195,8 @@ msgstr "Igualar el estilo de la valla" # Source-Hash: 95057eef5cd69340 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "MEP" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -205,8 +205,8 @@ msgstr "Instalaciones" # Source-Hash: 50accd740fa2e736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Off" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -215,8 +215,8 @@ msgstr "Desactivado" # Source-Hash: 9cc01faad79c28da # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "On" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -225,8 +225,8 @@ msgstr "Activado" # Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opening" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -235,8 +235,8 @@ msgstr "Abertura" # Source-Hash: 9514d3c022e68808 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opening width (m)" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -245,8 +245,8 @@ msgstr "Ancho de la abertura (m)" # Source-Hash: 6b108fb1d0eb8f9d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Open rails" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -255,8 +255,8 @@ msgstr "Barandas abiertas" # Source-Hash: a5a7af5e5fff1c81 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Outdoor" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -265,8 +265,8 @@ msgstr "Exterior" # Source-Hash: 9295ddc2805b21e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Picket" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -275,8 +275,8 @@ msgstr "Estacas" # Source-Hash: 3a08ede9e51d5395 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Roof type" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -285,8 +285,8 @@ msgstr "Tipo de cubierta" # Source-Hash: 0f9daa442776a317 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rooms already create their floor and ceiling. Use these for platforms and one-off structure." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -295,8 +295,8 @@ msgstr "Las estancias ya crean su suelo y su techo. Usa esto para plataformas y # Source-Hash: fc79fd0c7730de76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Search build tools and kitchen items" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -305,8 +305,8 @@ msgstr "Buscar herramientas de construcción y elementos de cocina" # Source-Hash: dc1901f276edca6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Search tools, fridge, sink…" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -315,8 +315,8 @@ msgstr "Buscar herramientas, nevera, fregadero…" # Source-Hash: 9558db89023d4f05 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Select a curved wall to match its radius and arc." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -325,8 +325,8 @@ msgstr "Selecciona un muro curvo para igualar su radio y su arco." # Source-Hash: d327097d9ac1099f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Single gate" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -335,8 +335,8 @@ msgstr "Puerta simple" # Source-Hash: 99acd5128c51c8a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slab, ceiling, column…" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -345,8 +345,8 @@ msgstr "Forjado, techo, pilar…" # Source-Hash: af6f8885fe0fa4e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Solid privacy" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -355,8 +355,8 @@ msgstr "Privacidad total" # Source-Hash: e2b1a3bb9630b33b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Trace a line alongside an existing lineset (F)." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -365,8 +365,8 @@ msgstr "Trazar una línea junto a una línea frigorífica existente (F)." # Source-Hash: eba3df14a2de0812 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Vertical slats" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -375,8 +375,8 @@ msgstr "Lamas verticales" # Source-Hash: 2ee62be78ba76f53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "All projects" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -385,8 +385,8 @@ msgstr "Todos los proyectos" # Source-Hash: 20226b68d5467072 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Preview" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -395,8 +395,8 @@ msgstr "Vista previa" # Source-Hash: 9f2cbc9214c8f7b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Project name" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -405,8 +405,8 @@ msgstr "Nombre del proyecto" # Source-Hash: 150e143a84240eee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rename project" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -415,8 +415,8 @@ msgstr "Cambiar nombre del proyecto" # Source-Hash: 331e1584943b09b9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Share" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -425,8 +425,8 @@ msgstr "Compartir" # Source-Hash: 4b2f676fb4c9ec63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add {label}" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -435,8 +435,8 @@ msgstr "Añadir {label}" # Source-Hash: 53f98cc505aacbb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add to kitchen" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -445,8 +445,8 @@ msgstr "Añadir a la cocina" # Source-Hash: 923a2e81dcc77852 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Choose an item, then click to place it. Appliances include their cabinetry." #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -455,8 +455,8 @@ msgstr "Elige un elemento y haz clic para colocarlo. Los electrodomésticos incl # Source-Hash: 44156a2c888e8a4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Find in this project · {length}" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -465,8 +465,8 @@ msgstr "Buscar en este proyecto · {length}" # Source-Hash: aeda65db67edac21 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Find {name}" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -475,8 +475,8 @@ msgstr "Buscar {name}" # Source-Hash: c1d847411ba09cd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen · Add" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -485,8 +485,8 @@ msgstr "Cocina · Añadir" # Source-Hash: bb3f4f8d3407c409 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen · In this project" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -495,8 +495,8 @@ msgstr "Cocina · En este proyecto" # Source-Hash: 25ffad31086309f1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen cabinet" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -505,8 +505,8 @@ msgstr "Mueble de cocina" # Source-Hash: a5af7817a7e8947d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No matching kitchen items placed yet." #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -515,8 +515,8 @@ msgstr "Todavía no hay elementos de cocina coincidentes." # Source-Hash: 640155f99c25773b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Select and show in scene" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -525,8 +525,8 @@ msgstr "Seleccionar y mostrar en la escena" # Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Ceiling" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -535,8 +535,8 @@ msgstr "Techo" # Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -545,8 +545,8 @@ msgstr "Pilar" # Source-Hash: 787e10f5db16904e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Door" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -555,8 +555,8 @@ msgstr "Puerta" # Source-Hash: e971d82044e2f48e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duct" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -565,8 +565,8 @@ msgstr "Conducto" # Source-Hash: 457155657704f7cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "DWV Pipe" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -575,8 +575,8 @@ msgstr "Tubería de desagüe" # Source-Hash: ab5cbab7be160a1c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Elevator" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -585,8 +585,8 @@ msgstr "Ascensor" # Source-Hash: 02042fde61b5aa11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fence" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -595,8 +595,8 @@ msgstr "Valla" # Source-Hash: 3bf1c1a8dbb93743 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "HVAC Unit" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -605,8 +605,8 @@ msgstr "Equipo de climatización" # Source-Hash: 1176d2568d093bf1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -615,8 +615,8 @@ msgstr "Cocina" # Source-Hash: 362b03eba9d8234c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Lineset" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -625,8 +625,8 @@ msgstr "Línea frigorífica" # Source-Hash: c34c9b36492c6e21 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Liquid Line" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -635,18 +635,28 @@ msgstr "Línea de líquido" # Source-Hash: 95057eef5cd69340 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "MEP" #: apps/editor/lib/build-palette.ts #, fuzzy msgid "app.lib.buildPalette.mep" msgstr "Instalaciones" +# Source-Hash: 5cc981e79d737694 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post" +#: apps/editor/lib/build-palette.ts +#, fuzzy +msgid "app.lib.buildPalette.post" +msgstr "Poste" + # Source-Hash: 161e5386b939e1bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Register" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -655,8 +665,8 @@ msgstr "Rejilla" # Source-Hash: f5f730969df63d1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Roof" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -665,8 +675,8 @@ msgstr "Cubierta" # Source-Hash: d7145f84f8e0e3fe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shelf" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -675,8 +685,8 @@ msgstr "Estantería" # Source-Hash: 8775bc8dc9593964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slab" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -685,8 +695,8 @@ msgstr "Forjado" # Source-Hash: 95e8af5d2b3ca73d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Spawn point" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -695,8 +705,8 @@ msgstr "Punto de aparición" # Source-Hash: f05bc67c57e4d530 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stairs" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -705,8 +715,8 @@ msgstr "Escalera" # Source-Hash: 96281876ce53ba08 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Terrace" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -715,8 +725,8 @@ msgstr "Terraza" # Source-Hash: d457508edd5bb8cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Terrain" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -725,8 +735,8 @@ msgstr "Terreno" # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -735,8 +745,8 @@ msgstr "Muro" # Source-Hash: aa3c35ed33e181e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -745,8 +755,8 @@ msgstr "Ventana" # Source-Hash: d40c50013043284f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Fitting" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -755,8 +765,8 @@ msgstr "Añadir accesorio" # Source-Hash: 534540df302975a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Gate" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -765,8 +775,8 @@ msgstr "Añadir puerta de valla" # Source-Hash: 8b9110c4e72f2db2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Open Passage" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -775,8 +785,8 @@ msgstr "Añadir paso abierto" # Source-Hash: 7136b5836de6e69f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Trap" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -785,8 +795,8 @@ msgstr "Añadir sifón" # Source-Hash: 8f4b2028ad75465d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Build" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -795,8 +805,8 @@ msgstr "Construir" # Source-Hash: a23831beeb35ad3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Create from" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -805,8 +815,8 @@ msgstr "Crear a partir de" # Source-Hash: 8146c309bd8326f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Draw the roof footprint with two corner clicks." #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -815,8 +825,8 @@ msgstr "Dibuja la planta de la cubierta con dos clics en esquinas." # Source-Hash: e971d82044e2f48e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duct" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -825,8 +835,8 @@ msgstr "Conducto" # Source-Hash: 457155657704f7cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "DWV Pipe" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -835,8 +845,8 @@ msgstr "Tubería de desagüe" # Source-Hash: 281d63a4b3e2de4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Features & extensions" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -845,8 +855,8 @@ msgstr "Elementos y ampliaciones" # Source-Hash: 02042fde61b5aa11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fence" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -855,8 +865,8 @@ msgstr "Valla" # Source-Hash: 62803100bd6e7cc2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follow lineset" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -865,8 +875,8 @@ msgstr "Seguir la línea frigorífica" # Source-Hash: c80972ec078ac551 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gates & openings" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -875,8 +885,8 @@ msgstr "Puertas y aberturas" # Source-Hash: 3720347aa16ee777 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hover a room to preview its boundary, then click to place." #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -885,8 +895,8 @@ msgstr "Pasa el cursor por una estancia para ver su contorno y haz clic para col # Source-Hash: 1176d2568d093bf1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -895,8 +905,8 @@ msgstr "Cocina" # Source-Hash: 95057eef5cd69340 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "MEP" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -905,8 +915,8 @@ msgstr "Instalaciones" # Source-Hash: 2e6d8cda361c648d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Modular Cabinet" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -915,8 +925,8 @@ msgstr "Mueble modular" # Source-Hash: 50accd740fa2e736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Off" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -925,8 +935,8 @@ msgstr "Desactivado" # Source-Hash: 9cc01faad79c28da # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "On" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -935,8 +945,8 @@ msgstr "Activado" # Source-Hash: 3fafdc69e7756f19 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Painting" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -945,8 +955,8 @@ msgstr "Pintura" # Source-Hash: f5f730969df63d1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Roof" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -955,8 +965,8 @@ msgstr "Cubierta" # Source-Hash: 3a08ede9e51d5395 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Roof type" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -965,8 +975,8 @@ msgstr "Tipo de cubierta" # Source-Hash: 0c35bee851cc57a2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {# tool} other {# tools}}" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -975,8 +985,8 @@ msgstr "{count, plural, one {# herramienta} many {# herramientas} other {# herra # Source-Hash: 3241ecabee8221a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Conical" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -985,8 +995,8 @@ msgstr "Cónica" # Source-Hash: b5c56dd8c68de309 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Draw" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -995,8 +1005,8 @@ msgstr "Dibujar" # Source-Hash: 6949d667043bee0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dutch" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1005,8 +1015,8 @@ msgstr "Holandesa" # Source-Hash: 9cab4d4c95f63cdd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flat" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1015,8 +1025,8 @@ msgstr "Plana" # Source-Hash: deaffa095d126dfe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gable" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1025,8 +1035,8 @@ msgstr "Dos aguas" # Source-Hash: 7f53d9ffca39984a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gambrel" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1035,8 +1045,8 @@ msgstr "Holandés de buhardilla" # Source-Hash: 9eda0ea8d447066d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hip" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1045,8 +1055,8 @@ msgstr "Cuatro aguas" # Source-Hash: 7f7bb0e875af3260 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Mansard" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1055,8 +1065,8 @@ msgstr "Mansarda" # Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Room" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1065,8 +1075,8 @@ msgstr "Estancia" # Source-Hash: c8d0df27faa3feaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shed" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1075,8 +1085,8 @@ msgstr "Un agua" # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1085,8 +1095,8 @@ msgstr "Muro" # Source-Hash: 8d17e7556ce142da # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Another session saved first — refresh?" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1095,8 +1105,8 @@ msgstr "Otra sesión guardó primero: ¿actualizar?" # Source-Hash: 8f4b2028ad75465d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Build" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1105,8 +1115,8 @@ msgstr "Construir" # Source-Hash: a2bd204e93e90598 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dismiss" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1115,8 +1125,8 @@ msgstr "Cerrar" # Source-Hash: daebc0755d239c99 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Items" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1125,8 +1135,8 @@ msgstr "Elementos" # Source-Hash: cf2e870fce0f2f51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Paint" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1135,8 +1145,8 @@ msgstr "Pintar" # Source-Hash: 854555777b69a4b1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reload" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1145,8 +1155,8 @@ msgstr "Recargar" # Source-Hash: 8dc78e215a97d9fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scene" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1155,8 +1165,8 @@ msgstr "Escena" # Source-Hash: 83909f82446ee9c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Settings" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1165,8 +1175,8 @@ msgstr "Ajustes" # Source-Hash: ee255fa26d076dcc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Your changes haven't been saved. Reload to pick up the latest version." #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1175,8 +1185,8 @@ msgstr "Tus cambios no se han guardado. Recarga para obtener la versión más re # Source-Hash: 703e1b4b9b715d3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Anyone with the link can view this project. They cannot edit it." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1185,8 +1195,8 @@ msgstr "Cualquier persona con el enlace puede ver este proyecto, pero no editarl # Source-Hash: 07e04484867c17d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Copied" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1195,8 +1205,8 @@ msgstr "Copiado" # Source-Hash: 4f60d1e142affa9c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Copy" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1205,8 +1215,8 @@ msgstr "Copiar" # Source-Hash: 8ff50e1a9962a4db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Could not read the sharing state." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1215,8 +1225,8 @@ msgstr "No se pudo leer el estado de uso compartido." # Source-Hash: 791e281338a51483 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Could not turn off the public link." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1225,8 +1235,8 @@ msgstr "No se pudo desactivar el enlace público." # Source-Hash: 2c5ddecfd652ba63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Could not turn on the public link." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1235,8 +1245,8 @@ msgstr "No se pudo activar el enlace público." # Source-Hash: 15e49d4da8765318 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Embed code" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1245,8 +1255,8 @@ msgstr "Código de inserción" # Source-Hash: d4523c2d303f99b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Embed link" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1255,8 +1265,8 @@ msgstr "Enlace de inserción" # Source-Hash: 252f2cbf5e1609a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide controls" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1265,8 +1275,8 @@ msgstr "Ocultar controles" # Source-Hash: ba77c0610a63bb2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Link" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1275,8 +1285,8 @@ msgstr "Enlace" # Source-Hash: a2560430aaec31d9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Only the 3D view, no header or toolbar." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1285,8 +1295,8 @@ msgstr "Solo la vista 3D, sin encabezado ni barra de herramientas." # Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Open" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1295,8 +1305,8 @@ msgstr "Abrir" # Source-Hash: b34faaa5378056c6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Public link" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1305,38 +1315,78 @@ msgstr "Enlace público" # Source-Hash: 7525e8007fcab09b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Share project" #: apps/editor/components/share-panel.tsx #, fuzzy msgid "app.sharePanel.shareProject" msgstr "Compartir proyecto" +# Source-Hash: c90de8776040735c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Above" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.above" +msgstr "Superiores" + # Source-Hash: 3d3f438d5a49eba7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Automatic dimensions" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.automaticDimensions" msgstr "Cotas automáticas" +# Source-Hash: 1794e014a604344c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Below" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.below" +msgstr "Inferiores" + +# Source-Hash: 69578b7dd7723fa1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Both" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.both" +msgstr "Ambos" + # Source-Hash: 14622745dbf93f4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Camera" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.camera" msgstr "Cámara" +# Source-Hash: a03ae72f209e32db +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceilings" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.ceilings" +msgstr "Techos" + # Source-Hash: e6bce525c47ba3ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Clean plan; dimensions appear with selection" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1345,8 +1395,8 @@ msgstr "Plano limpio; las cotas aparecen al seleccionar" # Source-Hash: 61ce356577cfb04a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Collapse sidebar" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1355,8 +1405,8 @@ msgstr "Contraer barra lateral" # Source-Hash: 2416a48df28d6205 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Crisp, opaque edge lines" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1365,8 +1415,8 @@ msgstr "Aristas nítidas y opacas" # Source-Hash: 4da8b3678ed77b45 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Cutaway" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1375,18 +1425,28 @@ msgstr "Corte" # Source-Hash: 4ca0e0e73229540c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Default" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.default" msgstr "Predeterminado" +# Source-Hash: 12df69f42beb0643 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.dimensions" +msgstr "Dimensiones" + # Source-Hash: a313661ef9dd0a65 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Display" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1395,8 +1455,8 @@ msgstr "Visualización" # Source-Hash: d0db46f206a88e2e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Display settings" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1405,8 +1465,8 @@ msgstr "Ajustes de visualización" # Source-Hash: 0286962ab8e9cfcd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Door/window marks" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1415,18 +1475,28 @@ msgstr "Marcas de puertas y ventanas" # Source-Hash: 027bbc8b7287c06a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Edges" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.edges" msgstr "Aristas" +# Source-Hash: 9bacee5dbd658209 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Editing" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.editing" +msgstr "Edición" + # Source-Hash: d86126c5d16c6238 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Enter VR" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1435,8 +1505,8 @@ msgstr "Entrar en RV" # Source-Hash: eb99fb0b382e58cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Exit VR" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1445,8 +1515,8 @@ msgstr "Salir de RV" # Source-Hash: aeac665749d3101d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Expand sidebar" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1455,8 +1525,8 @@ msgstr "Expandir barra lateral" # Source-Hash: 08c178ee733ff009 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Expert" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1465,28 +1535,18 @@ msgstr "Experto" # Source-Hash: be12f8788f1f0a05 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Exploded" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.exploded" msgstr "Despiece" -# Source-Hash: c6f865a366ef5755 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Face of stud" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.faceOfStud" -msgstr "Cara del montante" - # Source-Hash: 0c583f1d4201293b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Faint outline of major creases" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1495,28 +1555,18 @@ msgstr "Contorno tenue de los pliegues principales" # Source-Hash: 08ecd5878b08139d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Feet & inches" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.feetInches" msgstr "Pies y pulgadas" -# Source-Hash: 43b8017fa821c46c -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finished faces" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.finishedFaces" -msgstr "Caras acabadas" - # Source-Hash: 8827df1cdeb02ed9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flat and fast — no ambient occlusion" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1525,8 +1575,8 @@ msgstr "Plano y rápido: sin oclusión ambiental" # Source-Hash: 060a718cdcff61b3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Floor plan annotations" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1535,8 +1585,8 @@ msgstr "Anotaciones del plano de planta" # Source-Hash: 483171f79dc32ae5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Floor plan mode" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1545,8 +1595,8 @@ msgstr "Modo plano de planta" # Source-Hash: 8bb9e54fc786ca77 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Full ambient occlusion" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1555,8 +1605,8 @@ msgstr "Oclusión ambiental completa" # Source-Hash: 91fd3544d9ce16bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Full documentation and annotation controls" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1565,38 +1615,70 @@ msgstr "Documentación y anotaciones completas" # Source-Hash: 131bac2467f4fdf6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Full height" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.fullHeight" msgstr "Altura completa" -# Source-Hash: c9838bc98cb35125 +# Source-Hash: 91c2dd3678e981b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Full wall thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ghosted for reference" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy -msgid "app.viewerToolbar.fullWallThickness" -msgstr "Espesor total del muro" +msgid "app.viewerToolbar.ghostedForReference" +msgstr "Atenuados como referencia" # Source-Hash: 7e4a0a38f694be6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Grid" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.grid" msgstr "Cuadrícula" +# Source-Hash: 81ef3a25ccb6eaf7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "ID" +#. Short for inside dimension: measured between the inside faces of walls. +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.id" +msgstr "Int." + +# Source-Hash: 09f615a2c6a14a76 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "ID + OD" +#. Inside and outside dimensions together. +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.idOd" +msgstr "Int. + Ext." + +# Source-Hash: 8a7ff5011275abbd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inside" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.inside" +msgstr "Interior" + # Source-Hash: 4bf4a6861d7d633e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Levels: {mode}" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1605,8 +1687,8 @@ msgstr "Plantas: {mode}" # Source-Hash: 803532407fb5962b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Low" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1615,8 +1697,8 @@ msgstr "Bajo" # Source-Hash: 32f9a404c0bdce10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Magnetic snap" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1625,8 +1707,8 @@ msgstr "Ajuste magnético" # Source-Hash: 387082cd5f118bed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Manual" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1635,8 +1717,8 @@ msgstr "Manual" # Source-Hash: 2fb69122dd996c0a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Manual dimensions" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1645,18 +1727,28 @@ msgstr "Cotas manuales" # Source-Hash: c6aa74075f37313a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Measurements" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.measurements" msgstr "Medidas" +# Source-Hash: b2cac1ec253d4394 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Measure walls" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.measureWalls" +msgstr "Medir los muros" + # Source-Hash: 0a39470be3b84536 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Meters" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1665,38 +1757,59 @@ msgstr "Metros" # Source-Hash: 83cce6c521e71d01 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Millimeters" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.millimeters" msgstr "Milímetros" -# Source-Hash: b784527bb90b9c5e +# Source-Hash: 340a0a4e7703227b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "3D measurements" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "2D only" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.n2dOnly" +msgstr "Solo 2D" + +# Source-Hash: ed5416e4329bd789 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "3D only" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy -msgid "app.viewerToolbar.n3dMeasurements" -msgstr "Medidas 3D" +msgid "app.viewerToolbar.n3dOnly" +msgstr "Solo 3D" # Source-Hash: 4ff58913a4492199 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No edge lines" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.noEdgeLines" msgstr "Sin aristas" +# Source-Hash: fdaa3b3faa1844fd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "OD" +#. Short for outside dimension: measured between the outside faces of walls. +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.od" +msgstr "Ext." + # Source-Hash: 50accd740fa2e736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Off" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1705,8 +1818,8 @@ msgstr "Desactivado" # Source-Hash: 9cc01faad79c28da # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "On" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1715,28 +1828,68 @@ msgstr "Activado" # Source-Hash: ed59dd8ce7797a66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Orthographic" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.orthographic" msgstr "Ortográfica" +# Source-Hash: 370413dd021d6ea7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Other levels" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.otherLevels" +msgstr "Otros niveles" + +# Source-Hash: dc4fe6cb415ed882 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outside" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.outside" +msgstr "Exterior" + +# Source-Hash: 4b5cbc83a3533c2a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overall size, outside face to outside face" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.overallSizeOutsideFaceToOutsideFace" +msgstr "Tamaño total, de cara exterior a cara exterior" + # Source-Hash: 316e25993ff72b88 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Perspective" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.perspective" msgstr "Perspectiva" +# Source-Hash: 007a63bd7c1e2b55 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plan" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.plan" +msgstr "Plano" + # Source-Hash: 20226b68d5467072 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Preview" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1745,8 +1898,8 @@ msgstr "Vista previa" # Source-Hash: 34c20b72a42ca618 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Preview mode" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1755,8 +1908,8 @@ msgstr "Modo de vista previa" # Source-Hash: 5e58af99d6d4fa6a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Render" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1765,8 +1918,8 @@ msgstr "Renderizado" # Source-Hash: f363702a10aedaeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rendered" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1775,18 +1928,48 @@ msgstr "Renderizado" # Source-Hash: 4959d5538efc595c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Room labels" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.roomLabels" msgstr "Etiquetas de estancias" +# Source-Hash: 257efab00820fb67 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room sizes, inside face to inside face" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.roomSizesInsideFaceToInsideFace" +msgstr "Tamaño de las habitaciones, de cara interior a cara interior" + +# Source-Hash: 1ed28930a451001d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room sizes inside, overall size outside" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.roomSizesInsideOverallSizeOutside" +msgstr "Tamaño de las habitaciones por dentro, tamaño total por fuera" + +# Source-Hash: 8dc78e215a97d9fc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scene" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.scene" +msgstr "Escena" + # Source-Hash: 82720864e5034398 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scene theme" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1795,28 +1978,38 @@ msgstr "Tema de la escena" # Source-Hash: 4c6bcb30b40047fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shadows" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.shadows" msgstr "Sombras" -# Source-Hash: 59dc62417b44931d +# Source-Hash: e04ae95c14479764 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single wall axis" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shared by 2D and 3D" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.sharedBy2dAnd3d" +msgstr "Compartido por 2D y 3D" + +# Source-Hash: 827e0c6ac9936b69 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy -msgid "app.viewerToolbar.singleWallAxis" -msgstr "Eje único del muro" +msgid "app.viewerToolbar.show" +msgstr "Mostrar" # Source-Hash: d266d83ec490df4e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Soft" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1825,8 +2018,8 @@ msgstr "Suaves" # Source-Hash: ef3e765e692faf4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Solid" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1835,8 +2028,8 @@ msgstr "Sólido" # Source-Hash: e9f59b513f2f45ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Solo" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1845,8 +2038,8 @@ msgstr "Aislado" # Source-Hash: 481b7608ce12139b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stack" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1855,8 +2048,8 @@ msgstr "Apilado" # Source-Hash: 61ad94ca68b0458e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stair annotations" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1865,28 +2058,18 @@ msgstr "Anotaciones de escaleras" # Source-Hash: f82927a01d4c5e45 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Strong" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.strong" msgstr "Marcadas" -# Source-Hash: e1be031e67d95382 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structural core face" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.structuralCoreFace" -msgstr "Cara del núcleo estructural" - # Source-Hash: efc50964d7b0ec47 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Structural grids & column centers" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1895,18 +2078,28 @@ msgstr "Ejes estructurales y centros de pilares" # Source-Hash: 5ce4f6b80cd30f86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Translucent" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.translucent" msgstr "Translúcido" +# Source-Hash: 07511ce5a194e1ed +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turn on Dimensions to show them" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.turnOnDimensionsToShowThem" +msgstr "Activa las dimensiones para mostrarlas" + # Source-Hash: b404dded35241274 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Units" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1915,38 +2108,18 @@ msgstr "Unidades" # Source-Hash: faf51e28b748e0d9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Walkthrough" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.walkthrough" msgstr "Recorrido" -# Source-Hash: 62281975e51da7e3 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall centerline" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.wallCenterline" -msgstr "Eje del muro" - -# Source-Hash: ff145d7003118ec6 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall dimensions" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.wallDimensions" -msgstr "Cotas de muros" - # Source-Hash: 13969d1d6e310aa4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Walls: {label}" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1983,8 +2156,8 @@ msgstr "Planta baja" # Source-Hash: fdd8b3366021a1cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Orbit Left" #: packages/editor/src/components/ui/action-menu/camera-actions.tsx #, fuzzy @@ -1993,8 +2166,8 @@ msgstr "Orbitar a la izquierda" # Source-Hash: 4a56359f284a3b17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Orbit Right" #: packages/editor/src/components/ui/action-menu/camera-actions.tsx #, fuzzy @@ -2003,8 +2176,8 @@ msgstr "Orbitar a la derecha" # Source-Hash: f5c12d738240f889 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top View" #: packages/editor/src/components/ui/action-menu/camera-actions.tsx #, fuzzy @@ -2013,8 +2186,8 @@ msgstr "Vista superior" # Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/editor/src/components/ui/action-menu/control-modes.tsx #, fuzzy @@ -2023,8 +2196,8 @@ msgstr "Eliminar" # Source-Hash: a4395168488bb476 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Select" #: packages/editor/src/components/ui/action-menu/control-modes.tsx #, fuzzy @@ -2033,8 +2206,8 @@ msgstr "Seleccionar" # Source-Hash: d9a257653600d5a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Resume following" #: packages/editor/src/components/ui/action-menu/follow-pascal-pill.tsx #, fuzzy @@ -2043,8 +2216,8 @@ msgstr "Reanudar seguimiento" # Source-Hash: 4f073f8051cca3ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follow Pascal: Off" #: packages/editor/src/components/ui/action-menu/follow-pascal-toggle.tsx #, fuzzy @@ -2053,8 +2226,8 @@ msgstr "Seguir a Pascal: desactivado" # Source-Hash: 328ea04bb8cd12f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follow Pascal: On" #: packages/editor/src/components/ui/action-menu/follow-pascal-toggle.tsx #, fuzzy @@ -2063,8 +2236,8 @@ msgstr "Seguir a Pascal: activado" # Source-Hash: 7f4dcb90defe1ac2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Appliance" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2073,8 +2246,8 @@ msgstr "Electrodoméstico" # Source-Hash: 0655333424a8b6fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bathroom" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2083,8 +2256,8 @@ msgstr "Baño" # Source-Hash: ed68e72f5353712b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Furniture" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2093,8 +2266,8 @@ msgstr "Muebles" # Source-Hash: 1176d2568d093bf1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2103,8 +2276,8 @@ msgstr "Cocina" # Source-Hash: a5a7af5e5fff1c81 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Outdoor" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2113,8 +2286,8 @@ msgstr "Exterior" # Source-Hash: c69865ec5d9d1ac9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Angle" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2123,8 +2296,8 @@ msgstr "Ángulo" # Source-Hash: 622f566fe1e3d8e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Angular dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2133,8 +2306,8 @@ msgstr "Cota angular" # Source-Hash: 7e3b0d541355305e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Arc length" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2143,8 +2316,8 @@ msgstr "Longitud de arco" # Source-Hash: 8332ab41e22958f1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Area" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2153,8 +2326,8 @@ msgstr "Área" # Source-Hash: 88c7750ed51d47a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Center mark" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2163,8 +2336,8 @@ msgstr "Marca de centro" # Source-Hash: 634912dabb092872 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Chord dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2173,8 +2346,8 @@ msgstr "Cota de cuerda" # Source-Hash: 3cb090120253f68f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Continuous dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2183,8 +2356,8 @@ msgstr "Cota continua" # Source-Hash: fb91b1d43b8362d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Coordinate dimensions" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2193,8 +2366,8 @@ msgstr "Cotas de coordenadas" # Source-Hash: 530cb7ea461e8298 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Diameter dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2203,8 +2376,8 @@ msgstr "Cota de diámetro" # Source-Hash: fe7ddb094aa8ff4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Distance" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2213,8 +2386,8 @@ msgstr "Distancia" # Source-Hash: fee6203bb9046929 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Floor plan" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2223,8 +2396,8 @@ msgstr "Plano de planta" # Source-Hash: a73539fc472e2e12 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Linear dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2233,8 +2406,8 @@ msgstr "Cota lineal" # Source-Hash: 6bba239f244c3d28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Measurement options" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2243,8 +2416,8 @@ msgstr "Opciones de medida" # Source-Hash: 2cf5ca9b834ce8d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Measurement type" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2253,8 +2426,8 @@ msgstr "Tipo de medida" # Source-Hash: 0431574a0e6d69d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Measure: {selectedLabel}" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2263,8 +2436,8 @@ msgstr "Medir: {selectedLabel}" # Source-Hash: ac87e14dabd5a256 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Perimeter" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2273,8 +2446,8 @@ msgstr "Perímetro" # Source-Hash: 6c9acc0589bdd4d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Radius dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2283,8 +2456,8 @@ msgstr "Cota de radio" # Source-Hash: 01b0015e4e176124 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Smart" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2293,8 +2466,8 @@ msgstr "Inteligente" # Source-Hash: 429bd43d726de417 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Volume" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2303,8 +2476,8 @@ msgstr "Volumen" # Source-Hash: 64f3eb5e1936906d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Point and ask" #: packages/editor/src/components/ui/action-menu/point-ask-button.tsx #, fuzzy @@ -2313,8 +2486,8 @@ msgstr "Señalar y preguntar" # Source-Hash: d86d31e83f6f0888 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Point and ask (C)" #: packages/editor/src/components/ui/action-menu/point-ask-button.tsx #, fuzzy @@ -2323,18 +2496,28 @@ msgstr "Señalar y preguntar (C)" # Source-Hash: 65622d2ef53c1f3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Point and ask works in the 3D view" #: packages/editor/src/components/ui/action-menu/point-ask-button.tsx #, fuzzy msgid "editor.actionMenu.pointAskButton.pointAndAskWorksInThe" msgstr "Señalar y preguntar funciona en la vista 3D" +# Source-Hash: e14858b33b6e2623 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam" +#: packages/editor/src/components/ui/action-menu/structure-tools.tsx +#, fuzzy +msgid "editor.actionMenu.structureTools.beam" +msgstr "Viga" + # Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Ceiling" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2343,8 +2526,8 @@ msgstr "Techo" # Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2353,8 +2536,8 @@ msgstr "Pilar" # Source-Hash: 787e10f5db16904e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Door" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2363,8 +2546,8 @@ msgstr "Puerta" # Source-Hash: e971d82044e2f48e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duct" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2373,8 +2556,8 @@ msgstr "Conducto" # Source-Hash: 6d0c3833d87535e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duct Fitting" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2383,8 +2566,8 @@ msgstr "Accesorio de conducto" # Source-Hash: 457155657704f7cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "DWV Pipe" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2393,8 +2576,8 @@ msgstr "Tubería de desagüe" # Source-Hash: ab5cbab7be160a1c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Elevator" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2403,8 +2586,8 @@ msgstr "Ascensor" # Source-Hash: 02042fde61b5aa11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fence" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2413,8 +2596,8 @@ msgstr "Valla" # Source-Hash: 7f4d93d5f2083844 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gable Roof" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2423,8 +2606,8 @@ msgstr "Cubierta a dos aguas" # Source-Hash: 3bf1c1a8dbb93743 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "HVAC Unit" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2433,8 +2616,8 @@ msgstr "Equipo de climatización" # Source-Hash: 362b03eba9d8234c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Lineset" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2443,8 +2626,8 @@ msgstr "Línea frigorífica" # Source-Hash: c34c9b36492c6e21 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Liquid Line" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2453,8 +2636,8 @@ msgstr "Línea de líquido" # Source-Hash: c040baa6ed4c7aa5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Pipe Fitting" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2463,8 +2646,8 @@ msgstr "Accesorio de tubería" # Source-Hash: 161e5386b939e1bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Register" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2473,8 +2656,8 @@ msgstr "Rejilla" # Source-Hash: d7145f84f8e0e3fe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shelf" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2483,8 +2666,8 @@ msgstr "Estantería" # Source-Hash: 8775bc8dc9593964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slab" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2493,8 +2676,8 @@ msgstr "Forjado" # Source-Hash: 3e2f6b4274f592c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Spawn Point" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2503,8 +2686,8 @@ msgstr "Punto de aparición" # Source-Hash: f05bc67c57e4d530 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stairs" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2513,8 +2696,8 @@ msgstr "Escalera" # Source-Hash: b778a315e82065a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Trap" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2523,8 +2706,8 @@ msgstr "Sifón" # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2533,8 +2716,8 @@ msgstr "Muro" # Source-Hash: aa3c35ed33e181e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2543,18 +2726,28 @@ msgstr "Ventana" # Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy msgid "editor.actionMenu.structureTools.zone" msgstr "Zona" +# Source-Hash: a309ae5ee641f072 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dashed outlines of the neighbouring levels’ walls, to line walls up and check a roof against the walls under it." +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.dashedOutlinesOfTheNeighbouringLevels" +msgstr "Contornos discontinuos de los muros de las plantas contiguas, para alinear muros y comprobar una cubierta respecto a los muros que tiene debajo." + # Source-Hash: cdf3f12939ba108c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete guide image" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2563,8 +2756,8 @@ msgstr "Eliminar imagen guía" # Source-Hash: 6add06abbafa8289 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete scan" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2573,8 +2766,8 @@ msgstr "Eliminar escaneo 3D" # Source-Hash: 6f5e541cb5fb502f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {# guide image on this level} other {# guide images on this level}}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2583,8 +2776,8 @@ msgstr "{count, plural, one {# imagen guía en esta planta} many {# imágenes gu # Source-Hash: 8a832a2f33757bf8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guide image {number}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2593,8 +2786,8 @@ msgstr "Imagen guía {number}" # Source-Hash: 7f3aaccfe8d1af1f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guide images" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2603,8 +2796,8 @@ msgstr "Imágenes guía" # Source-Hash: 9b1de02505434d74 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guide image settings" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2613,8 +2806,8 @@ msgstr "Ajustes de imágenes guía" # Source-Hash: 892d5dd34372028b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guides" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2623,8 +2816,8 @@ msgstr "Guías" # Source-Hash: ccfb05c78d47d6f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guides: Hidden" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2633,8 +2826,8 @@ msgstr "Guías: ocultas" # Source-Hash: 6d7ca85c4f389991 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guides: Visible" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2643,8 +2836,8 @@ msgstr "Guías: visibles" # Source-Hash: 5f6264ac469f57c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide guide images" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2653,8 +2846,8 @@ msgstr "Ocultar imágenes guía" # Source-Hash: cae234c23229c80b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide reference floor" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2663,8 +2856,8 @@ msgstr "Ocultar planta de referencia" # Source-Hash: 469a8416de876e0e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide scans" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2673,18 +2866,38 @@ msgstr "Ocultar escaneos 3D" # Source-Hash: 873620c284a5651f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count} below" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy msgid "editor.actionMenu.viewToggles.levelsBelow" msgstr "{count} por debajo" +# Source-Hash: 6661c6766fdd1a7f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No level above" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.noLevelAbove" +msgstr "Sin planta superior" + +# Source-Hash: e34d9ec372c823ef +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No level below" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.noLevelBelow" +msgstr "Sin planta inferior" + # Source-Hash: 22a59ae72d8c9504 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No lower floor available." #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2693,8 +2906,8 @@ msgstr "No hay ninguna planta inferior." # Source-Hash: 1c0b8a5503c5daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opacity" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2703,8 +2916,8 @@ msgstr "Opacidad" # Source-Hash: 8bbd9bc90ac70a4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference floor" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2713,8 +2926,8 @@ msgstr "Planta de referencia" # Source-Hash: 45493691a23c7690 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference floor: {selectedLevelName}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2723,8 +2936,8 @@ msgstr "Planta de referencia: {selectedLevelName}" # Source-Hash: 7178c7b5a4581367 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference floor settings" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2733,8 +2946,8 @@ msgstr "Ajustes de la planta de referencia" # Source-Hash: a52848021f822f5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "References" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2743,8 +2956,8 @@ msgstr "Referencias" # Source-Hash: e59c9eec7dbd6ba1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Upload GLB meshes as scan references or blueprint images as guide references." #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2753,8 +2966,8 @@ msgstr "Sube mallas GLB como escaneos 3D de referencia o imágenes de planos com # Source-Hash: 3e73d06c3e96efba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference settings" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2763,8 +2976,8 @@ msgstr "Ajustes de referencias" # Source-Hash: aa0df2c2f00672e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "References: Hidden" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2773,8 +2986,8 @@ msgstr "Referencias: ocultas" # Source-Hash: 9976708fc92bfa91 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "References: Visible" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2783,8 +2996,8 @@ msgstr "Referencias: visibles" # Source-Hash: 320a5f1ec012900b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Riser diagram" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2793,8 +3006,8 @@ msgstr "Esquema de montantes" # Source-Hash: 357b3d3eaf878a9f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {# scan on this level} other {# scans on this level}}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2803,8 +3016,8 @@ msgstr "{count, plural, one {# escaneo 3D en esta planta} many {# escaneos 3D en # Source-Hash: f09f12547484c888 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scan {number}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2813,8 +3026,8 @@ msgstr "Escaneo 3D {number}" # Source-Hash: 3260bfa69cca50e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scans" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2823,8 +3036,8 @@ msgstr "Escaneos 3D" # Source-Hash: c9c52015095997e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scan settings" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2833,8 +3046,8 @@ msgstr "Ajustes de escaneos 3D" # Source-Hash: 60abc9f1a8aec65c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scans: Hidden" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2843,8 +3056,8 @@ msgstr "Escaneos 3D: ocultos" # Source-Hash: 2d2ff119a7dd7911 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scans: Visible" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2853,8 +3066,8 @@ msgstr "Escaneos 3D: visibles" # Source-Hash: 8211234b205fd9a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Show guide images" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2863,8 +3076,8 @@ msgstr "Mostrar imágenes guía" # Source-Hash: 7786cae6acb04cfa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Show reference floor" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2873,30 +3086,92 @@ msgstr "Mostrar planta de referencia" # Source-Hash: 6066f0b6cff8a910 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Show scans" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy msgid "editor.actionMenu.viewToggles.showScans" msgstr "Mostrar escaneos 3D" +# Source-Hash: c100768fc929ccf4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show walls below and above" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.showWallsBelowAndAbove" +msgstr "Mostrar muros inferiores y superiores" + # Source-Hash: def6dff836767bda # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Upload scan or guide image" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy msgid "editor.actionMenu.viewToggles.uploadScanOrGuideImage" msgstr "Subir escaneo 3D o imagen guía" -# Source-Hash: 6aee0962fc18c0f1 +# Source-Hash: e9ac75feeb58a5be # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back to home" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls above" +#: apps/editor/components/viewer-toolbar.tsx +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsAbove" +msgstr "Muros superiores" + +# Source-Hash: 790a0b5c6dbf0e9b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below" +#: apps/editor/components/viewer-toolbar.tsx +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsBelow" +msgstr "Muros inferiores" + +# Source-Hash: e74e28937511bce9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below and above" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsBelowAndAbove" +msgstr "Muros inferiores y superiores" + +# Source-Hash: 7c7bd2a996dfd5ce +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below and above settings" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsBelowAndAboveSettings" +msgstr "Ajustes de muros inferiores y superiores" + +# Source-Hash: 43bc80f62aeab442 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below and above: shown" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsBelowAndAboveShown" +msgstr "Muros inferiores y superiores: visibles" + +# Source-Hash: 6aee0962fc18c0f1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back to home" +#: packages/editor/src/components/editor/index.tsx #, fuzzy msgid "editor.backToHome" msgstr "Volver al inicio" @@ -2985,12 +3260,45 @@ msgstr "Estancia rectangular" msgid "editor.buildPanel.rooms.title" msgstr "Estancias" -# Source-Hash: 8a21a03c4acf396b -# Review: human -# English: "{lead} Close a loop and it becomes a room; leave it open for partitions." +# Source-Hash: 9755d557ce490458 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divides a room or closes off a porch without building a wall; rooms close on it. Change any wall later from its controls." +#: packages/editor/src/components/ui/build-panel/build-panel.tsx +#, fuzzy +msgid "editor.buildPanel.rooms.wallKinds.invisibleHelp" +msgstr "Divide una habitación o cierra un porche sin construir un muro; las habitaciones se cierran en él. Cambia cualquier muro después desde sus controles." + +# Source-Hash: abe7e7de0d337058 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall kind" +#: packages/editor/src/components/ui/build-panel/build-panel.tsx +#, fuzzy +msgid "editor.buildPanel.rooms.wallKinds.label" +msgstr "Tipo de muro" + +# Source-Hash: b4d012ac50ef1e82 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A guard for stairs, balconies and mezzanines; rooms close on it. Change any wall later from its controls." #: packages/editor/src/components/ui/build-panel/build-panel.tsx -msgid "editor.buildPanel.rooms.walls.caption" -msgstr "{lead} Cierra el contorno para crear una estancia o déjalo abierto para tabiques." +#, fuzzy +msgid "editor.buildPanel.rooms.wallKinds.railingHelp" +msgstr "Una barandilla para escaleras, balcones y altillos; las habitaciones se cierran en ella. Cambia cualquier muro después desde sus controles." + +# Source-Hash: 5e6d896656f4e056 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "One wall per two clicks. Its sides become exterior or interior from the rooms it bounds. Change any wall later from its controls." +#: packages/editor/src/components/ui/build-panel/build-panel.tsx +#, fuzzy +msgid "editor.buildPanel.rooms.wallKinds.standardHelp" +msgstr "Un muro cada dos clics. Sus caras pasan a ser exteriores o interiores según las habitaciones que delimita. Cambia cualquier muro después desde sus controles." # Source-Hash: aac9a732d2159ccc # Review: human @@ -2999,13 +3307,6 @@ msgstr "{lead} Cierra el contorno para crear una estancia o déjalo abierto para msgid "editor.buildPanel.rooms.walls.label" msgstr "Muros" -# Source-Hash: 9843edd68426fa2d -# Review: human -# English: "Draw one wall at a time." -#: packages/editor/src/components/ui/build-panel/build-panel.tsx -msgid "editor.buildPanel.rooms.walls.lead" -msgstr "Dibuja un muro cada vez." - # Source-Hash: aac9a732d2159ccc # Review: human # English: "Walls" @@ -3013,26735 +3314,29167 @@ msgstr "Dibuja un muro cada vez." msgid "editor.buildPanel.rooms.walls.title" msgstr "Muros" -# Source-Hash: 1f3650da23603008 +# Source-Hash: 1dba2aacc55e0bb7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Camera controls hint" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete from this project" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.cameraControlsHint" -msgstr "Ayuda de controles de cámara" +msgid "editor.buildPanel.wallTypeControls.deleteFromThisProject" +msgstr "Eliminar de este proyecto" -# Source-Hash: 101b6a54c377049a +# Source-Hash: 58a1b780e877ddc3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pan" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate as a new type…" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.cameraHint.pan" -msgstr "Desplazar" +msgid "editor.buildPanel.wallTypeControls.duplicateAsANewType" +msgstr "Duplicar como tipo nuevo…" -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: 43e7aad9a5f75b6a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit layers…" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.cameraHint.rotate" -msgstr "Girar" +msgid "editor.buildPanel.wallTypeControls.editLayers" +msgstr "Editar capas…" -# Source-Hash: 663cecc316eb91b8 +# Source-Hash: 8f1ea5a4c16ba810 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zoom" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit or duplicate this wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.cameraHint.zoom" -msgstr "Zoom" +msgid "editor.buildPanel.wallTypeControls.editOrDuplicateThisWallType" +msgstr "Editar o duplicar este tipo de muro" -# Source-Hash: 34b7ca7ff46c44a9 +# Source-Hash: 273fcb71b4f9272f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{label}: {finish}" -#: packages/editor/src/components/ui/controls/finish-swatch.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New wall type…" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.controls.finishSwatch.ariaLabel" -msgstr "{label}: {finish}" +msgid "editor.buildPanel.wallTypeControls.newWallType" +msgstr "Nuevo tipo de muro…" -# Source-Hash: 4ca0e0e73229540c +# Source-Hash: 079e4005e0093122 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default" -#: packages/editor/src/components/ui/controls/finish-swatch.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Presets stay as cited. Duplicate one to change its layers." +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.controls.finishSwatch.default" -msgstr "Predeterminado" +msgid "editor.buildPanel.wallTypeControls.presetsStayAsCitedDuplicateOne" +msgstr "Los preajustes se mantienen tal como se citan. Duplica uno para cambiar sus capas." -# Source-Hash: a2bd204e93e90598 +# Source-Hash: b071c943d8da1500 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dismiss" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.dismiss" -msgstr "Cerrar" +msgid "editor.buildPanel.wallTypeEditorDialog.add" +msgstr "Añadir" -# Source-Hash: 9222f970dce6cc60 +# Source-Hash: fcc69acc0fd92288 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dismiss camera controls hint" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Air space" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.dismissCameraControlsHint" -msgstr "Cerrar la ayuda de controles de cámara" +msgid "editor.buildPanel.wallTypeEditorDialog.airSpace" +msgstr "Cámara de aire" -# Source-Hash: aeac665749d3101d +# Source-Hash: 46fb2832f979d656 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Expand sidebar" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A wall type holds at most {limit, plural, one {# layer} other {# layers}}." +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.expandSidebar" -msgstr "Expandir barra lateral" +msgid "editor.buildPanel.wallTypeEditorDialog.aWallTypeHoldsAtMost" +msgstr "Un tipo de muro admite como máximo {limit, plural, one {# capa} many {# capas} other {# capas}}." -# Source-Hash: dd86efcab72fc5c7 +# Source-Hash: 75d323d0159b0df8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Axis" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brick veneer" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.axis" -msgstr "Eje" +msgid "editor.buildPanel.wallTypeEditorDialog.brickVeneer" +msgstr "Chapado de ladrillo" -# Source-Hash: 5232a826549f915e +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "⌥ axis" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.axis2" -msgstr "⌥ eje" +msgid "editor.buildPanel.wallTypeEditorDialog.cancel" +msgstr "Cancelar" -# Source-Hash: 7001600001844c92 +# Source-Hash: 4da800c75b9a6b23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "⚠ no equipment" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drywall" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.noEquipment" -msgstr "⚠ sin equipo" +msgid "editor.buildPanel.wallTypeEditorDialog.drywall" +msgstr "Placa de yeso" -# Source-Hash: eae0194029f96edb +# Source-Hash: 1f2e15ce909adf0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {# register} other {# registers}}" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.registerCount" -msgstr "{count, plural, one {# rejilla} many {# rejillas} other {# rejillas}}" +msgid "editor.buildPanel.wallTypeEditorDialog.duplicateWallType" +msgstr "Duplicar tipo de muro" -# Source-Hash: 8fb180251a321cef +# Source-Hash: 832628bc67f36778 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.rTRotate" -msgstr "R/T girar" +msgid "editor.buildPanel.wallTypeEditorDialog.editWallType" +msgstr "Editar tipo de muro" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 6fb660d4eabe8d6a +# Source-Hash: 7d3d13d418b64f1b # Review: required -# English: "{count, plural, one {{number} run} other {{number} runs}}" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Every wall type has one framing core" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.runCount" -msgstr "{count, plural, one {{number} tramo} many {{number} tramos} other {{number} tramos}}" +msgid "editor.buildPanel.wallTypeEditorDialog.everyWallTypeHasOneFraming" +msgstr "Cada tipo de muro tiene un núcleo de entramado" -# Source-Hash: 88e6c2e1c344b2fc +# Source-Hash: fd89c31f16639f50 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fiber cement" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.system" -msgstr "Sistema" +msgid "editor.buildPanel.wallTypeEditorDialog.fiberCement" +msgstr "Fibrocemento" -# Source-Hash: f0e76aea883d4e48 +# Source-Hash: b3907da0ad234f10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add a floor under the roof" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.addAFloorUnderTheRoof" -msgstr "Añadir una planta bajo la cubierta" +msgid "editor.buildPanel.wallTypeEditorDialog.finish" +msgstr "Acabado" -# Source-Hash: a982ff9b075af829 +# Source-Hash: 23306d290f066b1e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add level above" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framing core" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.addLevelAbove" -msgstr "Añadir planta encima" +msgid "editor.buildPanel.wallTypeEditorDialog.framingCore" +msgstr "Núcleo de entramado" -# Source-Hash: 0db7d221df08fa6b +# Source-Hash: b50fa488c2bfb502 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add level below" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{fullReason} Remove one to add another." +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.addLevelBelow" -msgstr "Añadir planta debajo" +msgid "editor.buildPanel.wallTypeEditorDialog.fullreasonRemoveOneToAddAnother" +msgstr "{fullReason} Quita una para añadir otra." -# Source-Hash: c0774c185060fc13 +# Source-Hash: e3e25fbbf14e97fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gypsum sheathing" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.cancel" -msgstr "Cancelar" +msgid "editor.buildPanel.wallTypeEditorDialog.gypsumSheathing" +msgstr "Tablero de yeso" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 8a7ff5011275abbd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inside" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.delete" -msgstr "Eliminar" +msgid "editor.buildPanel.wallTypeEditorDialog.inside" +msgstr "Interior" -# Source-Hash: 8e29375893d63408 +# Source-Hash: 7d6ed24c02ab0c5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete level" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.deleteLevel" -msgstr "Eliminar planta" +msgid "editor.buildPanel.wallTypeEditorDialog.insulation" +msgstr "Aislamiento" -# Source-Hash: c3bc69ec52022250 +# Source-Hash: 9a4325140858cfec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Are you sure you want to delete {levelName}? All walls, floors, and objects on this level will be permanently removed." -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lap siding" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.deleteLevelConfirm" -msgstr "¿Seguro que quieres eliminar {levelName}? Todos los muros, forjados y objetos de esta planta se eliminarán de forma permanente." +msgid "editor.buildPanel.wallTypeEditorDialog.lapSiding" +msgstr "Revestimiento solapado" -# Source-Hash: 5b2826ddac95cd0c +# Source-Hash: d7ee1cefa20d0e32 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag to reorder" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layer" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.dragToReorder" -msgstr "Arrastra para reordenar" +msgid "editor.buildPanel.wallTypeEditorDialog.layer" +msgstr "Capa" -# Source-Hash: 933177338f5a03ed +# Source-Hash: bd00fff893ace820 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate level" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layer role" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.duplicateLevel" -msgstr "Duplicar planta" +msgid "editor.buildPanel.wallTypeEditorDialog.layerRole" +msgstr "Función de la capa" -# Source-Hash: 9614c6825a7c67bf +# Source-Hash: e5536deeaabfacec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate with options..." -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lining" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.duplicateWithOptions" -msgstr "Duplicar con opciones..." +msgid "editor.buildPanel.wallTypeEditorDialog.lining" +msgstr "Trasdosado" -# Source-Hash: 5ec91bb339806413 +# Source-Hash: 964b86ae1474ff98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Exit unit focus" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Material" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.exitUnitFocus" -msgstr "Salir del enfoque de unidad" +msgid "editor.buildPanel.wallTypeEditorDialog.material" +msgstr "Material" -# Source-Hash: a88c3f8bed58b4fa +# Source-Hash: 75d79fb9a2e8fcf6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Focused unit has zones here" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mineral wool board" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.focusedUnitHasZonesHere" -msgstr "La unidad enfocada tiene zonas aquí" +msgid "editor.buildPanel.wallTypeEditorDialog.mineralWoolBoard" +msgstr "Panel de lana mineral" -# Source-Hash: 655055a310fb5d13 +# Source-Hash: 78acc1bad880ce0f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The ground floor stands {distance} over grade. Seat the ground floor 8 in over grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move in" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.groundFloorOverGrade" -msgstr "La planta baja está {distance} por encima de la rasante. Asentar la planta baja 8 in sobre la rasante" +msgid "editor.buildPanel.wallTypeEditorDialog.moveIn" +msgstr "Mover hacia dentro" -# Source-Hash: 77548faae4869eec +# Source-Hash: 2de6ee30b4e608bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The ground floor stands {distance} under grade. Seat the ground floor 8 in over grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move out" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.groundFloorUnderGrade" -msgstr "La planta baja está {distance} por debajo de la rasante. Asentar la planta baja 8 in sobre la rasante" +msgid "editor.buildPanel.wallTypeEditorDialog.moveOut" +msgstr "Mover hacia fuera" -# Source-Hash: e3763ae2dc62c03f +# Source-Hash: 6cc5df35f0338e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground line: the levels under it are below grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Name" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.groundLineTheLevelsUnderIt" -msgstr "Línea de rasante: las plantas inferiores quedan bajo rasante" +msgid "editor.buildPanel.wallTypeEditorDialog.name" +msgstr "Nombre" -# Source-Hash: e12035eb47cc61cc +# Source-Hash: 4b3edeb00b32607e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground · {offset}" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.groundOffset" -msgstr "Rasante · {offset}" +msgid "editor.buildPanel.wallTypeEditorDialog.newWallType" +msgstr "Nuevo tipo de muro" -# Source-Hash: 5661c11383217661 +# Source-Hash: 4f7f8af75bf8e914 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Insert level here" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "OSB" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.insertLevelHere" -msgstr "Insertar planta aquí" +msgid "editor.buildPanel.wallTypeEditorDialog.osb" +msgstr "OSB" -# Source-Hash: 0215b36d5a08597a +# Source-Hash: dc4fe6cb415ed882 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level height" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outside" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.levelHeight" -msgstr "Altura de planta" +msgid "editor.buildPanel.wallTypeEditorDialog.outside" +msgstr "Exterior" -# Source-Hash: 91af436e81bb0875 +# Source-Hash: a6fd2cbf5c2154e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paste copied selection" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plaster" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.pasteCopiedSelection" -msgstr "Pegar la selección copiada" +msgid "editor.buildPanel.wallTypeEditorDialog.plaster" +msgstr "Enlucido" -# Source-Hash: 68bc52f53240cbec +# Source-Hash: e669c2c08bd80e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reorder {levelName}" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plywood" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.reorderLevelname" -msgstr "Reordenar {levelName}" +msgid "editor.buildPanel.wallTypeEditorDialog.plywood" +msgstr "Contrachapado" -# Source-Hash: 625d53de72ebc2ef +# Source-Hash: ca36e9fd7fba1fce # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Seat the building so this floor stands at grade; the floors under it are below grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove layer" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.seatTheBuildingSoThisFloor" -msgstr "Asentar el edificio para que esta planta quede a nivel de rasante; las inferiores quedan bajo rasante" +msgid "editor.buildPanel.wallTypeEditorDialog.removeLayer" +msgstr "Quitar capa" -# Source-Hash: 7ac9c00895c30d76 +# Source-Hash: 7d8f351c35f89b94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set as ground floor" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rigid foam" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.setAsGroundFloor" -msgstr "Establecer como planta baja" +msgid "editor.buildPanel.wallTypeEditorDialog.rigidFoam" +msgstr "Espuma rígida" -# Source-Hash: d6b381247066a7aa +# Source-Hash: e8bc984965d5753d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The ground level cannot be deleted" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Save wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.theGroundLevelCannotBeDeleted" -msgstr "La planta baja no se puede eliminar" +msgid "editor.buildPanel.wallTypeEditorDialog.saveWallType" +msgstr "Guardar tipo de muro" -# Source-Hash: b1122051dce0d7a1 +# Source-Hash: 36a588e44085108c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "This floor stands at grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sheathing" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.thisFloorStandsAtGrade" -msgstr "Esta planta está a nivel de rasante" +msgid "editor.buildPanel.wallTypeEditorDialog.sheathing" +msgstr "Tablero" -# Source-Hash: 062cc0f1afef0c52 +# Source-Hash: 9450fcb4a14674af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unit" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stone veneer" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.unit" -msgstr "Unidad" +msgid "editor.buildPanel.wallTypeEditorDialog.stoneVeneer" +msgstr "Chapado de piedra" -# Source-Hash: 5871b7c20478f4a1 +# Source-Hash: 687cf7bc64b0224e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor area" -#: packages/editor/src/i18n/floor-footprint-name.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stucco" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floorFootprint.area" -msgstr "Superficie de suelo" +msgid "editor.buildPanel.wallTypeEditorDialog.stucco" +msgstr "Estuco" -# Source-Hash: 8b2e1435272aa86a +# Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{room} floor" -#: packages/editor/src/i18n/floor-footprint-name.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floorFootprint.room" -msgstr "Suelo de {room}" +msgid "editor.buildPanel.wallTypeEditorDialog.thickness" +msgstr "Espesor" -# Source-Hash: 4731183fec06cbdf +# Source-Hash: 72e31eecaeb87447 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shared floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx -#: packages/editor/src/i18n/floor-footprint-name.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Total {thickness}" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floorFootprint.shared" -msgstr "Suelo compartido" +msgid "editor.buildPanel.wallTypeEditorDialog.totalThickness" +msgstr "Total {thickness}" -# Source-Hash: c0774c185060fc13 +# Source-Hash: eab795728c4a3f5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/helpers/building-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.helpers.buildingHelper.cancel" -msgstr "Cancelar" +msgid "editor.buildPanel.wallTypeEditorDialog.wallType" +msgstr "Tipo de muro" -# Source-Hash: 4c6ca3441c74da9e +# Source-Hash: 3744d42a0e4ee161 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place building" -#: packages/editor/src/components/ui/helpers/building-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plain wall" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.helpers.buildingHelper.placeBuilding" -msgstr "Colocar edificio" +msgid "editor.buildPanel.wallTypes.plainWall" +msgstr "Muro simple" -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: 1f3650da23603008 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" -#: packages/editor/src/components/ui/helpers/building-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera controls hint" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.buildingHelper.rotate" -msgstr "Girar" +msgid "editor.cameraControlsHint" +msgstr "Ayuda de controles de cámara" -# Source-Hash: 832470d3aeee82fd +# Source-Hash: 101b6a54c377049a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel placement" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pan" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.cancelPlacement" -msgstr "Cancelar colocación" +msgid "editor.cameraHint.pan" +msgstr "Desplazar" -# Source-Hash: e374fcaee33c3e2c +# Source-Hash: 306d409f8a1cf480 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuation — click or press C to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.continuationClickOrPressCTo" -msgstr "Continuación: haz clic o pulsa C para cambiar" +msgid "editor.cameraHint.rotate" +msgstr "Girar" -# Source-Hash: b108c7dc2ec2b9de +# Source-Hash: 663cecc316eb91b8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuation: {label}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zoom" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.continuationLabel" -msgstr "Continuación: {label}" +msgid "editor.cameraHint.zoom" +msgstr "Zoom" -# Source-Hash: 729d87891cb7dbb1 +# Source-Hash: 34b7ca7ff46c44a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag to draw fence" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label}: {finish}" +#: packages/editor/src/components/ui/controls/finish-swatch.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.dragToDrawFence" -msgstr "Arrastra para dibujar la valla" +msgid "editor.controls.finishSwatch.ariaLabel" +msgstr "{label}: {finish}" -# Source-Hash: b52e874718af1916 +# Source-Hash: 4ca0e0e73229540c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Erase: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default" +#: packages/editor/src/components/ui/controls/finish-swatch.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.eraseScope" -msgstr "Borrar: {scope}" +msgid "editor.controls.finishSwatch.default" +msgstr "Predeterminado" -# Source-Hash: 61f7494abc319e66 +# Source-Hash: a2bd204e93e90598 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Erase scope — click or press Shift to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dismiss" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.eraseScopeClickOrPressShift" -msgstr "Alcance del borrado: haz clic o pulsa Mayús para cambiar" +msgid "editor.dismiss" +msgstr "Cerrar" -# Source-Hash: 59993c163d68cc53 +# Source-Hash: 9222f970dce6cc60 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Erase scope: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dismiss camera controls hint" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.eraseScopeLabel" -msgstr "Alcance del borrado: {scope}" +msgid "editor.dismissCameraControlsHint" +msgstr "Cerrar la ayuda de controles de cámara" -# Source-Hash: a4bdcbc6cab772bf +# Source-Hash: aeac665749d3101d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fence type — click or press T to switch between straight, curved and freehand" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Expand sidebar" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.fenceTypeClickOrPressT" -msgstr "Tipo de valla: haz clic o pulsa T para alternar entre recta, curva y a mano alzada" +msgid "editor.expandSidebar" +msgstr "Expandir barra lateral" -# Source-Hash: 2a9ed258727078ac +# Source-Hash: dd86efcab72fc5c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fewer shortcuts" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Axis" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.fewerShortcuts" -msgstr "Menos atajos" +msgid "editor.floatingActionMenu.axis" +msgstr "Eje" -# Source-Hash: 698fa6e78af4d4b7 +# Source-Hash: 5232a826549f915e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish curve (or double-click)" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "⌥ axis" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.finishCurveOrDoubleClick" -msgstr "Terminar la curva (o doble clic)" +msgid "editor.floatingActionMenu.axis2" +msgstr "⌥ eje" -# Source-Hash: 09f6d79edf5cfd16 +# Source-Hash: 7001600001844c92 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid: {length}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "⚠ no equipment" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.gridLength" -msgstr "Cuadrícula: {length}" +msgid "editor.floatingActionMenu.noEquipment" +msgstr "⚠ sin equipo" -# Source-Hash: c493b562040c4328 +# Source-Hash: eae0194029f96edb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid step — click or tap Ctrl to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# register} other {# registers}}" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.gridStepClickOrTapCtrl" -msgstr "Paso de cuadrícula: haz clic o pulsa Ctrl para cambiar" +msgid "editor.floatingActionMenu.registerCount" +msgstr "{count, plural, one {# rejilla} many {# rejillas} other {# rejillas}}" -# Source-Hash: d36a8c93d81b3a36 +# Source-Hash: 8fb180251a321cef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid step: {length}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.gridStepLength" -msgstr "Paso de cuadrícula: {length}" +msgid "editor.floatingActionMenu.rTRotate" +msgstr "R/T girar" -# Source-Hash: abea993ede7daa7e +# Source-Hash: 6fb660d4eabe8d6a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a painted surface to erase" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {{number} run} other {{number} runs}}" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.hoverAPaintedSurfaceToErase" -msgstr "Pasa el cursor por una superficie pintada para borrarla" +msgid "editor.floatingActionMenu.runCount" +msgstr "{count, plural, one {{number} tramo} many {{number} tramos} other {{number} tramos}}" -# Source-Hash: fc1ed0ddc0cfcef5 +# Source-Hash: 88e6c2e1c344b2fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a surface to paint" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.hoverASurfaceToPaint" -msgstr "Pasa el cursor por una superficie para pintarla" +msgid "editor.floatingActionMenu.system" +msgstr "Sistema" -# Source-Hash: 63dec5de4a337015 +# Source-Hash: f0e76aea883d4e48 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a surface to pick its material" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add a floor under the roof" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.hoverASurfaceToPickIts" -msgstr "Pasa el cursor por una superficie para tomar su material" +msgid "editor.floatingLevelSelector.addAFloorUnderTheRoof" +msgstr "Añadir una planta bajo la cubierta" -# Source-Hash: 7ad6dc1b1f03f970 +# Source-Hash: a982ff9b075af829 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "More shortcuts" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add level above" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.moreShortcuts" -msgstr "Más atajos" +msgid "editor.floatingLevelSelector.addLevelAbove" +msgstr "Añadir planta encima" -# Source-Hash: 476b8f5f9ee542e6 +# Source-Hash: 0db7d221df08fa6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add level below" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.paintScope" -msgstr "Pintar: {scope}" +msgid "editor.floatingLevelSelector.addLevelBelow" +msgstr "Añadir planta debajo" -# Source-Hash: 9c09ce4c34122277 +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint scope — click or press Shift to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.paintScopeClickOrPressShift" -msgstr "Alcance de la pintura: haz clic o pulsa Mayús para cambiar" +msgid "editor.floatingLevelSelector.cancel" +msgstr "Cancelar" -# Source-Hash: 7890aa81687f6654 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint scope: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.paintScopeLabel" -msgstr "Alcance de la pintura: {scope}" +msgid "editor.floatingLevelSelector.delete" +msgstr "Eliminar" -# Source-Hash: a75b3abc0784b12b +# Source-Hash: 8e29375893d63408 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete level" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.pickScope" -msgstr "Tomar: {scope}" +msgid "editor.floatingLevelSelector.deleteLevel" +msgstr "Eliminar planta" -# Source-Hash: 69c1044e6ea87ccf +# Source-Hash: c3bc69ec52022250 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place gate on a fence" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Are you sure you want to delete {levelName}? All walls, floors, and objects on this level will be permanently removed." +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.placeGateOnAFence" -msgstr "Colocar puerta en una valla" +msgid "editor.floatingLevelSelector.deleteLevelConfirm" +msgstr "¿Seguro que quieres eliminar {levelName}? Todos los muros, forjados y objetos de esta planta se eliminarán de forma permanente." -# Source-Hash: 3754255b8affc7a0 +# Source-Hash: 5b2826ddac95cd0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place passage on a fence" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag to reorder" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.placePassageOnAFence" -msgstr "Colocar paso en una valla" +msgid "editor.floatingLevelSelector.dragToReorder" +msgstr "Arrastra para reordenar" -# Source-Hash: a8328c8964e947fa +# Source-Hash: 933177338f5a03ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select a material to paint" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate level" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.selectAMaterialToPaint" -msgstr "Elige un material para pintar" +msgid "editor.floatingLevelSelector.duplicateLevel" +msgstr "Duplicar planta" -# Source-Hash: 6f95d7116aea5738 +# Source-Hash: 9614c6825a7c67bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping: Angles" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate with options..." +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingAngles" -msgstr "Ajuste: ángulos" +msgid "editor.floatingLevelSelector.duplicateWithOptions" +msgstr "Duplicar con opciones..." -# Source-Hash: 2d6d8d85d2ebed47 +# Source-Hash: 5ec91bb339806413 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping: Grid" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Exit unit focus" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingGrid" -msgstr "Ajuste: cuadrícula" +msgid "editor.floatingLevelSelector.exitUnitFocus" +msgstr "Salir del enfoque de unidad" -# Source-Hash: 9096c5f9d8ce0f7c +# Source-Hash: a88c3f8bed58b4fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping: Lines" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Focused unit has zones here" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingLines" -msgstr "Ajuste: líneas" +msgid "editor.floatingLevelSelector.focusedUnitHasZonesHere" +msgstr "La unidad enfocada tiene zonas aquí" -# Source-Hash: b663afbf0835cf32 +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The ground floor stands {distance} over grade. Seat the ground floor 8 in over grade" +# Source-Hash: 6a00e82fda812178 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping mode — click or press Shift to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingModeClickOrPressShift" -msgstr "Modo de ajuste: haz clic o pulsa Mayús para cambiar" +msgid "editor.floatingLevelSelector.groundFloorOverGrade" +msgstr "La planta baja está {distance} sobre rasante. {action}" -# Source-Hash: d00e984fc88f71aa +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The ground floor stands {distance} under grade. Seat the ground floor 8 in over grade" +# Source-Hash: 61f400e77494df9b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping: Off" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingOff" -msgstr "Ajuste: desactivado" +msgid "editor.floatingLevelSelector.groundFloorUnderGrade" +msgstr "La planta baja está {distance} bajo rasante. {action}" -# Source-Hash: 6be9d0d312200761 +# Source-Hash: e3763ae2dc62c03f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight continuation is unavailable for curved or freehand fences" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground line: the levels under it are below grade" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.straightContinuationIsUnavailableForCurved" -msgstr "La continuación recta no está disponible en vallas curvas o a mano alzada" +msgid "editor.floatingLevelSelector.groundLineTheLevelsUnderIt" +msgstr "Línea de rasante: las plantas inferiores quedan bajo rasante" -# Source-Hash: 0d56b1f0a0493302 +# Source-Hash: e12035eb47cc61cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight: Continuous" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground · {offset}" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.straightContinuous" -msgstr "Recta: continua" +msgid "editor.floatingLevelSelector.groundOffset" +msgstr "Rasante · {offset}" -# Source-Hash: c034e85d3e7fd27e +# Source-Hash: 5661c11383217661 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight fence continuation — click or press C to toggle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insert level here" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.straightFenceContinuationClickOrPress" -msgstr "Continuación de valla recta: haz clic o pulsa C para alternar" +msgid "editor.floatingLevelSelector.insertLevelHere" +msgstr "Insertar planta aquí" -# Source-Hash: e3f679cdb4a3d603 +# Source-Hash: 0215b36d5a08597a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight: Single" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level height" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.straightSingle" -msgstr "Recta: simple" +msgid "editor.floatingLevelSelector.levelHeight" +msgstr "Altura de planta" -# Source-Hash: 9a56d90d461b4bca +# Source-Hash: 91af436e81bb0875 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add point" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paste copied selection" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.addPoint" -msgstr "Añadir punto" +msgid "editor.floatingLevelSelector.pasteCopiedSelection" +msgstr "Pegar la selección copiada" -# Source-Hash: c3dc3918c823a5e6 +# Source-Hash: 68bc52f53240cbec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add point · click the first to close" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reorder {levelName}" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.addPointClickTheFirstTo" -msgstr "Añadir punto · haz clic en el primero para cerrar" +msgid "editor.floatingLevelSelector.reorderLevelname" +msgstr "Reordenar {levelName}" -# Source-Hash: d8cf72d482d56cd7 +# Source-Hash: 625d53de72ebc2ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Brush size" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Seat the building so this floor stands at grade; the floors under it are below grade" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.brushSize" -msgstr "Tamaño del pincel" +msgid "editor.floatingLevelSelector.seatTheBuildingSoThisFloor" +msgstr "Asentar el edificio para que esta planta quede a nivel de rasante; las inferiores quedan bajo rasante" -# Source-Hash: c0774c185060fc13 +# Source-Hash: 7ac9c00895c30d76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set as ground floor" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.cancel" -msgstr "Cancelar" +msgid "editor.floatingLevelSelector.setAsGroundFloor" +msgstr "Establecer como planta baja" -# Source-Hash: 104fdab7934ec66c +# Source-Hash: d6b381247066a7aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel picking" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The ground level cannot be deleted" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.cancelPicking" -msgstr "Cancelar selección" +msgid "editor.floatingLevelSelector.theGroundLevelCannotBeDeleted" +msgstr "La planta baja no se puede eliminar" -# Source-Hash: c318cf0ce70b8977 +# Source-Hash: b1122051dce0d7a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel stroke" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This floor stands at grade" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.cancelStroke" -msgstr "Cancelar trazo" +msgid "editor.floatingLevelSelector.thisFloorStandsAtGrade" +msgstr "Esta planta está a nivel de rasante" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: 062cc0f1afef0c52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unit" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.done" -msgstr "Hecho" +msgid "editor.floatingLevelSelector.unit" +msgstr "Unidad" -# Source-Hash: e297db9ca0ce6d31 +# Source-Hash: 5871b7c20478f4a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw the mezzanine" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor area" +#: packages/editor/src/i18n/floor-footprint-name.ts #, fuzzy -msgid "editor.helpers.helperManager.drawTheMezzanine" -msgstr "Dibujar el altillo" +msgid "editor.floorFootprint.area" +msgstr "Superficie de suelo" -# Source-Hash: c8be604718a7a9fd +# Source-Hash: 8b2e1435272aa86a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw the opening" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{room} floor" +#: packages/editor/src/i18n/floor-footprint-name.ts #, fuzzy -msgid "editor.helpers.helperManager.drawTheOpening" -msgstr "Dibujar la abertura" +msgid "editor.floorFootprint.room" +msgstr "Suelo de {room}" -# Source-Hash: 231386ae6d534163 +# Source-Hash: 4731183fec06cbdf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw the terrace" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shared floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +#: packages/editor/src/i18n/floor-footprint-name.ts #, fuzzy -msgid "editor.helpers.helperManager.drawTheTerrace" -msgstr "Dibujar la terraza" +msgid "editor.floorFootprint.shared" +msgstr "Suelo compartido" -# Source-Hash: e092e803eb60af69 +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Exit smart measure" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/helpers/building-helper.tsx #, fuzzy -msgid "editor.helpers.helperManager.exitSmartMeasure" -msgstr "Salir de la medida inteligente" +msgid "editor.helpers.buildingHelper.cancel" +msgstr "Cancelar" -# Source-Hash: b3907da0ad234f10 +# Source-Hash: 4c6ca3441c74da9e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place building" +#: packages/editor/src/components/ui/helpers/building-helper.tsx #, fuzzy -msgid "editor.helpers.helperManager.finish" -msgstr "Terminar" +msgid "editor.helpers.buildingHelper.placeBuilding" +msgstr "Colocar edificio" -# Source-Hash: f74bd937ae2e3a40 +# Source-Hash: 306d409f8a1cf480 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish at the edge" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/editor/src/components/ui/helpers/building-helper.tsx #, fuzzy -msgid "editor.helpers.helperManager.finishAtTheEdge" -msgstr "Terminar en el borde" +msgid "editor.helpers.buildingHelper.rotate" +msgstr "Girar" -# Source-Hash: 21029cf1c45697cc +# Source-Hash: 832470d3aeee82fd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Free move" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel placement" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.freeMove" -msgstr "Movimiento libre" +msgid "editor.helpers.contextualHelperPanel.cancelPlacement" +msgstr "Cancelar colocación" -# Source-Hash: 3247d8689bed6ff6 +# Source-Hash: e374fcaee33c3e2c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Free move · slide doors and windows" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuation — click or press C to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.freeMoveSlideDoorsAndWindows" -msgstr "Movimiento libre · deslizar puertas y ventanas" +msgid "editor.helpers.contextualHelperPanel.continuationClickOrPressCTo" +msgstr "Continuación: haz clic o pulsa C para cambiar" -# Source-Hash: b5ad765b43e75a5c +# Source-Hash: b108c7dc2ec2b9de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hold to pick a material" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuation: {label}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.holdToPickAMaterial" -msgstr "Mantén pulsado para tomar un material" +msgid "editor.helpers.contextualHelperPanel.continuationLabel" +msgstr "Continuación: {label}" -# Source-Hash: 46b53c5449c98964 +# Source-Hash: 729d87891cb7dbb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inspect surface dimensions" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag to draw fence" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.inspectSurfaceDimensions" -msgstr "Inspeccionar las dimensiones de la superficie" +msgid "editor.helpers.contextualHelperPanel.dragToDrawFence" +msgstr "Arrastra para dibujar la valla" -# Source-Hash: 63f1f7006ae14177 +# Source-Hash: b52e874718af1916 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint with this material" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Erase: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.paintWithThisMaterial" -msgstr "Pintar con este material" +msgid "editor.helpers.contextualHelperPanel.eraseScope" +msgstr "Borrar: {scope}" -# Source-Hash: 188f55cc5afbe34f +# Source-Hash: 61f7494abc319e66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick target height" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Erase scope — click or press Shift to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.pickTargetHeight" -msgstr "Elegir altura objetivo" +msgid "editor.helpers.contextualHelperPanel.eraseScopeClickOrPressShift" +msgstr "Alcance del borrado: haz clic o pulsa Mayús para cambiar" -# Source-Hash: 2880fc9752eababa +# Source-Hash: 59993c163d68cc53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pin measurement lens" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Erase scope: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.pinMeasurementLens" -msgstr "Fijar la lupa de medida" +msgid "editor.helpers.contextualHelperPanel.eraseScopeLabel" +msgstr "Alcance del borrado: {scope}" -# Source-Hash: 722741535b346e09 +# Source-Hash: a4bdcbc6cab772bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fence type — click or press T to switch between straight, curved and freehand" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.place" -msgstr "Colocar" +msgid "editor.helpers.contextualHelperPanel.fenceTypeClickOrPressT" +msgstr "Tipo de valla: haz clic o pulsa T para alternar entre recta, curva y a mano alzada" -# Source-Hash: 82010a7fd6350c93 +# Source-Hash: 2a9ed258727078ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place inside the room" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fewer shortcuts" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.placeInsideTheRoom" -msgstr "Colocar dentro de la estancia" +msgid "editor.helpers.contextualHelperPanel.fewerShortcuts" +msgstr "Menos atajos" -# Source-Hash: 8b97f4503edb27b9 +# Source-Hash: 698fa6e78af4d4b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Press anywhere, drag to the opposite corner" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish curve (or double-click)" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.pressAnywhereDragToTheOpposite" -msgstr "Pulsa en cualquier punto y arrastra hasta la esquina opuesta" +msgid "editor.helpers.contextualHelperPanel.finishCurveOrDoubleClick" +msgstr "Terminar la curva (o doble clic)" -# Source-Hash: 786f0b1c81b2a6c0 +# Source-Hash: 09f6d79edf5cfd16 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raise or lower" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid: {length}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.raiseOrLower" -msgstr "Subir o bajar" +msgid "editor.helpers.contextualHelperPanel.gridLength" +msgstr "Cuadrícula: {length}" -# Source-Hash: b033f46ae3a0cbb7 +# Source-Hash: c493b562040c4328 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove a painted part, or reset a surface" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid step — click or tap Ctrl to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.removeAPaintedPartOrReset" -msgstr "Quitar una parte pintada o restablecer una superficie" +msgid "editor.helpers.contextualHelperPanel.gridStepClickOrTapCtrl" +msgstr "Paso de cuadrícula: haz clic o pulsa Ctrl para cambiar" -# Source-Hash: 0dc6d121791696f7 +# Source-Hash: d36a8c93d81b3a36 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove last point" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid step: {length}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.removeLastPoint" -msgstr "Quitar el último punto" +msgid "editor.helpers.contextualHelperPanel.gridStepLength" +msgstr "Paso de cuadrícula: {length}" -# Source-Hash: f85bdac0a1d16603 +# Source-Hash: abea993ede7daa7e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Resize" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a painted surface to erase" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.resize" -msgstr "Cambiar tamaño" +msgid "editor.helpers.contextualHelperPanel.hoverAPaintedSurfaceToErase" +msgstr "Pasa el cursor por una superficie pintada para borrarla" -# Source-Hash: 8a665ecaeffa9308 +# Source-Hash: fc1ed0ddc0cfcef5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ±45°" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a surface to paint" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.rotate45" -msgstr "Girar ±45°" +msgid "editor.helpers.contextualHelperPanel.hoverASurfaceToPaint" +msgstr "Pasa el cursor por una superficie para pintarla" -# Source-Hash: 6099ee99f8c38700 +# Source-Hash: 63dec5de4a337015 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate the selection ±45°" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a surface to pick its material" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.rotateTheSelection45" -msgstr "Girar la selección ±45°" +msgid "editor.helpers.contextualHelperPanel.hoverASurfaceToPickIts" +msgstr "Pasa el cursor por una superficie para tomar su material" -# Source-Hash: c93ae898b4d59f6f +# Source-Hash: 7ad6dc1b1f03f970 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set one corner, then the opposite" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "More shortcuts" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.setOneCornerThenTheOpposite" -msgstr "Fija una esquina y luego la opuesta" +msgid "editor.helpers.contextualHelperPanel.moreShortcuts" +msgstr "Más atajos" -# Source-Hash: c0774c185060fc13 +# Source-Hash: 476b8f5f9ee542e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/helpers/item-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.itemHelper.cancel" -msgstr "Cancelar" +msgid "editor.helpers.contextualHelperPanel.paintScope" +msgstr "Pintar: {scope}" -# Source-Hash: ed7f3d8417a3e074 +# Source-Hash: 9c09ce4c34122277 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Force place" -#: packages/editor/src/components/ui/helpers/item-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint scope — click or press Shift to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.itemHelper.forcePlace" -msgstr "Forzar colocación" +msgid "editor.helpers.contextualHelperPanel.paintScopeClickOrPressShift" +msgstr "Alcance de la pintura: haz clic o pulsa Mayús para cambiar" -# Source-Hash: 722741535b346e09 +# Source-Hash: 7890aa81687f6654 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place" -#: packages/editor/src/components/ui/helpers/item-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint scope: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.itemHelper.place" -msgstr "Colocar" +msgid "editor.helpers.contextualHelperPanel.paintScopeLabel" +msgstr "Alcance de la pintura: {scope}" -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: a75b3abc0784b12b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" -#: packages/editor/src/components/ui/helpers/item-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.itemHelper.rotate" -msgstr "Girar" +msgid "editor.helpers.contextualHelperPanel.pickScope" +msgstr "Tomar: {scope}" -# Source-Hash: e9dfc2a178bca5f7 +# Source-Hash: 69c1044e6ea87ccf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guided constraints bypassed" -#: packages/editor/src/components/ui/helpers/registered-tool-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place gate on a fence" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.registeredToolHelper.guidedConstraintsBypassed" -msgstr "Restricciones guiadas omitidas" +msgid "editor.helpers.contextualHelperPanel.placeGateOnAFence" +msgstr "Colocar puerta en una valla" -# Source-Hash: c69865ec5d9d1ac9 +# Source-Hash: 3754255b8affc7a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Angle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place passage on a fence" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.angle.g10zaw" -msgstr "Ángulo" +msgid "editor.helpers.contextualHelperPanel.placePassageOnAFence" +msgstr "Colocar paso en una valla" -# Source-Hash: 9c562983f6fed685 +# Source-Hash: a8328c8964e947fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arm length m" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select a material to paint" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.armLengthM.1jclqgw" -msgstr "Longitud del brazo m" +msgid "editor.helpers.contextualHelperPanel.selectAMaterialToPaint" +msgstr "Elige un material para pintar" -# Source-Hash: 38461bc364321749 +# Source-Hash: 6f95d7116aea5738 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Attachment side" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping: Angles" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.attachmentSide.6n9s5v" -msgstr "Lado de conexión" +msgid "editor.helpers.contextualHelperPanel.snappingAngles" +msgstr "Ajuste: ángulos" -# Source-Hash: 441124187e7da2fc +# Source-Hash: 2d6d8d85d2ebed47 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping: Grid" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.autoHangers.10554ka" -msgstr "Colgadores automáticos" +msgid "editor.helpers.contextualHelperPanel.snappingGrid" +msgstr "Ajuste: cuadrícula" -# Source-Hash: e20033e4b0045f1c +# Source-Hash: 9096c5f9d8ce0f7c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto miter corners" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping: Lines" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.autoMiterCorners.zxr5lt" -msgstr "Inglete automático en esquinas" +msgid "editor.helpers.contextualHelperPanel.snappingLines" +msgstr "Ajuste: líneas" -# Source-Hash: 92f3a8b63963daeb +# Source-Hash: b663afbf0835cf32 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto span" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping mode — click or press Shift to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.autoSpan.1gas9r6" -msgstr "Luz automática" +msgid "editor.helpers.contextualHelperPanel.snappingModeClickOrPressShift" +msgstr "Modo de ajuste: haz clic o pulsa Mayús para cambiar" -# Source-Hash: 8b2dfb9b9137fda0 +# Source-Hash: d00e984fc88f71aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back ratio" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping: Off" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.backRatio.1ughd99" -msgstr "Proporción trasera" +msgid "editor.helpers.contextualHelperPanel.snappingOff" +msgstr "Ajuste: desactivado" -# Source-Hash: 75dfae8d9f03fa0e +# Source-Hash: 6be9d0d312200761 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight continuation is unavailable for curved or freehand fences" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.baseHeight.1hs4zdf" -msgstr "Altura de la base" +msgid "editor.helpers.contextualHelperPanel.straightContinuationIsUnavailableForCurved" +msgstr "La continuación recta no está disponible en vallas curvas o a mano alzada" -# Source-Hash: 1cc2da12e8463e85 +# Source-Hash: 0d56b1f0a0493302 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base style" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight: Continuous" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.baseStyle.24vty5" -msgstr "Estilo de base" +msgid "editor.helpers.contextualHelperPanel.straightContinuous" +msgstr "Recta: continua" -# Source-Hash: f9d95c6df06b6223 +# Source-Hash: c034e85d3e7fd27e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Beam height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight fence continuation — click or press C to toggle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.beamHeight.1kq0oh1" -msgstr "Canto de viga" +msgid "editor.helpers.contextualHelperPanel.straightFenceContinuationClickOrPress" +msgstr "Continuación de valla recta: haz clic o pulsa C para alternar" -# Source-Hash: a133f8d23b1274dc +# Source-Hash: e3f679cdb4a3d603 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Beam width" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight: Single" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.beamWidth.1q1mzbe" -msgstr "Ancho de viga" +msgid "editor.helpers.contextualHelperPanel.straightSingle" +msgstr "Recta: simple" -# Source-Hash: b98c0d0189526335 +# Source-Hash: 9a56d90d461b4bca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Body shape" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add point" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.bodyShape.arvkuw" -msgstr "Forma del cuerpo" +msgid "editor.helpers.helperManager.addPoint" +msgstr "Añadir punto" -# Source-Hash: 2251ecab18467631 +# Source-Hash: c3dc3918c823a5e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bracket style" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add point · click the first to close" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.bracketStyle.1vvoptm" -msgstr "Estilo de ménsula" +msgid "editor.helpers.helperManager.addPointClickTheFirstTo" +msgstr "Añadir punto · haz clic en el primero para cerrar" -# Source-Hash: 5e9d4a4fcea481ca +# Source-Hash: d8cf72d482d56cd7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Branch angle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brush size" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.branchAngle.v56zme" -msgstr "Ángulo de derivación" +msgid "editor.helpers.helperManager.brushSize" +msgstr "Tamaño del pincel" -# Source-Hash: dec709f1f9c714ee +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cab height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cabHeight.1yn34mk" -msgstr "Altura de cabina" +msgid "editor.helpers.helperManager.cancel" +msgstr "Cancelar" -# Source-Hash: 87863f8366e1c88a +# Source-Hash: 104fdab7934ec66c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Canopy form" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel picking" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.canopyForm.1czzggp" -msgstr "Forma de la marquesina" +msgid "editor.helpers.helperManager.cancelPicking" +msgstr "Cancelar selección" -# Source-Hash: d52b53241789ee63 +# Source-Hash: c318cf0ce70b8977 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel stroke" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cap.s0thej" -msgstr "Remate" +msgid "editor.helpers.helperManager.cancelStroke" +msgstr "Cancelar trazo" -# Source-Hash: 2f2e49598ec8188e +# Source-Hash: 16552c2580bbe8b8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap overhang" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.capOverhang.kxxz9j" -msgstr "Vuelo del remate" +msgid "editor.helpers.helperManager.done" +msgstr "Hecho" -# Source-Hash: 8523c086e95b83e2 +# Source-Hash: e297db9ca0ce6d31 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap shape" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw the mezzanine" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.capShape.17mbxhu" -msgstr "Forma del remate" +msgid "editor.helpers.helperManager.drawTheMezzanine" +msgstr "Dibujar el altillo" -# Source-Hash: acd98600a518dd95 +# Source-Hash: c8be604718a7a9fd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap thickness" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw the opening" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.capThickness.u835q9" -msgstr "Espesor del remate" +msgid "editor.helpers.helperManager.drawTheOpening" +msgstr "Dibujar la abertura" -# Source-Hash: 7af3b69b4b5aeb19 +# Source-Hash: 231386ae6d534163 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Carcass height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw the terrace" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.carcassHeight.1aks0zy" -msgstr "Altura del casco" +msgid "editor.helpers.helperManager.drawTheTerrace" +msgstr "Dibujar la terraza" -# Source-Hash: 827709caa79db37f +# Source-Hash: e092e803eb60af69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cleanout style" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Exit smart measure" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cleanoutStyle.127zz6z" -msgstr "Estilo de registro" +msgid "editor.helpers.helperManager.exitSmartMeasure" +msgstr "Salir de la medida inteligente" -# Source-Hash: a549dc98e2a1bd07 +# Source-Hash: b3907da0ad234f10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar diameter" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.collarDiameter.1d5k28r" -msgstr "Diámetro del collarín" +msgid "editor.helpers.helperManager.finish" +msgstr "Terminar" -# Source-Hash: aa0232fc6f3eeadc +# Source-Hash: f74bd937ae2e3a40 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish at the edge" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.collarHeight.1dqwsrf" -msgstr "Altura del collarín" +msgid "editor.helpers.helperManager.finishAtTheEdge" +msgstr "Terminar en el borde" -# Source-Hash: cbd8079c3f540a4c +# Source-Hash: 21029cf1c45697cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar shape" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free move" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.collarShape.1gacv11" -msgstr "Forma del collarín" +msgid "editor.helpers.helperManager.freeMove" +msgstr "Movimiento libre" -# Source-Hash: 557cde7f95616454 +# Source-Hash: 3247d8689bed6ff6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar width" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free move · slide doors and windows" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.collarWidth.qvc9ik" -msgstr "Ancho del collarín" +msgid "editor.helpers.helperManager.freeMoveSlideDoorsAndWindows" +msgstr "Movimiento libre · deslizar puertas y ventanas" -# Source-Hash: 30edd1c180aac9b4 +# Source-Hash: b5ad765b43e75a5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Columns" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hold to pick a material" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.columns.1sy73ks" -msgstr "Columnas" +msgid "editor.helpers.helperManager.holdToPickAMaterial" +msgstr "Mantén pulsado para tomar un material" -# Source-Hash: cd5b2f70924b7c2d +# Source-Hash: 46b53c5449c98964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Conical full circle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inspect surface dimensions" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.conicalFullCircle.1pgkpz5" -msgstr "Cónica de círculo completo" +msgid "editor.helpers.helperManager.inspectSurfaceDimensions" +msgstr "Inspeccionar las dimensiones de la superficie" -# Source-Hash: dc90f3abb935e7e2 +# Source-Hash: 63f1f7006ae14177 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connection mode" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint with this material" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.connectionMode.1nty478" -msgstr "Modo de conexión" +msgid "editor.helpers.helperManager.paintWithThisMaterial" +msgstr "Pintar con este material" -# Source-Hash: 1a9a49d7135d4f15 +# Source-Hash: 188f55cc5afbe34f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connection offset" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick target height" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.connectionOffset.2m70s8" -msgstr "Desfase de conexión" +msgid "editor.helpers.helperManager.pickTargetHeight" +msgstr "Elegir altura objetivo" -# Source-Hash: 69be301fcb8030e2 +# Source-Hash: 2880fc9752eababa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner bevel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pin measurement lens" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cornerBevel.16iniho" -msgstr "Bisel de esquina" +msgid "editor.helpers.helperManager.pinMeasurementLens" +msgstr "Fijar la lupa de medida" -# Source-Hash: b997a96a9dc7e450 +# Source-Hash: 722741535b346e09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Covering type" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.coveringType.95yd3k" -msgstr "Tipo de revestimiento" +msgid "editor.helpers.helperManager.place" +msgstr "Colocar" -# Source-Hash: 03b33160d8baa966 +# Source-Hash: 82010a7fd6350c93 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place inside the room" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cricketHeight.pok31n" -msgstr "Altura del caballete" +msgid "editor.helpers.helperManager.placeInsideTheRoom" +msgstr "Colocar dentro de la estancia" -# Source-Hash: 21552eee05ccb5d6 +# Source-Hash: 8b97f4503edb27b9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket length" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Press anywhere, drag to the opposite corner" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cricketLength.i2aht8" -msgstr "Longitud del caballete" +msgid "editor.helpers.helperManager.pressAnywhereDragToTheOpposite" +msgstr "Pulsa en cualquier punto y arrastra hasta la esquina opuesta" -# Source-Hash: c13b707bfdeac855 +# Source-Hash: 786f0b1c81b2a6c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket side" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raise or lower" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cricketSide.1xnwil7" -msgstr "Lado del caballete" +msgid "editor.helpers.helperManager.raiseOrLower" +msgstr "Subir o bajar" -# Source-Hash: 4ee7089fa1b3e63b +# Source-Hash: b033f46ae3a0cbb7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket style" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove a painted part, or reset a surface" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cricketStyle.10j0lat" -msgstr "Estilo del caballete" +msgid "editor.helpers.helperManager.removeAPaintedPartOrReset" +msgstr "Quitar una parte pintada o restablecer una superficie" -# Source-Hash: b8ff053666ee326b +# Source-Hash: 0dc6d121791696f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curb" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove last point" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.curb.5xi2ol" -msgstr "Bordillo" +msgid "editor.helpers.helperManager.removeLastPoint" +msgstr "Quitar el último punto" -# Source-Hash: 8da648df210dbc0d +# Source-Hash: f85bdac0a1d16603 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curb height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Resize" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.curbHeight.1yn97sg" -msgstr "Altura del bordillo" +msgid "editor.helpers.helperManager.resize" +msgstr "Cambiar tamaño" -# Source-Hash: 0c01b9848f5d9673 +# Source-Hash: 8a665ecaeffa9308 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curve offset" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ±45°" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.curveOffset.l4xhvr" -msgstr "Desfase de curva" +msgid "editor.helpers.helperManager.rotate45" +msgstr "Girar ±45°" -# Source-Hash: 69179f4caa384585 +# Source-Hash: 6099ee99f8c38700 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Damper angle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate the selection ±45°" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.damperAngle.h5fxn7" -msgstr "Ángulo de la compuerta" +msgid "editor.helpers.helperManager.rotateTheSelection45" +msgstr "Girar la selección ±45°" -# Source-Hash: 15cff91231e806a4 +# Source-Hash: c93ae898b4d59f6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Deck thickness" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set one corner, then the opposite" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.deckThickness.4jmqze" -msgstr "Espesor de la tarima" +msgid "editor.helpers.helperManager.setOneCornerThenTheOpposite" +msgstr "Fija una esquina y luego la opuesta" -# Source-Hash: eff1e7dc0901b9d0 +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default level id" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/helpers/item-helper.tsx #, fuzzy -msgid "editor.inspector.field.defaultLevelId.xmrjzp" -msgstr "ID de planta predeterminada" +msgid "editor.helpers.itemHelper.cancel" +msgstr "Cancelar" -# Source-Hash: 99ac4d03c3061f3a +# Source-Hash: ed7f3d8417a3e074 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Force place" +#: packages/editor/src/components/ui/helpers/item-helper.tsx #, fuzzy -msgid "editor.inspector.field.depth.1lu11u2" -msgstr "Profundidad" +msgid "editor.helpers.itemHelper.forcePlace" +msgstr "Forzar colocación" -# Source-Hash: 016d8e70618916d4 +# Source-Hash: 722741535b346e09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diameter" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place" +#: packages/editor/src/components/ui/helpers/item-helper.tsx #, fuzzy -msgid "editor.inspector.field.diameter.s3robe" -msgstr "Diámetro" +msgid "editor.helpers.itemHelper.place" +msgstr "Colocar" -# Source-Hash: dab4100e83e4e6b3 +# Source-Hash: 306d409f8a1cf480 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diameter2" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/editor/src/components/ui/helpers/item-helper.tsx #, fuzzy -msgid "editor.inspector.field.diameter2.pm6cl4" -msgstr "Diámetro 2" +msgid "editor.helpers.itemHelper.rotate" +msgstr "Girar" -# Source-Hash: 5747145349432396 +# Source-Hash: e9dfc2a178bca5f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door duration ms" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guided constraints bypassed" +#: packages/editor/src/components/ui/helpers/registered-tool-helper.tsx #, fuzzy -msgid "editor.inspector.field.doorDurationMs.13nx909" -msgstr "Duración de puerta ms" +msgid "editor.helpers.registeredToolHelper.guidedConstraintsBypassed" +msgstr "Restricciones guiadas omitidas" -# Source-Hash: 6f4aca26196c221f +# Source-Hash: c69865ec5d9d1ac9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.doorHeight.92r9k4" -msgstr "Altura de puerta" +msgid "editor.inspector.field.angle.g10zaw" +msgstr "Ángulo" -# Source-Hash: 990ae81752236e3a +# Source-Hash: 9c562983f6fed685 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door panel style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arm length m" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.doorPanelStyle.2qog4q" -msgstr "Estilo del panel de puerta" +msgid "editor.inspector.field.armLengthM.1jclqgw" +msgstr "Longitud del brazo m" -# Source-Hash: c94e002123bb1199 +# Source-Hash: 38461bc364321749 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Attachment side" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.doorStyle.gerpos" -msgstr "Estilo de puerta" +msgid "editor.inspector.field.attachmentSide.6n9s5v" +msgstr "Lado de conexión" -# Source-Hash: 91aeb04b0b7b605e +# Source-Hash: 441124187e7da2fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.doorWidth.sy732l" -msgstr "Ancho de puerta" +msgid "editor.inspector.field.autoHangers.10554ka" +msgstr "Colgadores automáticos" -# Source-Hash: baad1238f70f79ea +# Source-Hash: e20033e4b0045f1c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspout enabled" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto miter corners" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.downspoutEnabled.1gn00nv" -msgstr "Bajante activada" +msgid "editor.inspector.field.autoMiterCorners.zxr5lt" +msgstr "Inglete automático en esquinas" -# Source-Hash: e288531858c4c44d +# Source-Hash: 92f3a8b63963daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspout position" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto span" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.downspoutPosition.fxcsop" -msgstr "Posición de la bajante" +msgid "editor.inspector.field.autoSpan.1gas9r6" +msgstr "Luz automática" -# Source-Hash: 861d28317325cf61 +# Source-Hash: 8b2dfb9b9137fda0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct material" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.ductMaterial.i8eonq" -msgstr "Material del conducto" +msgid "editor.inspector.field.backRatio.1ughd99" +msgstr "Proporción trasera" -# Source-Hash: ad8ab4ae38c3299c +# Source-Hash: 75dfae8d9f03fa0e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch gablet rake" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchGabletRake.6paydp" -msgstr "Alero del hastial mixto" +msgid "editor.inspector.field.baseHeight.1hs4zdf" +msgstr "Altura de la base" -# Source-Hash: 913d25cf2c5ff179 +# Source-Hash: 1cc2da12e8463e85 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch hip height ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchHipHeightRatio.1etnwgg" -msgstr "Proporción de altura mixta" +msgid "editor.inspector.field.baseStyle.24vty5" +msgstr "Estilo de base" -# Source-Hash: f4a80233d49f2b20 +# Source-Hash: f9d95c6df06b6223 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch hip width ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchHipWidthRatio.1dopfvb" -msgstr "Proporción de ancho mixta" +msgid "editor.inspector.field.beamHeight.1kq0oh1" +msgstr "Canto de viga" -# Source-Hash: 92021b0e37f9a25a +# Source-Hash: a133f8d23b1274dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch top rake thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchTopRakeThickness.1w9khxt" -msgstr "Espesor del alero superior" +msgid "editor.inspector.field.beamWidth.1q1mzbe" +msgstr "Ancho de viga" -# Source-Hash: d0a2ec13d71ce659 +# Source-Hash: b98c0d0189526335 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch waist length ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Body shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchWaistLengthRatio.agtoxw" -msgstr "Proporción de longitud de cintura" +msgid "editor.inspector.field.bodyShape.arvkuw" +msgstr "Forma del cuerpo" -# Source-Hash: 993396ccca2cd1d5 +# Source-Hash: 2251ecab18467631 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dwell ms" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bracket style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dwellMs.1lkk0o5" -msgstr "Espera ms" +msgid "editor.inspector.field.bracketStyle.1vvoptm" +msgstr "Estilo de ménsula" -# Source-Hash: 9cf550eb019bca1b +# Source-Hash: 5e9d4a4fcea481ca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edge inset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Branch angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.edgeInset.1obeimx" -msgstr "Retranqueo del borde" +msgid "editor.inspector.field.branchAngle.v56zme" +msgstr "Ángulo de derivación" -# Source-Hash: 8a3bc5111b9e97f4 +# Source-Hash: dec709f1f9c714ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cab height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.elevation.4jbp44" -msgstr "Cota" +msgid "editor.inspector.field.cabHeight.1yn34mk" +msgstr "Altura de cabina" -# Source-Hash: 1fc91958e30dbeaf +# Source-Hash: 87863f8366e1c88a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End cap left" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Canopy form" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.endCapLeft.19jel4v" -msgstr "Tapa final izquierda" +msgid "editor.inspector.field.canopyForm.1czzggp" +msgstr "Forma de la marquesina" -# Source-Hash: 4c9ae62e0ed70635 +# Source-Hash: d52b53241789ee63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End cap right" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.endCapRight.lhse9c" -msgstr "Tapa final derecha" +msgid "editor.inspector.field.cap.s0thej" +msgstr "Remate" -# Source-Hash: a9cba06250228a55 +# Source-Hash: 2f2e49598ec8188e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End caps" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.endCaps.4fsb5b" -msgstr "Tapas finales" +msgid "editor.inspector.field.capOverhang.kxxz9j" +msgstr "Vuelo del remate" -# Source-Hash: ebad74353b5a7610 +# Source-Hash: 8523c086e95b83e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End post" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.endPost.1guwsk0" -msgstr "Poste final" +msgid "editor.inspector.field.capShape.17mbxhu" +msgstr "Forma del remate" -# Source-Hash: ecbe36df4238439e +# Source-Hash: acd98600a518dd95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equipment type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.equipmentType.1mc2ywt" -msgstr "Tipo de equipo" +msgid "editor.inspector.field.capThickness.u835q9" +msgstr "Espesor del remate" -# Source-Hash: 66f1018b50c2e426 +# Source-Hash: 7af3b69b4b5aeb19 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fill to floor" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Carcass height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.fillToFloor.1oppnkf" -msgstr "Rellenar hasta el suelo" +msgid "editor.inspector.field.carcassHeight.1aks0zy" +msgstr "Altura del casco" -# Source-Hash: 1cfe33235b30b1d8 +# Source-Hash: 827709caa79db37f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finial" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cleanout style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.finial.1ertf4s" -msgstr "Remate" +msgid "editor.inspector.field.cleanoutStyle.127zz6z" +msgstr "Estilo de registro" -# Source-Hash: 28cd69e506709f16 +# Source-Hash: a549dc98e2a1bd07 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fitting type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.fittingType.18mz17s" -msgstr "Tipo de accesorio" +msgid "editor.inspector.field.collarDiameter.1d5k28r" +msgstr "Diámetro del collarín" -# Source-Hash: 3c1aec5e6fb180cf +# Source-Hash: aa0232fc6f3eeadc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flashing height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flashingHeight.3e8nn6" -msgstr "Altura del tapajuntas" +msgid "editor.inspector.field.collarHeight.1dqwsrf" +msgstr "Altura del collarín" -# Source-Hash: 327ba762101db94d +# Source-Hash: cbd8079c3f540a4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flashing projection" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flashingProjection.hhf0fk" -msgstr "Vuelo del tapajuntas" +msgid "editor.inspector.field.collarShape.1gacv11" +msgstr "Forma del collarín" -# Source-Hash: 9473e2ab53370b40 +# Source-Hash: 557cde7f95616454 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueCount.j3t2ci" -msgstr "Número de conductos" +msgid "editor.inspector.field.collarWidth.qvc9ik" +msgstr "Ancho del collarín" -# Source-Hash: fd0b65425ed3df8b +# Source-Hash: 30edd1c180aac9b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Columns" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueDiameter.cjhubg" -msgstr "Diámetro del conducto" +msgid "editor.inspector.field.columns.1sy73ks" +msgstr "Columnas" -# Source-Hash: 07ebe5e3780c624b +# Source-Hash: cd5b2f70924b7c2d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Conical full circle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueHeight.1dhc4y4" -msgstr "Altura del conducto" +msgid "editor.inspector.field.conicalFullCircle.1pgkpz5" +msgstr "Cónica de círculo completo" -# Source-Hash: ff8319792830d591 +# Source-Hash: dc90f3abb935e7e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connection mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueShape.1ealiy4" -msgstr "Forma del conducto" +msgid "editor.inspector.field.connectionMode.1nty478" +msgstr "Modo de conexión" -# Source-Hash: 5acf77854a0030ec +# Source-Hash: 1a9a49d7135d4f15 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connection offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueSpacing.exhzco" -msgstr "Separación de conductos" +msgid "editor.inspector.field.connectionOffset.2m70s8" +msgstr "Desfase de conexión" -# Source-Hash: 0a64209c0edacaa1 +# Source-Hash: 69be301fcb8030e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Footing style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner bevel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.footingStyle.e3btg6" -msgstr "Estilo de zapata" +msgid "editor.inspector.field.cornerBevel.16iniho" +msgstr "Bisel de esquina" -# Source-Hash: fd413477f1a9e5ed +# Source-Hash: b997a96a9dc7e450 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Covering type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.frameDepth.1934a5n" -msgstr "Profundidad del marco" +msgid "editor.inspector.field.coveringType.95yd3k" +msgstr "Tipo de revestimiento" -# Source-Hash: 6aa2318fa815e5f2 +# Source-Hash: 03b33160d8baa966 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.frameThickness.1agxzd8" -msgstr "Espesor del marco" +msgid "editor.inspector.field.cricketHeight.pok31n" +msgstr "Altura del caballete" -# Source-Hash: 9a3495a1e3181b56 +# Source-Hash: 21552eee05ccb5d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Framing strategy" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket length" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.framingStrategy.3jx9qe" -msgstr "Estrategia de entramado" +msgid "editor.inspector.field.cricketLength.i2aht8" +msgstr "Longitud del caballete" -# Source-Hash: 49f329aab535fd3a +# Source-Hash: c13b707bfdeac855 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "From level id" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket side" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.fromLevelId.15ieejs" -msgstr "ID de planta de origen" +msgid "editor.inspector.field.cricketSide.1xnwil7" +msgstr "Lado del caballete" -# Source-Hash: dbd062efc7f4fd7f +# Source-Hash: 4ee7089fa1b3e63b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gableOverhang.2z0obw" -msgstr "Vuelo del hastial" +msgid "editor.inspector.field.cricketStyle.10j0lat" +msgstr "Estilo del caballete" -# Source-Hash: 517caa8af48afb22 +# Source-Hash: b8ff053666ee326b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel lower height ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curb" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gambrelLowerHeightRatio.wqq7lg" -msgstr "Proporción de altura inferior holandesa" +msgid "editor.inspector.field.curb.5xi2ol" +msgstr "Bordillo" -# Source-Hash: 03ecb8f3b625d49d +# Source-Hash: 8da648df210dbc0d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel lower width ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curb height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gambrelLowerWidthRatio.uvyb1v" -msgstr "Proporción de ancho inferior holandesa" +msgid "editor.inspector.field.curbHeight.1yn97sg" +msgstr "Altura del bordillo" -# Source-Hash: f3ca5555e8c54375 +# Source-Hash: 0c01b9848f5d9673 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap x" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curve offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gapX.wjxa7" -msgstr "Separación x" +msgid "editor.inspector.field.curveOffset.l4xhvr" +msgstr "Desfase de curva" -# Source-Hash: 2736f7c5dfc7d917 +# Source-Hash: 69179f4caa384585 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap y" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Damper angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gapY.mkbl8" -msgstr "Separación y" +msgid "editor.inspector.field.damperAngle.h5fxn7" +msgstr "Ángulo de la compuerta" -# Source-Hash: 5d03ca50d712339b +# Source-Hash: 15cff91231e806a4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.glassThickness.s97b0x" -msgstr "Espesor del vidrio" +msgid "editor.inspector.field.deckThickness.4jmqze" +msgstr "Espesor de la tarima" -# Source-Hash: 4fc3e60be28f60d5 +# Source-Hash: eff1e7dc0901b9d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground clearance" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default level id" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.groundClearance.4os7f0" -msgstr "Separación al suelo" +msgid "editor.inspector.field.defaultLevelId.xmrjzp" +msgstr "ID de planta predeterminada" -# Source-Hash: 6a22a09b67309545 +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guard infill" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.guardInfill.16heiig" -msgstr "Relleno de la barandilla" +msgid "editor.inspector.field.depth.1lu11u2" +msgstr "Profundidad" -# Source-Hash: 98dfdac04af3c762 +# Source-Hash: 016d8e70618916d4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gutter enabled" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gutterEnabled.1oxiltf" -msgstr "Canalón activado" +msgid "editor.inspector.field.diameter.s3robe" +msgstr "Diámetro" -# Source-Hash: 4bdc3cdf0fe0ac3c +# Source-Hash: dab4100e83e4e6b3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gutter profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diameter2" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gutterProfile.1ngzqi3" -msgstr "Perfil del canalón" +msgid "editor.inspector.field.diameter2.pm6cl4" +msgstr "Diámetro 2" -# Source-Hash: 76555670cba9bb13 +# Source-Hash: 5747145349432396 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gutter size" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door duration ms" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gutterSize.jgavtz" -msgstr "Tamaño del canalón" +msgid "editor.inspector.field.doorDurationMs.13nx909" +msgstr "Duración de puerta ms" -# Source-Hash: c14d3aa4a98efa98 +# Source-Hash: 6f4aca26196c221f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger max reach" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.hangerMaxReach.1869epv" -msgstr "Alcance máximo del colgador" +msgid "editor.inspector.field.doorHeight.92r9k4" +msgstr "Altura de puerta" -# Source-Hash: dfbc357fb556559b +# Source-Hash: 990ae81752236e3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door panel style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.hangerSpacing.i2b5d7" -msgstr "Separación de colgadores" +msgid "editor.inspector.field.doorPanelStyle.2qog4q" +msgstr "Estilo del panel de puerta" -# Source-Hash: 3ce5e50c572644ed +# Source-Hash: c94e002123bb1199 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.hangerStyle.l7v7gb" -msgstr "Estilo de colgador" +msgid "editor.inspector.field.doorStyle.gerpos" +msgstr "Estilo de puerta" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: 91aeb04b0b7b605e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.height.7puwki" -msgstr "Altura" +msgid "editor.inspector.field.doorWidth.sy732l" +msgstr "Ancho de puerta" -# Source-Hash: d0b836103c795726 +# Source-Hash: baad1238f70f79ea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height2" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspout enabled" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.height2.7b3jlc" -msgstr "Altura 2" +msgid "editor.inspector.field.downspoutEnabled.1gn00nv" +msgstr "Bajante activada" -# Source-Hash: 681fd794e601ace5 +# Source-Hash: e288531858c4c44d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height above ridge" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspout position" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.heightAboveRidge.1k99brk" -msgstr "Altura sobre la cumbrera" +msgid "editor.inspector.field.downspoutPosition.fxcsop" +msgstr "Posición de la bajante" -# Source-Hash: b4905e5ec62a170f +# Source-Hash: 861d28317325cf61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High edge height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct material" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.highEdgeHeight.1s7v90t" -msgstr "Altura del borde alto" +msgid "editor.inspector.field.ductMaterial.i8eonq" +msgstr "Material del conducto" -# Source-Hash: c136d5cd7f3ce04a +# Source-Hash: ad8ab4ae38c3299c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch gablet rake" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.highOverhang.67w55d" -msgstr "Vuelo alto" +msgid "editor.inspector.field.dutchGabletRake.6paydp" +msgstr "Alero del hastial mixto" -# Source-Hash: 8b4cd537cc650dac +# Source-Hash: 913d25cf2c5ff179 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High side mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch hip height ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.highSideMode.1rc1r5j" -msgstr "Modo del lado alto" +msgid "editor.inspector.field.dutchHipHeightRatio.1etnwgg" +msgstr "Proporción de altura mixta" -# Source-Hash: c38e4e73ed9779f4 +# Source-Hash: f4a80233d49f2b20 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hood overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch hip width ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.hoodOverhang.1q1hcin" -msgstr "Vuelo de la campana" +msgid "editor.inspector.field.dutchHipWidthRatio.1dopfvb" +msgstr "Proporción de ancho mixta" -# Source-Hash: 9884ee52a0e84c0d +# Source-Hash: 92021b0e37f9a25a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Infill placement" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch top rake thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.infillPlacement.11dxzpo" -msgstr "Posición del relleno" +msgid "editor.inspector.field.dutchTopRakeThickness.1w9khxt" +msgstr "Espesor del alero superior" -# Source-Hash: 37fde9f9290ddc59 +# Source-Hash: d0a2ec13d71ce659 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inlet shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch waist length ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.inletShape.ypayh2" -msgstr "Forma de la entrada" +msgid "editor.inspector.field.dutchWaistLengthRatio.agtoxw" +msgstr "Proporción de longitud de cintura" -# Source-Hash: d840917007332b94 +# Source-Hash: 993396ccca2cd1d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inner radius" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dwell ms" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.innerRadius.1fkmg0j" -msgstr "Radio interior" +msgid "editor.inspector.field.dwellMs.1lkk0o5" +msgstr "Espera ms" -# Source-Hash: c8ce389856a90ae2 +# Source-Hash: 9cf550eb019bca1b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Insulated" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edge inset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.insulated.iwziey" -msgstr "Aislado" +msgid "editor.inspector.field.edgeInset.1obeimx" +msgstr "Retranqueo del borde" -# Source-Hash: 043a7a10b6c91f4f +# Source-Hash: 8a3bc5111b9e97f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Insulation r" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.insulationR.663ufx" -msgstr "Aislamiento R" +msgid "editor.inspector.field.elevation.4jbp44" +msgstr "Cota" -# Source-Hash: fe661655ba41b709 +# Source-Hash: 1fc91958e30dbeaf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End cap left" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lanternHeight.oz7zpm" -msgstr "Altura de la linterna" +msgid "editor.inspector.field.endCapLeft.19jel4v" +msgstr "Tapa final izquierda" -# Source-Hash: ab22022e7d5597af +# Source-Hash: 4c9ae62e0ed70635 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern top scale" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End cap right" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lanternTopScale.hkmpp2" -msgstr "Escala superior de la linterna" +msgid "editor.inspector.field.endCapRight.lhse9c" +msgstr "Tapa final derecha" -# Source-Hash: 17f854a76ebc033a +# Source-Hash: a9cba06250228a55 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ledger depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End caps" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.ledgerDepth.7av8k9" -msgstr "Profundidad del larguero" +msgid "editor.inspector.field.endCaps.4fsb5b" +msgstr "Tapas finales" -# Source-Hash: 547d3a8a9e3e24f5 +# Source-Hash: ebad74353b5a7610 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ledger height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End post" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.ledgerHeight.zo2oif" -msgstr "Altura del larguero" +msgid "editor.inspector.field.endPost.1guwsk0" +msgstr "Poste final" -# Source-Hash: 88603f884243c81e +# Source-Hash: ecbe36df4238439e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ledger vertical offset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equipment type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.ledgerVerticalOffset.1athbgt" -msgstr "Desfase vertical del larguero" +msgid "editor.inspector.field.equipmentType.1mc2ywt" +msgstr "Tipo de equipo" -# Source-Hash: 6519f495202b830d +# Source-Hash: 66f1018b50c2e426 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left end condition" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fill to floor" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.leftEndCondition.1syqlaw" -msgstr "Condición del extremo izquierdo" +msgid "editor.inspector.field.fillToFloor.1oppnkf" +msgstr "Rellenar hasta el suelo" -# Source-Hash: d041b8217c356977 +# Source-Hash: 1cfe33235b30b1d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finial" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.leftOverhang.1ydl9ma" -msgstr "Vuelo izquierdo" +msgid "editor.inspector.field.finial.1ertf4s" +msgstr "Remate" -# Source-Hash: 643687bc3adaac76 +# Source-Hash: 28cd69e506709f16 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fitting type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.length.1kpdcfp" -msgstr "Longitud" +msgid "editor.inspector.field.fittingType.18mz17s" +msgstr "Tipo de accesorio" -# Source-Hash: d6deaf0ceb9f43af +# Source-Hash: 3c1aec5e6fb180cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Liquid diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flashing height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.liquidDiameter.w3pk7c" -msgstr "Diámetro de líquido" +msgid "editor.inspector.field.flashingHeight.3e8nn6" +msgstr "Altura del tapajuntas" -# Source-Hash: 45aca762426392fa +# Source-Hash: 327ba762101db94d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Louver count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flashing projection" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.louverCount.lhw2gr" -msgstr "Número de lamas" +msgid "editor.inspector.field.flashingProjection.hhf0fk" +msgstr "Vuelo del tapajuntas" -# Source-Hash: c645a86c55eb0075 +# Source-Hash: 9473e2ab53370b40 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low beam inset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lowBeamInset.1g7yw5l" -msgstr "Retranqueo de la viga baja" +msgid "editor.inspector.field.flueCount.j3t2ci" +msgstr "Número de conductos" -# Source-Hash: 7e7b896682c78c5b +# Source-Hash: fd0b65425ed3df8b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low edge height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lowEdgeHeight.47mae1" -msgstr "Altura del borde bajo" +msgid "editor.inspector.field.flueDiameter.cjhubg" +msgstr "Diámetro del conducto" -# Source-Hash: 9deb775fc64854b2 +# Source-Hash: 07ebe5e3780c624b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lowOverhang.t4nz1h" -msgstr "Vuelo bajo" +msgid "editor.inspector.field.flueHeight.1dhc4y4" +msgstr "Altura del conducto" -# Source-Hash: 9aa621d270fe64b1 +# Source-Hash: ff8319792830d591 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard steep height ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.mansardSteepHeightRatio.1hbb8rq" -msgstr "Proporción de altura empinada mansarda" +msgid "editor.inspector.field.flueShape.1ealiy4" +msgstr "Forma del conducto" -# Source-Hash: 7cb03b27c632949b +# Source-Hash: 5acf77854a0030ec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard steep width ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.mansardSteepWidthRatio.6xk6vd" -msgstr "Proporción de ancho empinado mansarda" +msgid "editor.inspector.field.flueSpacing.exhzco" +msgstr "Separación de conductos" -# Source-Hash: 95772435857a7424 +# Source-Hash: 0a64209c0edacaa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match host roof material" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Footing style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.matchHostRoofMaterial.s56zwj" -msgstr "Igualar el material de la cubierta base" +msgid "editor.inspector.field.footingStyle.e3btg6" +msgstr "Estilo de zapata" -# Source-Hash: dc22618e31654bde +# Source-Hash: fd413477f1a9e5ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match host roof structure" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame depth" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.matchHostRoofStructure.bojht3" -msgstr "Igualar la estructura de la cubierta base" +msgid "editor.inspector.field.frameDepth.1934a5n" +msgstr "Profundidad del marco" -# Source-Hash: 06b36a09a84fa8b1 +# Source-Hash: 6aa2318fa815e5f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mount" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.mount.h80tay" -msgstr "Montaje" +msgid "editor.inspector.field.frameThickness.1agxzd8" +msgstr "Espesor del marco" -# Source-Hash: a288700f96d2b362 +# Source-Hash: 9a3495a1e3181b56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framing strategy" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.mountingType.1xvin1e" -msgstr "Tipo de montaje" +msgid "editor.inspector.field.framingStrategy.3jx9qe" +msgstr "Estrategia de entramado" -# Source-Hash: 3087bc9b219af9ef +# Source-Hash: 49f329aab535fd3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Neck height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "From level id" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.neckHeight.19ym8n1" -msgstr "Altura del cuello" +msgid "editor.inspector.field.fromLevelId.15ieejs" +msgstr "ID de planta de origen" -# Source-Hash: 1c0b8a5503c5daeb +# Source-Hash: dbd062efc7f4fd7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opacity" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.opacity.1pmpfd2" -msgstr "Opacidad" +msgid "editor.inspector.field.gableOverhang.2z0obw" +msgstr "Vuelo del hastial" -# Source-Hash: 51b7ab6a0a78d90a +# Source-Hash: 517caa8af48afb22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel lower height ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.openingAngle.brhi7c" -msgstr "Ángulo de apertura" +msgid "editor.inspector.field.gambrelLowerHeightRatio.wqq7lg" +msgstr "Proporción de altura inferior holandesa" -# Source-Hash: 1d714b576a057902 +# Source-Hash: 03ecb8f3b625d49d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening offset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel lower width ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.openingOffset.wpoqt6" -msgstr "Desfase del hueco" +msgid "editor.inspector.field.gambrelLowerWidthRatio.uvyb1v" +msgstr "Proporción de ancho inferior holandesa" -# Source-Hash: 55e5629865efd03d +# Source-Hash: f3ca5555e8c54375 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening side" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap x" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.openingSide.18l2iwe" -msgstr "Lado de apertura" +msgid "editor.inspector.field.gapX.wjxa7" +msgstr "Separación x" -# Source-Hash: 9824d357692ecb8a +# Source-Hash: 2736f7c5dfc7d917 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Operation state" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap y" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.operationState.1lwrz07" -msgstr "Estado de apertura" +msgid "editor.inspector.field.gapY.mkbl8" +msgstr "Separación y" -# Source-Hash: 4f1cbc14dcfb8f3b +# Source-Hash: 5d03ca50d712339b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Outlet shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.outletShape.lgpqhx" -msgstr "Forma de la salida" +msgid "editor.inspector.field.glassThickness.s97b0x" +msgstr "Espesor del vidrio" -# Source-Hash: 88540def2ce16ac5 +# Source-Hash: 4fc3e60be28f60d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground clearance" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.overhang.b5ljpv" -msgstr "Vuelo" +msgid "editor.inspector.field.groundClearance.4os7f0" +msgstr "Separación al suelo" -# Source-Hash: 50d7e5e370667f63 +# Source-Hash: 6a22a09b67309545 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guard infill" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.panelHeight.1kf31vk" -msgstr "Altura del panel" +msgid "editor.inspector.field.guardInfill.16heiig" +msgstr "Relleno de la barandilla" -# Source-Hash: 068d9e0adabc4578 +# Source-Hash: 98dfdac04af3c762 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gutter enabled" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.panelWidth.946581" -msgstr "Ancho del panel" +msgid "editor.inspector.field.gutterEnabled.1oxiltf" +msgstr "Canalón activado" -# Source-Hash: aca94a3adc0b0f01 +# Source-Hash: 4bdc3cdf0fe0ac3c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern alignment" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gutter profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.patternAlignment.jd1ht0" -msgstr "Alineación del patrón" +msgid "editor.inspector.field.gutterProfile.1ngzqi3" +msgstr "Perfil del canalón" -# Source-Hash: 9e9f9408ec2c8f0b +# Source-Hash: 76555670cba9bb13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gutter size" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.patternCount.1r37pve" -msgstr "Número de patrones" +msgid "editor.inspector.field.gutterSize.jgavtz" +msgstr "Tamaño del canalón" -# Source-Hash: 4712c449e9a42d3b +# Source-Hash: c14d3aa4a98efa98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern distribution" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger max reach" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.patternDistribution.fmam51" -msgstr "Distribución del patrón" +msgid "editor.inspector.field.hangerMaxReach.1869epv" +msgstr "Alcance máximo del colgador" -# Source-Hash: 63f833f219b9a592 +# Source-Hash: dfbc357fb556559b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern remainder" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.patternRemainder.i47p5y" -msgstr "Resto del patrón" +msgid "editor.inspector.field.hangerSpacing.i2b5d7" +msgstr "Separación de colgadores" -# Source-Hash: e0b8f766411329ff +# Source-Hash: 3ce5e50c572644ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketProfile.1xgzuyc" -msgstr "Perfil del listón" +msgid "editor.inspector.field.hangerStyle.l7v7gb" +msgstr "Estilo de colgador" -# Source-Hash: dfac7d68ea16e8a8 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket rail count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketRailCount.atgt6w" -msgstr "Número de travesaños" +msgid "editor.inspector.field.height.7puwki" +msgstr "Altura" -# Source-Hash: cd2652254a81d288 +# Source-Hash: d0b836103c795726 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height2" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketSpacing.p8d98w" -msgstr "Separación de listones" +msgid "editor.inspector.field.height2.7b3jlc" +msgstr "Altura 2" -# Source-Hash: 462f6cb03b23d773 +# Source-Hash: 681fd794e601ace5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket top" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height above ridge" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketTop.1tskplu" -msgstr "Remate del listón" +msgid "editor.inspector.field.heightAboveRidge.1k99brk" +msgstr "Altura sobre la cumbrera" -# Source-Hash: 0a4dbbe1cf592326 +# Source-Hash: b4905e5ec62a170f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket top clearance" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High edge height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketTopClearance.16eq1k0" -msgstr "Holgura superior del listón" +msgid "editor.inspector.field.highEdgeHeight.1s7v90t" +msgstr "Altura del borde alto" -# Source-Hash: c99ccea380ca41bf +# Source-Hash: c136d5cd7f3ce04a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket variation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketVariation.f7vl1c" -msgstr "Variación de listones" +msgid "editor.inspector.field.highOverhang.67w55d" +msgstr "Vuelo alto" -# Source-Hash: 798382373625fecd +# Source-Hash: 8b4cd537cc650dac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High side mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketWidth.3fr3rh" -msgstr "Ancho del listón" +msgid "editor.inspector.field.highSideMode.1rc1r5j" +msgstr "Modo del lado alto" -# Source-Hash: 48ce215c3be034c7 +# Source-Hash: c38e4e73ed9779f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pipe material" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hood overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.pipeMaterial.1ggc2wy" -msgstr "Material de la tubería" +msgid "editor.inspector.field.hoodOverhang.1q1hcin" +msgstr "Vuelo de la campana" -# Source-Hash: 75e3449fc1776d09 +# Source-Hash: 9884ee52a0e84c0d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pitch" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Infill placement" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.pitch.xe6ekx" -msgstr "Pendiente" +msgid "editor.inspector.field.infillPlacement.11dxzpo" +msgstr "Posición del relleno" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: 37fde9f9290ddc59 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inlet shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.position.1quewx6" -msgstr "Posición" +msgid "editor.inspector.field.inletShape.ypayh2" +msgstr "Forma de la entrada" -# Source-Hash: d090baf9f08c2280 +# Source-Hash: d840917007332b94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post bracing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inner radius" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postBracing.crq8nn" -msgstr "Arriostramiento de postes" +msgid "editor.inspector.field.innerRadius.1fkmg0j" +msgstr "Radio interior" -# Source-Hash: 6467b580eed1d333 +# Source-Hash: c8ce389856a90ae2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post cap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulated" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postCap.1xcvxrv" -msgstr "Remate del poste" +msgid "editor.inspector.field.insulated.iwziey" +msgstr "Aislado" -# Source-Hash: e1d91cdd16cc6593 +# Source-Hash: 043a7a10b6c91f4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation r" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postCount.22r56c" -msgstr "Número de postes" +msgid "editor.inspector.field.insulationR.663ufx" +msgstr "Aislamiento R" -# Source-Hash: d6d8b8653cb43624 +# Source-Hash: fe661655ba41b709 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postDepth.1ko6j1m" -msgstr "Profundidad del poste" +msgid "editor.inspector.field.lanternHeight.oz7zpm" +msgstr "Altura de la linterna" -# Source-Hash: dd071e84e259ee48 +# Source-Hash: ab22022e7d5597af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post inset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern top scale" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postInset.le36li" -msgstr "Retranqueo del poste" +msgid "editor.inspector.field.lanternTopScale.hkmpp2" +msgstr "Escala superior de la linterna" -# Source-Hash: 88c5d586822e58f0 +# Source-Hash: 17f854a76ebc033a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post layout mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ledger depth" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postLayoutMode.16jre62" -msgstr "Modo de distribución de postes" +msgid "editor.inspector.field.ledgerDepth.7av8k9" +msgstr "Profundidad del larguero" -# Source-Hash: faa36308c1ecb2a9 +# Source-Hash: 547d3a8a9e3e24f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post size" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ledger height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postSize.1jodxek" -msgstr "Tamaño del poste" +msgid "editor.inspector.field.ledgerHeight.zo2oif" +msgstr "Altura del larguero" -# Source-Hash: c8e8490c957e01f3 +# Source-Hash: 88603f884243c81e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ledger vertical offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postSpacing.voppfi" -msgstr "Separación de postes" +msgid "editor.inspector.field.ledgerVerticalOffset.1athbgt" +msgstr "Desfase vertical del larguero" -# Source-Hash: b98cbe8478508d41 +# Source-Hash: 6519f495202b830d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post through" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left end condition" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postThrough.1abgu4a" -msgstr "Poste pasante" +msgid "editor.inspector.field.leftEndCondition.1syqlaw" +msgstr "Condición del extremo izquierdo" -# Source-Hash: d1492df1fbb22c29 +# Source-Hash: d041b8217c356977 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postWidth.rk26fz" -msgstr "Ancho del poste" +msgid "editor.inspector.field.leftOverhang.1ydl9ma" +msgstr "Vuelo izquierdo" -# Source-Hash: 96ad4bd0f7baa40e +# Source-Hash: 643687bc3adaac76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.profile.1kwlci6" -msgstr "Perfil" +msgid "editor.inspector.field.length.1kpdcfp" +msgstr "Longitud" -# Source-Hash: d01cd36d3939abab +# Source-Hash: d6deaf0ceb9f43af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Projection" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Liquid diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.projection.jhtig0" -msgstr "Proyección" +msgid "editor.inspector.field.liquidDiameter.w3pk7c" +msgstr "Diámetro de líquido" -# Source-Hash: 800a7a9159519b46 +# Source-Hash: 45aca762426392fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Purlin height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Louver count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.purlinHeight.eo9cjm" -msgstr "Altura de correa" +msgid "editor.inspector.field.louverCount.lhw2gr" +msgstr "Número de lamas" -# Source-Hash: da4d0d12715d6c33 +# Source-Hash: c645a86c55eb0075 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Purlin spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low beam inset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.purlinSpacing.4gbzb2" -msgstr "Separación de correas" +msgid "editor.inspector.field.lowBeamInset.1g7yw5l" +msgstr "Retranqueo de la viga baja" -# Source-Hash: b4774bcbdf599812 +# Source-Hash: 7e7b896682c78c5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Purlin width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low edge height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.purlinWidth.r6tu3j" -msgstr "Ancho de correa" +msgid "editor.inspector.field.lowEdgeHeight.47mae1" +msgstr "Altura del borde bajo" -# Source-Hash: 2a4dd54f8a8c15ef +# Source-Hash: 9deb775fc64854b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafter end inset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rafterEndInset.14c0wy5" -msgstr "Retranqueo del extremo del cabio" +msgid "editor.inspector.field.lowOverhang.t4nz1h" +msgstr "Vuelo bajo" -# Source-Hash: 5a80a11b97c0e043 +# Source-Hash: 9aa621d270fe64b1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafter height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard steep height ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rafterHeight.1e1n99w" -msgstr "Altura del cabio" +msgid "editor.inspector.field.mansardSteepHeightRatio.1hbb8rq" +msgstr "Proporción de altura empinada mansarda" -# Source-Hash: b6348d554660af5b +# Source-Hash: 7cb03b27c632949b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafter spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard steep width ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rafterSpacing.19subc0" -msgstr "Separación de cabios" +msgid "editor.inspector.field.mansardSteepWidthRatio.6xk6vd" +msgstr "Proporción de ancho empinado mansarda" -# Source-Hash: 112c447946c3beaa +# Source-Hash: 95772435857a7424 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafter width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match host roof material" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rafterWidth.eksj4t" -msgstr "Ancho del cabio" +msgid "editor.inspector.field.matchHostRoofMaterial.s56zwj" +msgstr "Igualar el material de la cubierta base" -# Source-Hash: 7020d720876a2106 +# Source-Hash: dc22618e31654bde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match host roof structure" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.railingHeight.6wf4bm" -msgstr "Altura de la barandilla" - -# Source-Hash: 3e89ce193885b5b4 +msgid "editor.inspector.field.matchHostRoofStructure.bojht3" +msgstr "Igualar la estructura de la cubierta base" + +# Source-Hash: 06b36a09a84fa8b1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mount" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.railingMode.ov7xpu" -msgstr "Modo de barandilla" +msgid "editor.inspector.field.mount.h80tay" +msgstr "Montaje" -# Source-Hash: 174342bb31a86afc +# Source-Hash: a288700f96d2b362 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.railingStyle.1nyd2u" -msgstr "Estilo de barandilla" +msgid "editor.inspector.field.mountingType.1xvin1e" +msgstr "Tipo de montaje" -# Source-Hash: a44eedc895b95474 +# Source-Hash: 3087bc9b219af9ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Resize lock" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Neck height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.resizeLock.b2hbr0" -msgstr "Bloquear proporciones" +msgid "editor.inspector.field.neckHeight.19ym8n1" +msgstr "Altura del cuello" -# Source-Hash: edd319917231def8 +# Source-Hash: 1c0b8a5503c5daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opacity" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.returnDiameter.166ozhe" -msgstr "Diámetro de retorno" +msgid "editor.inspector.field.opacity.1pmpfd2" +msgstr "Opacidad" -# Source-Hash: dafa151b183daa77 +# Source-Hash: 51b7ab6a0a78d90a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.returnHeight.b9sq6y" -msgstr "Altura de retorno" +msgid "editor.inspector.field.openingAngle.brhi7c" +msgstr "Ángulo de apertura" -# Source-Hash: cd55fd029ad2803b +# Source-Hash: 1d714b576a057902 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.returnShape.1e3a27i" -msgstr "Forma del retorno" +msgid "editor.inspector.field.openingOffset.wpoqt6" +msgstr "Desfase del hueco" -# Source-Hash: 6a7c411667124177 +# Source-Hash: 55e5629865efd03d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening side" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.returnWidth.z9r3h3" -msgstr "Ancho del retorno" +msgid "editor.inspector.field.openingSide.18l2iwe" +msgstr "Lado de apertura" -# Source-Hash: 460bd11bfc2e5697 +# Source-Hash: 9824d357692ecb8a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right end condition" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Operation state" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rightEndCondition.tjlw3l" -msgstr "Condición del extremo derecho" +msgid "editor.inspector.field.operationState.1lwrz07" +msgstr "Estado de apertura" -# Source-Hash: 1ed35f8d27ae5583 +# Source-Hash: 4f1cbc14dcfb8f3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outlet shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rightOverhang.yqbeft" -msgstr "Vuelo derecho" +msgid "editor.inspector.field.outletShape.lgpqhx" +msgstr "Forma de la salida" -# Source-Hash: 39c02aa2d97a62ba +# Source-Hash: 88540def2ce16ac5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.roofHeight.1uhy6qy" -msgstr "Altura de la cubierta" +msgid "editor.inspector.field.overhang.b5ljpv" +msgstr "Vuelo" -# Source-Hash: d62f8833d77ca8a1 +# Source-Hash: 50d7e5e370667f63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.roofStyle.pawqfy" -msgstr "Estilo de cubierta" +msgid "editor.inspector.field.panelHeight.1kf31vk" +msgstr "Altura del panel" -# Source-Hash: 0ddd561a4126b826 +# Source-Hash: 068d9e0adabc4578 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.roofThickness.1xlr3rx" -msgstr "Espesor de la cubierta" +msgid "editor.inspector.field.panelWidth.946581" +msgstr "Ancho del panel" -# Source-Hash: 3a08ede9e51d5395 +# Source-Hash: aca94a3adc0b0f01 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern alignment" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.roofType.1m9kv5h" -msgstr "Tipo de cubierta" +msgid "editor.inspector.field.patternAlignment.jd1ht0" +msgstr "Alineación del patrón" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: 9e9f9408ec2c8f0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rotation.ly2rj" -msgstr "Rotación" +msgid "editor.inspector.field.patternCount.1r37pve" +msgstr "Número de patrones" -# Source-Hash: c913b494c3901a17 +# Source-Hash: 4712c449e9a42d3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rows" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern distribution" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rows.1ba1neg" -msgstr "Filas" +msgid "editor.inspector.field.patternDistribution.fmam51" +msgstr "Distribución del patrón" -# Source-Hash: 8210f376c0d29acc +# Source-Hash: 63f833f219b9a592 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scale" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern remainder" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.scale.b6rpxt" -msgstr "Escala" +msgid "editor.inspector.field.patternRemainder.i47p5y" +msgstr "Resto del patrón" -# Source-Hash: adb6face4bac5245 +# Source-Hash: e0b8f766411329ff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Seam detail" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.seamDetail.197za48" -msgstr "Detalle de junta" +msgid "editor.inspector.field.picketProfile.1xgzuyc" +msgstr "Perfil del listón" -# Source-Hash: 4b2aed9d56cc4dee +# Source-Hash: dfac7d68ea16e8a8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segment type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket rail count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.segmentType.l667sy" -msgstr "Tipo de segmento" +msgid "editor.inspector.field.picketRailCount.atgt6w" +msgstr "Número de travesaños" -# Source-Hash: a7794a81141b4de4 +# Source-Hash: cd2652254a81d288 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shaftStyle.1i5ampa" -msgstr "Estilo del hueco" +msgid "editor.inspector.field.picketSpacing.p8d98w" +msgstr "Separación de listones" -# Source-Hash: 8eb6438543b18cdb +# Source-Hash: 462f6cb03b23d773 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft wall thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket top" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shaftWallThickness.bduslr" -msgstr "Espesor del muro del hueco" +msgid "editor.inspector.field.picketTop.1tskplu" +msgstr "Remate del listón" -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: 0a4dbbe1cf592326 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket top clearance" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shape.iq9t52" -msgstr "Forma" +msgid "editor.inspector.field.picketTopClearance.16eq1k0" +msgstr "Holgura superior del listón" -# Source-Hash: 44a8ab89c854cad1 +# Source-Hash: c99ccea380ca41bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape2" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket variation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shape2.fi0nx8" -msgstr "Forma 2" +msgid "editor.inspector.field.picketVariation.f7vl1c" +msgstr "Variación de listones" -# Source-Hash: fcee9712879570ae +# Source-Hash: 798382373625fecd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed high side" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shedHighSide.bzzddg" -msgstr "Lado alto de la cubierta a un agua" +msgid "editor.inspector.field.picketWidth.3fr3rh" +msgstr "Ancho del listón" -# Source-Hash: f5a931cd6e97e5e2 +# Source-Hash: 48ce215c3be034c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingle thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pipe material" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shingleThickness.1hn5wxr" -msgstr "Espesor de la teja" +msgid "editor.inspector.field.pipeMaterial.1ggc2wy" +msgstr "Material de la tubería" -# Source-Hash: b14990b3e4222dd3 +# Source-Hash: 75e3449fc1776d09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder extent" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pitch" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shoulderExtent.11j8uiv" -msgstr "Extensión del hombro" +msgid "editor.inspector.field.pitch.xe6ekx" +msgstr "Pendiente" -# Source-Hash: 505de343ec5010e6 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shoulderHeight.xyqn6g" -msgstr "Altura del hombro" +msgid "editor.inspector.field.position.1quewx6" +msgstr "Posición" -# Source-Hash: 58d48c01b7ec1a40 +# Source-Hash: d090baf9f08c2280 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post bracing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shoulderStyle.1hkcv2w" -msgstr "Estilo del hombro" +msgid "editor.inspector.field.postBracing.crq8nn" +msgstr "Arriostramiento de postes" -# Source-Hash: af84db1026bf2e6c +# Source-Hash: 6467b580eed1d333 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show center column" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post cap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.showCenterColumn.1uggg45" -msgstr "Mostrar columna central" +msgid "editor.inspector.field.postCap.1xcvxrv" +msgstr "Remate del poste" -# Source-Hash: 80214dc086ebc1b1 +# Source-Hash: e1d91cdd16cc6593 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show infill" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.showInfill.33rv7u" -msgstr "Mostrar relleno" +msgid "editor.inspector.field.postCount.22r56c" +msgstr "Número de postes" -# Source-Hash: f02d6cdfb4c6ad08 +# Source-Hash: d6d8b8653cb43624 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show step supports" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post depth" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.showStepSupports.1kg8h8m" -msgstr "Mostrar soportes de peldaño" +msgid "editor.inspector.field.postDepth.1ko6j1m" +msgstr "Profundidad del poste" -# Source-Hash: 5d1147c774718b76 +# Source-Hash: dd071e84e259ee48 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Side flashing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post inset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.sideFlashing.cv744o" -msgstr "Tapajuntas lateral" +msgid "editor.inspector.field.postInset.le36li" +msgstr "Retranqueo del poste" -# Source-Hash: 60bb3338e0ad558c +# Source-Hash: 88c5d586822e58f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Size" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post layout mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.size.1a4x3zw" -msgstr "Tamaño" +msgid "editor.inspector.field.postLayoutMode.16jre62" +msgstr "Modo de distribución de postes" -# Source-Hash: fbdbc6c97c75b030 +# Source-Hash: faa36308c1ecb2a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Skylight type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post size" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.skylightType.1a5vj3i" -msgstr "Tipo de claraboya" +msgid "editor.inspector.field.postSize.1jodxek" +msgstr "Tamaño del poste" -# Source-Hash: c9a6561cb3c3da82 +# Source-Hash: c8e8490c957e01f3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab opening mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.slabOpeningMode.g4f730" -msgstr "Modo de hueco en forjado" +msgid "editor.inspector.field.postSpacing.voppfi" +msgstr "Separación de postes" -# Source-Hash: ef0efc845ccdba78 +# Source-Hash: b98cbe8478508d41 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slat gap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post through" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.slatGap.slmk93" -msgstr "Separación de lamas" +msgid "editor.inspector.field.postThrough.1abgu4a" +msgstr "Poste pasante" -# Source-Hash: 4daab7a2ce2ecef3 +# Source-Hash: d1492df1fbb22c29 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slide direction" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.slideDirection.1527q13" -msgstr "Dirección de deslizamiento" +msgid "editor.inspector.field.postWidth.rk26fz" +msgstr "Ancho del poste" -# Source-Hash: 93b34a5b546664c4 +# Source-Hash: 96ad4bd0f7baa40e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Span" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.span.1bmmuw1" -msgstr "Luz" +msgid "editor.inspector.field.profile.1kwlci6" +msgstr "Perfil" -# Source-Hash: 3b006be0b1f0493f +# Source-Hash: d01cd36d3939abab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Speed" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Projection" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.speed.2w2xwg" -msgstr "Velocidad" +msgid "editor.inspector.field.projection.jhtig0" +msgstr "Proyección" -# Source-Hash: c8cfb8336a240cb1 +# Source-Hash: 800a7a9159519b46 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spin speed" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Purlin height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.spinSpeed.1ozx746" -msgstr "Velocidad de giro" +msgid "editor.inspector.field.purlinHeight.eo9cjm" +msgstr "Altura de correa" -# Source-Hash: c9f54c3b258961c7 +# Source-Hash: da4d0d12715d6c33 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Purlin spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.stairType.1u05e02" -msgstr "Tipo de escalera" +msgid "editor.inspector.field.purlinSpacing.4gbzb2" +msgstr "Separación de correas" -# Source-Hash: 0af6194a8b8d8be6 +# Source-Hash: b4774bcbdf599812 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standoff" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Purlin width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.standoff.4wv2g0" -msgstr "Separador" +msgid "editor.inspector.field.purlinWidth.r6tu3j" +msgstr "Ancho de correa" -# Source-Hash: 0464d4efa1e80c62 +# Source-Hash: 2a4dd54f8a8c15ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standoff height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafter end inset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.standoffHeight.1qdnff" -msgstr "Altura del separador" +msgid "editor.inspector.field.rafterEndInset.14c0wy5" +msgstr "Retranqueo del extremo del cabio" -# Source-Hash: 85da28b0b26b8c2a +# Source-Hash: 5a80a11b97c0e043 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start post" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafter height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.startPost.1ood9kv" -msgstr "Poste inicial" +msgid "editor.inspector.field.rafterHeight.1e1n99w" +msgstr "Altura del cabio" -# Source-Hash: d5dc1ba8cca3193d +# Source-Hash: b6348d554660af5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Step count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafter spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.stepCount.nzorrw" -msgstr "Número de peldaños" +msgid "editor.inspector.field.rafterSpacing.19subc0" +msgstr "Separación de cabios" -# Source-Hash: cadbb9cadd6a5e6f +# Source-Hash: 112c447946c3beaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Strap spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafter width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.strapSpacing.1cyt3dc" -msgstr "Separación de flejes" +msgid "editor.inspector.field.rafterWidth.eksj4t" +msgstr "Ancho del cabio" -# Source-Hash: c017cd56b3ae5865 +# Source-Hash: 7020d720876a2106 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Strap style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.strapStyle.fh1oy4" -msgstr "Estilo de fleje" +msgid "editor.inspector.field.railingHeight.6wf4bm" +msgstr "Altura de la barandilla" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: 3e89ce193885b5b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.style.nf3vcm" -msgstr "Estilo" +msgid "editor.inspector.field.railingMode.ov7xpu" +msgstr "Modo de barandilla" -# Source-Hash: 7b3f016989c631a7 +# Source-Hash: 174342bb31a86afc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Suction diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.suctionDiameter.nutxtj" -msgstr "Diámetro de aspiración" +msgid "editor.inspector.field.railingStyle.1nyd2u" +msgstr "Estilo de barandilla" -# Source-Hash: 3f1e0fd30e5b1f39 +# Source-Hash: a44eedc895b95474 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Resize lock" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supplyDiameter.h5ldh5" -msgstr "Diámetro de impulsión" +msgid "editor.inspector.field.resizeLock.b2hbr0" +msgstr "Bloquear proporciones" -# Source-Hash: 05c9b608538e181d +# Source-Hash: edd319917231def8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supplyHeight.zy6ru1" -msgstr "Altura de impulsión" +msgid "editor.inspector.field.returnDiameter.166ozhe" +msgstr "Diámetro de retorno" -# Source-Hash: 3c9400722baa474d +# Source-Hash: dafa151b183daa77 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supplyShape.k39wnb" -msgstr "Forma de impulsión" +msgid "editor.inspector.field.returnHeight.b9sq6y" +msgstr "Altura de retorno" -# Source-Hash: af7619025438f995 +# Source-Hash: cd55fd029ad2803b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supplyWidth.g66axi" -msgstr "Ancho de impulsión" +msgid "editor.inspector.field.returnShape.1e3a27i" +msgstr "Forma del retorno" -# Source-Hash: 617e198cf3f214d3 +# Source-Hash: 6a7c411667124177 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Support offset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supportOffset.1w4cocr" -msgstr "Desfase del soporte" +msgid "editor.inspector.field.returnWidth.z9r3h3" +msgstr "Ancho del retorno" -# Source-Hash: 2686abc093f3dfb1 +# Source-Hash: 460bd11bfc2e5697 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sweep angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right end condition" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.sweepAngle.ucmmlw" -msgstr "Ángulo de barrido" +msgid "editor.inspector.field.rightEndCondition.tjlw3l" +msgstr "Condición del extremo derecho" -# Source-Hash: 88e6c2e1c344b2fc +# Source-Hash: 1ed35f8d27ae5583 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.system.13qbhrw" -msgstr "Sistema" +msgid "editor.inspector.field.rightOverhang.yqbeft" +msgstr "Vuelo derecho" -# Source-Hash: ccb3afc48bd9a284 +# Source-Hash: 39c02aa2d97a62ba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terminal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.terminal.1501knl" -msgstr "Terminal" +msgid "editor.inspector.field.roofHeight.1uhy6qy" +msgstr "Altura de la cubierta" -# Source-Hash: de1777c521046f7d +# Source-Hash: d62f8833d77ca8a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terminal type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.terminalType.1ne8lgb" -msgstr "Tipo de terminal" +msgid "editor.inspector.field.roofStyle.pawqfy" +msgstr "Estilo de cubierta" -# Source-Hash: fdbb503f0941bd56 +# Source-Hash: 0ddd561a4126b826 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.thickness.1l8hu45" -msgstr "Espesor" +msgid "editor.inspector.field.roofThickness.1xlr3rx" +msgstr "Espesor de la cubierta" -# Source-Hash: 58cb60c14826f1d0 +# Source-Hash: 3a08ede9e51d5395 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilt angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.tiltAngle.1312yw1" -msgstr "Ángulo de inclinación" +msgid "editor.inspector.field.roofType.1m9kv5h" +msgstr "Tipo de cubierta" -# Source-Hash: 7057972ff4c78dc7 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "To level id" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.toLevelId.8i5qx7" -msgstr "ID de planta de destino" +msgid "editor.inspector.field.rotation.ly2rj" +msgstr "Rotación" -# Source-Hash: fa8fc3d5c612e774 +# Source-Hash: c913b494c3901a17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top landing depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rows" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.topLandingDepth.ki7gk2" -msgstr "Profundidad del descansillo superior" +msgid "editor.inspector.field.rows.1ba1neg" +msgstr "Filas" -# Source-Hash: 6e4a0b98089ec2cd +# Source-Hash: 8210f376c0d29acc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top landing mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scale" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.topLandingMode.zk0h7e" -msgstr "Modo del descansillo superior" +msgid "editor.inspector.field.scale.b6rpxt" +msgstr "Escala" -# Source-Hash: c182bb3c8a701085 +# Source-Hash: adb6face4bac5245 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top rail height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Seam detail" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.topRailHeight.fscisv" -msgstr "Altura del travesaño superior" +msgid "editor.inspector.field.seamDetail.197za48" +msgstr "Detalle de junta" -# Source-Hash: 8c5502f1d8087b7b +# Source-Hash: 4b2aed9d56cc4dee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transition mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segment type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.transitionMode.f3evgt" -msgstr "Modo de transición" +msgid "editor.inspector.field.segmentType.l667sy" +msgstr "Tipo de segmento" -# Source-Hash: 96eb5997f0aa2dde +# Source-Hash: a7794a81141b4de4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transition width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.transitionWidth.rtgz3m" -msgstr "Ancho de transición" +msgid "editor.inspector.field.shaftStyle.1i5ampa" +msgstr "Estilo del hueco" -# Source-Hash: 812d27902509339f +# Source-Hash: 8eb6438543b18cdb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vane count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft wall thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.vaneCount.55vtye" -msgstr "Número de álabes" +msgid "editor.inspector.field.shaftWallThickness.bduslr" +msgstr "Espesor del muro del hueco" -# Source-Hash: 1e7dcd717c8ac239 +# Source-Hash: 85ea1d3c8b749680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.wallHeight.18vmh5c" -msgstr "Altura del muro" +msgid "editor.inspector.field.shape.iq9t52" +msgstr "Forma" -# Source-Hash: f14bdaed6101896a +# Source-Hash: 44a8ab89c854cad1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall shell" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape2" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.wallShell.vqsyhv" -msgstr "Envolvente del muro" +msgid "editor.inspector.field.shape2.fi0nx8" +msgstr "Forma 2" -# Source-Hash: 801268585c9a679b +# Source-Hash: fcee9712879570ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall skirt height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed high side" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.wallSkirtHeight.1uea2ad" -msgstr "Altura del zócalo" +msgid "editor.inspector.field.shedHighSide.bzzddg" +msgstr "Lado alto de la cubierta a un agua" -# Source-Hash: 6b377d0ba1565477 +# Source-Hash: f5a931cd6e97e5e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall thickness" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingle thickness" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.wallThickness.17wn4iv" -msgstr "Espesor del muro" +msgid "editor.inspector.field.shingleThickness.1hn5wxr" +msgstr "Espesor de la teja" -# Source-Hash: 3a0ccd6c46877a87 +# Source-Hash: b14990b3e4222dd3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder extent" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.width.gfxz9b" -msgstr "Ancho" +msgid "editor.inspector.field.shoulderExtent.11j8uiv" +msgstr "Extensión del hombro" -# Source-Hash: de05070474f589b4 +# Source-Hash: 505de343ec5010e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width2" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.width2.1nqawvr" -msgstr "Ancho 2" +msgid "editor.inspector.field.shoulderHeight.xyqn6g" +msgstr "Altura del hombro" -# Source-Hash: 6199b641888a83fa +# Source-Hash: 58d48c01b7ec1a40 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "With back" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.withBack.1ay8nus" -msgstr "Con trasera" +msgid "editor.inspector.field.shoulderStyle.1hkcv2w" +msgstr "Estilo del hombro" -# Source-Hash: 699934d8b9571b64 +# Source-Hash: af84db1026bf2e6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "With bottom" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show center column" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.withBottom.1x1z1vo" -msgstr "Con base" +msgid "editor.inspector.field.showCenterColumn.1uggg45" +msgstr "Mostrar columna central" -# Source-Hash: 03987b9aadaab50f +# Source-Hash: 80214dc086ebc1b1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "With sides" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show infill" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.withSides.uq066x" -msgstr "Con laterales" +msgid "editor.inspector.field.showInfill.33rv7u" +msgstr "Mostrar relleno" -# Source-Hash: f571cb2d06ae01ae +# Source-Hash: f02d6cdfb4c6ad08 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Advanced" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show step supports" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.advanced.qwfkor" -msgstr "Avanzado" +msgid "editor.inspector.field.showStepSupports.1kg8h8m" +msgstr "Mostrar soportes de peldaño" -# Source-Hash: a886619d15bae47e +# Source-Hash: 5d1147c774718b76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Air" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Side flashing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.air.15jotdj" -msgstr "Aire" +msgid "editor.inspector.field.sideFlashing.cv744o" +msgstr "Tapajuntas lateral" -# Source-Hash: b69fc1f8128958fc +# Source-Hash: 60bb3338e0ad558c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Appearance" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Size" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.appearance.dli9wf" -msgstr "Apariencia" +msgid "editor.inspector.field.size.1a4x3zw" +msgstr "Tamaño" -# Source-Hash: faaa4f6b40001667 +# Source-Hash: fbdbc6c97c75b030 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Body" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Skylight type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.body.ign4wl" -msgstr "Cuerpo" +msgid "editor.inspector.field.skylightType.1a5vj3i" +msgstr "Tipo de claraboya" -# Source-Hash: fdf7108a011bd94b +# Source-Hash: c9a6561cb3c3da82 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cab" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab opening mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.cab.o4z1ox" -msgstr "Cabina" +msgid "editor.inspector.field.slabOpeningMode.g4f730" +msgstr "Modo de hueco en forjado" -# Source-Hash: 5737c4567e0f6863 +# Source-Hash: ef0efc845ccdba78 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slat gap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.cabinet.rzvymr" -msgstr "Mueble" +msgid "editor.inspector.field.slatGap.slmk93" +msgstr "Separación de lamas" -# Source-Hash: d52b53241789ee63 +# Source-Hash: 4daab7a2ce2ecef3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slide direction" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.cap.s0thej" -msgstr "Remate" +msgid "editor.inspector.field.slideDirection.1527q13" +msgstr "Dirección de deslizamiento" -# Source-Hash: 93a545688c917e69 +# Source-Hash: 93b34a5b546664c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Span" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.collar.1am2iqo" -msgstr "Collarín" +msgid "editor.inspector.field.span.1bmmuw1" +msgstr "Luz" -# Source-Hash: 7a9c55b1c5a6e61d +# Source-Hash: 3b006be0b1f0493f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connection" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Speed" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.connection.2r1h4p" -msgstr "Conexión" +msgid "editor.inspector.field.speed.2w2xwg" +msgstr "Velocidad" -# Source-Hash: d613df280aa13b42 +# Source-Hash: c8cfb8336a240cb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connections" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spin speed" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.connections.ai4w8u" -msgstr "Conexiones" +msgid "editor.inspector.field.spinSpeed.1ozx746" +msgstr "Velocidad de giro" -# Source-Hash: ce1429556f57d7ee +# Source-Hash: c9f54c3b258961c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Construction" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.construction.j6p9kc" -msgstr "Construcción" +msgid "editor.inspector.field.stairType.1u05e02" +msgstr "Tipo de escalera" -# Source-Hash: f8ba7d73d3006d57 +# Source-Hash: 0af6194a8b8d8be6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standoff" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.cricket.6iwg8g" -msgstr "Caballete desviador" +msgid "editor.inspector.field.standoff.4wv2g0" +msgstr "Separador" -# Source-Hash: b8ff053666ee326b +# Source-Hash: 0464d4efa1e80c62 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curb" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standoff height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.curb.5xi2ol" -msgstr "Bordillo" +msgid "editor.inspector.field.standoffHeight.1qdnff" +msgstr "Altura del separador" -# Source-Hash: 3b9c59e996dcc9c5 +# Source-Hash: 85da28b0b26b8c2a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curve points" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start post" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.curvePoints.ztdcnn" -msgstr "Puntos de curva" +msgid "editor.inspector.field.startPost.1ood9kv" +msgstr "Poste inicial" -# Source-Hash: 12df69f42beb0643 +# Source-Hash: d5dc1ba8cca3193d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Step count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.dimensions.pewa8g" -msgstr "Dimensiones" +msgid "editor.inspector.field.stepCount.nzorrw" +msgstr "Número de peldaños" -# Source-Hash: 20f60b98de67849b +# Source-Hash: cadbb9cadd6a5e6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Doors" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Strap spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.doors.18w2kpa" -msgstr "Puertas" +msgid "editor.inspector.field.strapSpacing.1cyt3dc" +msgstr "Separación de flejes" -# Source-Hash: 6b6f8068bbc4c902 +# Source-Hash: c017cd56b3ae5865 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dormer" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Strap style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.dormer.1fjs5tq" -msgstr "Buhardilla" +msgid "editor.inspector.field.strapStyle.fh1oy4" +msgstr "Estilo de fleje" -# Source-Hash: cda262793b4cc754 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dormer roof" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.dormerRoof.u9uy2g" -msgstr "Cubierta de buhardilla" +msgid "editor.inspector.field.style.nf3vcm" +msgstr "Estilo" -# Source-Hash: 00a4416e0a33d856 +# Source-Hash: 7b3f016989c631a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drainage" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Suction diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.drainage.7easy0" -msgstr "Desagüe" +msgid "editor.inspector.field.suctionDiameter.nutxtj" +msgstr "Diámetro de aspiración" -# Source-Hash: 8a3bc5111b9e97f4 +# Source-Hash: 3f1e0fd30e5b1f39 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.elevation.4jbp44" -msgstr "Cota" +msgid "editor.inspector.field.supplyDiameter.h5ldh5" +msgstr "Diámetro de impulsión" -# Source-Hash: a9cba06250228a55 +# Source-Hash: 05c9b608538e181d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End caps" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.endCaps.4fsb5b" -msgstr "Tapas finales" +msgid "editor.inspector.field.supplyHeight.zy6ru1" +msgstr "Altura de impulsión" -# Source-Hash: 228f2206862e41cf +# Source-Hash: 3c9400722baa474d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equipment" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.equipment.1xtq0ev" -msgstr "Equipo" +msgid "editor.inspector.field.supplyShape.k39wnb" +msgstr "Forma de impulsión" -# Source-Hash: a19276baa3688cbf +# Source-Hash: af7619025438f995 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Face" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.face.1531fr0" -msgstr "Cara" +msgid "editor.inspector.field.supplyWidth.g66axi" +msgstr "Ancho de impulsión" -# Source-Hash: fb34ee7c59cb84ac +# Source-Hash: 617e198cf3f214d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fitting" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Support offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.fitting.171z1r4" -msgstr "Accesorio" +msgid "editor.inspector.field.supportOffset.1w4cocr" +msgstr "Desfase del soporte" -# Source-Hash: f817c09ef0bb6d69 +# Source-Hash: 2686abc093f3dfb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flues" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sweep angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.flues.nq6pye" -msgstr "Conductos" +msgid "editor.inspector.field.sweepAngle.ucmmlw" +msgstr "Ángulo de barrido" -# Source-Hash: a3c10560fa3c1612 +# Source-Hash: 88e6c2e1c344b2fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Footprint" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.footprint.g8q2pg" -msgstr "Huella" +msgid "editor.inspector.field.system.13qbhrw" +msgstr "Sistema" -# Source-Hash: ce3a6c03765dbbd8 +# Source-Hash: ccb3afc48bd9a284 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terminal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.frame.q7q9fq" -msgstr "Marco" +msgid "editor.inspector.field.terminal.1501knl" +msgstr "Terminal" -# Source-Hash: 523b9912e283b644 +# Source-Hash: de1777c521046f7d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Geometry" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terminal type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.geometry.a21os1" -msgstr "Geometría" +msgid "editor.inspector.field.terminalType.1ne8lgb" +msgstr "Tipo de terminal" -# Source-Hash: 7e4a0a38f694be6b +# Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.grid.d8gwxd" -msgstr "Cuadrícula" +msgid "editor.inspector.field.thickness.1l8hu45" +msgstr "Espesor" -# Source-Hash: 30d8dba84c42040e +# Source-Hash: 58cb60c14826f1d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hangers" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilt angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.hangers.agnfzn" -msgstr "Colgadores" +msgid "editor.inspector.field.tiltAngle.1312yw1" +msgstr "Ángulo de inclinación" -# Source-Hash: 8c1bc3a078056ff7 +# Source-Hash: 7057972ff4c78dc7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hardware" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "To level id" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.hardware.1nygwm1" -msgstr "Herrajes" +msgid "editor.inspector.field.toLevelId.8i5qx7" +msgstr "ID de planta de destino" -# Source-Hash: 2a47557eb4a5f766 +# Source-Hash: fa8fc3d5c612e774 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hung wall" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top landing depth" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.hungWall.1ftr1gz" -msgstr "Muro colgado" +msgid "editor.inspector.field.topLandingDepth.ki7gk2" +msgstr "Profundidad del descansillo superior" -# Source-Hash: 7d6ed24c02ab0c5c +# Source-Hash: 6e4a0b98089ec2cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Insulation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top landing mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.insulation.1kyo5e7" -msgstr "Aislamiento" +msgid "editor.inspector.field.topLandingMode.zk0h7e" +msgstr "Modo del descansillo superior" -# Source-Hash: d4c6c2495c233bb5 +# Source-Hash: c182bb3c8a701085 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top rail height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.lantern.1h7o2xb" -msgstr "Linterna" +msgid "editor.inspector.field.topRailHeight.fscisv" +msgstr "Altura del travesaño superior" -# Source-Hash: cc3d601d59e2e26c +# Source-Hash: 8c5502f1d8087b7b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Levels" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transition mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.levels.1s6yaru" -msgstr "Plantas" +msgid "editor.inspector.field.transitionMode.f3evgt" +msgstr "Modo de transición" -# Source-Hash: 1a849e52a46d5087 +# Source-Hash: 96eb5997f0aa2dde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Line" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transition width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.line.166mv5z" -msgstr "Línea" +msgid "editor.inspector.field.transitionWidth.rtgz3m" +msgstr "Ancho de transición" -# Source-Hash: 9ab4f7a738ebee13 +# Source-Hash: 812d27902509339f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lines" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vane count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.lines.12bghr0" -msgstr "Líneas" +msgid "editor.inspector.field.vaneCount.55vtye" +msgstr "Número de álabes" -# Source-Hash: c0ff16d77ebc9593 +# Source-Hash: 1e7dcd717c8ac239 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Motion" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.motion.1be7sjr" -msgstr "Movimiento" +msgid "editor.inspector.field.wallHeight.18vmh5c" +msgstr "Altura del muro" -# Source-Hash: 81d365ccef73068c +# Source-Hash: f14bdaed6101896a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall shell" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.mounting.feutd2" -msgstr "Montaje" +msgid "editor.inspector.field.wallShell.vqsyhv" +msgstr "Envolvente del muro" -# Source-Hash: e04298381837252f +# Source-Hash: 801268585c9a679b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall skirt height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.opening.dfet3" -msgstr "Abertura" +msgid "editor.inspector.field.wallSkirtHeight.1uea2ad" +msgstr "Altura del zócalo" -# Source-Hash: f46314c54627858d +# Source-Hash: 6b377d0ba1565477 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel dimensions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.panelDimensions.b59qe6" -msgstr "Dimensiones del panel" - -# Source-Hash: 4712c449e9a42d3b +msgid "editor.inspector.field.wallThickness.17wn4iv" +msgstr "Espesor del muro" + +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern distribution" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.patternDistribution.fmam51" -msgstr "Distribución del patrón" +msgid "editor.inspector.field.width.gfxz9b" +msgstr "Ancho" -# Source-Hash: b3be684ac62fbf53 +# Source-Hash: de05070474f589b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width2" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.placement.13lcvts" -msgstr "Colocación" +msgid "editor.inspector.field.width2.1nqawvr" +msgstr "Ancho 2" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: 6199b641888a83fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "With back" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.position.1quewx6" -msgstr "Posición" +msgid "editor.inspector.field.withBack.1ay8nus" +msgstr "Con trasera" -# Source-Hash: 96ad4bd0f7baa40e +# Source-Hash: 699934d8b9571b64 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "With bottom" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.profile.1kwlci6" -msgstr "Perfil" +msgid "editor.inspector.field.withBottom.1x1z1vo" +msgstr "Con base" -# Source-Hash: 240ed9c77627b9a1 +# Source-Hash: 03987b9aadaab50f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "With sides" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.railing.19a5bnr" -msgstr "Barandilla" +msgid "editor.inspector.field.withSides.uq066x" +msgstr "Con laterales" -# Source-Hash: 2e0aa7113b021c67 +# Source-Hash: f571cb2d06ae01ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Advanced" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.return.1klrjrz" -msgstr "Retorno" +msgid "editor.inspector.group.advanced.qwfkor" +msgstr "Avanzado" -# Source-Hash: 83909f82446ee9c3 +# Source-Hash: a886619d15bae47e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Settings" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Air" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.settings.ktdb8o" -msgstr "Ajustes" +msgid "editor.inspector.group.air.15jotdj" +msgstr "Aire" -# Source-Hash: 4fc63ad21de30103 +# Source-Hash: b69fc1f8128958fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Appearance" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.shaft.mad9cv" -msgstr "Hueco" +msgid "editor.inspector.group.appearance.dli9wf" +msgstr "Apariencia" -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: faaa4f6b40001667 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Body" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.shape.iq9t52" -msgstr "Forma" +msgid "editor.inspector.group.body.ign4wl" +msgstr "Cuerpo" -# Source-Hash: 8c6e3985459dacf9 +# Source-Hash: fdf7108a011bd94b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cab" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.shoulder.1nyfx25" -msgstr "Hombro" +msgid "editor.inspector.group.cab.o4z1ox" +msgstr "Cabina" -# Source-Hash: 60bb3338e0ad558c +# Source-Hash: 5737c4567e0f6863 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Size" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.size.1a4x3zw" -msgstr "Tamaño" +msgid "editor.inspector.group.cabinet.rzvymr" +msgstr "Mueble" -# Source-Hash: a20c89205a4448d2 +# Source-Hash: d52b53241789ee63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.structure.gezdra" -msgstr "Estructura" +msgid "editor.inspector.group.cap.s0thej" +msgstr "Remate" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: 93a545688c917e69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.style.nf3vcm" -msgstr "Estilo" +msgid "editor.inspector.group.collar.1am2iqo" +msgstr "Collarín" -# Source-Hash: b45f382a67d6c0eb +# Source-Hash: 7a9c55b1c5a6e61d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connection" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.supply.1oy2zwu" -msgstr "Impulsión" +msgid "editor.inspector.group.connection.2r1h4p" +msgstr "Conexión" -# Source-Hash: 78a454b7ac7a3cd9 +# Source-Hash: d613df280aa13b42 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connections" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.surface.wtamqk" -msgstr "Superficie" +msgid "editor.inspector.group.connections.ai4w8u" +msgstr "Conexiones" -# Source-Hash: ccb3afc48bd9a284 +# Source-Hash: ce1429556f57d7ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terminal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Construction" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.terminal.1501knl" -msgstr "Terminal" +msgid "editor.inspector.group.construction.j6p9kc" +msgstr "Construcción" -# Source-Hash: 399fc3e62f491f08 +# Source-Hash: f8ba7d73d3006d57 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Topology" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.topology.18t8dyc" -msgstr "Topología" +msgid "editor.inspector.group.cricket.6iwg8g" +msgstr "Caballete desviador" -# Source-Hash: f425799b82e085ed +# Source-Hash: b8ff053666ee326b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transform" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curb" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.transform.1c55ayj" -msgstr "Transformación" +msgid "editor.inspector.group.curb.5xi2ol" +msgstr "Bordillo" -# Source-Hash: b778a315e82065a0 +# Source-Hash: 3b9c59e996dcc9c5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curve points" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.trap.1qc7vhe" -msgstr "Sifón" +msgid "editor.inspector.group.curvePoints.ztdcnn" +msgstr "Puntos de curva" -# Source-Hash: c44f7ab8bbd24858 +# Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.type.1m2zofh" -msgstr "Tipo" +msgid "editor.inspector.group.dimensions.pewa8g" +msgstr "Dimensiones" -# Source-Hash: c8fd17853839516f +# Source-Hash: 20f60b98de67849b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Abs" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Doors" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.abs.132mz8b" -msgstr "ABS" +msgid "editor.inspector.group.doors.18w2kpa" +msgstr "Puertas" -# Source-Hash: fd9eb1a16cb6b996 +# Source-Hash: 6b6f8068bbc4c902 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Access panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dormer" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.accessPanel.13sptb5" -msgstr "Registro de acceso" +msgid "editor.inspector.group.dormer.1fjs5tq" +msgstr "Buhardilla" -# Source-Hash: db8064add8c27a5c +# Source-Hash: cda262793b4cc754 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Air handler" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dormer roof" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.airHandler.1crnyg3" -msgstr "Unidad de tratamiento de aire" +msgid "editor.inspector.group.dormerRoof.u9uy2g" +msgstr "Cubierta de buhardilla" -# Source-Hash: d8234782848be927 +# Source-Hash: 00a4416e0a33d856 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Alternating" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drainage" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.alternating.5jashi" -msgstr "Alterno" +msgid "editor.inspector.group.drainage.7easy0" +msgstr "Desagüe" -# Source-Hash: 63cbda7b09662368 +# Source-Hash: 8a3bc5111b9e97f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arched" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.arched.14188w0" -msgstr "En arco" +msgid "editor.inspector.group.elevation.4jbp44" +msgstr "Cota" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: a9cba06250228a55 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End caps" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.auto.540b06" -msgstr "Auto" +msgid "editor.inspector.group.endCaps.4fsb5b" +msgstr "Tapas finales" -# Source-Hash: d18036b75b2c3e4f +# Source-Hash: 228f2206862e41cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Automatic" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equipment" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.automatic.r122ro" -msgstr "Automático" +msgid "editor.inspector.group.equipment.1xtq0ev" +msgstr "Equipo" -# Source-Hash: 7ceade8f25b58fe9 +# Source-Hash: a19276baa3688cbf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Face" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.back.1hzmxtu" -msgstr "Volver" +msgid "editor.inspector.group.face.1531fr0" +msgstr "Cara" -# Source-Hash: 3eda29328f91485d +# Source-Hash: fb34ee7c59cb84ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Balusters" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fitting" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.balusters.1j3w6ng" -msgstr "Balaustres" +msgid "editor.inspector.group.fitting.171z1r4" +msgstr "Accesorio" -# Source-Hash: f211248ec8619e4c +# Source-Hash: f817c09ef0bb6d69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Band" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flues" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.band.160umau" -msgstr "Banda" +msgid "editor.inspector.group.flues.nq6pye" +msgstr "Conductos" -# Source-Hash: 8f9ff05c6a3b08a6 +# Source-Hash: a3c10560fa3c1612 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base plate" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Footprint" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.basePlate.17fcg8k" -msgstr "Placa base" +msgid "editor.inspector.group.footprint.g8q2pg" +msgstr "Huella" -# Source-Hash: 19ae2360207ecf5a +# Source-Hash: ce3a6c03765dbbd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Boards" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.boards.u14hig" -msgstr "Tablas" +msgid "editor.inspector.group.frame.q7q9fq" +msgstr "Marco" -# Source-Hash: c0fee00bdfb09d37 +# Source-Hash: 523b9912e283b644 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bookshelf" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Geometry" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.bookshelf.ls0zqk" -msgstr "Estantería" +msgid "editor.inspector.group.geometry.a21os1" +msgstr "Geometría" -# Source-Hash: 69578b7dd7723fa1 +# Source-Hash: 7e4a0a38f694be6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Both" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.both.mkyb42" -msgstr "Ambos" +msgid "editor.inspector.group.grid.d8gwxd" +msgstr "Cuadrícula" -# Source-Hash: b3a163b453896bef +# Source-Hash: 30d8dba84c42040e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hangers" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.bottom.9mpruy" -msgstr "Inferior" +msgid "editor.inspector.group.hangers.agnfzn" +msgstr "Colgadores" -# Source-Hash: e9a89a5e4ac8cd61 +# Source-Hash: 8c1bc3a078056ff7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hardware" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.box.1nbjcuq" -msgstr "Caja" +msgid "editor.inspector.group.hardware.1nygwm1" +msgstr "Herrajes" -# Source-Hash: 2c2815df4f724abe +# Source-Hash: 2a47557eb4a5f766 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Break" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hung wall" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.break.17spnvc" -msgstr "Corte" +msgid "editor.inspector.group.hungWall.1ftr1gz" +msgstr "Muro colgado" -# Source-Hash: 0d5a25303d3d8058 +# Source-Hash: 7d6ed24c02ab0c5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Butterfly" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.butterfly.pvv0g4" -msgstr "Mariposa" +msgid "editor.inspector.group.insulation.1kyo5e7" +msgstr "Aislamiento" -# Source-Hash: 5e2429ced8144ab4 +# Source-Hash: d4c6c2495c233bb5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cable" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cable.fp50zq" -msgstr "Cable" +msgid "editor.inspector.group.lantern.1h7o2xb" +msgstr "Linterna" -# Source-Hash: 69129e514347672a +# Source-Hash: cc3d601d59e2e26c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cast iron" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Levels" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.castIron.1q2z4qk" -msgstr "Fundición" +msgid "editor.inspector.group.levels.1s6yaru" +msgstr "Plantas" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: 1a849e52a46d5087 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Line" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.ceiling.1t2zaqo" -msgstr "Techo" +msgid "editor.inspector.group.line.166mv5z" +msgstr "Línea" -# Source-Hash: 5211341ed18f33f6 +# Source-Hash: 9ab4f7a738ebee13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lines" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.center.kzdxno" -msgstr "Centro" +msgid "editor.inspector.group.lines.12bghr0" +msgstr "Líneas" -# Source-Hash: 65f410261609060b +# Source-Hash: c0ff16d77ebc9593 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center opening" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Motion" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.centerOpening.bn1rvw" -msgstr "Apertura central" +msgid "editor.inspector.group.motion.1be7sjr" +msgstr "Movimiento" -# Source-Hash: cf5f9756cc866f3e +# Source-Hash: 81d365ccef73068c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cleanout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cleanout.lww8bm" -msgstr "Registro de limpieza" +msgid "editor.inspector.group.mounting.feutd2" +msgstr "Montaje" -# Source-Hash: e71d1d949f1d1b41 +# Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Concrete pad" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.concretePad.m1zdij" -msgstr "Losa de hormigón" +msgid "editor.inspector.group.opening.dfet3" +msgstr "Abertura" -# Source-Hash: a3804c4f5e6aefbc +# Source-Hash: f46314c54627858d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Condenser" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel dimensions" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.condenser.a74nps" -msgstr "Condensador" +msgid "editor.inspector.group.panelDimensions.b59qe6" +msgstr "Dimensiones del panel" -# Source-Hash: 6786ac75cbe9af57 +# Source-Hash: 4712c449e9a42d3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corbeled" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern distribution" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.corbeled.bovs4v" -msgstr "Con ménsulas" +msgid "editor.inspector.group.patternDistribution.fmam51" +msgstr "Distribución del patrón" -# Source-Hash: 8a4beb9a57edc26e +# Source-Hash: b3be684ac62fbf53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.count.1qoi4r8" -msgstr "Cantidad" +msgid "editor.inspector.group.placement.13lcvts" +msgstr "Colocación" -# Source-Hash: db1f8f141714b363 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Coupling" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.coupling.111aap2" -msgstr "Manguito" +msgid "editor.inspector.group.position.1quewx6" +msgstr "Posición" -# Source-Hash: 7a9a92d2e59a3bbc +# Source-Hash: 96ad4bd0f7baa40e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Covering specific" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.coveringSpecific.1h9fo8w" -msgstr "Específico del revestimiento" +msgid "editor.inspector.group.profile.1kwlci6" +msgstr "Perfil" -# Source-Hash: d500c4b7827d3390 +# Source-Hash: 240ed9c77627b9a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cross" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cross.1elubzv" -msgstr "Cruz" +msgid "editor.inspector.group.railing.19a5bnr" +msgstr "Barandilla" -# Source-Hash: 7ca7f00b3ba531f4 +# Source-Hash: 2e0aa7113b021c67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cubby" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cubby.ivq4qc" -msgstr "Hueco" +msgid "editor.inspector.group.return.1klrjrz" +msgstr "Retorno" -# Source-Hash: a028e08962c388e0 +# Source-Hash: 83909f82446ee9c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curved" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Settings" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.curved.6noz1s" -msgstr "Curvo" +msgid "editor.inspector.group.settings.ktdb8o" +msgstr "Ajustes" -# Source-Hash: c65f02bcdc3231d6 +# Source-Hash: 4fc63ad21de30103 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cylinder" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cylinder.eol6vj" -msgstr "Cilindro" +msgid "editor.inspector.group.shaft.mad9cv" +msgstr "Hueco" -# Source-Hash: 53f224e2828d5ab7 +# Source-Hash: 85ea1d3c8b749680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Damper" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.damper.wgri80" -msgstr "Compuerta" +msgid "editor.inspector.group.shape.iq9t52" +msgstr "Forma" -# Source-Hash: 748877ae309c313c +# Source-Hash: 8c6e3985459dacf9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Destination" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.destination.gfzm1r" -msgstr "Destino" +msgid "editor.inspector.group.shoulder.1nyfx25" +msgstr "Hombro" -# Source-Hash: bfb3561e28d92a39 +# Source-Hash: 60bb3338e0ad558c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diffuser" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Size" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.diffuser.1igj0jh" -msgstr "Difusor" +msgid "editor.inspector.group.size.1a4x3zw" +msgstr "Tamaño" -# Source-Hash: 6cff941e10ff22b3 +# Source-Hash: a20c89205a4448d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dog ear" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.dogEar.xhtvjt" -msgstr "Oreja de perro" +msgid "editor.inspector.group.structure.gezdra" +msgstr "Estructura" -# Source-Hash: de47e23eb81efe02 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dome" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.dome.1c87e56" -msgstr "Cúpula" +msgid "editor.inspector.group.style.nf3vcm" +msgstr "Estilo" -# Source-Hash: 3cd71355956a1821 +# Source-Hash: b45f382a67d6c0eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.double.13h5354" -msgstr "Doble" +msgid "editor.inspector.group.supply.1oy2zwu" +msgstr "Impulsión" -# Source-Hash: 72a84a9762461745 +# Source-Hash: 78a454b7ac7a3cd9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct board" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.ductBoard.lc3o4t" -msgstr "Panel de conducto" +msgid "editor.inspector.group.surface.wtamqk" +msgstr "Superficie" -# Source-Hash: 6949d667043bee0b +# Source-Hash: ccb3afc48bd9a284 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terminal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.dutch.1djx429" -msgstr "Holandesa" +msgid "editor.inspector.group.terminal.1501knl" +msgstr "Terminal" -# Source-Hash: e6637bddef6aabd6 +# Source-Hash: 399fc3e62f491f08 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elbow" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Topology" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.elbow.1flup74" -msgstr "Codo" +msgid "editor.inspector.group.topology.18t8dyc" +msgstr "Topología" -# Source-Hash: 135874d189176d13 +# Source-Hash: f425799b82e085ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transform" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.end.1llf32i" -msgstr "Final" +msgid "editor.inspector.group.transform.1c55ayj" +msgstr "Transformación" -# Source-Hash: ada9fc2eec2c7d61 +# Source-Hash: b778a315e82065a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End cap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.endCap.1p4v4na" -msgstr "Tapa final" +msgid "editor.inspector.group.trap.1qc7vhe" +msgstr "Sifón" -# Source-Hash: 73916b8395208874 +# Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equal fit" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.equalFit.11vw52c" -msgstr "Ajuste igual" +msgid "editor.inspector.group.type.1m2zofh" +msgstr "Tipo" -# Source-Hash: 83579a6e420df2ec +# Source-Hash: c8fd17853839516f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fixed count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Abs" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.fixedCount.1o3dznu" -msgstr "Cantidad fija" +msgid "editor.inspector.option.abs.132mz8b" +msgstr "ABS" -# Source-Hash: 4fb65101d0b1a222 +# Source-Hash: fd9eb1a16cb6b996 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fixed spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Access panel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.fixedSpacing.hl4dr4" -msgstr "Separación fija" +msgid "editor.inspector.option.accessPanel.13sptb5" +msgstr "Registro de acceso" -# Source-Hash: 9cab4d4c95f63cdd +# Source-Hash: db8064add8c27a5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Air handler" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.flat.ly0bei" -msgstr "Plana" +msgid "editor.inspector.option.airHandler.1crnyg3" +msgstr "Unidad de tratamiento de aire" -# Source-Hash: a9cad0badcc16693 +# Source-Hash: d8234782848be927 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flex" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Alternating" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.flex.ktpamq" -msgstr "Flexible" +msgid "editor.inspector.option.alternating.5jashi" +msgstr "Alterno" -# Source-Hash: 7843c5142b7d066d +# Source-Hash: 63cbda7b09662368 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floating" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arched" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.floating.1oadpln" -msgstr "Flotante" +msgid "editor.inspector.option.arched.14188w0" +msgstr "En arco" -# Source-Hash: d7148fa065bc709b +# Source-Hash: 05b65242d8c48791 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.floor.q9caf1" -msgstr "Planta" +msgid "editor.inspector.option.auto.540b06" +msgstr "Auto" -# Source-Hash: eaaa20f3b603140f +# Source-Hash: d18036b75b2c3e4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flush" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Automatic" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.flush.olwwu5" -msgstr "Enrasado" +msgid "editor.inspector.option.automatic.r122ro" +msgstr "Automático" -# Source-Hash: e360f89d3c0ec456 +# Source-Hash: 7ceade8f25b58fe9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.front.uhugl4" -msgstr "Frente" +msgid "editor.inspector.option.back.1hzmxtu" +msgstr "Volver" -# Source-Hash: bccfc0565157dae6 +# Source-Hash: 3eda29328f91485d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Furnace" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Balusters" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.furnace.w0mzpf" -msgstr "Caldera de aire" +msgid "editor.inspector.option.balusters.1j3w6ng" +msgstr "Balaustres" -# Source-Hash: deaffa095d126dfe +# Source-Hash: f211248ec8619e4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Band" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.gable.1ekyx6" -msgstr "Dos aguas" +msgid "editor.inspector.option.band.160umau" +msgstr "Banda" -# Source-Hash: 7f53d9ffca39984a +# Source-Hash: 8f9ff05c6a3b08a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base plate" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.gambrel.1yo90d9" -msgstr "Holandés de buhardilla" +msgid "editor.inspector.option.basePlate.17fcg8k" +msgstr "Placa base" -# Source-Hash: 3c4900155c96b139 +# Source-Hash: 19ae2360207ecf5a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Generic" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Boards" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.generic.1074oey" -msgstr "Genérico" +msgid "editor.inspector.option.boards.u14hig" +msgstr "Tablas" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: c0fee00bdfb09d37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bookshelf" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.glass.163tc5n" -msgstr "Vidrio" +msgid "editor.inspector.option.bookshelf.ls0zqk" +msgstr "Estantería" -# Source-Hash: 88810658a2b97bc6 +# Source-Hash: 69578b7dd7723fa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass frame" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Both" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.glassFrame.jp9s3m" -msgstr "Marco de vidrio" +msgid "editor.inspector.option.both.mkyb42" +msgstr "Ambos" -# Source-Hash: 2d4223f80dc3945c +# Source-Hash: b3a163b453896bef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Globe" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.globe.1avkqoy" -msgstr "Globo" +msgid "editor.inspector.option.bottom.9mpruy" +msgstr "Inferior" -# Source-Hash: 398af4f45ba60c85 +# Source-Hash: e9a89a5e4ac8cd61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grounded" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.grounded.jwoq73" -msgstr "Apoyado en el suelo" +msgid "editor.inspector.option.box.1nbjcuq" +msgstr "Caja" -# Source-Hash: 4972a0e68d69be58 +# Source-Hash: 2c2815df4f724abe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guard" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Break" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.guard.1m575se" -msgstr "Barandilla" +msgid "editor.inspector.option.break.17spnvc" +msgstr "Corte" -# Source-Hash: 67be98efb58a7767 +# Source-Hash: 0d5a25303d3d8058 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Half round" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Butterfly" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.halfRound.m5hob0" -msgstr "Media caña" +msgid "editor.inspector.option.butterfly.pvv0g4" +msgstr "Mariposa" -# Source-Hash: 229199467e9cf2db +# Source-Hash: 5e2429ced8144ab4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hidden" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cable" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.hidden.gp48rd" -msgstr "Oculto" +msgid "editor.inspector.option.cable.fp50zq" +msgstr "Cable" -# Source-Hash: 9eda0ea8d447066d +# Source-Hash: 69129e514347672a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hip" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cast iron" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.hip.r0jnjy" -msgstr "Cuatro aguas" +msgid "editor.inspector.option.castIron.1q2z4qk" +msgstr "Fundición" -# Source-Hash: ac9c79f08ef130a1 +# Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Horizontal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.horizontal.tyapah" -msgstr "Horizontal" +msgid "editor.inspector.option.ceiling.1t2zaqo" +msgstr "Techo" -# Source-Hash: 6a9b4142ab179557 +# Source-Hash: 5211341ed18f33f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Include" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.include.1a27vnr" -msgstr "Incluir" +msgid "editor.inspector.option.center.kzdxno" +msgstr "Centro" -# Source-Hash: 8061b426b9d1b5fa +# Source-Hash: 65f410261609060b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Independent high beam" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center opening" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.independentHighBeam.1tn0zvy" -msgstr "Viga alta independiente" +msgid "editor.inspector.option.centerOpening.bn1rvw" +msgstr "Apertura central" -# Source-Hash: 1dc686f2068f976b +# Source-Hash: cf5f9756cc866f3e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Industrial" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cleanout" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.industrial.8sd9u" -msgstr "Industrial" +msgid "editor.inspector.option.cleanout.lww8bm" +msgstr "Registro de limpieza" -# Source-Hash: 0c9b1ec8947ee177 +# Source-Hash: e71d1d949f1d1b41 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inline" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Concrete pad" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.inline.1uh05lg" -msgstr "En línea" +msgid "editor.inspector.option.concretePad.m1zdij" +msgstr "Losa de hormigón" -# Source-Hash: 88d5b9ecb242c650 +# Source-Hash: a3804c4f5e6aefbc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Integrated" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Condenser" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.integrated.1xd9lv0" -msgstr "Integrado" +msgid "editor.inspector.option.condenser.a74nps" +msgstr "Condensador" -# Source-Hash: bb197b9219f32603 +# Source-Hash: 6786ac75cbe9af57 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Joined" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corbeled" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.joined.1x2o8ds" -msgstr "Unido" +msgid "editor.inspector.option.corbeled.bovs4v" +msgstr "Con ménsulas" -# Source-Hash: 0299cc0ee05d17fc +# Source-Hash: 8a4beb9a57edc26e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kickout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.kickout.vt8s6p" -msgstr "Desviador" +msgid "editor.inspector.option.count.1qoi4r8" +msgstr "Cantidad" -# Source-Hash: a0712c8461bb0758 +# Source-Hash: db1f8f141714b363 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Knee" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Coupling" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.knee.186hcui" -msgstr "Rodilla" +msgid "editor.inspector.option.coupling.111aap2" +msgstr "Manguito" -# Source-Hash: 083febe9876348ec +# Source-Hash: 7a9a92d2e59a3bbc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "K style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Covering specific" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.kStyle.m8kfwz" -msgstr "Estilo K" +msgid "editor.inspector.option.coveringSpecific.1h9fo8w" +msgstr "Específico del revestimiento" -# Source-Hash: de9566487b17a73b +# Source-Hash: d500c4b7827d3390 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cross" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.landing.tyqarg" -msgstr "Descansillo" +msgid "editor.inspector.option.cross.1elubzv" +msgstr "Cruz" -# Source-Hash: d4c6c2495c233bb5 +# Source-Hash: 7ca7f00b3ba531f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cubby" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.lantern.1h7o2xb" -msgstr "Linterna" +msgid "editor.inspector.option.cubby.ivq4qc" +msgstr "Hueco" -# Source-Hash: 9477f663422698ae +# Source-Hash: a028e08962c388e0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Leave" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curved" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.leave.1xf0sbk" -msgstr "Salir" +msgid "editor.inspector.option.curved.6noz1s" +msgstr "Curvo" -# Source-Hash: f365c6b6dd9ebab9 +# Source-Hash: c65f02bcdc3231d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cylinder" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.left.14n06mo" -msgstr "Izquierda" +msgid "editor.inspector.option.cylinder.eol6vj" +msgstr "Cilindro" -# Source-Hash: 0608743fc1736d86 +# Source-Hash: 53f224e2828d5ab7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Damper" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.level.i4lhtp" -msgstr "Planta" +msgid "editor.inspector.option.damper.wgri80" +msgstr "Compuerta" -# Source-Hash: a281a83a9fef6b88 +# Source-Hash: 748877ae309c313c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Destination" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.lowProfile.1h9lgzg" -msgstr "Perfil bajo" +msgid "editor.inspector.option.destination.gfzm1r" +msgstr "Destino" -# Source-Hash: 7f7bb0e875af3260 +# Source-Hash: bfb3561e28d92a39 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diffuser" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.mansard.dwzck9" -msgstr "Mansarda" +msgid "editor.inspector.option.diffuser.1igj0jh" +msgstr "Difusor" -# Source-Hash: 387082cd5f118bed +# Source-Hash: 6cff941e10ff22b3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Manual" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dog ear" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.manual.1wu7r43" -msgstr "Manual" +msgid "editor.inspector.option.dogEar.xhtvjt" +msgstr "Oreja de perro" -# Source-Hash: 321ca5101ab61db7 +# Source-Hash: de47e23eb81efe02 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Maximum spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dome" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.maximumSpacing.n1fzl4" -msgstr "Separación máxima" +msgid "editor.inspector.option.dome.1c87e56" +msgstr "Cúpula" -# Source-Hash: 8e464a8f52254f27 +# Source-Hash: 3cd71355956a1821 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Metal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.metal.1az9fgc" -msgstr "Metal" +msgid "editor.inspector.option.double.13h5354" +msgstr "Doble" -# Source-Hash: c6185ecb219a9435 +# Source-Hash: 72a84a9762461745 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Metal panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct board" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.metalPanel.1xdz476" -msgstr "Panel metálico" +msgid "editor.inspector.option.ductBoard.lc3o4t" +msgstr "Panel de conducto" -# Source-Hash: 2fd92342f3986843 +# Source-Hash: 6949d667043bee0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Minimal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.minimal.fwmiwg" -msgstr "Mínimo" +msgid "editor.inspector.option.dutch.1djx429" +msgstr "Holandesa" -# Source-Hash: 5d8a5912056f83ce +# Source-Hash: e6637bddef6aabd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mono" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elbow" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.mono.oszvd6" -msgstr "Una vertiente" +msgid "editor.inspector.option.elbow.1flup74" +msgstr "Codo" -# Source-Hash: f2953d2931e36d0c +# Source-Hash: 135874d189176d13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.none.deku7v" -msgstr "Ninguno" +msgid "editor.inspector.option.end.1llf32i" +msgstr "Final" -# Source-Hash: 7b6e4a6b86ba5112 +# Source-Hash: ada9fc2eec2c7d61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Omit" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End cap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.omit.okcs7w" -msgstr "Omitir" +msgid "editor.inspector.option.endCap.1p4v4na" +msgstr "Tapa final" -# Source-Hash: 3e52f04f92e08070 +# Source-Hash: 73916b8395208874 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equal fit" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.open.n6hn1l" -msgstr "Abrir" +msgid "editor.inspector.option.equalFit.11vw52c" +msgstr "Ajuste igual" -# Source-Hash: e04298381837252f +# Source-Hash: 83579a6e420df2ec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fixed count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.opening.dfet3" -msgstr "Abertura" +msgid "editor.inspector.option.fixedCount.1o3dznu" +msgstr "Cantidad fija" -# Source-Hash: cc72b9bda6b30b5c +# Source-Hash: 4fb65101d0b1a222 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open rack" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fixed spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.openRack.mvt1x0" -msgstr "Estante abierto" +msgid "editor.inspector.option.fixedSpacing.hl4dr4" +msgstr "Separación fija" -# Source-Hash: ed6d7b3dd9d5fc69 +# Source-Hash: 9cab4d4c95f63cdd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Oval" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.oval.1jiqzxx" -msgstr "Óvalo" +msgid "editor.inspector.option.flat.ly0bei" +msgstr "Plana" -# Source-Hash: 9295ddc2805b21e2 +# Source-Hash: a9cad0badcc16693 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flex" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.picket.zyeoy1" -msgstr "Estacas" - -# Source-Hash: 180ffb8b75c977aa +msgid "editor.inspector.option.flex.ktpamq" +msgstr "Flexible" + +# Source-Hash: 7843c5142b7d066d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pointed" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floating" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.pointed.effedk" -msgstr "Puntiagudo" +msgid "editor.inspector.option.floating.1oadpln" +msgstr "Flotante" -# Source-Hash: fca7919fb0c0669c +# Source-Hash: d7148fa065bc709b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post and rail" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.postAndRail.lajk2u" -msgstr "Poste y travesaño" +msgid "editor.inspector.option.floor.q9caf1" +msgstr "Planta" -# Source-Hash: a78b28a428b27e20 +# Source-Hash: eaaa20f3b603140f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preserve high edge" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flush" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.preserveHighEdge.y6ywf0" -msgstr "Conservar el borde alto" +msgid "editor.inspector.option.flush.olwwu5" +msgstr "Enrasado" -# Source-Hash: 325c6f53f6dc7634 +# Source-Hash: e360f89d3c0ec456 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preserve low edge" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.preserveLowEdge.196m5pk" -msgstr "Conservar el borde bajo" +msgid "editor.inspector.option.front.uhugl4" +msgstr "Frente" -# Source-Hash: 95c0b860d22a62cb +# Source-Hash: bccfc0565157dae6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preserve pitch" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Furnace" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.preservePitch.1uq973r" -msgstr "Conservar la pendiente" +msgid "editor.inspector.option.furnace.w0mzpf" +msgstr "Caldera de aire" -# Source-Hash: d4e11841abf22593 +# Source-Hash: deaffa095d126dfe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Privacy" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.privacy.1th4hrb" -msgstr "Privacidad" +msgid "editor.inspector.option.gable.1ekyx6" +msgstr "Dos aguas" -# Source-Hash: 1a8c46c7712a83b6 +# Source-Hash: 7f53d9ffca39984a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Purlins" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.purlins.od124c" -msgstr "Correas" +msgid "editor.inspector.option.gambrel.1yo90d9" +msgstr "Holandés de buhardilla" -# Source-Hash: a9650f6f94de9247 +# Source-Hash: 3c4900155c96b139 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pvc" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Generic" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.pvc.1oc4u2w" -msgstr "PVC" +msgid "editor.inspector.option.generic.1074oey" +msgstr "Genérico" -# Source-Hash: 47587b825e9a696b +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pyramid" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.pyramid.17ucsqv" -msgstr "Pirámide" +msgid "editor.inspector.option.glass.163tc5n" +msgstr "Vidrio" -# Source-Hash: a9cb232546779779 +# Source-Hash: 88810658a2b97bc6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafters" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass frame" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.rafters.16tzbby" -msgstr "Cabios" +msgid "editor.inspector.option.glassFrame.jp9s3m" +msgstr "Marco de vidrio" -# Source-Hash: 947eacd2689daced +# Source-Hash: 2d4223f80dc3945c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rail" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Globe" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.rail.39zqc9" -msgstr "Travesaño" +msgid "editor.inspector.option.globe.1avkqoy" +msgstr "Globo" -# Source-Hash: bd50bd18e682db41 +# Source-Hash: 398af4f45ba60c85 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grounded" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.raised.4kyx9h" -msgstr "Elevado" +msgid "editor.inspector.option.grounded.jwoq73" +msgstr "Apoyado en el suelo" -# Source-Hash: 3b6f225112035fde +# Source-Hash: 4972a0e68d69be58 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rect" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guard" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.rect.tpfvaf" -msgstr "Rect." +msgid "editor.inspector.option.guard.1m575se" +msgstr "Barandilla" -# Source-Hash: 68206f70689b2340 +# Source-Hash: 67be98efb58a7767 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reducer" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Half round" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.reducer.18byt67" -msgstr "Reductor" +msgid "editor.inspector.option.halfRound.m5hob0" +msgstr "Media caña" -# Source-Hash: 2e0aa7113b021c67 +# Source-Hash: 229199467e9cf2db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hidden" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.return.1klrjrz" -msgstr "Retorno" +msgid "editor.inspector.option.hidden.gp48rd" +msgstr "Oculto" -# Source-Hash: 63b39b1681f74fe4 +# Source-Hash: 9eda0ea8d447066d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return grille" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hip" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.returnGrille.r28ncm" -msgstr "Rejilla de retorno" +msgid "editor.inspector.option.hip.r0jnjy" +msgstr "Cuatro aguas" -# Source-Hash: b34d5ee0f218221d +# Source-Hash: ac9c79f08ef130a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Horizontal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.right.8humpx" -msgstr "Derecha" +msgid "editor.inspector.option.horizontal.tyapah" +msgstr "Horizontal" -# Source-Hash: ad0457800a1f0eb4 +# Source-Hash: 6a9b4142ab179557 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Include" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.round.1vx0wyj" -msgstr "Redondo" +msgid "editor.inspector.option.include.1a27vnr" +msgstr "Incluir" -# Source-Hash: fc826da6c99303e6 +# Source-Hash: 8061b426b9d1b5fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rounded" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Independent high beam" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.rounded.199nwpm" -msgstr "Redondeado" +msgid "editor.inspector.option.independentHighBeam.1tn0zvy" +msgstr "Viga alta independiente" -# Source-Hash: dc67a1cdb2482f23 +# Source-Hash: 1dc686f2068f976b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sanitary tee" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Industrial" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.sanitaryTee.oro3d4" -msgstr "Te sanitaria" +msgid "editor.inspector.option.industrial.8sd9u" +msgstr "Industrial" -# Source-Hash: beb3fec22c287185 +# Source-Hash: 0c9b1ec8947ee177 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scalloped" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inline" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.scalloped.1eltba0" -msgstr "Festoneado" +msgid "editor.inspector.option.inline.1uh05lg" +msgstr "En línea" -# Source-Hash: e16f85e4bebfefb1 +# Source-Hash: 88d5b9ecb242c650 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scoop" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Integrated" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.scoop.qy5zdv" -msgstr "Cuchara" +msgid "editor.inspector.option.integrated.1xd9lv0" +msgstr "Integrado" -# Source-Hash: f9a95d8407fafda4 +# Source-Hash: bb197b9219f32603 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segmented panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Joined" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.segmentedPanel.5r3hwl" -msgstr "Panel segmentado" +msgid "editor.inspector.option.joined.1x2o8ds" +msgstr "Unido" -# Source-Hash: c8d0df27faa3feaa +# Source-Hash: 0299cc0ee05d17fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kickout" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.shed.6t994v" -msgstr "Un agua" +msgid "editor.inspector.option.kickout.vt8s6p" +msgstr "Desviador" -# Source-Hash: 7fbc26cd497cfd12 +# Source-Hash: a0712c8461bb0758 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sheet metal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Knee" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.sheetMetal.l164lv" -msgstr "Chapa" +msgid "editor.inspector.option.knee.186hcui" +msgstr "Rodilla" -# Source-Hash: 26e2c261223cbb46 +# Source-Hash: 083febe9876348ec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "K style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.shingle.pfmynh" -msgstr "Teja asfáltica" +msgid "editor.inspector.option.kStyle.m8kfwz" +msgstr "Estilo K" -# Source-Hash: e9046e9823b400a0 +# Source-Hash: de9566487b17a73b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingled" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.shingled.1nm9inf" -msgstr "Con tejas" +msgid "editor.inspector.option.landing.tyqarg" +msgstr "Descansillo" -# Source-Hash: a05a390ae205fdd8 +# Source-Hash: d4c6c2495c233bb5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Simple" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.simple.12mfu73" -msgstr "Sencillo" +msgid "editor.inspector.option.lantern.1h7o2xb" +msgstr "Linterna" -# Source-Hash: 62ab2eb3c775da95 +# Source-Hash: 9477f663422698ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Leave" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.single.1uzxurt" -msgstr "Simple" +msgid "editor.inspector.option.leave.1xf0sbk" +msgstr "Salir" -# Source-Hash: aee3b2bd78c87d0b +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single left" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.singleLeft.1atdh02" -msgstr "Simple izquierda" +msgid "editor.inspector.option.left.14n06mo" +msgstr "Izquierda" -# Source-Hash: cc43ffbef4ac7ae0 +# Source-Hash: 0608743fc1736d86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single right" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.singleRight.1axbu67" -msgstr "Simple derecha" +msgid "editor.inspector.option.level.i4lhtp" +msgstr "Planta" -# Source-Hash: 7672d2764445c110 +# Source-Hash: a281a83a9fef6b88 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slant box" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.slantBox.1ta99vy" -msgstr "Caja inclinada" +msgid "editor.inspector.option.lowProfile.1h9lgzg" +msgstr "Perfil bajo" -# Source-Hash: 405e07a8cc2c88e1 +# Source-Hash: 7f7bb0e875af3260 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slat" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.slat.1p9njbz" -msgstr "Lama" +msgid "editor.inspector.option.mansard.dwzck9" +msgstr "Mansarda" -# Source-Hash: 18cbc73c5e1590aa +# Source-Hash: 387082cd5f118bed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sliding" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Manual" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.sliding.cd0jox" -msgstr "Corredera" +msgid "editor.inspector.option.manual.1wu7r43" +msgstr "Manual" -# Source-Hash: e6d82e606b8c9301 +# Source-Hash: 321ca5101ab61db7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slope" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Maximum spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.slope.1bn2qw" -msgstr "Pendiente" +msgid "editor.inspector.option.maximumSpacing.n1fzl4" +msgstr "Separación máxima" -# Source-Hash: f6998707123fe72d +# Source-Hash: 8e464a8f52254f27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sloped" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Metal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.sloped.lo4sh0" -msgstr "Inclinado" +msgid "editor.inspector.option.metal.1az9fgc" +msgstr "Metal" -# Source-Hash: ef3e765e692faf4c +# Source-Hash: c6185ecb219a9435 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Metal panel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.solid.o4uy6s" -msgstr "Sólido" +msgid "editor.inspector.option.metalPanel.1xdz476" +msgstr "Panel metálico" -# Source-Hash: 8008b6f17089beaf +# Source-Hash: 2fd92342f3986843 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Minimal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.solidPanel.2yaw62" -msgstr "Panel opaco" +msgid "editor.inspector.option.minimal.fwmiwg" +msgstr "Mínimo" -# Source-Hash: f9a4a870cb3d3c41 +# Source-Hash: 5d8a5912056f83ce # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spiral" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mono" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.spiral.91hcl4" -msgstr "Helicoidal" +msgid "editor.inspector.option.mono.oszvd6" +msgstr "Una vertiente" -# Source-Hash: beef1cf79388b77b +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Splash" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.splash.1uke4cm" -msgstr "Salpicadero" +msgid "editor.inspector.option.none.deku7v" +msgstr "Ninguno" -# Source-Hash: 324677a79ab15e22 +# Source-Hash: 7b6e4a6b86ba5112 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spread" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Omit" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.spread.1g1zysu" -msgstr "Separación" +msgid "editor.inspector.option.omit.okcs7w" +msgstr "Omitir" -# Source-Hash: 39287346366fc206 +# Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.square.1xl1lk6" -msgstr "Cuadrado" +msgid "editor.inspector.option.open.n6hn1l" +msgstr "Abrir" -# Source-Hash: 53d7084bc41c1ad6 +# Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.stair.1xf86e" -msgstr "Escalera" +msgid "editor.inspector.option.opening.dfet3" +msgstr "Abertura" -# Source-Hash: d998c212030bc7c2 +# Source-Hash: cc72b9bda6b30b5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open rack" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.standard.vuco" -msgstr "Estándar" +msgid "editor.inspector.option.openRack.mvt1x0" +msgstr "Estante abierto" -# Source-Hash: 0a26a1e61c825660 +# Source-Hash: ed6d7b3dd9d5fc69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Oval" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.start.30xvgf" -msgstr "Inicio" +msgid "editor.inspector.option.oval.1jiqzxx" +msgstr "Óvalo" -# Source-Hash: ed3989f23a2d185e +# Source-Hash: 9295ddc2805b21e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Step" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.step.jtn9kf" -msgstr "Escalonado" +msgid "editor.inspector.option.picket.zyeoy1" +msgstr "Estacas" -# Source-Hash: 2c6b1cf17a973d67 +# Source-Hash: 180ffb8b75c977aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stepped" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pointed" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.stepped.naxzh0" -msgstr "Escalonado" +msgid "editor.inspector.option.pointed.effedk" +msgstr "Puntiagudo" -# Source-Hash: 4ee35f740730ae87 +# Source-Hash: fca7919fb0c0669c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post and rail" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.straight.lxqbfr" -msgstr "Recto" +msgid "editor.inspector.option.postAndRail.lajk2u" +msgstr "Poste y travesaño" -# Source-Hash: b9b45ac5ba1daeee +# Source-Hash: a78b28a428b27e20 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Strap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preserve high edge" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.strap.14q0ps9" -msgstr "Fleje" +msgid "editor.inspector.option.preserveHighEdge.y6ywf0" +msgstr "Conservar el borde alto" -# Source-Hash: b45f382a67d6c0eb +# Source-Hash: 325c6f53f6dc7634 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preserve low edge" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.supply.1oy2zwu" -msgstr "Impulsión" +msgid "editor.inspector.option.preserveLowEdge.196m5pk" +msgstr "Conservar el borde bajo" -# Source-Hash: 00e7a2b3b2aa36ac +# Source-Hash: 95c0b860d22a62cb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply register" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preserve pitch" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.supplyRegister.1lzdbbn" -msgstr "Rejilla de impulsión" +msgid "editor.inspector.option.preservePitch.1uq973r" +msgstr "Conservar la pendiente" -# Source-Hash: f86f1f22230596b7 +# Source-Hash: d4e11841abf22593 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tapered" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Privacy" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.tapered.3y5blo" -msgstr "Ahusado" +msgid "editor.inspector.option.privacy.1th4hrb" +msgstr "Privacidad" -# Source-Hash: 5fed23c2217b83fb +# Source-Hash: 1a8c46c7712a83b6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Purlins" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.targetSpacing.14uibc9" -msgstr "Separación objetivo" +msgid "editor.inspector.option.purlins.od124c" +msgstr "Correas" -# Source-Hash: f3ceed7f867f090f +# Source-Hash: a9650f6f94de9247 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tee" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pvc" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.tee.7d6tjp" -msgstr "Te" +msgid "editor.inspector.option.pvc.1oc4u2w" +msgstr "PVC" -# Source-Hash: 787005b26aec58a3 +# Source-Hash: 47587b825e9a696b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilted" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pyramid" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.tilted.6n0u5j" -msgstr "Inclinado" +msgid "editor.inspector.option.pyramid.17ucsqv" +msgstr "Pirámide" -# Source-Hash: 27644f0497fd9849 +# Source-Hash: a9cb232546779779 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafters" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.top.2nypcs" -msgstr "Superior" +msgid "editor.inspector.option.rafters.16tzbby" +msgstr "Cabios" -# Source-Hash: e6657000554dfe53 +# Source-Hash: 947eacd2689daced # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transition" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rail" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.transition.1rziz9e" -msgstr "Transición" +msgid "editor.inspector.option.rail.39zqc9" +msgstr "Travesaño" -# Source-Hash: 04bc0909a133a7e9 +# Source-Hash: bd50bd18e682db41 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vent" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.vent.xda5j2" -msgstr "Ventilación" +msgid "editor.inspector.option.raised.4kyx9h" +msgstr "Elevado" -# Source-Hash: 7eee9aff0dd520b6 +# Source-Hash: 3b6f225112035fde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walk on" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rect" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.walkOn.1n5sg9l" -msgstr "Pisar sobre" +msgid "editor.inspector.option.rect.tpfvaf" +msgstr "Rect." -# Source-Hash: 2210e5ee50b74dc9 +# Source-Hash: 68206f70689b2340 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reducer" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wall.blj585" -msgstr "Muro" +msgid "editor.inspector.option.reducer.18byt67" +msgstr "Reductor" -# Source-Hash: f3578f7177ad0054 +# Source-Hash: 2e0aa7113b021c67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall abutment" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wallAbutment.lza941" -msgstr "Encuentro con el muro" +msgid "editor.inspector.option.return.1klrjrz" +msgstr "Retorno" -# Source-Hash: 8dcf182f91ba3245 +# Source-Hash: 63b39b1681f74fe4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall ledger" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return grille" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wallLedger.5m8ana" -msgstr "Larguero de muro" +msgid "editor.inspector.option.returnGrille.r28ncm" +msgstr "Rejilla de retorno" -# Source-Hash: 0adda30be5f17975 +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall shelf" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wallShelf.yiozfl" -msgstr "Estante de pared" +msgid "editor.inspector.option.right.8humpx" +msgstr "Derecha" -# Source-Hash: 29d8590334492601 +# Source-Hash: ad0457800a1f0eb4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waste" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.waste.3xrp79" -msgstr "Desagüe" +msgid "editor.inspector.option.round.1vx0wyj" +msgstr "Redondo" -# Source-Hash: 00249876bb37079f +# Source-Hash: fc826da6c99303e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wye" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rounded" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wye.14vupc8" -msgstr "Y" +msgid "editor.inspector.option.rounded.199nwpm" +msgstr "Redondeado" -# Source-Hash: 179b025e25f9a091 +# Source-Hash: dc67a1cdb2482f23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collapse" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sanitary tee" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.collapse" -msgstr "Contraer" +msgid "editor.inspector.option.sanitaryTee.oro3d4" +msgstr "Te sanitaria" -# Source-Hash: dbeae4c43f49327f +# Source-Hash: beb3fec22c287185 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling ({area})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scalloped" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.ceiling" -msgstr "Techo ({area})" +msgid "editor.inspector.option.scalloped.1eltba0" +msgstr "Festoneado" -# Source-Hash: d29165c9d4bfc3cb +# Source-Hash: e16f85e4bebfefb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collection" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scoop" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.collection" -msgstr "Colección" +msgid "editor.inspector.option.scoop.qy5zdv" +msgstr "Cuchara" -# Source-Hash: 8f536b859be662a0 +# Source-Hash: f9a95d8407fafda4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flight ({width}×{length}m)" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segmented panel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.flight" -msgstr "Tramo ({width}×{length}m)" +msgid "editor.inspector.option.segmentedPanel.5r3hwl" +msgstr "Panel segmentado" -# Source-Hash: 46dcbf4548374073 +# Source-Hash: c8d0df27faa3feaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing ({width}×{length}m)" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.landing" -msgstr "Descansillo ({width}×{length}m)" +msgid "editor.inspector.option.shed.6t994v" +msgstr "Un agua" -# Source-Hash: 3ea44453fcd08a6e +# Source-Hash: 7fbc26cd497cfd12 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Node" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sheet metal" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.node" -msgstr "Nodo" +msgid "editor.inspector.option.sheetMetal.l164lv" +msgstr "Chapa" -# Source-Hash: 93f3a04e15b6fb49 +# Source-Hash: 26e2c261223cbb46 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof ({count, plural, one {# segment} other {# segments}})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.roof" -msgstr "Cubierta ({count, plural, one {# segmento} many {# segmentos} other {# segmentos}})" +msgid "editor.inspector.option.shingle.pfmynh" +msgstr "Teja asfáltica" -# Source-Hash: a730fab01c172704 +# Source-Hash: e9046e9823b400a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{roofType, select, hip {Hip} gable {Gable} shed {Shed} gambrel {Gambrel} dutch {Dutch} mansard {Mansard} flat {Flat} conical {Conical} barrel {Barrel} other {Roof}} ({width}×{depth}m)" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingled" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.roofSegment" -msgstr "{roofType, select, hip {A cuatro aguas} gable {A dos aguas} shed {A un agua} gambrel {Holandesa} dutch {Mixta} mansard {Mansarda} flat {Plana} conical {Cónica} barrel {Abovedada} other {Cubierta}} ({width}×{depth}m)" +msgid "editor.inspector.option.shingled.1nm9inf" +msgstr "Con tejas" -# Source-Hash: 54efcb0756c2f2c1 +# Source-Hash: a05a390ae205fdd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room ({area})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Simple" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.room" -msgstr "Estancia ({area})" +msgid "editor.inspector.option.simple.12mfu73" +msgstr "Sencillo" -# Source-Hash: e38a4b9986a9d21a +# Source-Hash: 62ab2eb3c775da95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab ({area})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.slab" -msgstr "Forjado ({area})" +msgid "editor.inspector.option.single.1uzxurt" +msgstr "Simple" -# Source-Hash: 57398365d4b9066f +# Source-Hash: aee3b2bd78c87d0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Staircase ({count, plural, one {# segment} other {# segments}})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single left" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.staircase" -msgstr "Escalera ({count, plural, one {# segmento} many {# segmentos} other {# segmentos}})" +msgid "editor.inspector.option.singleLeft.1atdh02" +msgstr "Simple izquierda" -# Source-Hash: a17f8fc29aae896e +# Source-Hash: cc43ffbef4ac7ae0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone ({area})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single right" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.zone" -msgstr "Zona ({area})" +msgid "editor.inspector.option.singleRight.1axbu67" +msgstr "Simple derecha" -# Source-Hash: 5cabcabb8bc14809 +# Source-Hash: 7672d2764445c110 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Expand" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slant box" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.expand" -msgstr "Expandir" +msgid "editor.inspector.option.slantBox.1ta99vy" +msgstr "Caja inclinada" -# Source-Hash: 6731e9dd94e8b268 +# Source-Hash: 405e07a8cc2c88e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{levelName} options" -#: packages/editor/src/components/ui/floating-level-selector.tsx -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slat" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.levelOptions" -msgstr "Opciones de {levelName}" +msgid "editor.inspector.option.slat.1p9njbz" +msgstr "Lama" -# Source-Hash: d6952b4e54d246dd +# Source-Hash: 18cbc73c5e1590aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rename" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sliding" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.rename" -msgstr "Cambiar nombre" +msgid "editor.inspector.option.sliding.cd0jox" +msgstr "Corredera" -# Source-Hash: 21eafa019ad62fea +# Source-Hash: e6d82e606b8c9301 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{role, select, room {Room colour} other {Zone colour}}" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx -#: packages/editor/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slope" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.spaceColour" -msgstr "{role, select, room {Color de la estancia} other {Color de la zona}}" +msgid "editor.inspector.option.slope.1bn2qw" +msgstr "Pendiente" -# Source-Hash: f5de042416a2c04f +# Source-Hash: f6998707123fe72d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unit colour" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sloped" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.unitColour" -msgstr "Color de la unidad" +msgid "editor.inspector.option.sloped.lo4sh0" +msgstr "Inclinado" -# Source-Hash: c0774c185060fc13 +# Source-Hash: ef3e765e692faf4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.cancel" -msgstr "Cancelar" +msgid "editor.inspector.option.solid.o4uy6s" +msgstr "Sólido" -# Source-Hash: 07c11e7e4d4681d6 +# Source-Hash: 8008b6f17089beaf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose what to copy from {levelName}." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid panel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.chooseWhatToCopyFromLevel" -msgstr "Elige qué copiar de {levelName}." +msgid "editor.inspector.option.solidPanel.2yaw62" +msgstr "Panel opaco" -# Source-Hash: 9500d4378a319532 +# Source-Hash: f9a4a870cb3d3c41 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose what to copy from this level." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spiral" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.chooseWhatToCopyFromThisLevel" -msgstr "Elige qué copiar de esta planta." +msgid "editor.inspector.option.spiral.91hcl4" +msgstr "Helicoidal" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: beef1cf79388b77b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Splash" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.duplicate" -msgstr "Duplicar" +msgid "editor.inspector.option.splash.1uke4cm" +msgstr "Salpicadero" -# Source-Hash: a56e3eb43e60b45c +# Source-Hash: 324677a79ab15e22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate Level" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spread" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.duplicateLevel" -msgstr "Duplicar planta" +msgid "editor.inspector.option.spread.1g1zysu" +msgstr "Separación" -# Source-Hash: e4c6ab1ea473a082 +# Source-Hash: 39287346366fc206 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Everything" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.everything" -msgstr "Todo" +msgid "editor.inspector.option.square.1xl1lk6" +msgstr "Cuadrado" -# Source-Hash: ac3f119e560388ab +# Source-Hash: 53d7084bc41c1ad6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure, finishes, and placed items, without guide references." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureFinishesAndPlacedItemsWithout" -msgstr "Estructura, acabados y elementos colocados, sin referencias de guía." +msgid "editor.inspector.option.stair.1xf86e" +msgstr "Escalera" -# Source-Hash: acbdf968391d5273 +# Source-Hash: d998c212030bc7c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure + furniture" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureFurniture" -msgstr "Estructura + mobiliario" +msgid "editor.inspector.option.standard.vuco" +msgstr "Estándar" -# Source-Hash: ce682864a140fe75 +# Source-Hash: 0a26a1e61c825660 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure + materials" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureMaterials" -msgstr "Estructura + materiales" +msgid "editor.inspector.option.start.30xvgf" +msgstr "Inicio" -# Source-Hash: 5ee44d53847c5ea2 +# Source-Hash: ed3989f23a2d185e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure, materials, furniture, and references." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Step" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureMaterialsFurnitureAndReferences" -msgstr "Estructura, materiales, mobiliario y referencias." +msgid "editor.inspector.option.step.jtn9kf" +msgstr "Escalonado" -# Source-Hash: 95aa1b43dbdb3f02 +# Source-Hash: 2c6b1cf17a973d67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure only" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stepped" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureOnly" -msgstr "Solo estructura" +msgid "editor.inspector.option.stepped.naxzh0" +msgstr "Escalonado" -# Source-Hash: 2c53b46c9ca9fe2f +# Source-Hash: 4ee35f740730ae87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure with the current material and finish assignments." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureWithTheCurrentMaterialAnd" -msgstr "Estructura con las asignaciones actuales de materiales y acabados." +msgid "editor.inspector.option.straight.lxqbfr" +msgstr "Recto" -# Source-Hash: 3350e9008eaba15d +# Source-Hash: b9b45ac5ba1daeee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls, slabs, roofs, stairs, windows, and doors without finishes." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Strap" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.wallsSlabsRoofsStairsWindowsAnd" -msgstr "Muros, forjados, cubiertas, escaleras, ventanas y puertas, sin acabados." +msgid "editor.inspector.option.strap.14q0ps9" +msgstr "Fleje" -# Source-Hash: 395fd0821b203517 +# Source-Hash: b45f382a67d6c0eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add or remove objects from the selection" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.addOrRemoveObjectsFromThe" -msgstr "Añadir o quitar objetos de la selección" +msgid "editor.inspector.option.supply.1oy2zwu" +msgstr "Impulsión" -# Source-Hash: 8428cb0af9c6d6a0 +# Source-Hash: 00e7a2b3b2aa36ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Adjust one side’s corner radius" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply register" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.adjustOneSideSCornerRadius" -msgstr "Ajustar el radio de esquina de un lado" +msgid "editor.inspector.option.supplyRegister.1lzdbbn" +msgstr "Rejilla de impulsión" -# Source-Hash: d63b45c195713993 +# Source-Hash: f86f1f22230596b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear the selection (or click outside)" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tapered" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.clearTheSelectionOrClickOutside" -msgstr "Borrar la selección (o hacer clic fuera)" +msgid "editor.inspector.option.tapered.3y5blo" +msgstr "Ahusado" -# Source-Hash: 40b1afbeadbd6213 +# Source-Hash: 5fed23c2217b83fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click a handle dot to show move arrows" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target spacing" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.clickAHandleDotToShow" -msgstr "Haz clic en un punto de control para ver las flechas de movimiento" +msgid "editor.inspector.option.targetSpacing.14uibc9" +msgstr "Separación objetivo" -# Source-Hash: 0b82a35c71549580 +# Source-Hash: f3ceed7f867f090f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click or drag the selection to move it as one" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tee" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.clickOrDragTheSelectionTo" -msgstr "Haz clic o arrastra la selección para moverla en bloque" +msgid "editor.inspector.option.tee.7d6tjp" +msgstr "Te" -# Source-Hash: 73a761f393f69cb9 +# Source-Hash: 787005b26aec58a3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click the handle dot to show move + rotate handles" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilted" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.clickTheHandleDotToShow" -msgstr "Haz clic en el punto de control para ver los controles de mover y girar" +msgid "editor.inspector.option.tilted.6n0u5j" +msgstr "Inclinado" -# Source-Hash: c0045cef191fee69 +# Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Detach the joint while dragging an arrow" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.detachTheJointWhileDraggingAn" -msgstr "Separar la unión al arrastrar una flecha" +msgid "editor.inspector.option.top.2nypcs" +msgstr "Superior" -# Source-Hash: a019c8948c104a9e +# Source-Hash: e6657000554dfe53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag left or right to rotate selected object" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transition" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.dragLeftOrRightToRotate" -msgstr "Arrastra a izquierda o derecha para girar el objeto seleccionado" +msgid "editor.inspector.option.transition.1rziz9e" +msgstr "Transición" -# Source-Hash: 7db0364deb12f06e +# Source-Hash: 04bc0909a133a7e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag selected movable object" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vent" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.dragSelectedMovableObject" -msgstr "Arrastrar el objeto móvil seleccionado" +msgid "editor.inspector.option.vent.xda5j2" +msgstr "Ventilación" -# Source-Hash: 0f258dd389afdc73 +# Source-Hash: 7eee9aff0dd520b6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Group selection (session only)" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walk on" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.groupSelectionSessionOnly" -msgstr "Agrupar la selección (solo esta sesión)" +msgid "editor.inspector.option.walkOn.1n5sg9l" +msgstr "Pisar sobre" -# Source-Hash: 85330d62893a45c3 +# Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hold to rotate freely" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.holdToRotateFreely" -msgstr "Mantén pulsado para girar libremente" +msgid "editor.inspector.option.wall.blj585" +msgstr "Muro" -# Source-Hash: 8a665ecaeffa9308 +# Source-Hash: f3578f7177ad0054 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ±45°" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall abutment" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.rotate45" -msgstr "Girar ±45°" +msgid "editor.inspector.option.wallAbutment.lza941" +msgstr "Encuentro con el muro" -# Source-Hash: 6099ee99f8c38700 +# Source-Hash: 8dcf182f91ba3245 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate the selection ±45°" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall ledger" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.rotateTheSelection45" -msgstr "Girar la selección ±45°" +msgid "editor.inspector.option.wallLedger.5m8ana" +msgstr "Larguero de muro" -# Source-Hash: 0f6b418b18ff96f3 +# Source-Hash: 0adda30be5f17975 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotating freely (no angle step)" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall shelf" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.rotatingFreely" -msgstr "Giro libre (sin pasos de ángulo)" +msgid "editor.inspector.option.wallShelf.yiozfl" +msgstr "Estante de pared" -# Source-Hash: 7ed174d6b03563b1 +# Source-Hash: 29d8590334492601 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Switch the rotation axis (Y → X → Z)" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waste" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.switchTheRotationAxisYX" -msgstr "Cambiar el eje de giro (Y → X → Z)" +msgid "editor.inspector.option.waste.3xrp79" +msgstr "Desagüe" -# Source-Hash: d6f2c5cea683de62 +# Source-Hash: 00249876bb37079f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ungroup session selection" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wye" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.ungroupSessionSelection" -msgstr "Desagrupar la selección de la sesión" +msgid "editor.inspector.option.wye.14vupc8" +msgstr "Y" -# Source-Hash: 384842ae1e1c6825 +# Source-Hash: 179b025e25f9a091 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuous" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collapse" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx #, fuzzy -msgid "editor.lib.continuation.continuous" -msgstr "Continuo" +msgid "editor.layers.collapse" +msgstr "Contraer" -# Source-Hash: ebf0eb7af4636a16 +# Source-Hash: dbeae4c43f49327f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuous canopy" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling ({area})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.continuousCanopy" -msgstr "Marquesina continua" +msgid "editor.layers.defaultName.ceiling" +msgstr "Techo ({area})" -# Source-Hash: 1d8e87cd807e8d40 +# Source-Hash: d29165c9d4bfc3cb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuous run" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collection" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx #, fuzzy -msgid "editor.lib.continuation.continuousRun" -msgstr "Línea continua" +msgid "editor.layers.defaultName.collection" +msgstr "Colección" -# Source-Hash: 8990683667567c6b +# Source-Hash: 8f536b859be662a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curved fence" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight ({width}×{length}m)" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.curvedFence" -msgstr "Valla curva" +msgid "editor.layers.defaultName.flight" +msgstr "Tramo ({width}×{length}m)" -# Source-Hash: edf1b9a2ad3ab910 +# Source-Hash: 46dcbf4548374073 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Freehand fence" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing ({width}×{length}m)" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.freehandFence" -msgstr "Valla a mano alzada" +msgid "editor.layers.defaultName.landing" +msgstr "Descansillo ({width}×{length}m)" -# Source-Hash: 2cdb7c1c7cd7c4fd +# Source-Hash: 3ea44453fcd08a6e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place multiple" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Node" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx #, fuzzy -msgid "editor.lib.continuation.placeMultiple" -msgstr "Colocar varios" +msgid "editor.layers.defaultName.node" +msgstr "Nodo" -# Source-Hash: 90bf945df6f9c979 +# Source-Hash: 93f3a04e15b6fb49 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place once" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof ({count, plural, one {# segment} other {# segments}})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.placeOnce" -msgstr "Colocar una vez" +msgid "editor.layers.defaultName.roof" +msgstr "Cubierta ({count, plural, one {# segmento} many {# segmentos} other {# segmentos}})" -# Source-Hash: 8ec6152e139b0e3f +# Source-Hash: a730fab01c172704 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Polygon room" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{roofType, select, hip {Hip} gable {Gable} shed {Shed} gambrel {Gambrel} dutch {Dutch} mansard {Mansard} flat {Flat} conical {Conical} barrel {Barrel} other {Roof}} ({width}×{depth}m)" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.polygonRoom" -msgstr "Estancia poligonal" +msgid "editor.layers.defaultName.roofSegment" +msgstr "{roofType, select, hip {A cuatro aguas} gable {A dos aguas} shed {A un agua} gambrel {Holandesa} dutch {Mixta} mansard {Mansarda} flat {Plana} conical {Cónica} barrel {Abovedada} other {Cubierta}} ({width}×{depth}m)" -# Source-Hash: 83a45603ac7f41e8 +# Source-Hash: 54efcb0756c2f2c1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangle room" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room ({area})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.rectangleRoom" -msgstr "Estancia rectangular" +msgid "editor.layers.defaultName.room" +msgstr "Estancia ({area})" -# Source-Hash: 7fd85d0408141157 +# Source-Hash: e38a4b9986a9d21a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single cabinet" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab ({area})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.singleCabinet" -msgstr "Mueble individual" +msgid "editor.layers.defaultName.slab" +msgstr "Forjado ({area})" -# Source-Hash: dd1bdbc26165baa5 +# Source-Hash: 57398365d4b9066f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single canopy" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Staircase ({count, plural, one {# segment} other {# segments}})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.singleCanopy" -msgstr "Marquesina individual" +msgid "editor.layers.defaultName.staircase" +msgstr "Escalera ({count, plural, one {# segmento} many {# segmentos} other {# segmentos}})" -# Source-Hash: 5fb1a69316be983e +# Source-Hash: a17f8fc29aae896e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single fence" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone ({area})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.singleFence" -msgstr "Valla simple" +msgid "editor.layers.defaultName.zone" +msgstr "Zona ({area})" -# Source-Hash: aac9a732d2159ccc +# Source-Hash: 5cabcabb8bc14809 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Expand" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx #, fuzzy -msgid "editor.lib.continuation.walls" -msgstr "Muros" +msgid "editor.layers.expand" +msgstr "Expandir" -# Source-Hash: 4e4f1a24e4a9d61e +# Source-Hash: 6731e9dd94e8b268 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut opening" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{levelName} options" +#: packages/editor/src/components/ui/floating-level-selector.tsx +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.lib.hudTitle.cutOpening" -msgstr "Abrir hueco" +msgid "editor.layers.levelOptions" +msgstr "Opciones de {levelName}" -# Source-Hash: 60e8d235f3084a9e +# Source-Hash: d6952b4e54d246dd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Divide room" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rename" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx #, fuzzy -msgid "editor.lib.hudTitle.divideRoom" -msgstr "Dividir estancia" +msgid "editor.layers.rename" +msgstr "Cambiar nombre" -# Source-Hash: aa496ec33d21ab03 +# Source-Hash: 21eafa019ad62fea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit {kind}" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{role, select, room {Room colour} other {Zone colour}}" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#: packages/editor/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.lib.hudTitle.editKind" -msgstr "Editar {kind}" +msgid "editor.layers.spaceColour" +msgstr "{role, select, room {Color de la estancia} other {Color de la zona}}" -# Source-Hash: f3ea3efa7102844f +# Source-Hash: f5de042416a2c04f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Erase" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unit colour" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.lib.hudTitle.erase" -msgstr "Borrar" +msgid "editor.layers.unitColour" +msgstr "Color de la unidad" -# Source-Hash: 3f907e76526472bf +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level terrain" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.levelTerrain" -msgstr "Nivelar el terreno" +msgid "editor.levelDuplicateDialog.cancel" +msgstr "Cancelar" -# Source-Hash: 4e911c300d74eb47 +# Source-Hash: 07c11e7e4d4681d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lower terrain" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose what to copy from {levelName}." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.lowerTerrain" -msgstr "Bajar el terreno" +msgid "editor.levelDuplicateDialog.chooseWhatToCopyFromLevel" +msgstr "Elige qué copiar de {levelName}." -# Source-Hash: 194a147d4618a994 +# Source-Hash: 9500d4378a319532 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose what to copy from this level." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.mezzanine" -msgstr "Altillo" +msgid "editor.levelDuplicateDialog.chooseWhatToCopyFromThisLevel" +msgstr "Elige qué copiar de esta planta." -# Source-Hash: c48c4129c9ed249a +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move {kind}" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.moveKind" -msgstr "Mover {kind}" +msgid "editor.levelDuplicateDialog.duplicate" +msgstr "Duplicar" -# Source-Hash: 89f6b7ca8904c656 +# Source-Hash: a56e3eb43e60b45c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move room" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate Level" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.moveRoom" -msgstr "Mover estancia" +msgid "editor.levelDuplicateDialog.duplicateLevel" +msgstr "Duplicar planta" -# Source-Hash: 9c707069572fb3db +# Source-Hash: e4c6ab1ea473a082 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move selection" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Everything" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.moveSelection" -msgstr "Mover selección" +msgid "editor.levelDuplicateDialog.everything" +msgstr "Todo" -# Source-Hash: cf2e870fce0f2f51 +# Source-Hash: ac3f119e560388ab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure, finishes, and placed items, without guide references." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.paint" -msgstr "Pintar" +msgid "editor.levelDuplicateDialog.structureFinishesAndPlacedItemsWithout" +msgstr "Estructura, acabados y elementos colocados, sin referencias de guía." -# Source-Hash: ca197314cb70aa56 +# Source-Hash: acbdf968391d5273 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint a rectangle" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure + furniture" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.paintARectangle" -msgstr "Pintar un rectángulo" +msgid "editor.levelDuplicateDialog.structureFurniture" +msgstr "Estructura + mobiliario" -# Source-Hash: ea4ce729e17254f8 +# Source-Hash: ce682864a140fe75 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint a shape" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure + materials" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.paintAShape" -msgstr "Pintar una forma" +msgid "editor.levelDuplicateDialog.structureMaterials" +msgstr "Estructura + materiales" -# Source-Hash: 01359502b07284d4 +# Source-Hash: 5ee44d53847c5ea2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick material" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure, materials, furniture, and references." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.pickMaterial" -msgstr "Tomar material" +msgid "editor.levelDuplicateDialog.structureMaterialsFurnitureAndReferences" +msgstr "Estructura, materiales, mobiliario y referencias." -# Source-Hash: 4066e8a3f60b1711 +# Source-Hash: 95aa1b43dbdb3f02 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raise terrain" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure only" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.raiseTerrain" -msgstr "Elevar el terreno" +msgid "editor.levelDuplicateDialog.structureOnly" +msgstr "Solo estructura" -# Source-Hash: f85bdac0a1d16603 +# Source-Hash: 2c53b46c9ca9fe2f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Resize" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure with the current material and finish assignments." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.resize" -msgstr "Cambiar tamaño" +msgid "editor.levelDuplicateDialog.structureWithTheCurrentMaterialAnd" +msgstr "Estructura con las asignaciones actuales de materiales y acabados." -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: 3350e9008eaba15d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls, slabs, roofs, stairs, windows, and doors without finishes." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.rotate" -msgstr "Girar" +msgid "editor.levelDuplicateDialog.wallsSlabsRoofsStairsWindowsAnd" +msgstr "Muros, forjados, cubiertas, escaleras, ventanas y puertas, sin acabados." -# Source-Hash: a4395168488bb476 +# Source-Hash: 4f60d1e142affa9c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Copy" +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx #, fuzzy -msgid "editor.lib.hudTitle.select" -msgstr "Seleccionar" +msgid "editor.levelWallCopyPrompt.copy" +msgstr "Copiar" -# Source-Hash: ec1f1d68af469867 +# Source-Hash: 8ccaf4c98e335cc8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Smart measure" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Copy exterior walls from the level {direction}?" +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx #, fuzzy -msgid "editor.lib.hudTitle.smartMeasure" -msgstr "Medida inteligente" +msgid "editor.levelWallCopyPrompt.copyExteriorWallsFromTheLevel" +msgstr "¿Copiar los muros exteriores de la planta {direction, select, below {inferior} above {superior} other {contigua}}?" -# Source-Hash: 5ba5f22bd1a69e09 +# Source-Hash: f6ad0e813d2945bb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Smooth terrain" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No thanks" +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx #, fuzzy -msgid "editor.lib.hudTitle.smoothTerrain" -msgstr "Suavizar el terreno" +msgid "editor.levelWallCopyPrompt.noThanks" +msgstr "No, gracias" -# Source-Hash: cbb4687261739397 +# Source-Hash: d2aecc3c47120ad5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Split {kind}" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{sourceName}’s outside walls, in place, so this level lines up with it." +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx #, fuzzy -msgid "editor.lib.hudTitle.splitKind" -msgstr "Dividir {kind}" +msgid "editor.levelWallCopyPrompt.sourcenameSOutsideWallsInPlace" +msgstr "Los muros exteriores de {sourceName}, en su sitio, para que esta planta quede alineada con ella." -# Source-Hash: 96281876ce53ba08 +# Source-Hash: 395fd0821b203517 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terrace" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add or remove objects from the selection" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.lib.hudTitle.terrace" -msgstr "Terraza" +msgid "editor.lib.contextualHelp.addOrRemoveObjectsFromThe" +msgstr "Añadir o quitar objetos de la selección" -# Source-Hash: 8ec6152e139b0e3f +# Source-Hash: 8428cb0af9c6d6a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Polygon room" -#: packages/editor/src/lib/wall-draw-variant.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Adjust one side’s corner radius" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.lib.wallDrawVariant.polygonRoom" -msgstr "Estancia poligonal" +msgid "editor.lib.contextualHelp.adjustOneSideSCornerRadius" +msgstr "Ajustar el radio de esquina de un lado" -# Source-Hash: 83a45603ac7f41e8 +# Source-Hash: d63b45c195713993 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangle room" -#: packages/editor/src/lib/wall-draw-variant.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear the selection (or click outside)" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.lib.wallDrawVariant.rectangleRoom" -msgstr "Estancia rectangular" +msgid "editor.lib.contextualHelp.clearTheSelectionOrClickOutside" +msgstr "Borrar la selección (o hacer clic fuera)" -# Source-Hash: aac9a732d2159ccc +# Source-Hash: 40b1afbeadbd6213 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls" -#: packages/editor/src/lib/wall-draw-variant.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click a handle dot to show move arrows" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.lib.wallDrawVariant.walls" -msgstr "Muros" +msgid "editor.lib.contextualHelp.clickAHandleDotToShow" +msgstr "Haz clic en un punto de control para ver las flechas de movimiento" +# Source-Hash: 0b82a35c71549580 # Review: required -# Source-Hash: c2626e1fbf89b3c9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{action, select, close {Close} open {Open} stop {Stop} other {Play}}" -#: packages/editor/src/components/editor/registry-action-contributions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click or drag the selection to move it as one" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.mechanismAction" -msgstr "{action, select, close {Cerrar} open {Abrir} stop {Detener} other {Reproducir}}" +msgid "editor.lib.contextualHelp.clickOrDragTheSelectionTo" +msgstr "Haz clic o arrastra la selección para moverla en bloque" +# Source-Hash: 73a761f393f69cb9 # Review: required -# Source-Hash: f08fbb462e9afc0e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curve" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click the handle dot to show move + rotate handles" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.curve" -msgstr "Curva" +msgid "editor.lib.contextualHelp.clickTheHandleDotToShow" +msgstr "Haz clic en el punto de control para ver los controles de mover y girar" +# Source-Hash: c0045cef191fee69 # Review: required -# Source-Hash: 5af05fb6661e4d6a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut out" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Detach the joint while dragging an arrow" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.cutOut" -msgstr "Recortar" +msgid "editor.lib.contextualHelp.detachTheJointWhileDraggingAn" +msgstr "Separar la unión al arrastrar una flecha" +# Source-Hash: a019c8948c104a9e # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag left or right to rotate selected object" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.delete" -msgstr "Eliminar" +msgid "editor.lib.contextualHelp.dragLeftOrRightToRotate" +msgstr "Arrastra a izquierda o derecha para girar el objeto seleccionado" +# Source-Hash: 7db0364deb12f06e # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag selected movable object" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.duplicate" -msgstr "Duplicar" +msgid "editor.lib.contextualHelp.dragSelectedMovableObject" +msgstr "Arrastrar el objeto móvil seleccionado" +# Source-Hash: 0f258dd389afdc73 # Review: required -# Source-Hash: 94b212bd79c05141 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit mesh" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Group selection (session only)" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.editMesh" -msgstr "Editar malla" +msgid "editor.lib.contextualHelp.groupSelectionSessionOnly" +msgstr "Agrupar la selección (solo esta sesión)" +# Source-Hash: 85330d62893a45c3 # Review: required -# Source-Hash: ce90cf37224f73cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Find in catalog" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hold to rotate freely" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.findInCatalog" -msgstr "Buscar en el catálogo" +msgid "editor.lib.contextualHelp.holdToRotateFreely" +msgstr "Mantén pulsado para girar libremente" +# Source-Hash: 8a665ecaeffa9308 # Review: required -# Source-Hash: d5e550c345e7161c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Group selection" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ±45°" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.groupSelection" -msgstr "Agrupar selección" +msgid "editor.lib.contextualHelp.rotate45" +msgstr "Girar ±45°" +# Source-Hash: 6099ee99f8c38700 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate the selection ±45°" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.move" -msgstr "Mover" +msgid "editor.lib.contextualHelp.rotateTheSelection45" +msgstr "Girar la selección ±45°" +# Source-Hash: 0f6b418b18ff96f3 # Review: required -# Source-Hash: 473a9d4463761107 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate left" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotating freely (no angle step)" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.rotateLeft" -msgstr "Girar a la izquierda" +msgid "editor.lib.contextualHelp.rotatingFreely" +msgstr "Giro libre (sin pasos de ángulo)" +# Source-Hash: 7ed174d6b03563b1 # Review: required -# Source-Hash: b1bf4e65c8d8c8ef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate right" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Switch the rotation axis (Y → X → Z)" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.rotateRight" -msgstr "Girar a la derecha" +msgid "editor.lib.contextualHelp.switchTheRotationAxisYX" +msgstr "Cambiar el eje de giro (Y → X → Z)" +# Source-Hash: d6f2c5cea683de62 # Review: required -# Source-Hash: 6f4dbbc4a3f58fca -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ungroup selection" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ungroup session selection" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.ungroupSelection" -msgstr "Desagrupar selección" +msgid "editor.lib.contextualHelp.ungroupSessionSelection" +msgstr "Desagrupar la selección de la sesión" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: 384842ae1e1c6825 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuous" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.ceiling" -msgstr "Techo" +msgid "editor.lib.continuation.continuous" +msgstr "Continuo" -# Source-Hash: 3530ac1f4046cd22 +# Source-Hash: ebf0eb7af4636a16 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Column" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuous canopy" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.column" -msgstr "Pilar" +msgid "editor.lib.continuation.continuousCanopy" +msgstr "Marquesina continua" -# Source-Hash: 787e10f5db16904e +# Source-Hash: 1d8e87cd807e8d40 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuous run" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.door" -msgstr "Puerta" +msgid "editor.lib.continuation.continuousRun" +msgstr "Línea continua" -# Source-Hash: ab5cbab7be160a1c +# Source-Hash: 8990683667567c6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevator" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curved fence" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.elevator" -msgstr "Ascensor" +msgid "editor.lib.continuation.curvedFence" +msgstr "Valla curva" -# Source-Hash: 02042fde61b5aa11 +# Source-Hash: edf1b9a2ad3ab910 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fence" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Freehand fence" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.fence" -msgstr "Valla" +msgid "editor.lib.continuation.freehandFence" +msgstr "Valla a mano alzada" -# Source-Hash: 4c3ff8cdc6feda97 +# Source-Hash: 2cdb7c1c7cd7c4fd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guide image" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place multiple" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.guide" -msgstr "Imagen guía" +msgid "editor.lib.continuation.placeMultiple" +msgstr "Colocar varios" -# Source-Hash: 2743a0e9d2743807 +# Source-Hash: 90bf945df6f9c979 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Item" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place once" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.item" -msgstr "Elemento" +msgid "editor.lib.continuation.placeOnce" +msgstr "Colocar una vez" -# Source-Hash: f5f730969df63d1d +# Source-Hash: 8ec6152e139b0e3f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Polygon room" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.roof" -msgstr "Cubierta" +msgid "editor.lib.continuation.polygonRoom" +msgstr "Estancia poligonal" -# Source-Hash: a130b4eec084c79a +# Source-Hash: 83a45603ac7f41e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof segment" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangle room" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.roofSegment" -msgstr "Segmento de cubierta" +msgid "editor.lib.continuation.rectangleRoom" +msgstr "Estancia rectangular" -# Source-Hash: 612dcd5bf06a79c4 +# Source-Hash: 7fd85d0408141157 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single cabinet" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.room" -msgstr "Estancia" +msgid "editor.lib.continuation.singleCabinet" +msgstr "Mueble individual" -# Source-Hash: b22b2f20cc7cd416 +# Source-Hash: dd1bdbc26165baa5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "3D Scan" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single canopy" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.scan" -msgstr "Escaneo 3D" +msgid "editor.lib.continuation.singleCanopy" +msgstr "Marquesina individual" -# Source-Hash: 170b2049ef0f9131 +# Source-Hash: 5fb1a69316be983e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Selection" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single fence" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.selection" -msgstr "Selección" +msgid "editor.lib.continuation.singleFence" +msgstr "Valla simple" -# Source-Hash: 8775bc8dc9593964 +# Source-Hash: aac9a732d2159ccc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.slab" -msgstr "Forjado" +msgid "editor.lib.continuation.walls" +msgstr "Muros" -# Source-Hash: 53d7084bc41c1ad6 +# Source-Hash: 4e4f1a24e4a9d61e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut opening" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.nodeDisplay.stair" -msgstr "Escalera" +msgid "editor.lib.hudTitle.cutOpening" +msgstr "Abrir hueco" -# Source-Hash: 52de428c16bb81e6 +# Source-Hash: 60e8d235f3084a9e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair segment" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divide room" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.nodeDisplay.stairSegment" -msgstr "Segmento de escalera" +msgid "editor.lib.hudTitle.divideRoom" +msgstr "Dividir estancia" -# Source-Hash: 2210e5ee50b74dc9 +# Source-Hash: aa496ec33d21ab03 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit {kind}" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.nodeDisplay.wall" -msgstr "Muro" +msgid "editor.lib.hudTitle.editKind" +msgstr "Editar {kind}" -# Source-Hash: aa3c35ed33e181e5 +# Source-Hash: f3ea3efa7102844f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Window" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Erase" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.nodeDisplay.window" -msgstr "Ventana" +msgid "editor.lib.hudTitle.erase" +msgstr "Borrar" -# Source-Hash: a107b4d76d6972e3 +# Source-Hash: 3f907e76526472bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level terrain" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.nodeDisplay.zone" -msgstr "Zona" +msgid "editor.lib.hudTitle.levelTerrain" +msgstr "Nivelar el terreno" -# Source-Hash: c0774c185060fc13 +# Source-Hash: 4e911c300d74eb47 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lower terrain" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.cancel" -msgstr "Cancelar" +msgid "editor.lib.hudTitle.lowerTerrain" +msgstr "Bajar el terreno" -# Source-Hash: 6dbabf32ff8c6f37 +# Source-Hash: 194a147d4618a994 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collection name…" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.collectionName" -msgstr "Nombre de la colección…" +msgid "editor.lib.hudTitle.mezzanine" +msgstr "Altillo" -# Source-Hash: 135af27a14a4cda7 +# Source-Hash: c48c4129c9ed249a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collections" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move {kind}" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.collections" -msgstr "Colecciones" +msgid "editor.lib.hudTitle.moveKind" +msgstr "Mover {kind}" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 89f6b7ca8904c656 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move room" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.delete" -msgstr "Eliminar" +msgid "editor.lib.hudTitle.moveRoom" +msgstr "Mover estancia" -# Source-Hash: c53d71b05b8163b2 +# Source-Hash: 9c707069572fb3db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete \"{name}\"?" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move selection" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.deleteName" -msgstr "¿Eliminar «{name}»?" +msgid "editor.lib.hudTitle.moveSelection" +msgstr "Mover selección" -# Source-Hash: e9f7cceb39860c56 +# Source-Hash: cf2e870fce0f2f51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "New" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.new" -msgstr "Nuevo" +msgid "editor.lib.hudTitle.paint" +msgstr "Pintar" -# Source-Hash: 649bc1b1799f2311 +# Source-Hash: ca197314cb70aa56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No collections yet. Create one to group elements together." -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint a rectangle" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.noCollectionsYetCreateOneTo" -msgstr "Aún no hay colecciones. Crea una para agrupar elementos." +msgid "editor.lib.hudTitle.paintARectangle" +msgstr "Pintar un rectángulo" -# Source-Hash: d6952b4e54d246dd +# Source-Hash: ea4ce729e17254f8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rename" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint a shape" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.rename" -msgstr "Cambiar nombre" +msgid "editor.lib.hudTitle.paintAShape" +msgstr "Pintar una forma" -# Source-Hash: 2000cf124b4e1139 +# Source-Hash: 01359502b07284d4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A thicker floor grows upward: the rooms below keep their height." -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx -#, fuzzy -msgid "editor.panels.floorFoundationPanel.aThickerFloorGrowsUpwardThe" -msgstr "Un suelo más grueso crece hacia arriba: las estancias inferiores mantienen su altura." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick material" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.pickMaterial" +msgstr "Tomar material" -# Source-Hash: 0d57958b99b6b352 +# Source-Hash: 4066e8a3f60b1711 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edge finish" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raise terrain" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.edgeFinish" -msgstr "Acabado del borde" +msgid "editor.lib.hudTitle.raiseTerrain" +msgstr "Elevar el terreno" -# Source-Hash: 8e458d8b21f26f09 +# Source-Hash: f85bdac0a1d16603 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Resize" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorPlate" -msgstr "Forjado" +msgid "editor.lib.hudTitle.resize" +msgstr "Cambiar tamaño" -# Source-Hash: 2bb71e5633801afb +# Source-Hash: 306d409f8a1cf480 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate {thicknessLabel} thick, resting on the walls below" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorPlateThicknesslabelThickRestingOn" -msgstr "Forjado de {thicknessLabel} de espesor, apoyado en los muros inferiores" +msgid "editor.lib.hudTitle.rotate" +msgstr "Girar" -# Source-Hash: 73614b8faa059cd6 +# Source-Hash: a4395168488bb476 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor thickness" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorThickness" -msgstr "Espesor del suelo" +msgid "editor.lib.hudTitle.select" +msgstr "Seleccionar" -# Source-Hash: a40a1fbacd5d2551 +# Source-Hash: ec1f1d68af469867 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor top +{height}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Smart measure" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorTopAbove" -msgstr "Cara superior del suelo +{height}" +msgid "editor.lib.hudTitle.smartMeasure" +msgstr "Medida inteligente" -# Source-Hash: 5c3849e15933737f +# Source-Hash: 5ba5f22bd1a69e09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor top {height}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Smooth terrain" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorTopValue" -msgstr "Cara superior del suelo {height}" +msgid "editor.lib.hudTitle.smoothTerrain" +msgstr "Suavizar el terreno" -# Source-Hash: 19802dd369749ea7 +# Source-Hash: cbb4687261739397 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation finish" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Split {kind}" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.foundationFinish" -msgstr "Acabado de la cimentación" +msgid "editor.lib.hudTitle.splitKind" +msgstr "Dividir {kind}" -# Source-Hash: 3a4599be1ad687be +# Source-Hash: 96281876ce53ba08 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation height" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terrace" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.foundationHeight" -msgstr "Altura de cimentación" +msgid "editor.lib.hudTitle.terrace" +msgstr "Terraza" -# Source-Hash: 8e458d8b21f26f09 +# Source-Hash: 472d127eb9416ec5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invisible" +#: packages/editor/src/lib/wall-draw-variant.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.kicker" -msgstr "Forjado" +msgid "editor.lib.wallDrawVariant.kind.invisible" +msgstr "Invisible" -# Source-Hash: 66d52bfbb94f7bb3 +# Source-Hash: 240ed9c77627b9a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate · {level}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" +#: packages/editor/src/lib/wall-draw-variant.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.kickerLevel" -msgstr "Forjado · {level}" +msgid "editor.lib.wallDrawVariant.kind.railing" +msgstr "Barandilla" -# Source-Hash: 0189e5a1987b4ec0 +# Source-Hash: d998c212030bc7c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate · {level} · rests on {below}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/editor/src/lib/wall-draw-variant.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.kickerRestsOn" -msgstr "Forjado · {level} · apoya en {below}" +msgid "editor.lib.wallDrawVariant.kind.standard" +msgstr "Estándar" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 648ef10535b0af73 +# Source-Hash: 8ec6152e139b0e3f # Review: required -# English: "{count, plural, =2 {Lower both} other {Lower all {number}}}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Polygon room" +#: packages/editor/src/lib/wall-draw-variant.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.lowerTogether" -msgstr "{count, plural, =2 {Bajar ambos} one {Bajar los {number}} many {Bajar los {number}} other {Bajar los {number}}}" +msgid "editor.lib.wallDrawVariant.polygonRoom" +msgstr "Estancia poligonal" -# Source-Hash: c2fcc43bb7f1c5e2 +# Source-Hash: 83a45603ac7f41e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Not to scale" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangle room" +#: packages/editor/src/lib/wall-draw-variant.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.notToScale" -msgstr "Sin escala" +msgid "editor.lib.wallDrawVariant.rectangleRoom" +msgstr "Estancia rectangular" -# Source-Hash: e9440fa9f770b7a4 +# Source-Hash: aac9a732d2159ccc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "On the ground" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls" +#: packages/editor/src/lib/wall-draw-variant.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.onTheGround" -msgstr "Sobre el terreno" +msgid "editor.lib.wallDrawVariant.walls" +msgstr "Muros" -# Source-Hash: 7c3692a361075ecf +# Source-Hash: c2626e1fbf89b3c9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised on a foundation" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{action, select, close {Close} open {Open} stop {Stop} other {Play}}" +#: packages/editor/src/components/editor/registry-action-contributions.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.raisedOnAFoundation" -msgstr "Elevado sobre una cimentación" +msgid "editor.mechanismAction" +msgstr "{action, select, close {Cerrar} open {Abrir} stop {Detener} other {Reproducir}}" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 769c3ca1ca0cd4f0 +# Source-Hash: f08fbb462e9afc0e # Review: required -# English: "{count, plural, =2 {Raise both} other {Raise all {number}}}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curve" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.raiseTogether" -msgstr "{count, plural, =2 {Subir ambos} one {Subir los {number}} many {Subir los {number}} other {Subir los {number}}}" +msgid "editor.nodeActionMenu.curve" +msgstr "Curva" -# Source-Hash: 719ae422da204ca7 +# Source-Hash: 5af05fb6661e4d6a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate · {thickness}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut out" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.floorPlate" -msgstr "Forjado · {thickness}" +msgid "editor.nodeActionMenu.cutOut" +msgstr "Recortar" -# Source-Hash: 069d64adffa05db7 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor top" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.floorTop" -msgstr "Cara superior del suelo" +msgid "editor.nodeActionMenu.delete" +msgstr "Eliminar" -# Source-Hash: 48c832c1fc389290 +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.foundation" -msgstr "Cimentación" +msgid "editor.nodeActionMenu.duplicate" +msgstr "Duplicar" -# Source-Hash: 7759a59b8685c885 +# Source-Hash: 94b212bd79c05141 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation · {foundation}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx -#, fuzzy -msgid "editor.panels.floorFoundationPanel.section.foundationKind" -msgstr "Cimentación · {foundation}" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit mesh" +#: packages/editor/src/components/editor/node-action-menu.tsx +#, fuzzy +msgid "editor.nodeActionMenu.editMesh" +msgstr "Editar malla" -# Source-Hash: 94cc8e9f1ee16edb +# Source-Hash: ce90cf37224f73cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Find in catalog" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.ground" -msgstr "Terreno" +msgid "editor.nodeActionMenu.findInCatalog" +msgstr "Buscar en el catálogo" -# Source-Hash: 51e274b2c90e2cf3 +# Source-Hash: d5e550c345e7161c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab · {thickness}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Group selection" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.slab" -msgstr "Forjado · {thickness}" +msgid "editor.nodeActionMenu.groupSelection" +msgstr "Agrupar selección" -# Source-Hash: 790a0b5c6dbf0e9b +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls below" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.wallsBelow" -msgstr "Muros inferiores" +msgid "editor.nodeActionMenu.move" +msgstr "Mover" -# Source-Hash: 90e96ae5f3d3f69c +# Source-Hash: 473a9d4463761107 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab {thickness} thick on the ground, floor top {top} above the ground" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate left" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.sectionOnGround" -msgstr "Forjado de {thickness} de espesor sobre el terreno, cara superior a {top} sobre el terreno" +msgid "editor.nodeActionMenu.rotateLeft" +msgstr "Girar a la izquierda" -# Source-Hash: 71ed2295d9932ed0 +# Source-Hash: b1bf4e65c8d8c8ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab {thickness} thick on a {foundation} foundation, floor top {top} above the ground" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate right" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.sectionRaised" -msgstr "Forjado de {thickness} de espesor sobre una cimentación {foundation}, cara superior a {top} sobre el terreno" +msgid "editor.nodeActionMenu.rotateRight" +msgstr "Girar a la derecha" -# Source-Hash: 8775bc8dc9593964 +# Source-Hash: 6f4dbbc4a3f58fca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ungroup selection" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.slab" -msgstr "Forjado" +msgid "editor.nodeActionMenu.ungroupSelection" +msgstr "Desagrupar selección" -# Source-Hash: ca51d643691c29ae +# Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab thickness" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.slabThickness" -msgstr "Espesor del forjado" +msgid "editor.nodeDisplay.ceiling" +msgstr "Techo" -# Source-Hash: 678c39468593275b +# Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The floor's outside edge, all around the footprint." -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Column" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.theFloorSOutsideEdgeAll" -msgstr "El borde exterior del suelo, en todo el perímetro de la huella." +msgid "editor.nodeDisplay.column" +msgstr "Pilar" -# Source-Hash: 6638ed5caa43bdb9 +# Source-Hash: 787e10f5db16904e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The foundation stands on the ground; the slab sits on it." -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.theFoundationStandsOnTheGround" -msgstr "La cimentación se apoya en el terreno; el forjado se apoya en ella." +msgid "editor.nodeDisplay.door" +msgstr "Puerta" -# Source-Hash: 5321416b442f23b4 +# Source-Hash: ab5cbab7be160a1c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The slab sits on the foundation (or the ground): a thicker slab raises the floor top and everything on it." -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevator" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.theSlabSitsOnTheFoundation" -msgstr "El forjado se apoya en la cimentación (o el terreno): uno más grueso sube la cara superior del suelo y todo lo que hay encima." +msgid "editor.nodeDisplay.elevator" +msgstr "Ascensor" -# Source-Hash: 044ccae8bec574e7 +# Source-Hash: 02042fde61b5aa11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Under the floor" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fence" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.underTheFloor" -msgstr "Bajo el suelo" +msgid "editor.nodeDisplay.fence" +msgstr "Valla" -# Source-Hash: 6aca44df3e582a81 +# Source-Hash: 4c3ff8cdc6feda97 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A hatch in the mezzanine: it cuts only the mezzanine’s floor." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guide image" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.aHatchInTheMezzanineIt" -msgstr "Trampilla en la entreplanta: solo corta el suelo de la entreplanta." +msgid "editor.nodeDisplay.guide" +msgstr "Imagen guía" -# Source-Hash: 2ce79639d42da658 +# Source-Hash: 2743a0e9d2743807 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Also cut the ceiling below" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Item" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.alsoCutTheCeilingBelow" -msgstr "Cortar también el techo inferior" +msgid "editor.nodeDisplay.item" +msgstr "Elemento" -# Source-Hash: e360814f64792300 +# Source-Hash: f5f730969df63d1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Also cut the floor above" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.alsoCutTheFloorAbove" -msgstr "Cortar también el suelo superior" +msgid "editor.nodeDisplay.roof" +msgstr "Cubierta" -# Source-Hash: c25cddf8b831c2b2 +# Source-Hash: a130b4eec084c79a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{area} · Drag its corners to change the shape." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof segment" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.areaDragCorners" -msgstr "{area} · Arrastra sus esquinas para cambiar la forma." +msgid "editor.nodeDisplay.roofSegment" +msgstr "Segmento de cubierta" -# Source-Hash: 32b168cf010a5daa +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{area} · Shape follows its owner." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.areaOwned" -msgstr "{area} · La forma sigue a su propietario." +msgid "editor.nodeDisplay.room" +msgstr "Estancia" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: b22b2f20cc7cd416 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "3D Scan" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.delete" -msgstr "Eliminar" +msgid "editor.nodeDisplay.scan" +msgstr "Escaneo 3D" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: 170b2049ef0f9131 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selection" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.done" -msgstr "Hecho" +msgid "editor.nodeDisplay.selection" +msgstr "Selección" -# Source-Hash: e04298381837252f +# Source-Hash: 8775bc8dc9593964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.kicker" -msgstr "Abertura" +msgid "editor.nodeDisplay.slab" +msgstr "Forjado" -# Source-Hash: 079ad92dac7947cf +# Source-Hash: 53d7084bc41c1ad6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening · {level}" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.kickerLevel" -msgstr "Hueco · {level}" +msgid "editor.nodeDisplay.stair" +msgstr "Escalera" -# Source-Hash: baf2c2c209637e5f +# Source-Hash: 52de428c16bb81e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening · in {room}" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair segment" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.kickerRoom" -msgstr "Hueco · en {room}" +msgid "editor.nodeDisplay.stairSegment" +msgstr "Segmento de escalera" -# Source-Hash: 1712c164335ecd86 +# Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening · in {room} · {level}" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.kickerRoomLevel" -msgstr "Hueco · en {room} · {level}" +msgid "editor.nodeDisplay.wall" +msgstr "Muro" -# Source-Hash: 88e673123b9dbfe1 +# Source-Hash: aa3c35ed33e181e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "On {level}, as one void with this opening." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Window" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.oneVoidWith" -msgstr "En {level}, como un único vacío con este hueco." +msgid "editor.nodeDisplay.window" +msgstr "Ventana" -# Source-Hash: c38959fc8fd3e59d +# Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Owned by Elevator" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.ownedByElevator" -msgstr "Pertenece al ascensor" +msgid "editor.nodeDisplay.zone" +msgstr "Zona" -# Source-Hash: 01494805cf60d78d +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Owned by Staircase" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.ownedByStaircase" -msgstr "Pertenece a la escalera" +msgid "editor.panels.collections.collectionsPopover.cancel" +msgstr "Cancelar" -# Source-Hash: 612dcd5bf06a79c4 +# Source-Hash: 6dbabf32ff8c6f37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collection name…" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.room" -msgstr "Estancia" +msgid "editor.panels.collections.collectionsPopover.collectionName" +msgstr "Nombre de la colección…" -# Source-Hash: 1405b914a324b153 +# Source-Hash: 135af27a14a4cda7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "There is no floor above this storey." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collections" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.thereIsNoFloorAboveThis" -msgstr "No hay suelo encima de esta planta." +msgid "editor.panels.collections.collectionsPopover.collections" +msgstr "Colecciones" -# Source-Hash: 776170dcae88e969 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "There is no storey below." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.thereIsNoStoreyBelow" -msgstr "No hay planta debajo." +msgid "editor.panels.collections.collectionsPopover.delete" +msgstr "Eliminar" -# Source-Hash: 0fdd1877a0f2d777 +# Source-Hash: c53d71b05b8163b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{source, select, stair {Stair opening} elevator {Elevator opening} ceiling {Ceiling opening} other {Floor opening}}" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete \"{name}\"?" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.title" -msgstr "{source, select, stair {Hueco de escalera} elevator {Hueco de ascensor} ceiling {Hueco de techo} other {Hueco de suelo}}" +msgid "editor.panels.collections.collectionsPopover.deleteName" +msgstr "¿Eliminar «{name}»?" -# Source-Hash: fa35c7653e1f649e +# Source-Hash: e9f7cceb39860c56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "One of them already wraps another corner. Unwrap it first." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.alreadyJoined" -msgstr "Una de ellas ya rodea otra esquina. Sepárala primero." +msgid "editor.panels.collections.collectionsPopover.new" +msgstr "Nuevo" -# Source-Hash: dd87eb1983876459 +# Source-Hash: 649bc1b1799f2311 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{kind, select, item {There is an item between them.} door {There is a door between them.} window {There is a window between them.} shelf {There is a shelf between them.} other {There is something between them.}}" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No collections yet. Create one to group elements together." +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.between" -msgstr "{kind, select, item {Hay un elemento entre ellas.} door {Hay una puerta entre ellas.} window {Hay una ventana entre ellas.} shelf {Hay un estante entre ellas.} other {Hay algo entre ellas.}}" +msgid "editor.panels.collections.collectionsPopover.noCollectionsYetCreateOneTo" +msgstr "Aún no hay colecciones. Crea una para agrupar elementos." -# Source-Hash: 58aea0b9789ae280 +# Source-Hash: d6952b4e54d246dd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "These windows cannot be merged." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rename" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.cannotMerge" -msgstr "Estas ventanas no se pueden unir." +msgid "editor.panels.collections.collectionsPopover.rename" +msgstr "Cambiar nombre" -# Source-Hash: 15170cfd9d666c4f +# Source-Hash: 0a605a51555bb514 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Their walls meet at too sharp or too flat an angle for a corner window." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Along house" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.cornerAngle" -msgstr "Sus muros se encuentran en un ángulo demasiado agudo o demasiado plano para una ventana de esquina." +msgid "editor.panels.deckBoardsFields.alongHouse" +msgstr "Paralelo a la casa" -# Source-Hash: f2818a1e20ebd6ca +# Source-Hash: 19ae2360207ecf5a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The window selected first is taller than the other wall. Select the other one first." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Boards" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.heightExceedsWall" -msgstr "La ventana seleccionada primero es más alta que el otro muro. Selecciona primero la otra." +msgid "editor.panels.deckBoardsFields.boards" +msgstr "Tablas" -# Source-Hash: 7c97fb4af929d4db +# Source-Hash: 2bc05aaf1fc289b3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "They are too far apart. Windows merge with at most {reach} between them." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label} boards {thickness} × {width} in, {gap} in apart, {direction, select, parallel {along the house, on joists square to it} diagonal {at 45° to the house} other {out from the house, on joists along it, carried by beams square to the house}}; joists {spacing} in on centre." +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.notAdjacent" -msgstr "Están demasiado separadas. Las ventanas se unen con un máximo de {reach} entre ellas." +msgid "editor.panels.deckBoardsFields.boardsSummary" +msgstr "Tablas {label} de {thickness} × {width} in, separadas {gap} in, {direction, select, parallel {paralelas a la casa, sobre viguetas perpendiculares a ella} diagonal {a 45° respecto a la casa} other {perpendiculares a la casa, sobre viguetas paralelas a ella, apoyadas en vigas perpendiculares a la casa}}; viguetas a {spacing} in entre ejes." -# Source-Hash: 57a281bdc4229b6d +# Source-Hash: 24c6255bfa1abd8f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "One of them is too far from the corner. A window joins one within {reach} of it." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck boards" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.notAtCorner" -msgstr "Una de ellas está demasiado lejos de la esquina. Una ventana se une a otra a menos de {reach}." +msgid "editor.panels.deckBoardsFields.deckBoards" +msgstr "Tablas de la tarima" -# Source-Hash: e7d41ce7879ec075 +# Source-Hash: 7420c0d2caee1c22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A roof or dormer window cannot join another window." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diagonal" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.notOnWall" -msgstr "Una ventana de cubierta o de buhardilla no puede unirse a otra ventana." +msgid "editor.panels.deckBoardsFields.diagonal" +msgstr "Diagonal" -# Source-Hash: eaad567d5e4257dc +# Source-Hash: df708ece3529bcba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{kind, select, item {Sliding them to the corner would overlap an item.} door {Sliding them to the corner would overlap a door.} window {Sliding them to the corner would overlap a window.} shelf {Sliding them to the corner would overlap a shelf.} other {Sliding them to the corner would overlap something.}}" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.overlap" -msgstr "{kind, select, item {Deslizarlas hasta la esquina se solaparía con un elemento.} door {Deslizarlas hasta la esquina se solaparía con una puerta.} window {Deslizarlas hasta la esquina se solaparía con una ventana.} shelf {Deslizarlas hasta la esquina se solaparía con un estante.} other {Deslizarlas hasta la esquina se solaparía con otro elemento.}}" +msgid "editor.panels.deckBoardsFields.gap" +msgstr "Junta" -# Source-Hash: ecb092821ed5b5e8 +# Source-Hash: 3660fcdd12159277 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Their walls do not meet at a corner." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Out from house" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.wallsNotMeeting" -msgstr "Sus muros no se encuentran en una esquina." +msgid "editor.panels.deckBoardsFields.outFromHouse" +msgstr "Perpendicular a la casa" -# Source-Hash: 37d9f63758abdb67 +# Source-Hash: 9ac7e4955593cc34 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mixed" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx -#: packages/editor/src/components/ui/panels/parametric-field-control.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Run" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mixed" -msgstr "Mixto" +msgid "editor.panels.deckBoardsFields.run" +msgstr "Sentido" -# Source-Hash: d7cf5045c01b2eb9 +# Source-Hash: 2000cf124b4e1139 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close" -#: packages/editor/src/components/ui/panels/mobile-panel-sheet.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A thicker floor grows upward: the rooms below keep their height." +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.mobilePanelSheet.close" -msgstr "Cerrar" +msgid "editor.panels.floorFoundationPanel.aThickerFloorGrowsUpwardThe" +msgstr "Un suelo más grueso crece hacia arriba: las estancias inferiores mantienen su altura." -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 0d57958b99b6b352 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edge finish" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.delete" -msgstr "Eliminar" +msgid "editor.panels.floorFoundationPanel.edgeFinish" +msgstr "Acabado del borde" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 8e458d8b21f26f09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.duplicate" -msgstr "Duplicar" +msgid "editor.panels.floorFoundationPanel.floorPlate" +msgstr "Forjado" -# Source-Hash: 7eb955d866c2668b +# Source-Hash: 2bb71e5633801afb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit properties" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate {thicknessLabel} thick, resting on the walls below" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.editProperties" -msgstr "Editar propiedades" +msgid "editor.panels.floorFoundationPanel.floorPlateThicknesslabelThickRestingOn" +msgstr "Forjado de {thicknessLabel} de espesor, apoyado en los muros inferiores" -# Source-Hash: 89f25aa13e8192bc +# Source-Hash: 73614b8faa059cd6 # Review: required # AI-Provider: cursor-agent # AI-Model: claude-opus -# English: "Edit {resolvedLabel}" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# English: "Floor thickness" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.editResolvedlabel" -msgstr "Editar {resolvedLabel}" +msgid "editor.panels.floorFoundationPanel.floorThickness" +msgstr "Espesor del suelo" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: a40a1fbacd5d2551 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor top +{height}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.move" -msgstr "Mover" +msgid "editor.panels.floorFoundationPanel.floorTopAbove" +msgstr "Cara superior del suelo +{height}" -# Source-Hash: 72be05e1796526c9 +# Source-Hash: 5c3849e15933737f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Currently {currentLabel}" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor top {height}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.currentlyCurrentlabel" -msgstr "Actualmente {currentLabel}" +msgid "editor.panels.floorFoundationPanel.floorTopValue" +msgstr "Cara superior del suelo {height}" -# Source-Hash: b2a1b3bc9676fe05 +# Source-Hash: 19802dd369749ea7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom height" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation finish" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.customHeight" -msgstr "Altura personalizada" +msgid "editor.panels.floorFoundationPanel.foundationFinish" +msgstr "Acabado de la cimentación" -# Source-Hash: a5c2353769b603d5 +# Source-Hash: 3a4599be1ad687be # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows level" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation height" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.followsLevel" -msgstr "Sigue la planta" +msgid "editor.panels.floorFoundationPanel.foundationHeight" +msgstr "Altura de cimentación" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: 8e458d8b21f26f09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.height" -msgstr "Altura" +msgid "editor.panels.floorFoundationPanel.kicker" +msgstr "Forjado" -# Source-Hash: 27644f0497fd9849 +# Source-Hash: 66d52bfbb94f7bb3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate · {level}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.top" -msgstr "Superior" +msgid "editor.panels.floorFoundationPanel.kickerLevel" +msgstr "Forjado · {level}" -# Source-Hash: 70f48b0141b656f2 +# Source-Hash: 0189e5a1987b4ec0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{label} (session only). Plain click reselects all members. Not saved with the project." -#: packages/editor/src/components/ui/panels/multi-parametric-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate · {level} · rests on {below}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiParametricInspector.labelSessionOnlyPlainClickReselects" -msgstr "{label} (solo en esta sesión). Un clic simple vuelve a seleccionar todos los miembros. No se guarda con el proyecto." +msgid "editor.panels.floorFoundationPanel.kickerRestsOn" +msgstr "Forjado · {level} · apoya en {below}" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 648ef10535b0af73 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, =2 {Lower both} other {Lower all {number}}}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.delete" -msgstr "Eliminar" +msgid "editor.panels.floorFoundationPanel.lowerTogether" +msgstr "{count, plural, =2 {Bajar ambos} one {Bajar los {number}} many {Bajar los {number}} other {Bajar los {number}}}" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: c2fcc43bb7f1c5e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not to scale" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.duplicate" -msgstr "Duplicar" +msgid "editor.panels.floorFoundationPanel.notToScale" +msgstr "Sin escala" -# Source-Hash: b0e7e3b47dfb5a0b +# Source-Hash: e9440fa9f770b7a4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Group" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On the ground" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.group" -msgstr "Agrupar" +msgid "editor.panels.floorFoundationPanel.onTheGround" +msgstr "Sobre el terreno" -# Source-Hash: ca0a95fe0b08b8b6 +# Source-Hash: 7c3692a361075ecf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Group (Ctrl/Cmd+G)" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised on a foundation" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.groupCtrlCmdG" -msgstr "Agrupar (Ctrl/Cmd+G)" +msgid "editor.panels.floorFoundationPanel.raisedOnAFoundation" +msgstr "Elevado sobre una cimentación" -# Source-Hash: 70f48b0141b656f2 +# Source-Hash: 769c3ca1ca0cd4f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{label} (session only). Plain click reselects all members. Not saved with the project." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, =2 {Raise both} other {Raise all {number}}}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.labelSessionOnlyPlainClickReselects" -msgstr "{label} (solo en esta sesión). Un clic simple vuelve a seleccionar todos los miembros. No se guarda con el proyecto." +msgid "editor.panels.floorFoundationPanel.raiseTogether" +msgstr "{count, plural, =2 {Subir ambos} one {Subir los {number}} many {Subir los {number}} other {Subir los {number}}}" -# Source-Hash: fc98ef29c2842341 +# Source-Hash: 719ae422da204ca7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{length} selected" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate · {thickness}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.lengthSelected" -msgstr "{length} seleccionados" +msgid "editor.panels.floorFoundationPanel.section.floorPlate" +msgstr "Forjado · {thickness}" -# Source-Hash: 323aaf1ebd04ada7 +# Source-Hash: 069d64adffa05db7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Merge windows" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor top" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.mergeWindows" -msgstr "Unir ventanas" +msgid "editor.panels.floorFoundationPanel.section.floorTop" +msgstr "Cara superior del suelo" -# Source-Hash: 7855d03a6140af77 +# Source-Hash: 48c832c1fc389290 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Merge windows into a corner window: both take the height, sill and type of the one you selected first" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.mergeWindowsIntoACornerWindow" -msgstr "Unir en una ventana de esquina: ambas toman la altura, el alféizar y el tipo de la primera seleccionada" +msgid "editor.panels.floorFoundationPanel.section.foundation" +msgstr "Cimentación" -# Source-Hash: b79da96502d2e1c0 +# Source-Hash: 7759a59b8685c885 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Merge windows into one across both: it keeps the type and style of the one you selected first" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation · {foundation}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.mergeWindowsIntoOneAcrossBoth" -msgstr "Unir en una sola ventana que abarca ambas: conserva el tipo y el estilo de la primera seleccionada" +msgid "editor.panels.floorFoundationPanel.section.foundationKind" +msgstr "Cimentación · {foundation}" -# Source-Hash: f409934681a046e8 +# Source-Hash: 94cc8e9f1ee16edb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select building" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx -#, fuzzy -msgid "editor.panels.multiSelectionPanel.selectBuilding" -msgstr "Seleccionar edificio" - -# Source-Hash: c62a73873bd0164d -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select the whole building to move all its levels" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx -#, fuzzy -msgid "editor.panels.multiSelectionPanel.selectTheWholeBuildingToMove" -msgstr "Selecciona todo el edificio para mover todas sus plantas" - -# Source-Hash: 7bd5f29203a28efb -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ungroup" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.ungroup" -msgstr "Desagrupar" +msgid "editor.panels.floorFoundationPanel.section.ground" +msgstr "Terreno" -# Source-Hash: aec9c3983a440d4a +# Source-Hash: 51e274b2c90e2cf3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ungroup (Ctrl/Cmd+Shift+G)" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab · {thickness}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.ungroupCtrlCmdShiftG" -msgstr "Desagrupar (Ctrl/Cmd+Mayús+G)" +msgid "editor.panels.floorFoundationPanel.section.slab" +msgstr "Forjado · {thickness}" -# Source-Hash: 420385f27c627cee +# Source-Hash: 790a0b5c6dbf0e9b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unwrap the corner" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.unwrapTheCorner" -msgstr "Separar la esquina" +msgid "editor.panels.floorFoundationPanel.section.wallsBelow" +msgstr "Muros inferiores" -# Source-Hash: 7906c9f4baebc70b +# Source-Hash: 90e96ae5f3d3f69c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unwrap the corner: both windows stay, each framed at the corner" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab {thickness} thick on the ground, floor top {top} above the ground" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.unwrapTheCornerBothWindowsStay" -msgstr "Separar la esquina: ambas ventanas se mantienen, cada una con su marco en la esquina" +msgid "editor.panels.floorFoundationPanel.sectionOnGround" +msgstr "Forjado de {thickness} de espesor sobre el terreno, cara superior a {top} sobre el terreno" -# Source-Hash: 170b2049ef0f9131 +# Source-Hash: 71ed2295d9932ed0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Selection" -#: packages/editor/src/components/ui/panels/panel-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab {thickness} thick on a {foundation} foundation, floor top {top} above the ground" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelManager.selection" -msgstr "Selección" +msgid "editor.panels.floorFoundationPanel.sectionRaised" +msgstr "Forjado de {thickness} de espesor sobre una cimentación {foundation}, cara superior a {top} sobre el terreno" -# Source-Hash: 7ceade8f25b58fe9 +# Source-Hash: 8775bc8dc9593964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.back" -msgstr "Volver" +msgid "editor.panels.floorFoundationPanel.slab" +msgstr "Forjado" -# Source-Hash: d7cf5045c01b2eb9 +# Source-Hash: ca51d643691c29ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab thickness" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.close" -msgstr "Cerrar" +msgid "editor.panels.floorFoundationPanel.slabThickness" +msgstr "Espesor del forjado" -# Source-Hash: 2dff25ca30c80559 +# Source-Hash: 678c39468593275b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close {title}" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The floor's outside edge, all around the footprint." +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.closeTitle" -msgstr "Cerrar {title}" +msgid "editor.panels.floorFoundationPanel.theFloorSOutsideEdgeAll" +msgstr "El borde exterior del suelo, en todo el perímetro de la huella." -# Source-Hash: 4f15c3e0fe6178b5 +# Source-Hash: 6638ed5caa43bdb9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collapse panel" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The foundation stands on the ground; the slab sits on it." +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.collapsePanel" -msgstr "Contraer panel" +msgid "editor.panels.floorFoundationPanel.theFoundationStandsOnTheGround" +msgstr "La cimentación se apoya en el terreno; el forjado se apoya en ella." -# Source-Hash: 135af27a14a4cda7 +# Source-Hash: 5321416b442f23b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collections" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The slab sits on the foundation (or the ground): a thicker slab raises the floor top and everything on it." +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.collections" -msgstr "Colecciones" +msgid "editor.panels.floorFoundationPanel.theSlabSitsOnTheFoundation" +msgstr "El forjado se apoya en la cimentación (o el terreno): uno más grueso sube la cara superior del suelo y todo lo que hay encima." -# Source-Hash: 64916cc9ea80f43f +# Source-Hash: 044ccae8bec574e7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Expand panel" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Under the floor" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.expandPanel" -msgstr "Expandir panel" +msgid "editor.panels.floorFoundationPanel.underTheFloor" +msgstr "Bajo el suelo" -# Source-Hash: 8a9a25621f200922 +# Source-Hash: 6aca44df3e582a81 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Manage collections…" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A hatch in the mezzanine: it cuts only the mezzanine’s floor." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.manageCollections" -msgstr "Gestionar colecciones…" +msgid "editor.panels.floorOpeningPanel.aHatchInTheMezzanineIt" +msgstr "Trampilla en la entreplanta: solo corta el suelo de la entreplanta." -# Source-Hash: 2ff02ed91f54235c +# Source-Hash: 2ce79639d42da658 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open {title}" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Also cut the ceiling below" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.openTitle" -msgstr "Abrir {title}" +msgid "editor.panels.floorOpeningPanel.alsoCutTheCeilingBelow" +msgstr "Cortar también el techo inferior" -# Source-Hash: bf91b71a9aa76e94 +# Source-Hash: e360814f64792300 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Also cut the floor above" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.reset" -msgstr "Restablecer" +msgid "editor.panels.floorOpeningPanel.alsoCutTheFloorAbove" +msgstr "Cortar también el suelo superior" -# Source-Hash: 04a212d6317f6787 +# Source-Hash: c25cddf8b831c2b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "“{title}” hit an error and was unloaded for this session." -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} · Drag its corners to change the shape." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.titleHitAnErrorAndWas" -msgstr "«{title}» ha tenido un error y se ha descargado durante esta sesión." +msgid "editor.panels.floorOpeningPanel.areaDragCorners" +msgstr "{area} · Arrastra sus esquinas para cambiar la forma." -# Source-Hash: 37d9f63758abdb67 +# Source-Hash: 32b168cf010a5daa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mixed" -#: packages/editor/src/components/ui/panels/parametric-field-control.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} · Shape follows its owner." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.parametricFieldControl.mixed" -msgstr "Mixto" +msgid "editor.panels.floorOpeningPanel.areaOwned" +msgstr "{area} · La forma sigue a su propietario." -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 71b5c7184cbd2e5d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/editor/src/components/ui/panels/parametric-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} · Drag its sides or corners to resize it; it moves with the stair." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.parametricInspector.actions" -msgstr "Acciones" +msgid "editor.panels.floorOpeningPanel.areaStairResize" +msgstr "{area} · Arrastra sus lados o esquinas para cambiar su tamaño; se mueve con la escalera." # Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" -#: packages/editor/src/components/ui/panels/parametric-inspector.tsx +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.parametricInspector.delete" +msgid "editor.panels.floorOpeningPanel.delete" msgstr "Eliminar" -# Source-Hash: e2411929697b7ed4 +# Source-Hash: 16552c2580bbe8b8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete with contents" -#: packages/editor/src/components/ui/panels/parametric-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.parametricInspector.deleteWithContents" -msgstr "Eliminar con el contenido" +msgid "editor.panels.floorOpeningPanel.done" +msgstr "Hecho" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/editor/src/components/ui/panels/parametric-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.parametricInspector.move" -msgstr "Mover" +msgid "editor.panels.floorOpeningPanel.kicker" +msgstr "Abertura" -# Source-Hash: c0774c185060fc13 +# Source-Hash: 079ad92dac7947cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening · {level}" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.cancel" -msgstr "Cancelar" +msgid "editor.panels.floorOpeningPanel.kickerLevel" +msgstr "Hueco · {level}" -# Source-Hash: 3a0701ebcb9f26cb +# Source-Hash: baf2c2c209637e5f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Capture" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening · in {room}" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.capture" -msgstr "Captura" +msgid "editor.panels.floorOpeningPanel.kickerRoom" +msgstr "Hueco · en {room}" -# Source-Hash: 5211341ed18f33f6 +# Source-Hash: 1712c164335ecd86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening · in {room} · {level}" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.center" -msgstr "Centro" +msgid "editor.panels.floorOpeningPanel.kickerRoomLevel" +msgstr "Hueco · en {room} · {level}" -# Source-Hash: a5b965dfb0bf2cd3 +# Source-Hash: 88e673123b9dbfe1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On {level}, as one void with this opening." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.clearScale" -msgstr "Borrar escala" +msgid "editor.panels.floorOpeningPanel.oneVoidWith" +msgstr "En {level}, como un único vacío con este hueco." -# Source-Hash: 4edc6e45b0c19447 +# Source-Hash: c38959fc8fd3e59d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click both ends of a known distance on the plan, then type its real length." -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Owned by Elevator" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.clickBothEndsOfAKnown" -msgstr "Haz clic en los dos extremos de una distancia conocida en el plano y escribe su longitud real." +msgid "editor.panels.floorOpeningPanel.ownedByElevator" +msgstr "Pertenece al ascensor" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 01494805cf60d78d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Owned by Staircase" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.delete" -msgstr "Eliminar" +msgid "editor.panels.floorOpeningPanel.ownedByStaircase" +msgstr "Pertenece a la escalera" -# Source-Hash: 59f7d81e8d36a157 +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw a line over a known dimension on the plan, then type its real length to scale the image exactly." -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.drawALineOverAKnown" -msgstr "Dibuja una línea sobre una cota conocida del plano y escribe su longitud real para escalar la imagen con exactitud." +msgid "editor.panels.floorOpeningPanel.room" +msgstr "Estancia" -# Source-Hash: 42f6d0e4f065f114 +# Source-Hash: 1405b914a324b153 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "There is no floor above this storey." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.editScale" -msgstr "Editar escala" +msgid "editor.panels.floorOpeningPanel.thereIsNoFloorAboveThis" +msgstr "No hay suelo encima de esta planta." -# Source-Hash: e156c84cbc90e0a7 +# Source-Hash: 776170dcae88e969 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guide Image" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "There is no storey below." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.guideImage" -msgstr "Imagen guía" +msgid "editor.panels.floorOpeningPanel.thereIsNoStoreyBelow" +msgstr "No hay planta debajo." -# Source-Hash: 591087ea83a48ead +# Source-Hash: 0fdd1877a0f2d777 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{source, select, stair {Stair opening} elevator {Elevator opening} ceiling {Ceiling opening} other {Floor opening}}" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.hide" -msgstr "Ocultar" +msgid "editor.panels.floorOpeningPanel.title" +msgstr "{source, select, stair {Hueco de escalera} elevator {Hueco de ascensor} ceiling {Hueco de techo} other {Hueco de suelo}}" -# Source-Hash: dd282ce13b9085ba +# Source-Hash: fa35c7653e1f649e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "One of them already wraps another corner. Unwrap it first." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.hideScale" -msgstr "Ocultar escala" +msgid "editor.panels.mergeRefusal.alreadyJoined" +msgstr "Una de ellas ya rodea otra esquina. Sepárala primero." -# Source-Hash: fc6eaa65315f601d +# Source-Hash: dd87eb1983876459 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Image" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{kind, select, item {There is an item between them.} door {There is a door between them.} window {There is a window between them.} shelf {There is a shelf between them.} other {There is something between them.}}" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.image" -msgstr "Imagen" +msgid "editor.panels.mergeRefusal.between" +msgstr "{kind, select, item {Hay un elemento entre ellas.} door {Hay una puerta entre ellas.} window {Hay una ventana entre ellas.} shelf {Hay un estante entre ellas.} other {Hay algo entre ellas.}}" -# Source-Hash: 241399e11d93bd7b +# Source-Hash: 58aea0b9789ae280 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lock" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "These windows cannot be merged." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.lock" -msgstr "Bloquear" +msgid "editor.panels.mergeRefusal.cannotMerge" +msgstr "Estas ventanas no se pueden unir." -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 15170cfd9d666c4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Their walls meet at too sharp or too flat an angle for a corner window." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.move" -msgstr "Mover" +msgid "editor.panels.mergeRefusal.cornerAngle" +msgstr "Sus muros se encuentran en un ángulo demasiado agudo o demasiado plano para una ventana de esquina." -# Source-Hash: 1c0b8a5503c5daeb +# Source-Hash: f2818a1e20ebd6ca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opacity" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The window selected first is taller than the other wall. Select the other one first." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.opacity" -msgstr "Opacidad" +msgid "editor.panels.mergeRefusal.heightExceedsWall" +msgstr "La ventana seleccionada primero es más alta que el otro muro. Selecciona primero la otra." -# Source-Hash: 6ca213a6b299f19f +# Source-Hash: 7c97fb4af929d4db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overlay image unavailable. Replace the image to restore it." -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "They are too far apart. Windows merge with at most {reach} between them." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.overlayImageUnavailableReplaceTheImage" -msgstr "Imagen superpuesta no disponible. Sustituye la imagen para restaurarla." +msgid "editor.panels.mergeRefusal.notAdjacent" +msgstr "Están demasiado separadas. Las ventanas se unen con un máximo de {reach} entre ellas." -# Source-Hash: 28fe6e9deddde6e8 +# Source-Hash: 57a281bdc4229b6d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "pos" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "One of them is too far from the corner. A window joins one within {reach} of it." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.pos" -msgstr "pos" +msgid "editor.panels.mergeRefusal.notAtCorner" +msgstr "Una de ellas está demasiado lejos de la esquina. Una ventana se une a otra a menos de {reach}." -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: e7d41ce7879ec075 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A roof or dormer window cannot join another window." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.position" -msgstr "Posición" +msgid "editor.panels.mergeRefusal.notOnWall" +msgstr "Una ventana de cubierta o de buhardilla no puede unirse a otra ventana." -# Source-Hash: 8b003432b36230c4 +# Source-Hash: eaad567d5e4257dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Quick Actions" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{kind, select, item {Sliding them to the corner would overlap an item.} door {Sliding them to the corner would overlap a door.} window {Sliding them to the corner would overlap a window.} shelf {Sliding them to the corner would overlap a shelf.} other {Sliding them to the corner would overlap something.}}" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.quickActions" -msgstr "Acciones rápidas" +msgid "editor.panels.mergeRefusal.overlap" +msgstr "{kind, select, item {Deslizarlas hasta la esquina se solaparía con un elemento.} door {Deslizarlas hasta la esquina se solaparía con una puerta.} window {Deslizarlas hasta la esquina se solaparía con una ventana.} shelf {Deslizarlas hasta la esquina se solaparía con un estante.} other {Deslizarlas hasta la esquina se solaparía con otro elemento.}}" -# Source-Hash: dcd4728e9ca90181 +# Source-Hash: ecb092821ed5b5e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reference Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Their walls do not meet at a corner." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.referenceScale" -msgstr "Escala de referencia" +msgid "editor.panels.mergeRefusal.wallsNotMeeting" +msgstr "Sus muros no se encuentran en una esquina." -# Source-Hash: 0cb87327b8076151 +# Source-Hash: 37d9f63758abdb67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mixed" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +#: packages/editor/src/components/ui/panels/parametric-field-control.tsx #, fuzzy -msgid "editor.panels.referencePanel.replace" -msgstr "Reemplazar" +msgid "editor.panels.mixed" +msgstr "Mixto" -# Source-Hash: 08b45f9ba66eab3b +# Source-Hash: d7cf5045c01b2eb9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replacing..." -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close" +#: packages/editor/src/components/ui/panels/mobile-panel-sheet.tsx #, fuzzy -msgid "editor.panels.referencePanel.replacing" -msgstr "Reemplazando..." +msgid "editor.panels.mobilePanelSheet.close" +msgstr "Cerrar" -# Source-Hash: 2714b5a81cedb625 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset Image Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx #, fuzzy -msgid "editor.panels.referencePanel.resetImageScale" -msgstr "Restablecer escala de imagen" +msgid "editor.panels.mobileSelectionBar.delete" +msgstr "Eliminar" -# Source-Hash: a05d3e429ae259ae +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset Rotation" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx #, fuzzy -msgid "editor.panels.referencePanel.resetRotation" -msgstr "Restablecer rotación" +msgid "editor.panels.mobileSelectionBar.duplicate" +msgstr "Duplicar" -# Source-Hash: 5f433581c8f404fa +# Source-Hash: 7eb955d866c2668b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "rot" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit properties" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx #, fuzzy -msgid "editor.panels.referencePanel.rot" -msgstr "rot" +msgid "editor.panels.mobileSelectionBar.editProperties" +msgstr "Editar propiedades" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: 89f25aa13e8192bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit {resolvedLabel}" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx #, fuzzy -msgid "editor.panels.referencePanel.rotation" -msgstr "Rotación" +msgid "editor.panels.mobileSelectionBar.editResolvedlabel" +msgstr "Editar {resolvedLabel}" -# Source-Hash: 58fee802997c811c +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx #, fuzzy -msgid "editor.panels.referencePanel.scale" -msgstr "escala" +msgid "editor.panels.mobileSelectionBar.move" +msgstr "Mover" -# Source-Hash: e7d0e7d41a775fd8 +# Source-Hash: 72be05e1796526c9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scaled · {scale}" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Currently {currentLabel}" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.panels.referencePanel.scaled" -msgstr "Escalado · {scale}" +msgid "editor.panels.multiHeightMode.currentlyCurrentlabel" +msgstr "Actualmente {currentLabel}" -# Source-Hash: cd92eebfb30e708f +# Source-Hash: b2a1b3bc9676fe05 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scaled (hidden) · {scale}" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom height" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.panels.referencePanel.scaledHidden" -msgstr "Escalado (oculto) · {scale}" +msgid "editor.panels.multiHeightMode.customHeight" +msgstr "Altura personalizada" -# Source-Hash: bfd20999de7f216a +# Source-Hash: a5c2353769b603d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scale & Opacity" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows level" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.panels.referencePanel.scaleOpacity" -msgstr "Escala y opacidad" +msgid "editor.panels.multiHeightMode.followsLevel" +msgstr "Sigue la planta" -# Source-Hash: 8d8777505acdf78e +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.panels.referencePanel.setScale" -msgstr "Definir escala" +msgid "editor.panels.multiHeightMode.height" +msgstr "Altura" -# Source-Hash: 827e0c6ac9936b69 +# Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.panels.referencePanel.show" -msgstr "Mostrar" +msgid "editor.panels.multiHeightMode.top" +msgstr "Superior" -# Source-Hash: 78be2337f0e81973 +# Source-Hash: 70f48b0141b656f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label} (session only). Plain click reselects all members. Not saved with the project." +#: packages/editor/src/components/ui/panels/multi-parametric-inspector.tsx #, fuzzy -msgid "editor.panels.referencePanel.showScale" -msgstr "Mostrar escala" +msgid "editor.panels.multiParametricInspector.labelSessionOnlyPlainClickReselects" +msgstr "{label} (solo en esta sesión). Un clic simple vuelve a seleccionar todos los miembros. No se guarda con el proyecto." -# Source-Hash: ad85a193442c8f76 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Uncalibrated" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.uncalibrated" -msgstr "Sin calibrar" +msgid "editor.panels.multiSelectionPanel.delete" +msgstr "Eliminar" -# Source-Hash: 6c500cc253ab3fd4 +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unlock" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.unlock" -msgstr "Desbloquear" +msgid "editor.panels.multiSelectionPanel.duplicate" +msgstr "Duplicar" -# Source-Hash: 4b8d7e52013d1691 +# Source-Hash: b0e7e3b47dfb5a0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "XYZ" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Group" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.xyz" -msgstr "XYZ" +msgid "editor.panels.multiSelectionPanel.group" +msgstr "Agrupar" -# Source-Hash: e01549105012f8d2 +# Source-Hash: ca0a95fe0b08b8b6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "+ Add mezzanine" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Group (Ctrl/Cmd+G)" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.addMezzanine" -msgstr "+ Añadir entreplanta" +msgid "editor.panels.multiSelectionPanel.groupCtrlCmdG" +msgstr "Agrupar (Ctrl/Cmd+G)" -# Source-Hash: 167b0fe7fdbcd51d +# Source-Hash: 70f48b0141b656f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A drawn slab: set its thickness and finishes here. It has no footprint height or foundation." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label} (session only). Plain click reselects all members. Not saved with the project." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.aDrawnSlabSetItsThickness" -msgstr "Forjado dibujado: define aquí su espesor y acabados. No tiene altura de huella ni cimentación." +msgid "editor.panels.multiSelectionPanel.labelSessionOnlyPlainClickReselects" +msgstr "{label} (solo en esta sesión). Un clic simple vuelve a seleccionar todos los miembros. No se guarda con el proyecto." -# Source-Hash: 6cb0969b65fb60bf +# Source-Hash: fc98ef29c2842341 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "At floor level" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{length} selected" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.atFloorLevel" -msgstr "A nivel del suelo" +msgid "editor.panels.multiSelectionPanel.lengthSelected" +msgstr "{length} seleccionados" -# Source-Hash: e8563d5ae1ee7390 +# Source-Hash: 323aaf1ebd04ada7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Built on" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Merge windows" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.builtOn" -msgstr "Construido sobre" +msgid "editor.panels.multiSelectionPanel.mergeWindows" +msgstr "Unir ventanas" -# Source-Hash: 8e5ca7510677460c +# Source-Hash: 7855d03a6140af77 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Built with" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Merge windows into a corner window: both take the height, sill and type of the one you selected first" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.builtWith" -msgstr "Construido con" +msgid "editor.panels.multiSelectionPanel.mergeWindowsIntoACornerWindow" +msgstr "Unir en una ventana de esquina: ambas toman la altura, el alféizar y el tipo de la primera seleccionada" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: b79da96502d2e1c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Merge windows into one across both: it keeps the type and style of the one you selected first" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.ceiling" -msgstr "Techo" +msgid "editor.panels.multiSelectionPanel.mergeWindowsIntoOneAcrossBoth" +msgstr "Unir en una sola ventana que abarca ambas: conserva el tipo y el estilo de la primera seleccionada" -# Source-Hash: 9bf177f59f971033 +# Source-Hash: f409934681a046e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "At {height}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select building" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.ceilingAt" -msgstr "A {height}" +msgid "editor.panels.multiSelectionPanel.selectBuilding" +msgstr "Seleccionar edificio" -# Source-Hash: 48768dc0fc7b86a4 +# Source-Hash: c62a73873bd0164d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close with walls" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select the whole building to move all its levels" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.closeWithWalls" -msgstr "Cerrar con muros" +msgid "editor.panels.multiSelectionPanel.selectTheWholeBuildingToMove" +msgstr "Selecciona todo el edificio para mover todas sus plantas" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 75c84b4f21aefde4 +# Source-Hash: 7bd5f29203a28efb # Review: required -# English: "{ambiguous, select, yes {Floor is several drawn slabs, mostly {name}} other {Floor is a drawn slab: {name}}}{shared, plural, =0 {} one { (shared with {sharedCount} room)} other { (shared with {sharedCount} rooms)}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ungroup" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.drawnFloor" -msgstr "{ambiguous, select, yes {El suelo son varios forjados dibujados, sobre todo {name}} other {El suelo es un forjado dibujado: {name}}}{shared, plural, =0 {} one { (compartido con {sharedCount} estancia)} many { (compartido con {sharedCount} estancias)} other { (compartido con {sharedCount} estancias)}}" +msgid "editor.panels.multiSelectionPanel.ungroup" +msgstr "Desagrupar" -# Source-Hash: 97e0fab8ffda6d6c +# Source-Hash: aec9c3983a440d4a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "This floor is a drawn slab: select it to edit or delete it." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ungroup (Ctrl/Cmd+Shift+G)" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.drawnFloorSwitchHint" -msgstr "Este suelo es un forjado dibujado: selecciónalo para editarlo o eliminarlo." +msgid "editor.panels.multiSelectionPanel.ungroupCtrlCmdShiftG" +msgstr "Desagrupar (Ctrl/Cmd+Mayús+G)" -# Source-Hash: ad5426620188242c +# Source-Hash: 420385f27c627cee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawn slab" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unwrap the corner" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.drawnSlab" -msgstr "Forjado dibujado" +msgid "editor.panels.multiSelectionPanel.unwrapTheCorner" +msgstr "Separar la esquina" -# Source-Hash: 0da0d104eaefbbad +# Source-Hash: 7906c9f4baebc70b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawn slab at {height}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unwrap the corner: both windows stay, each framed at the corner" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.drawnSlabAt" -msgstr "Forjado dibujado a {height}" +msgid "editor.panels.multiSelectionPanel.unwrapTheCornerBothWindowsStay" +msgstr "Separar la esquina: ambas ventanas se mantienen, cada una con su marco en la esquina" -# Source-Hash: 5dfead58503dbc86 +# Source-Hash: 170b2049ef0f9131 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit shape" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selection" +#: packages/editor/src/components/ui/panels/panel-manager.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.editShape" -msgstr "Editar forma" +msgid "editor.panels.panelManager.selection" +msgstr "Selección" -# Source-Hash: fadf264be55063e5 +# Source-Hash: 7ceade8f25b58fe9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat, at wall height" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.flatAtWallHeight" -msgstr "Plano, a la altura del muro" +msgid "editor.panels.panelWrapper.back" +msgstr "Volver" -# Source-Hash: d7148fa065bc709b +# Source-Hash: d7cf5045c01b2eb9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.floor" -msgstr "Planta" +msgid "editor.panels.panelWrapper.close" +msgstr "Cerrar" -# Source-Hash: 996e8191c069e779 +# Source-Hash: 4f15c3e0fe6178b5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{distance} down" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collapse panel" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.floorDown" -msgstr "{distance} más bajo" +msgid "editor.panels.panelWrapper.collapsePanel" +msgstr "Contraer panel" -# Source-Hash: 73614b8faa059cd6 +# Source-Hash: 135af27a14a4cda7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor thickness" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collections" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.floorThickness" -msgstr "Espesor del suelo" +msgid "editor.panels.panelWrapper.collections" +msgstr "Colecciones" -# Source-Hash: 79cdde853c3e8f61 +# Source-Hash: 64916cc9ea80f43f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{distance} up" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Expand panel" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.floorUp" -msgstr "{distance} más alto" +msgid "editor.panels.panelWrapper.expandPanel" +msgstr "Expandir panel" -# Source-Hash: 77bc12b7aba0eb60 +# Source-Hash: 8a9a25621f200922 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hand-drawn ceiling" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Manage collections…" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.handDrawnCeiling" -msgstr "Techo dibujado a mano" +msgid "editor.panels.panelWrapper.manageCollections" +msgstr "Gestionar colecciones…" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: bf91b71a9aa76e94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.height" -msgstr "Altura" +msgid "editor.panels.panelWrapper.reset" +msgstr "Restablecer" -# Source-Hash: 4d35023efe090b82 +# Source-Hash: 04a212d6317f6787 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Include floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "“{title}” hit an error and was unloaded for this session." +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.includeFloor" -msgstr "Incluir suelo" +msgid "editor.panels.panelWrapper.titleHitAnErrorAndWas" +msgstr "«{title}» ha tenido un error y se ha descargado durante esta sesión." -# Source-Hash: 6398ac77644eb5f6 +# Source-Hash: 37d9f63758abdb67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{part, select, floor {Include floor} walls {Include walls} other {Include ceiling}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mixed" +#: packages/editor/src/components/ui/panels/parametric-field-control.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.includePart" -msgstr "{part, select, floor {Incluir suelo} walls {Incluir muros} other {Incluir techo}}" +msgid "editor.panels.parametricFieldControl.mixed" +msgstr "Mixto" -# Source-Hash: 3629e64a6e796ca9 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Include walls" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/editor/src/components/ui/panels/parametric-inspector.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.includeWalls" -msgstr "Incluir muros" +msgid "editor.panels.parametricInspector.actions" +msgstr "Acciones" -# Source-Hash: f6d07fc7f239278b +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Keep outside dimensions" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/parametric-inspector.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.keepOutsideDimensions" -msgstr "Mantener dimensiones exteriores" +msgid "editor.panels.parametricInspector.delete" +msgstr "Eliminar" -# Source-Hash: 544410e3cb0e0b07 +# Source-Hash: e2411929697b7ed4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lowered {lift}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete with contents" +#: packages/editor/src/components/ui/panels/parametric-inspector.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.lowered" -msgstr "Bajado {lift}" +msgid "editor.panels.parametricInspector.deleteWithContents" +msgstr "Eliminar con el contenido" -# Source-Hash: c2daf78b740e4397 +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "+ New floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/editor/src/components/ui/panels/parametric-inspector.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.newFloor" -msgstr "+ Nuevo suelo" +msgid "editor.panels.parametricInspector.move" +msgstr "Mover" -# Source-Hash: ba9edc7910a60cea +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.noFloor" -msgstr "Sin suelo" +msgid "editor.panels.referencePanel.cancel" +msgstr "Cancelar" -# Source-Hash: ea2675041df74f40 +# Source-Hash: 3a0701ebcb9f26cb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Nothing to change." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Capture" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.nothingToChange" -msgstr "Nada que cambiar." +msgid "editor.panels.referencePanel.capture" +msgstr "Captura" -# Source-Hash: ebe0d375d7938c93 +# Source-Hash: 5211341ed18f33f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Not included" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.notIncluded" -msgstr "No incluido" +msgid "editor.panels.referencePanel.center" +msgstr "Centro" -# Source-Hash: e9440fa9f770b7a4 +# Source-Hash: a5b965dfb0bf2cd3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "On the ground" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.onTheGround" -msgstr "Sobre el terreno" +msgid "editor.panels.referencePanel.clearScale" +msgstr "Borrar escala" -# Source-Hash: a5deb36c485d91bd +# Source-Hash: 4edc6e45b0c19447 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "On the walls below" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click both ends of a known distance on the plan, then type its real length." +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.onTheWallsBelow" -msgstr "Sobre los muros inferiores" +msgid "editor.panels.referencePanel.clickBothEndsOfAKnown" +msgstr "Haz clic en los dos extremos de una distancia conocida en el plano y escribe su longitud real." -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 2256aec0d5bdc3ea +# Source-Hash: b26de372b4b0eaac # Review: required -# English: "{openSides, plural, one {{openSideCount} open side} other {{openSideCount} open sides}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.openSides" -msgstr "{openSides, plural, one {{openSideCount} lado abierto} many {{openSideCount} lados abiertos} other {{openSideCount} lados abiertos}}" +msgid "editor.panels.referencePanel.delete" +msgstr "Eliminar" -# Source-Hash: f704520c5e5b92b2 +# Source-Hash: 59f7d81e8d36a157 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Partial · {coverage, number, percent} covered" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw a line over a known dimension on the plan, then type its real length to scale the image exactly." +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.partialCovered" -msgstr "Parcial · {coverage, number, percent} cubierto" +msgid "editor.panels.referencePanel.drawALineOverAKnown" +msgstr "Dibuja una línea sobre una cota conocida del plano y escribe su longitud real para escalar la imagen con exactitud." -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: b648bee0231a41cd +# Source-Hash: 42f6d0e4f065f114 # Review: required -# English: "Partial · {walls, plural, one {{wallCount} wall} other {{wallCount} walls}}, {openSides, plural, one {{openSideCount} open side} other {{openSideCount} open sides}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.partialWalls" -msgstr "Parcial · {walls, plural, one {{wallCount} muro} many {{wallCount} muros} other {{wallCount} muros}}, {openSides, plural, one {{openSideCount} lado abierto} many {{openSideCount} lados abiertos} other {{openSideCount} lados abiertos}}" +msgid "editor.panels.referencePanel.editScale" +msgstr "Editar escala" -# Source-Hash: e503250e8ecb0030 +# Source-Hash: e156c84cbc90e0a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised {lift}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guide Image" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.raised" -msgstr "Elevado {lift}" +msgid "editor.panels.referencePanel.guideImage" +msgstr "Imagen guía" -# Source-Hash: 0cb87327b8076151 +# Source-Hash: 591087ea83a48ead # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.replace" -msgstr "Reemplazar" +msgid "editor.panels.referencePanel.hide" +msgstr "Ocultar" -# Source-Hash: a4395168488bb476 +# Source-Hash: dd282ce13b9085ba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.select" -msgstr "Seleccionar" +msgid "editor.panels.referencePanel.hideScale" +msgstr "Ocultar escala" -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: fc6eaa65315f601d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Image" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.shape" -msgstr "Forma" +msgid "editor.panels.referencePanel.image" +msgstr "Imagen" -# Source-Hash: aafd84823715d698 +# Source-Hash: 241399e11d93bd7b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Turning walls off keeps the ones shared with {rooms}." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lock" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.sharedWallsNote" -msgstr "Desactivar los muros conserva los compartidos con {rooms}." +msgid "editor.panels.referencePanel.lock" +msgstr "Bloquear" -# Source-Hash: c98df900d43f77bc +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sits on: {name} · {preset}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.sitsOnPreset" -msgstr "Apoya en: {name} · {preset}" +msgid "editor.panels.referencePanel.move" +msgstr "Mover" -# Source-Hash: a17a79e835fa2064 +# Source-Hash: 1c0b8a5503c5daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "the next room" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opacity" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.theNextRoom" -msgstr "la estancia contigua" +msgid "editor.panels.referencePanel.opacity" +msgstr "Opacidad" -# Source-Hash: ebae699e0cb18ea6 +# Source-Hash: 6ca213a6b299f19f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use existing" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overlay image unavailable. Replace the image to restore it." +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.useExisting" -msgstr "Usar el existente" +msgid "editor.panels.referencePanel.overlayImageUnavailableReplaceTheImage" +msgstr "Imagen superpuesta no disponible. Sustituye la imagen para restaurarla." -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 9976021d9162cd5e +# Source-Hash: 28fe6e9deddde6e8 # Review: required -# English: "{walls, plural, one {{wallCount} wall} other {{wallCount} walls}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "pos" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.wallCount" -msgstr "{walls, plural, one {{wallCount} muro} many {{wallCount} muros} other {{wallCount} muros}}" +msgid "editor.panels.referencePanel.pos" +msgstr "pos" -# Source-Hash: aac9a732d2159ccc +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.walls" -msgstr "Muros" +msgid "editor.panels.referencePanel.position" +msgstr "Posición" -# Source-Hash: 6c69eb46a0c40d52 +# Source-Hash: 8b003432b36230c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls thicken inward, so the building's outer size stays the same." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Quick Actions" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.wallsThickenInwardSoTheBuilding" -msgstr "Los muros engrosan hacia dentro, así que el tamaño exterior del edificio no cambia." +msgid "editor.panels.referencePanel.quickActions" +msgstr "Acciones rápidas" -# Source-Hash: 4e4f1a24e4a9d61e +# Source-Hash: dcd4728e9ca90181 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut opening" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reference Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.cutOpening" -msgstr "Abrir hueco" +msgid "editor.panels.referencePanel.referenceScale" +msgstr "Escala de referencia" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: 0cb87327b8076151 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.done" -msgstr "Hecho" +msgid "editor.panels.referencePanel.replace" +msgstr "Reemplazar" -# Source-Hash: 2c89abb1778a3f9b +# Source-Hash: 08b45f9ba66eab3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit floor" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replacing..." +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.editFloor" -msgstr "Editar suelo" +msgid "editor.panels.referencePanel.replacing" +msgstr "Reemplazando..." -# Source-Hash: ca18a6c5398fc8ab +# Source-Hash: 2714b5a81cedb625 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevator opening" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset Image Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.elevatorOpening" -msgstr "Hueco de ascensor" +msgid "editor.panels.referencePanel.resetImageScale" +msgstr "Restablecer escala de imagen" -# Source-Hash: eafea43e795f3708 +# Source-Hash: a05d3e429ae259ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No openings yet. Cut one for a stair void or a hatch." -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset Rotation" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.noOpeningsYetCutOneFor" -msgstr "Aún no hay huecos. Corta uno para el hueco de una escalera o una trampilla." +msgid "editor.panels.referencePanel.resetRotation" +msgstr "Restablecer rotación" -# Source-Hash: 60fac94ffa614238 +# Source-Hash: 5f433581c8f404fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening {number}" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "rot" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.openingNumber" -msgstr "Hueco {number}" +msgid "editor.panels.referencePanel.rot" +msgstr "rot" -# Source-Hash: 7aafbf90d659dcf6 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, =0 {No openings} one {{number} opening} other {{number} openings}}" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.openings" -msgstr "{count, plural, =0 {Sin aberturas} one {{number} abertura} many {{number} aberturas} other {{number} aberturas}}" +msgid "editor.panels.referencePanel.rotation" +msgstr "Rotación" -# Source-Hash: c1a1794d31990f5a +# Source-Hash: 58fee802997c811c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair opening" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.stairOpening" -msgstr "Hueco de escalera" +msgid "editor.panels.referencePanel.scale" +msgstr "escala" -# Source-Hash: f0a46329fef44d94 +# Source-Hash: e7d0e7d41a775fd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add stairs" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scaled · {scale}" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.addStairs" -msgstr "Añadir escalera" +msgid "editor.panels.referencePanel.scaled" +msgstr "Escalado · {scale}" -# Source-Hash: 8a2ab34a61b9d181 +# Source-Hash: cd92eebfb30e708f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add to a unit" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scaled (hidden) · {scale}" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.addToAUnit" -msgstr "Añadir a una unidad" +msgid "editor.panels.referencePanel.scaledHidden" +msgstr "Escalado (oculto) · {scale}" -# Source-Hash: 8332ab41e22958f1 +# Source-Hash: bfd20999de7f216a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Area" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scale & Opacity" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.area" -msgstr "Área" +msgid "editor.panels.referencePanel.scaleOpacity" +msgstr "Escala y opacidad" -# Source-Hash: 88f1a727e5528c10 +# Source-Hash: 8d8777505acdf78e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Browse" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.browse" -msgstr "Explorar" +msgid "editor.panels.referencePanel.setScale" +msgstr "Definir escala" -# Source-Hash: 8e5ca7510677460c +# Source-Hash: 827e0c6ac9936b69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Built with" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.builtWith" -msgstr "Construido con" +msgid "editor.panels.referencePanel.show" +msgstr "Mostrar" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: 78be2337f0e81973 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.ceiling" -msgstr "Techo" +msgid "editor.panels.referencePanel.showScale" +msgstr "Mostrar escala" -# Source-Hash: a5e4fe4960deced9 +# Source-Hash: ad85a193442c8f76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete room" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Uncalibrated" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.deleteRoom" -msgstr "Eliminar estancia" +msgid "editor.panels.referencePanel.uncalibrated" +msgstr "Sin calibrar" -# Source-Hash: 5dfead58503dbc86 +# Source-Hash: 6c500cc253ab3fd4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit shape" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unlock" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.editShape" -msgstr "Editar forma" +msgid "editor.panels.referencePanel.unlock" +msgstr "Desbloquear" -# Source-Hash: d7148fa065bc709b +# Source-Hash: 4b8d7e52013d1691 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "XYZ" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.floor" -msgstr "Planta" +msgid "editor.panels.referencePanel.xyz" +msgstr "XYZ" -# Source-Hash: d17c3b63449c052b +# Source-Hash: e01549105012f8d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{height} headroom" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "+ Add mezzanine" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.headroom" -msgstr "Altura libre de {height}" +msgid "editor.panels.roomConstructionRows.addMezzanine" +msgstr "+ Añadir entreplanta" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: 167b0fe7fdbcd51d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A drawn slab: set its thickness and finishes here. It has no footprint height or foundation." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.height" -msgstr "Altura" +msgid "editor.panels.roomConstructionRows.aDrawnSlabSetItsThickness" +msgstr "Forjado dibujado: define aquí su espesor y acabados. No tiene altura de huella ni cimentación." -# Source-Hash: 2d89c1638aa8dd7e +# Source-Hash: 6cb0969b65fb60bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide code" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "At floor level" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.hideCode" -msgstr "Ocultar código" +msgid "editor.panels.roomConstructionRows.atFloorLevel" +msgstr "A nivel del suelo" -# Source-Hash: e93969f5a7cbb140 +# Source-Hash: e14858b33b6e2623 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room · {level}" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.kickerLevel" -msgstr "Estancia · {level}" +msgid "editor.panels.roomConstructionRows.beam" +msgstr "Viga" -# Source-Hash: f4ad56b4e0c014b3 +# Source-Hash: 4b03c226d5f88a42 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine · in {room}" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam size" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.kickerMezzanineIn" -msgstr "Entreplanta · en {room}" +msgid "editor.panels.roomConstructionRows.beamSize" +msgstr "Tamaño de la viga" -# Source-Hash: de37205633316011 +# Source-Hash: e8563d5ae1ee7390 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room · not enclosed" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Built on" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.kickerNotEnclosed" -msgstr "Estancia · no cerrada" +msgid "editor.panels.roomConstructionRows.builtOn" +msgstr "Construido sobre" -# Source-Hash: 9e84d6d7b9885c4f +# Source-Hash: 8e5ca7510677460c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Loading…" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Built with" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.loading" -msgstr "Cargando…" +msgid "editor.panels.roomConstructionRows.builtWith" +msgstr "Construido con" -# Source-Hash: 194a147d4618a994 +# Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.mezzanine" -msgstr "Altillo" +msgid "editor.panels.roomConstructionRows.ceiling" +msgstr "Techo" -# Source-Hash: 97de3df03c4a0be6 +# Source-Hash: 9bf177f59f971033 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine name" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "At {height}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.mezzanineName" -msgstr "Nombre de la entreplanta" +msgid "editor.panels.roomConstructionRows.ceilingAt" +msgstr "A {height}" -# Source-Hash: 42cfb1bcb80d09e7 +# Source-Hash: 48768dc0fc7b86a4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine names" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close with walls" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.mezzanineNames" -msgstr "Nombres de entreplanta" +msgid "editor.panels.roomConstructionRows.closeWithWalls" +msgstr "Cerrar con muros" -# Source-Hash: 13b3e6a6afe319d1 +# Source-Hash: 75c84b4f21aefde4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "New unit" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{ambiguous, select, yes {Floor is several drawn slabs, mostly {name}} other {Floor is a drawn slab: {name}}}{shared, plural, =0 {} one { (shared with {sharedCount} room)} other { (shared with {sharedCount} rooms)}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.newUnit" -msgstr "Nueva unidad" +msgid "editor.panels.roomConstructionRows.drawnFloor" +msgstr "{ambiguous, select, yes {El suelo son varios forjados dibujados, sobre todo {name}} other {El suelo es un forjado dibujado: {name}}}{shared, plural, =0 {} one { (compartido con {sharedCount} estancia)} many { (compartido con {sharedCount} estancias)} other { (compartido con {sharedCount} estancias)}}" -# Source-Hash: f2953d2931e36d0c +# Source-Hash: 97e0fab8ffda6d6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This floor is a drawn slab: select it to edit or delete it." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.none" -msgstr "Ninguno" +msgid "editor.panels.roomConstructionRows.drawnFloorSwitchHint" +msgstr "Este suelo es un forjado dibujado: selecciónalo para editarlo o eliminarlo." -# Source-Hash: e92d6108b57df9e1 +# Source-Hash: ad5426620188242c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Not enough headroom" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawn slab" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.notEnoughHeadroom" -msgstr "Altura libre insuficiente" +msgid "editor.panels.roomConstructionRows.drawnSlab" +msgstr "Forjado dibujado" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 81a6770092b05d48 +# Source-Hash: 0da0d104eaefbbad # Review: required -# English: "{doors, plural, one {{doorCount} door} other {{doorCount} doors}} · {windows, plural, one {{windowCount} window} other {{windowCount} windows}}" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawn slab at {height}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.openingCounts" -msgstr "{doors, plural, one {{doorCount} puerta} many {{doorCount} puertas} other {{doorCount} puertas}} · {windows, plural, one {{windowCount} ventana} many {{windowCount} ventanas} other {{windowCount} ventanas}}" +msgid "editor.panels.roomConstructionRows.drawnSlabAt" +msgstr "Forjado dibujado a {height}" -# Source-Hash: a8cd9507ce472a48 +# Source-Hash: 5dfead58503dbc86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{area} · Close its walls to build its floor and ceiling." -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit shape" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.openRoomArea" -msgstr "{area} · Cierra sus muros para construir su suelo y su techo." +msgid "editor.panels.roomConstructionRows.editShape" +msgstr "Editar forma" -# Source-Hash: f8aa48ec39a15616 +# Source-Hash: fadf264be55063e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Over the mezzanine" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat, at wall height" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.overTheMezzanine" -msgstr "Sobre la entreplanta" +msgid "editor.panels.roomConstructionRows.flatAtWallHeight" +msgstr "Plano, a la altura del muro" -# Source-Hash: ac87e14dabd5a256 +# Source-Hash: d7148fa065bc709b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Perimeter" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.perimeter" -msgstr "Perímetro" +msgid "editor.panels.roomConstructionRows.floor" +msgstr "Planta" -# Source-Hash: ed2aaf0a8d5a9b7b +# Source-Hash: 996e8191c069e779 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{distance} down" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.pick" -msgstr "Elegir" +msgid "editor.panels.roomConstructionRows.floorDown" +msgstr "{distance} más bajo" -# Source-Hash: 7baaebbd411cc837 +# Source-Hash: 73614b8faa059cd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picking it adds a number" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor thickness" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.pickingItAddsANumber" -msgstr "Elegirlo añade un número" +msgid "editor.panels.roomConstructionRows.floorThickness" +msgstr "Espesor del suelo" -# Source-Hash: 9469a102f04ea196 +# Source-Hash: 79cdde853c3e8f61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{distance} up" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.remove" -msgstr "Quitar" +msgid "editor.panels.roomConstructionRows.floorUp" +msgstr "{distance} más alto" -# Source-Hash: 41ac9dd23bb558d7 +# Source-Hash: b6b724f9f4db6d3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove from unit" -#: packages/editor/src/components/ui/panels/room-panel.tsx -#, fuzzy -msgid "editor.panels.roomPanel.removeFromUnit" -msgstr "Quitar de la unidad" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{posts, plural, one {{postCount} post} other {{postCount} posts}} and {beams, plural, one {{beamCount} beam} other {{beamCount} beams}}, a post on each outside corner, kept with {room, select, deck {the deck} patio {the patio} other {the porch}}." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +#, fuzzy +msgid "editor.panels.roomConstructionRows.framingAutoHint" +msgstr "{posts, plural, one {{postCount} poste} many {{postCount} postes} other {{postCount} postes}} y {beams, plural, one {{beamCount} viga} many {{beamCount} vigas} other {{beamCount} vigas}}, con un poste en cada esquina exterior, vinculados a {room, select, deck {la tarima} patio {el patio} other {el porche}}." -# Source-Hash: a11d13b92b3cefdb +# Source-Hash: d18036b75b2c3e4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove from {unit}" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Automatic" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.removeFromUnitNamed" -msgstr "Quitar de {unit}" +msgid "editor.panels.roomConstructionRows.framingAutomatic" +msgstr "Automático" -# Source-Hash: d6952b4e54d246dd +# Source-Hash: 387082cd5f118bed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rename" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Manual" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.rename" -msgstr "Cambiar nombre" +msgid "editor.panels.roomConstructionRows.framingManual" +msgstr "Manual" -# Source-Hash: 3562f9bea0a4a8f3 +# Source-Hash: 287400b1b4b46abd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{name} · Rename" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kept as you edited them. Automatic rebuilds them from these settings." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.renameNamed" -msgstr "{name} · Cambiar nombre" +msgid "editor.panels.roomConstructionRows.framingManualHint" +msgstr "Se mantienen tal como los editaste. Automático los regenera a partir de estos ajustes." -# Source-Hash: d0d4e919bb58a977 +# Source-Hash: 50accd740fa2e736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Revert" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Off" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.revert" -msgstr "Revertir" +msgid "editor.panels.roomConstructionRows.framingOff" +msgstr "Desactivado" -# Source-Hash: 612dcd5bf06a79c4 +# Source-Hash: 4dfa7082b7e30280 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None. Automatic puts a post on each outside corner and a beam on them, to carry a roof over {room, select, deck {the deck} patio {the patio} other {the porch}}." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.room" -msgstr "Estancia" +msgid "editor.panels.roomConstructionRows.framingOffHint" +msgstr "Ninguno. Automático coloca un poste en cada esquina exterior y una viga sobre ellos para sostener una cubierta sobre {room, select, deck {la tarima} patio {el patio} other {el porche}}." -# Source-Hash: 15ae260fae44f42f +# Source-Hash: 77bc12b7aba0eb60 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room colour — used in the plan and labels" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hand-drawn ceiling" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.roomColourUsedInThePlan" -msgstr "Color de la estancia: se usa en el plano y las etiquetas" +msgid "editor.panels.roomConstructionRows.handDrawnCeiling" +msgstr "Techo dibujado a mano" -# Source-Hash: bf75e739dd7e5877 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room name" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.roomName" -msgstr "Nombre de la estancia" +msgid "editor.panels.roomConstructionRows.height" +msgstr "Altura" -# Source-Hash: 2ecf8c059646873b +# Source-Hash: 4d35023efe090b82 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room names" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Include floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.roomNames" -msgstr "Nombres de estancias" +msgid "editor.panels.roomConstructionRows.includeFloor" +msgstr "Incluir suelo" -# Source-Hash: e9a0a3688faba18b +# Source-Hash: 6398ac77644eb5f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scripted finish" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{part, select, floor {Include floor} walls {Include walls} other {Include ceiling}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.scriptedFinish" -msgstr "Acabado por script" +msgid "editor.panels.roomConstructionRows.includePart" +msgstr "{part, select, floor {Incluir suelo} walls {Incluir muros} other {Incluir techo}}" -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: 3629e64a6e796ca9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Include walls" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.shape" -msgstr "Forma" +msgid "editor.panels.roomConstructionRows.includeWalls" +msgstr "Incluir muros" -# Source-Hash: e51144ca1759a7bf +# Source-Hash: f6d07fc7f239278b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show mezzanine names" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keep outside dimensions" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.showMezzanineNames" -msgstr "Mostrar nombres de entreplanta" +msgid "editor.panels.roomConstructionRows.keepOutsideDimensions" +msgstr "Mantener dimensiones exteriores" -# Source-Hash: 875b7303c47df33f +# Source-Hash: 544410e3cb0e0b07 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show room names" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lowered {lift}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.showRoomNames" -msgstr "Mostrar nombres de estancias" +msgid "editor.panels.roomConstructionRows.lowered" +msgstr "Bajado {lift}" -# Source-Hash: f05bc67c57e4d530 +# Source-Hash: c2daf78b740e4397 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stairs" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "+ New floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.stairs" -msgstr "Escalera" +msgid "editor.panels.roomConstructionRows.newFloor" +msgstr "+ Nuevo suelo" -# Source-Hash: 062cc0f1afef0c52 +# Source-Hash: ba9edc7910a60cea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unit" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.unit" -msgstr "Unidad" +msgid "editor.panels.roomConstructionRows.noFloor" +msgstr "Sin suelo" -# Source-Hash: 91436d6b374e8263 +# Source-Hash: ea2675041df74f40 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Nothing to change." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.use" -msgstr "Usar" +msgid "editor.panels.roomConstructionRows.nothingToChange" +msgstr "Nada que cambiar." -# Source-Hash: 61880aff6cd698c9 +# Source-Hash: ebe0d375d7938c93 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{used} on this level" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not included" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.usedOnThisLevel" -msgstr "{used} en esta planta" +msgid "editor.panels.roomConstructionRows.notIncluded" +msgstr "No incluido" -# Source-Hash: 611604740ed4549c +# Source-Hash: e9440fa9f770b7a4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{use} “{name}”" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On the ground" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.useTyped" -msgstr "{use} «{name}»" +msgid "editor.panels.roomConstructionRows.onTheGround" +msgstr "Sobre el terreno" -# Source-Hash: 21242af83a2a6d17 +# Source-Hash: a5deb36c485d91bd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "View code" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On the walls below" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.viewCode" -msgstr "Ver código" +msgid "editor.panels.roomConstructionRows.onTheWallsBelow" +msgstr "Sobre los muros inferiores" -# Source-Hash: ba15840e60ce672b +# Source-Hash: 2256aec0d5bdc3ea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The script could not be read." -#: packages/editor/src/components/ui/panels/room-panel.tsx -#: packages/nodes/src/wall/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{openSides, plural, one {{openSideCount} open side} other {{openSideCount} open sides}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.scriptUnreadable" -msgstr "No se ha podido leer el script." +msgid "editor.panels.roomConstructionRows.openSides" +msgstr "{openSides, plural, one {{openSideCount} lado abierto} many {{openSideCount} lados abiertos} other {{openSideCount} lados abiertos}}" -# Source-Hash: 4e186fc057733162 +# Source-Hash: f704520c5e5b92b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Polygon" -#: packages/editor/src/components/ui/panels/shape-choice.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Partial · {coverage, number, percent} covered" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.shapeChoice.polygon" -msgstr "Polígono" +msgid "editor.panels.roomConstructionRows.partialCovered" +msgstr "Parcial · {coverage, number, percent} cubierto" -# Source-Hash: 2c2c20272b0370cc +# Source-Hash: b648bee0231a41cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangle" -#: packages/editor/src/components/ui/panels/shape-choice.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Partial · {walls, plural, one {{wallCount} wall} other {{wallCount} walls}}, {openSides, plural, one {{openSideCount} open side} other {{openSideCount} open sides}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.shapeChoice.rectangle" -msgstr "Rectángulo" +msgid "editor.panels.roomConstructionRows.partialWalls" +msgstr "Parcial · {walls, plural, one {{wallCount} muro} many {{wallCount} muros} other {{wallCount} muros}}, {openSides, plural, one {{openSideCount} lado abierto} many {{openSideCount} lados abiertos} other {{openSideCount} lados abiertos}}" -# Source-Hash: 5dc88f90e6aa4129 +# Source-Hash: 4b2a51c39b382184 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete region" -#: packages/editor/src/components/ui/panels/wall-region-list.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Posts and beam" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.wallRegionList.deleteRegion" -msgstr "Eliminar región" +msgid "editor.panels.roomConstructionRows.postsAndBeam" +msgstr "Postes y viga" -# Source-Hash: d81d8cbadf5d4f33 +# Source-Hash: faa36308c1ecb2a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint regions" -#: packages/editor/src/components/ui/panels/wall-region-list.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post size" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.wallRegionList.paintRegions" -msgstr "Regiones de pintura" +msgid "editor.panels.roomConstructionRows.postSize" +msgstr "Tamaño del poste" +# Source-Hash: cc25439729a97f76 # Review: required -# Source-Hash: 89ee318aad485f83 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Adjust design" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post spacing (max)" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.adjustDesign" -msgstr "Ajustar diseño" +msgid "editor.panels.roomConstructionRows.postSpacingMax" +msgstr "Separación de postes (máx.)" +# Source-Hash: e503250e8ecb0030 # Review: required -# Source-Hash: 7ceade8f25b58fe9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised {lift}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.back" -msgstr "Volver" +msgid "editor.panels.roomConstructionRows.raised" +msgstr "Elevado {lift}" +# Source-Hash: 0cb87327b8076151 # Review: required -# Source-Hash: ba9b68175315e177 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit parts" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.editParts" -msgstr "Editar piezas" +msgid "editor.panels.roomConstructionRows.replace" +msgstr "Reemplazar" +# Source-Hash: be1c56bb3ddc63c7 # Review: required -# Source-Hash: 07c62820f014ed6c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid attachment" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room type" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidAttachment" -msgstr "Fijación no válida" +msgid "editor.panels.roomConstructionRows.roomType" +msgstr "Tipo de estancia" +# Source-Hash: f3aa561772702108 # Review: required -# Source-Hash: f862aea8d7957c55 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid edit" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidEdit" -msgstr "Edición no válida" +msgid "editor.panels.roomConstructionRows.roomTypeDeck" +msgstr "Tarima" +# Source-Hash: f0028986efecf7d1 # Review: required -# Source-Hash: 190cf30b8edd8dd1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid placement" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outdoors: deck boards on a wood frame and posts, 1 in down from the house; no ceiling." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidPlacement" -msgstr "Colocación no válida" +msgid "editor.panels.roomConstructionRows.roomTypeDeckHint" +msgstr "Exterior: tablas de tarima sobre un entramado de madera y postes, 1 in por debajo de la casa; sin techo." +# Source-Hash: 78dbe13192c0894b # Review: required -# Source-Hash: 45bd2ec690cc48dc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid position" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Patio" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidPosition" -msgstr "Posición no válida" +msgid "editor.panels.roomConstructionRows.roomTypePatio" +msgstr "Patio" +# Source-Hash: 5e4ea6a084f67808 # Review: required -# Source-Hash: faccab895717c598 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid reset" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outdoors and open: a concrete slab 1½ in down from the house, no ceiling." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidReset" -msgstr "Restablecimiento no válido" +msgid "editor.panels.roomConstructionRows.roomTypePatioHint" +msgstr "Exterior y descubierto: una losa de hormigón 1½ in por debajo de la casa, sin techo." +# Source-Hash: 97d20e41044a3235 # Review: required -# Source-Hash: 28fe6e9deddde6e8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "pos" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Porch" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.pos" -msgstr "pos" +msgid "editor.panels.roomConstructionRows.roomTypePorch" +msgstr "Porche" +# Source-Hash: af2c941e8ef874bf # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outdoors under a ceiling: a concrete slab 1½ in down from the house, ceiling at the house’s." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.position" -msgstr "Posición" +msgid "editor.panels.roomConstructionRows.roomTypePorchHint" +msgstr "Exterior bajo techo: una losa de hormigón 1½ in por debajo de la casa, con el techo a la altura del de la casa." +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# Source-Hash: 3fce677837d5a876 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset this part" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.resetThisPart" -msgstr "Restablecer esta pieza" +msgid "editor.panels.roomConstructionRows.roomTypeRoom" +msgstr "Estancia" -# Source-Hash: 5eab376947d29a50 +# Source-Hash: fb0a6cc444058631 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reload editor" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An ordinary room inside the house." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.reloadEditor" -msgstr "Recargar el editor" +msgid "editor.panels.roomConstructionRows.roomTypeRoomHint" +msgstr "Una estancia normal dentro de la casa." +# Source-Hash: a4395168488bb476 # Review: required -# Source-Hash: 1063f1e315258b20 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close riser diagram" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.close" -msgstr "Cerrar diagrama de bajantes" +msgid "editor.panels.roomConstructionRows.select" +msgstr "Seleccionar" +# Source-Hash: 85ea1d3c8b749680 # Review: required -# Source-Hash: c2d59ee62035974c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV plumbing isometric" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.dwvPlumbingIsometric" -msgstr "Isometría de saneamiento y ventilación" +msgid "editor.panels.roomConstructionRows.shape" +msgstr "Forma" +# Source-Hash: aafd84823715d698 # Review: required -# Source-Hash: 3501a7c8a93d3b19 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV riser diagram" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turning walls off keeps the ones shared with {rooms}." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.dwvRiserDiagram" -msgstr "Diagrama de bajantes de saneamiento" +msgid "editor.panels.roomConstructionRows.sharedWallsNote" +msgstr "Desactivar los muros conserva los compartidos con {rooms}." +# Source-Hash: c98df900d43f77bc # Review: required -# Source-Hash: 225e3e3dc3bb01ee -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No drain, waste, or vent pipes yet. Draw plumbing to see the riser diagram." -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sits on: {name} · {preset}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.noDrainWasteOrVentPipes" -msgstr "Aún no hay tuberías de desagüe, saneamiento ni ventilación. Dibuja la fontanería para ver el diagrama de bajantes." +msgid "editor.panels.roomConstructionRows.sitsOnPreset" +msgstr "Apoya en: {name} · {preset}" +# Source-Hash: a17a79e835fa2064 # Review: required -# Source-Hash: bc8e172ba55160ae -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Riser Diagram" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "the next room" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.riserDiagram" -msgstr "Diagrama de bajantes" +msgid "editor.panels.roomConstructionRows.theNextRoom" +msgstr "la estancia contigua" +# Source-Hash: ebae699e0cb18ea6 # Review: required -# Source-Hash: 6a1132961f17f320 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{diameter}\" P-trap" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use existing" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.trap" -msgstr "Sifón de {diameter}\"" +msgid "editor.panels.roomConstructionRows.useExisting" +msgstr "Usar el existente" +# Source-Hash: 9976021d9162cd5e # Review: required -# Source-Hash: 04bc0909a133a7e9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vent" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{walls, plural, one {{wallCount} wall} other {{wallCount} walls}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.vent" -msgstr "Ventilación" +msgid "editor.panels.roomConstructionRows.wallCount" +msgstr "{walls, plural, one {{wallCount} muro} many {{wallCount} muros} other {{wallCount} muros}}" +# Source-Hash: aac9a732d2159ccc # Review: required -# Source-Hash: 02f3eef9f0fb6d9e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{diameter}\" VTR" -#. Vent through roof: where a plumbing vent stack exits the roof. -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.ventTermination" -msgstr "Salida a cubierta de {diameter}\"" +msgid "editor.panels.roomConstructionRows.walls" +msgstr "Muros" +# Source-Hash: 6c69eb46a0c40d52 # Review: required -# Source-Hash: 29d8590334492601 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waste" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls thicken inward, so the building's outer size stays the same." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.waste" -msgstr "Desagüe" +msgid "editor.panels.roomConstructionRows.wallsThickenInwardSoTheBuilding" +msgstr "Los muros engrosan hacia dentro, así que el tamaño exterior del edificio no cambia." -# Source-Hash: 0f8d128255bf4afa +# Source-Hash: 4e4f1a24e4a9d61e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{current} · {distance} above {shared}" -#: packages/editor/src/lib/room-built-on.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut opening" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.room.builtOn.above" -msgstr "{current} · {distance} por encima de {shared}" +msgid "editor.panels.roomOpeningsField.cutOpening" +msgstr "Abrir hueco" -# Source-Hash: 8416f433385a2936 +# Source-Hash: 16552c2580bbe8b8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{current} · {distance} below {shared}" -#: packages/editor/src/lib/room-built-on.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.room.builtOn.below" -msgstr "{current} · {distance} por debajo de {shared}" +msgid "editor.panels.roomOpeningsField.done" +msgstr "Hecho" -# Source-Hash: 6dc18e9fada391f2 +# Source-Hash: 2c89abb1778a3f9b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{current} · level with {shared}" -#: packages/editor/src/lib/room-built-on.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit floor" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.room.builtOn.levelWith" -msgstr "{current} · a nivel con {shared}" +msgid "editor.panels.roomOpeningsField.editFloor" +msgstr "Editar suelo" -# Source-Hash: 612dcd5bf06a79c4 +# Source-Hash: ca18a6c5398fc8ab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room" -#: packages/editor/src/components/editor/room-labels.tsx -#: packages/editor/src/lib/viewer-selection.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevator opening" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.roomLabel.room" -msgstr "Estancia" +msgid "editor.panels.roomOpeningsField.elevatorOpening" +msgstr "Hueco de ascensor" -# Source-Hash: a107b4d76d6972e3 +# Source-Hash: eafea43e795f3708 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone" -#: packages/editor/src/components/editor/room-labels.tsx -#: packages/editor/src/lib/viewer-selection.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No openings yet. Cut one for a stair void or a hatch." +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.roomLabel.zone" -msgstr "Zona" +msgid "editor.panels.roomOpeningsField.noOpeningsYetCutOneFor" +msgstr "Aún no hay huecos. Corta uno para el hueco de una escalera o una trampilla." -# Source-Hash: 7da15e7c88dab485 +# Source-Hash: 60fac94ffa614238 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Attic" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening {number}" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.roomName.attic" -msgstr "Desván" +msgid "editor.panels.roomOpeningsField.openingNumber" +msgstr "Hueco {number}" -# Source-Hash: 52adf6ccf54fd772 +# Source-Hash: 7aafbf90d659dcf6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Balcony" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, =0 {No openings} one {{number} opening} other {{number} openings}}" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.roomName.balcony" -msgstr "Balcón" +msgid "editor.panels.roomOpeningsField.openings" +msgstr "{count, plural, =0 {Sin aberturas} one {{number} abertura} many {{number} aberturas} other {{number} aberturas}}" -# Source-Hash: 8caa959c0ae800c3 +# Source-Hash: c1a1794d31990f5a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Basement" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair opening" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.roomName.basement" -msgstr "Sótano" +msgid "editor.panels.roomOpeningsField.stairOpening" +msgstr "Hueco de escalera" -# Source-Hash: 0655333424a8b6fb +# Source-Hash: f0a46329fef44d94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bathroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add stairs" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.bathroom" -msgstr "Baño" +msgid "editor.panels.roomPanel.addStairs" +msgstr "Añadir escalera" -# Source-Hash: f25239fe3891ea8f +# Source-Hash: 8a2ab34a61b9d181 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bedroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add to a unit" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.bedroom" -msgstr "Dormitorio" +msgid "editor.panels.roomPanel.addToAUnit" +msgstr "Añadir a una unidad" -# Source-Hash: 77d15570e2eba719 +# Source-Hash: 8332ab41e22958f1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Boiler room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Area" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.boilerRoom" -msgstr "Sala de calderas" +msgid "editor.panels.roomPanel.area" +msgstr "Área" -# Source-Hash: 5fbe77592f8f0ca9 +# Source-Hash: 88f1a727e5528c10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Carport" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Browse" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.carport" -msgstr "Cochera" +msgid "editor.panels.roomPanel.browse" +msgstr "Explorar" -# Source-Hash: f31dc305ce3a803a +# Source-Hash: 8e5ca7510677460c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cellar" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Built with" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.cellar" -msgstr "Bodega" +msgid "editor.panels.roomPanel.builtWith" +msgstr "Construido con" -# Source-Hash: e9af4141e3f8bdd1 +# Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Closet" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.closet" -msgstr "Armario" +msgid "editor.panels.roomPanel.ceiling" +msgstr "Techo" -# Source-Hash: 388530b7b9c6647d +# Source-Hash: a5e4fe4960deced9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corridor" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete room" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.corridor" -msgstr "Pasillo" +msgid "editor.panels.roomPanel.deleteRoom" +msgstr "Eliminar estancia" -# Source-Hash: 4d4a23b87e911d2b +# Source-Hash: 5dfead58503dbc86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Courtyard" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit shape" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.courtyard" -msgstr "Patio" +msgid "editor.panels.roomPanel.editShape" +msgstr "Editar forma" -# Source-Hash: f3aa561772702108 +# Source-Hash: d7148fa065bc709b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Deck" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.deck" -msgstr "Tarima" +msgid "editor.panels.roomPanel.floor" +msgstr "Planta" -# Source-Hash: 18d7f85ff03c43c9 +# Source-Hash: d17c3b63449c052b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Den" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{height} headroom" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.den" -msgstr "Estudio" +msgid "editor.panels.roomPanel.headroom" +msgstr "Altura libre de {height}" -# Source-Hash: 4424343cad1f08b0 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dining room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.diningRoom" -msgstr "Comedor" +msgid "editor.panels.roomPanel.height" +msgstr "Altura" -# Source-Hash: 5efd0185e89ee84e +# Source-Hash: 2d89c1638aa8dd7e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dressing room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide code" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.dressingRoom" -msgstr "Vestidor" +msgid "editor.panels.roomPanel.hideCode" +msgstr "Ocultar código" -# Source-Hash: f45768e27780dc72 +# Source-Hash: e93969f5a7cbb140 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "En-suite" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room · {level}" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.enSuite" -msgstr "Baño en suite" +msgid "editor.panels.roomPanel.kickerLevel" +msgstr "Estancia · {level}" -# Source-Hash: 51c664d19e5ea703 +# Source-Hash: f4ad56b4e0c014b3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Entrance" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine · in {room}" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.entrance" -msgstr "Entrada" +msgid "editor.panels.roomPanel.kickerMezzanineIn" +msgstr "Entreplanta · en {room}" -# Source-Hash: 4b32a81a5abf006a +# Source-Hash: de37205633316011 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Family room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room · not enclosed" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.familyRoom" -msgstr "Sala familiar" +msgid "editor.panels.roomPanel.kickerNotEnclosed" +msgstr "Estancia · no cerrada" -# Source-Hash: e87e6bd9a7d6d667 +# Source-Hash: 9e84d6d7b9885c4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gallery" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Loading…" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.gallery" -msgstr "Galería" +msgid "editor.panels.roomPanel.loading" +msgstr "Cargando…" -# Source-Hash: cf7cc0ba06d5eea1 +# Source-Hash: 194a147d4618a994 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Games room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.gamesRoom" -msgstr "Sala de juegos" +msgid "editor.panels.roomPanel.mezzanine" +msgstr "Altillo" -# Source-Hash: 53aa825a4737190a +# Source-Hash: 97de3df03c4a0be6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Garage" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine name" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.garage" -msgstr "Garaje" +msgid "editor.panels.roomPanel.mezzanineName" +msgstr "Nombre de la entreplanta" -# Source-Hash: 5073b3c2989a626d +# Source-Hash: 42cfb1bcb80d09e7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Garden" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine names" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.garden" -msgstr "Jardín" +msgid "editor.panels.roomPanel.mezzanineNames" +msgstr "Nombres de entreplanta" -# Source-Hash: 52fe13434cdb7b27 +# Source-Hash: 13b3e6a6afe319d1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Garden shed" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New unit" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.gardenShed" -msgstr "Caseta de jardín" +msgid "editor.panels.roomPanel.newUnit" +msgstr "Nueva unidad" -# Source-Hash: a2712156dcaec1ba +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guest room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.guestRoom" -msgstr "Habitación de invitados" +msgid "editor.panels.roomPanel.none" +msgstr "Ninguno" -# Source-Hash: a1128cf188432bb1 +# Source-Hash: e92d6108b57df9e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gym" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not enough headroom" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.gym" -msgstr "Gimnasio" +msgid "editor.panels.roomPanel.notEnoughHeadroom" +msgstr "Altura libre insuficiente" -# Source-Hash: 18664ee5a1abd06d +# Source-Hash: 81a6770092b05d48 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hallway" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{doors, plural, one {{doorCount} door} other {{doorCount} doors}} · {windows, plural, one {{windowCount} window} other {{windowCount} windows}}" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.hallway" -msgstr "Recibidor" +msgid "editor.panels.roomPanel.openingCounts" +msgstr "{doors, plural, one {{doorCount} puerta} many {{doorCount} puertas} other {{doorCount} puertas}} · {windows, plural, one {{windowCount} ventana} many {{windowCount} ventanas} other {{windowCount} ventanas}}" -# Source-Hash: 7dd957fc73d4d73a +# Source-Hash: a8cd9507ce472a48 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Home cinema" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} · Close its walls to build its floor and ceiling." +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.homeCinema" -msgstr "Cine en casa" +msgid "editor.panels.roomPanel.openRoomArea" +msgstr "{area} · Cierra sus muros para construir su suelo y su techo." -# Source-Hash: e1579515f44233ca +# Source-Hash: f8aa48ec39a15616 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kids' room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Over the mezzanine" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.kidsRoom" -msgstr "Habitación infantil" +msgid "editor.panels.roomPanel.overTheMezzanine" +msgstr "Sobre la entreplanta" -# Source-Hash: 1176d2568d093bf1 +# Source-Hash: ac87e14dabd5a256 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchen" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Perimeter" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.kitchen" -msgstr "Cocina" +msgid "editor.panels.roomPanel.perimeter" +msgstr "Perímetro" -# Source-Hash: 06eb4c431b9b09b6 +# Source-Hash: ed2aaf0a8d5a9b7b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchenette" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.kitchenette" -msgstr "Cocina americana" +msgid "editor.panels.roomPanel.pick" +msgstr "Elegir" -# Source-Hash: de9566487b17a73b +# Source-Hash: 7baaebbd411cc837 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picking it adds a number" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.landing" -msgstr "Descansillo" +msgid "editor.panels.roomPanel.pickingItAddsANumber" +msgstr "Elegirlo añade un número" -# Source-Hash: 558bcafa2ec70ded +# Source-Hash: 9469a102f04ea196 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Laundry" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.laundry" -msgstr "Lavadero" +msgid "editor.panels.roomPanel.remove" +msgstr "Quitar" -# Source-Hash: 8d211c78417ed1b0 +# Source-Hash: 41ac9dd23bb558d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Library" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove from unit" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.library" -msgstr "Biblioteca" +msgid "editor.panels.roomPanel.removeFromUnit" +msgstr "Quitar de la unidad" -# Source-Hash: 2204538bab0e77ac +# Source-Hash: a11d13b92b3cefdb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Living room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove from {unit}" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.livingRoom" -msgstr "Salón" +msgid "editor.panels.roomPanel.removeFromUnitNamed" +msgstr "Quitar de {unit}" -# Source-Hash: bb14c08f0c3db4ad +# Source-Hash: d6952b4e54d246dd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Loft" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rename" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.loft" -msgstr "Altillo" +msgid "editor.panels.roomPanel.rename" +msgstr "Cambiar nombre" -# Source-Hash: a6a0e8bf816cbcb9 +# Source-Hash: 3562f9bea0a4a8f3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lounge" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{name} · Rename" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.lounge" -msgstr "Sala de estar" +msgid "editor.panels.roomPanel.renameNamed" +msgstr "{name} · Cambiar nombre" -# Source-Hash: 194a147d4618a994 +# Source-Hash: d0d4e919bb58a977 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Revert" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.mezzanine" -msgstr "Altillo" +msgid "editor.panels.roomPanel.revert" +msgstr "Revertir" -# Source-Hash: 6b2c82e5fbccb28b +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mudroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.mudroom" -msgstr "Recibidor de servicio" +msgid "editor.panels.roomPanel.room" +msgstr "Estancia" -# Source-Hash: e3c3b9b917744680 +# Source-Hash: 15ae260fae44f42f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Nursery" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room colour — used in the plan and labels" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.nursery" -msgstr "Cuarto del bebé" +msgid "editor.panels.roomPanel.roomColourUsedInThePlan" +msgstr "Color de la estancia: se usa en el plano y las etiquetas" -# Source-Hash: c1f1fcd9cb418340 +# Source-Hash: bf75e739dd7e5877 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Office" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room name" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.office" -msgstr "Despacho" +msgid "editor.panels.roomPanel.roomName" +msgstr "Nombre de la estancia" -# Source-Hash: 5d98d41ec10bd05e +# Source-Hash: 2ecf8c059646873b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pantry" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room names" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.pantry" -msgstr "Despensa" +msgid "editor.panels.roomPanel.roomNames" +msgstr "Nombres de estancias" -# Source-Hash: 78dbe13192c0894b +# Source-Hash: e9a0a3688faba18b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Patio" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scripted finish" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.patio" -msgstr "Patio" +msgid "editor.panels.roomPanel.scriptedFinish" +msgstr "Acabado por script" -# Source-Hash: c3cfcccc167b1c19 +# Source-Hash: 85ea1d3c8b749680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Playroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.playroom" -msgstr "Cuarto de juegos" +msgid "editor.panels.roomPanel.shape" +msgstr "Forma" -# Source-Hash: 2e6324beaed18dd5 +# Source-Hash: e51144ca1759a7bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pool area" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show mezzanine names" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.poolArea" -msgstr "Zona de piscina" +msgid "editor.panels.roomPanel.showMezzanineNames" +msgstr "Mostrar nombres de entreplanta" -# Source-Hash: 97d20e41044a3235 +# Source-Hash: 875b7303c47df33f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Porch" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show room names" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.porch" -msgstr "Porche" +msgid "editor.panels.roomPanel.showRoomNames" +msgstr "Mostrar nombres de estancias" -# Source-Hash: 04cb81f4a4ae4ff3 +# Source-Hash: f05bc67c57e4d530 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Powder room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stairs" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.powderRoom" -msgstr "Aseo de cortesía" +msgid "editor.panels.roomPanel.stairs" +msgstr "Escalera" -# Source-Hash: 599c44d857832cd0 +# Source-Hash: 062cc0f1afef0c52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Primary bedroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unit" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.primaryBedroom" -msgstr "Dormitorio principal" +msgid "editor.panels.roomPanel.unit" +msgstr "Unidad" -# Source-Hash: 9a6ac3f1cdd8de2b +# Source-Hash: 91436d6b374e8263 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reading nook" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.readingNook" -msgstr "Rincón de lectura" +msgid "editor.panels.roomPanel.use" +msgstr "Usar" -# Source-Hash: 01f8cc22989822c4 +# Source-Hash: 61880aff6cd698c9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bathrooms" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{used} on this level" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.section.bathrooms" -msgstr "Baños" +msgid "editor.panels.roomPanel.usedOnThisLevel" +msgstr "{used} en esta planta" -# Source-Hash: 9ec82561de8cb788 +# Source-Hash: 611604740ed4549c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Circulation" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{use} “{name}”" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.section.circulation" -msgstr "Circulación" +msgid "editor.panels.roomPanel.useTyped" +msgstr "{use} «{name}»" -# Source-Hash: f74a48b6b49644d7 +# Source-Hash: 21242af83a2a6d17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Living" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "View code" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.section.living" -msgstr "Estar" +msgid "editor.panels.roomPanel.viewCode" +msgstr "Ver código" -# Source-Hash: 194a147d4618a994 +# Source-Hash: ba15840e60ce672b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The script could not be read." +#: packages/editor/src/components/ui/panels/room-panel.tsx +#: packages/nodes/src/wall/panel.tsx #, fuzzy -msgid "editor.roomName.section.mezzanine" -msgstr "Altillo" +msgid "editor.panels.scriptUnreadable" +msgstr "No se ha podido leer el script." -# Source-Hash: a5a7af5e5fff1c81 +# Source-Hash: 4e186fc057733162 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Outdoor" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Polygon" +#: packages/editor/src/components/ui/panels/shape-choice.tsx #, fuzzy -msgid "editor.roomName.section.outdoor" -msgstr "Exterior" +msgid "editor.panels.shapeChoice.polygon" +msgstr "Polígono" -# Source-Hash: 5df703d5b5e6ef7e +# Source-Hash: 2c2c20272b0370cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sleeping" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangle" +#: packages/editor/src/components/ui/panels/shape-choice.tsx #, fuzzy -msgid "editor.roomName.section.sleeping" -msgstr "Dormitorios" +msgid "editor.panels.shapeChoice.rectangle" +msgstr "Rectángulo" -# Source-Hash: c9d15ec19f814524 +# Source-Hash: 5dc88f90e6aa4129 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Utility & storage" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete region" +#: packages/editor/src/components/ui/panels/wall-region-list.tsx #, fuzzy -msgid "editor.roomName.section.utility" -msgstr "Servicio y almacenaje" +msgid "editor.panels.wallRegionList.deleteRegion" +msgstr "Eliminar región" -# Source-Hash: fbe13f7ab45e4cca +# Source-Hash: d81d8cbadf5d4f33 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Work & hobbies" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint regions" +#: packages/editor/src/components/ui/panels/wall-region-list.tsx #, fuzzy -msgid "editor.roomName.section.work" -msgstr "Trabajo y aficiones" +msgid "editor.panels.wallRegionList.paintRegions" +msgstr "Regiones de pintura" -# Source-Hash: 10ccb6591f6ad207 +# Source-Hash: 89ee318aad485f83 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shower room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Adjust design" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.showerRoom" -msgstr "Cuarto de ducha" +msgid "editor.proceduralItems.inspector.adjustDesign" +msgstr "Ajustar diseño" -# Source-Hash: 5254168cc5712cb2 +# Source-Hash: 7ceade8f25b58fe9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stairwell" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.stairwell" -msgstr "Caja de escalera" +msgid "editor.proceduralItems.inspector.back" +msgstr "Volver" -# Source-Hash: d1596647cd84ade3 +# Source-Hash: ba9b68175315e177 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Storage" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit parts" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.storage" -msgstr "Almacenaje" +msgid "editor.proceduralItems.inspector.editParts" +msgstr "Editar piezas" -# Source-Hash: 7abc2dc6e39b1747 +# Source-Hash: 07c62820f014ed6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Studio" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid attachment" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.studio" -msgstr "Estudio" +msgid "editor.proceduralItems.inspector.invalidAttachment" +msgstr "Fijación no válida" -# Source-Hash: ebe68e83e73021ae +# Source-Hash: f862aea8d7957c55 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Study" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid edit" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.study" -msgstr "Estudio" +msgid "editor.proceduralItems.inspector.invalidEdit" +msgstr "Edición no válida" -# Source-Hash: d69a0244649771ef +# Source-Hash: 190cf30b8edd8dd1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sunroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid placement" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.sunroom" -msgstr "Solario" +msgid "editor.proceduralItems.inspector.invalidPlacement" +msgstr "Colocación no válida" -# Source-Hash: 96281876ce53ba08 +# Source-Hash: 45bd2ec690cc48dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terrace" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid position" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.terrace" -msgstr "Terraza" +msgid "editor.proceduralItems.inspector.invalidPosition" +msgstr "Posición no válida" -# Source-Hash: a0cb3e6f5cf4fbec +# Source-Hash: faccab895717c598 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Toilet" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid reset" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.toilet" -msgstr "Aseo" +msgid "editor.proceduralItems.inspector.invalidReset" +msgstr "Restablecimiento no válido" -# Source-Hash: 6c01526f89f3106b +# Source-Hash: 28fe6e9deddde6e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Utility room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "pos" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.utilityRoom" -msgstr "Cuarto de servicio" +msgid "editor.proceduralItems.inspector.pos" +msgstr "pos" -# Source-Hash: fc42d89621ae7bac +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Veranda" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.veranda" -msgstr "Veranda" +msgid "editor.proceduralItems.inspector.position" +msgstr "Posición" -# Source-Hash: b45d7730e896fd99 +# Source-Hash: 3fce677837d5a876 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walk-in closet" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset this part" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.walkInCloset" -msgstr "Vestidor" +msgid "editor.proceduralItems.inspector.resetThisPart" +msgstr "Restablecer esta pieza" -# Source-Hash: 399f27253ef956cb +# Source-Hash: 5eab376947d29a50 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Workshop" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reload editor" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.roomName.workshop" -msgstr "Taller" +msgid "editor.reloadEditor" +msgstr "Recargar el editor" -# Source-Hash: 83909f82446ee9c3 +# Source-Hash: 1063f1e315258b20 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Settings" -#: packages/editor/src/components/ui/sidebar/icon-rail.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close riser diagram" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.sidebar.iconRail.settings" -msgstr "Ajustes" +msgid "editor.riserDiagramPanel.close" +msgstr "Cerrar diagrama de bajantes" -# Source-Hash: 91f90818d42a984e +# Source-Hash: c2d59ee62035974c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Site" -#: packages/editor/src/components/ui/sidebar/icon-rail.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV plumbing isometric" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.sidebar.iconRail.site" -msgstr "Parcela" +msgid "editor.riserDiagramPanel.dwvPlumbingIsometric" +msgstr "Isometría de saneamiento y ventilación" -# Source-Hash: 663175a9c461a96d +# Source-Hash: 3501a7c8a93d3b19 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV riser diagram" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.all" -msgstr "Todo" +msgid "editor.riserDiagramPanel.dwvRiserDiagram" +msgstr "Diagrama de bajantes de saneamiento" -# Source-Hash: fce9814c289e6b71 +# Source-Hash: 225e3e3dc3bb01ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Community" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No drain, waste, or vent pipes yet. Draw plumbing to see the riser diagram." +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.community" -msgstr "Comunidad" +msgid "editor.riserDiagramPanel.noDrainWasteOrVentPipes" +msgstr "Aún no hay tuberías de desagüe, saneamiento ni ventilación. Dibuja la fontanería para ver el diagrama de bajantes." -# Source-Hash: 663175a9c461a96d +# Source-Hash: bc8e172ba55160ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Riser Diagram" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.all" -msgstr "Todo" +msgid "editor.riserDiagramPanel.riserDiagram" +msgstr "Diagrama de bajantes" -# Source-Hash: fce9814c289e6b71 +# Source-Hash: 6a1132961f17f320 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Community" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{diameter}\" P-trap" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.community" -msgstr "Comunidad" +msgid "editor.riserDiagramPanel.trap" +msgstr "Sifón de {diameter}\"" -# Source-Hash: 8d211c78417ed1b0 +# Source-Hash: 04bc0909a133a7e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Library" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vent" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.library" -msgstr "Biblioteca" +msgid "editor.riserDiagramPanel.vent" +msgstr "Ventilación" -# Source-Hash: a0b7adfdfdec7307 +# Source-Hash: 02f3eef9f0fb6d9e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mine" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{diameter}\" VTR" +#. Vent through roof: where a plumbing vent stack exits the roof. +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.mine" -msgstr "Míos" +msgid "editor.riserDiagramPanel.ventTermination" +msgstr "Salida a cubierta de {diameter}\"" -# Source-Hash: 6024b7778b392ec3 +# Source-Hash: 29d8590334492601 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No results for “{search}”" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waste" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.noResultsForSearch" -msgstr "No hay resultados para “{search}”" +msgid "editor.riserDiagramPanel.waste" +msgstr "Desagüe" -# Source-Hash: 4ceb6dcb7827db7f +# Source-Hash: 0f8d128255bf4afa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Search..." -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{current} · {distance} above {shared}" +#: packages/editor/src/lib/room-built-on.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.search" -msgstr "Buscar..." +msgid "editor.room.builtOn.above" +msgstr "{current} · {distance} por encima de {shared}" -# Source-Hash: 8d211c78417ed1b0 +# Source-Hash: 8416f433385a2936 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Library" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{current} · {distance} below {shared}" +#: packages/editor/src/lib/room-built-on.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.library" -msgstr "Biblioteca" +msgid "editor.room.builtOn.below" +msgstr "{current} · {distance} por debajo de {shared}" -# Source-Hash: a0b7adfdfdec7307 +# Source-Hash: 6dc18e9fada391f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mine" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{current} · level with {shared}" +#: packages/editor/src/lib/room-built-on.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.mine" -msgstr "Míos" +msgid "editor.room.builtOn.levelWith" +msgstr "{current} · a nivel con {shared}" -# Source-Hash: 6024b7778b392ec3 +# Source-Hash: 782bc47cb30d5c66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No results for “{search}”" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cannot read \"{input}\"" +#: packages/editor/src/components/editor/room-handles.tsx #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.noResultsForSearch" -msgstr "No hay resultados para “{search}”" +msgid "editor.roomHandles.cannotReadInput" +msgstr "No se puede leer «{input}»" -# Source-Hash: 4ceb6dcb7827db7f +# Source-Hash: 70ca08939d758332 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Search..." -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimension value" +#: packages/editor/src/components/editor/room-handles.tsx #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.search" -msgstr "Buscar..." +msgid "editor.roomHandles.dimensionValue" +msgstr "Valor de la cota" -# Source-Hash: 3c67cde0578ac829 +# Source-Hash: d7148fa065bc709b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/editor/src/components/editor/room-handles.tsx #, fuzzy -msgid "editor.sidebar.panels.sitePanel.addLevel" -msgstr "Añadir planta" +msgid "editor.roomHandles.floor" +msgstr "Suelo" -# Source-Hash: 9a56d90d461b4bca +# Source-Hash: de281c37906e7d14 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add point" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type a size to move the wall" +#: packages/editor/src/components/editor/room-handles.tsx #, fuzzy -msgid "editor.sidebar.panels.sitePanel.addPoint" -msgstr "Añadir punto" +msgid "editor.roomHandles.typeASizeToMoveThe" +msgstr "Escribe una medida para mover el muro" -# Source-Hash: fedccec504a9ae33 +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Area:" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/editor/room-labels.tsx +#: packages/editor/src/lib/viewer-selection.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.area" -msgstr "Área:" +msgid "editor.roomLabel.room" +msgstr "Estancia" -# Source-Hash: 87b6880f6de7a45a +# Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base elevation" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone" +#: packages/editor/src/components/editor/room-labels.tsx +#: packages/editor/src/lib/viewer-selection.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.baseElevation" -msgstr "Cota base" +msgid "editor.roomLabel.zone" +msgstr "Zona" -# Source-Hash: d42f7d29e3fc4af7 +# Source-Hash: 7da15e7c88dab485 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Building" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Attic" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.building" -msgstr "Edificio" +msgid "editor.roomName.attic" +msgstr "Desván" -# Source-Hash: 7c90f458259d5cd8 +# Source-Hash: 52adf6ccf54fd772 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add new level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Balcony" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.buildingTreeNode.addNewLevel" -msgstr "Añadir nueva planta" +msgid "editor.roomName.balcony" +msgstr "Balcón" -# Source-Hash: d42f7d29e3fc4af7 +# Source-Hash: 8caa959c0ae800c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Building" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Basement" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.buildingTreeNode.building" -msgstr "Edificio" +msgid "editor.roomName.basement" +msgstr "Sótano" -# Source-Hash: bbc65c039ae86e11 +# Source-Hash: 0655333424a8b6fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Camera snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bathroom" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.cameraSnapshot" -msgstr "Instantánea de cámara" +msgid "editor.roomName.bathroom" +msgstr "Baño" -# Source-Hash: 3a0701ebcb9f26cb +# Source-Hash: f25239fe3891ea8f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Capture" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bedroom" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.capture" -msgstr "Captura" +msgid "editor.roomName.bedroom" +msgstr "Dormitorio" -# Source-Hash: 71f2343818c55e0c +# Source-Hash: 77d15570e2eba719 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear selection" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Boiler room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.clearSelection" -msgstr "Borrar selección" +msgid "editor.roomName.boilerRoom" +msgstr "Sala de calderas" -# Source-Hash: 67d29724469fa8d3 +# Source-Hash: 5fbe77592f8f0ca9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx -#, fuzzy -msgid "editor.sidebar.panels.sitePanel.clearSnapshot" -msgstr "Borrar instantánea" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Carport" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.carport" +msgstr "Cochera" -# Source-Hash: def517c77fda49ea +# Source-Hash: f31dc305ce3a803a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close walls around a space to make a room." -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cellar" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.closeWallsAroundASpaceTo" -msgstr "Cierra muros alrededor de un espacio para crear una estancia." +msgid "editor.roomName.cellar" +msgstr "Bodega" -# Source-Hash: 2b9af8da4b34cbfa +# Source-Hash: e9af4141e3f8bdd1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collection colour" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Closet" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.collectionColour" -msgstr "Color de la colección" +msgid "editor.roomName.closet" +msgstr "Armario" -# Source-Hash: 135af27a14a4cda7 +# Source-Hash: 388530b7b9c6647d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collections" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corridor" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.collections" -msgstr "Colecciones" +msgid "editor.roomName.corridor" +msgstr "Pasillo" -# Source-Hash: 6f4751c26f12aef9 +# Source-Hash: 4d4a23b87e911d2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete collection" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Courtyard" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.deleteCollection" -msgstr "Eliminar colección" +msgid "editor.roomName.courtyard" +msgstr "Patio" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: f3aa561772702108 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.delete" -msgstr "Eliminar" +msgid "editor.roomName.deck" +msgstr "Tarima" -# Source-Hash: 8e29375893d63408 +# Source-Hash: 18d7f85ff03c43c9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Den" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.deleteLevel" -msgstr "Eliminar planta" +msgid "editor.roomName.den" +msgstr "Estudio" -# Source-Hash: 6552e45eecc0a227 +# Source-Hash: 4424343cad1f08b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw a zone" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dining room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.drawAZone" -msgstr "Dibujar una zona" +msgid "editor.roomName.diningRoom" +msgstr "Comedor" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 5efd0185e89ee84e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dressing room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.duplicate" -msgstr "Duplicar" +msgid "editor.roomName.dressingRoom" +msgstr "Vestidor" -# Source-Hash: 933177338f5a03ed +# Source-Hash: f45768e27780dc72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "En-suite" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.duplicateLevel" -msgstr "Duplicar planta" +msgid "editor.roomName.enSuite" +msgstr "Baño en suite" -# Source-Hash: c038947f317cabba +# Source-Hash: 51c664d19e5ea703 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate level with options" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Entrance" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.duplicateLevelWithOptions" -msgstr "Duplicar planta con opciones" +msgid "editor.roomName.entrance" +msgstr "Entrada" -# Source-Hash: 9614c6825a7c67bf +# Source-Hash: 4b32a81a5abf006a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate with options..." -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Family room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.duplicateWithOptions" -msgstr "Duplicar con opciones..." +msgid "editor.roomName.familyRoom" +msgstr "Sala familiar" -# Source-Hash: 7c4196b9e791c195 +# Source-Hash: e87e6bd9a7d6d667 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elements" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gallery" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.elements" -msgstr "Elementos" +msgid "editor.roomName.gallery" +msgstr "Galería" -# Source-Hash: 1344ea2602e3aa9e +# Source-Hash: cf7cc0ba06d5eea1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guide" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Games room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.guide" -msgstr "Guía" +msgid "editor.roomName.gamesRoom" +msgstr "Sala de juegos" -# Source-Hash: 591087ea83a48ead +# Source-Hash: 53aa825a4737190a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Garage" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.hide" -msgstr "Ocultar" +msgid "editor.roomName.garage" +msgstr "Garaje" -# Source-Hash: 0608743fc1736d86 +# Source-Hash: 5073b3c2989a626d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Garden" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.level" -msgstr "Planta" +msgid "editor.roomName.garden" +msgstr "Jardín" -# Source-Hash: 13b3e6a6afe319d1 +# Source-Hash: 52fe13434cdb7b27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "New unit" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Garden shed" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.newUnit" -msgstr "Nueva unidad" +msgid "editor.roomName.gardenShed" +msgstr "Caseta de jardín" -# Source-Hash: 0192748d50f0e5f7 +# Source-Hash: a2712156dcaec1ba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No buildings yet" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guest room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.noBuildingsYet" -msgstr "Aún no hay edificios" +msgid "editor.roomName.guestRoom" +msgstr "Habitación de invitados" -# Source-Hash: 1be310702a12e433 +# Source-Hash: a1128cf188432bb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No elements on this level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gym" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.noElementsOnThisLevel" -msgstr "No hay elementos en esta planta" +msgid "editor.roomName.gym" +msgstr "Gimnasio" -# Source-Hash: 0956af88ced36992 +# Source-Hash: 18664ee5a1abd06d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No levels yet" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hallway" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.noLevelsYet" -msgstr "Aún no hay plantas" +msgid "editor.roomName.hallway" +msgstr "Recibidor" -# Source-Hash: 45c41bfb2ae19627 +# Source-Hash: 7dd957fc73d4d73a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {# object selected} other {# objects selected}}" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Home cinema" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.objectsSelected" -msgstr "{count, plural, one {# objeto seleccionado} many {# objetos seleccionados} other {# objetos seleccionados}}" +msgid "editor.roomName.homeCinema" +msgstr "Cine en casa" -# Source-Hash: a5434e26e5cb1b26 +# Source-Hash: e1579515f44233ca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Other zones" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kids' room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.otherZones" -msgstr "Otras zonas" +msgid "editor.roomName.kidsRoom" +msgstr "Habitación infantil" -# Source-Hash: 2aa38d84079d4dba +# Source-Hash: 1176d2568d093bf1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Perimeter:" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchen" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.perimeter" -msgstr "Perímetro:" +msgid "editor.roomName.kitchen" +msgstr "Cocina" -# Source-Hash: 4004b9a8e4f8c9d0 +# Source-Hash: 06eb4c431b9b09b6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Property Line" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchenette" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.propertyLine" -msgstr "Lindero" +msgid "editor.roomName.kitchenette" +msgstr "Cocina americana" -# Source-Hash: 3e7408ed44676176 +# Source-Hash: de9566487b17a73b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rooms" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.rooms" -msgstr "Estancias" +msgid "editor.roomName.landing" +msgstr "Descansillo" -# Source-Hash: ca39c0581c7318e6 +# Source-Hash: 558bcafa2ec70ded # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select a level to view content" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Laundry" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.selectALevelToViewContent" -msgstr "Selecciona una planta para ver su contenido" +msgid "editor.roomName.laundry" +msgstr "Lavadero" -# Source-Hash: 827e0c6ac9936b69 +# Source-Hash: 8d211c78417ed1b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Library" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.show" -msgstr "Mostrar" +msgid "editor.roomName.library" +msgstr "Biblioteca" -# Source-Hash: 91f90818d42a984e +# Source-Hash: 2204538bab0e77ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Site" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Living room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.site" -msgstr "Parcela" +msgid "editor.roomName.livingRoom" +msgstr "Salón" -# Source-Hash: c40163620df24a76 +# Source-Hash: bb14c08f0c3db4ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Take snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Loft" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.takeSnapshot" -msgstr "Tomar instantánea" +msgid "editor.roomName.loft" +msgstr "Altillo" -# Source-Hash: d6b381247066a7aa +# Source-Hash: a6a0e8bf816cbcb9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The ground level cannot be deleted" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lounge" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.theGroundLevelCannotBeDeleted" -msgstr "La planta baja no se puede eliminar" +msgid "editor.roomName.lounge" +msgstr "Sala de estar" -# Source-Hash: bbc65c039ae86e11 +# Source-Hash: 194a147d4618a994 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Camera snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.cameraSnapshot" -msgstr "Instantánea de cámara" +msgid "editor.roomName.mezzanine" +msgstr "Altillo" -# Source-Hash: 67d29724469fa8d3 +# Source-Hash: 6b2c82e5fbccb28b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mudroom" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.clearSnapshot" -msgstr "Borrar instantánea" +msgid "editor.roomName.mudroom" +msgstr "Recibidor de servicio" -# Source-Hash: 591087ea83a48ead +# Source-Hash: e3c3b9b917744680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Nursery" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.hide" -msgstr "Ocultar" +msgid "editor.roomName.nursery" +msgstr "Cuarto del bebé" -# Source-Hash: 827e0c6ac9936b69 +# Source-Hash: c1f1fcd9cb418340 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Office" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.show" -msgstr "Mostrar" +msgid "editor.roomName.office" +msgstr "Despacho" -# Source-Hash: c40163620df24a76 +# Source-Hash: 5d98d41ec10bd05e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Take snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pantry" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.takeSnapshot" -msgstr "Tomar instantánea" +msgid "editor.roomName.pantry" +msgstr "Despensa" -# Source-Hash: faecab10b69d4863 +# Source-Hash: 78dbe13192c0894b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Update snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Patio" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.updateSnapshot" -msgstr "Actualizar instantánea" +msgid "editor.roomName.patio" +msgstr "Patio" -# Source-Hash: 8a1fd8827a68f236 +# Source-Hash: c3cfcccc167b1c19 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "View snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Playroom" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.viewSnapshot" -msgstr "Ver instantánea" +msgid "editor.roomName.playroom" +msgstr "Cuarto de juegos" -# Source-Hash: b404dded35241274 +# Source-Hash: 2e6324beaed18dd5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Units" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pool area" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.units" -msgstr "Unidades" +msgid "editor.roomName.poolArea" +msgstr "Zona de piscina" -# Source-Hash: 149fec3fd1f08042 +# Source-Hash: 97d20e41044a3235 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete unit" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Porch" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.deleteUnit" -msgstr "Eliminar unidad" +msgid "editor.roomName.porch" +msgstr "Porche" -# Source-Hash: 930399d3fb247a7c +# Source-Hash: 04cb81f4a4ae4ff3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Focused" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Powder room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.focused" -msgstr "Enfocada" +msgid "editor.roomName.powderRoom" +msgstr "Aseo de cortesía" -# Source-Hash: 41ac9dd23bb558d7 +# Source-Hash: 599c44d857832cd0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove from unit" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Primary bedroom" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.removeFromUnit" -msgstr "Quitar de la unidad" +msgid "editor.roomName.primaryBedroom" +msgstr "Dormitorio principal" -# Source-Hash: 612dcd5bf06a79c4 +# Source-Hash: 9a6ac3f1cdd8de2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reading nook" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.room" -msgstr "Estancia" +msgid "editor.roomName.readingNook" +msgstr "Rincón de lectura" -# Source-Hash: a107b4d76d6972e3 +# Source-Hash: 01f8cc22989822c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bathrooms" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.zone" -msgstr "Zona" +msgid "editor.roomName.section.bathrooms" +msgstr "Baños" -# Source-Hash: faecab10b69d4863 +# Source-Hash: 9ec82561de8cb788 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Update snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Circulation" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.updateSnapshot" -msgstr "Actualizar instantánea" +msgid "editor.roomName.section.circulation" +msgstr "Circulación" -# Source-Hash: 28a12e6806c091b0 +# Source-Hash: f74a48b6b49644d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{assetType, select, guide {Uploading guide... {progress}%} other {Uploading scan... {progress}%}}" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Living" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.uploadingProgress" -msgstr "{assetType, select, guide {Subiendo guía... {progress}%} other {Subiendo escaneo 3D... {progress}%}}" +msgid "editor.roomName.section.living" +msgstr "Estar" -# Source-Hash: de389a2a46d53384 +# Source-Hash: 194a147d4618a994 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Upload scan/floorplan" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.uploadScanFloorplan" -msgstr "Subir escaneo 3D o plano" +msgid "editor.roomName.section.mezzanine" +msgstr "Altillo" -# Source-Hash: 8a1fd8827a68f236 +# Source-Hash: a5a7af5e5fff1c81 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "View snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outdoor" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.viewSnapshot" -msgstr "Ver instantánea" +msgid "editor.roomName.section.outdoor" +msgstr "Exterior" -# Source-Hash: ba9f809cb032ee57 +# Source-Hash: 5df703d5b5e6ef7e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "In {unitName}" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/zone-membership-checkbox.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sleeping" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.zoneMembershipCheckbox.inUnitname" -msgstr "En {unitName}" +msgid "editor.roomName.section.sleeping" +msgstr "Dormitorios" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: c9d15ec19f814524 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Utility & storage" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.actions" -msgstr "Acciones" +msgid "editor.roomName.section.utility" +msgstr "Servicio y almacenaje" -# Source-Hash: fcc43f22937d1536 +# Source-Hash: fbe13f7ab45e4cca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add one" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Work & hobbies" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.addOne" -msgstr "Añadir una" +msgid "editor.roomName.section.work" +msgstr "Trabajo y aficiones" -# Source-Hash: bbc65c039ae86e11 +# Source-Hash: 10ccb6591f6ad207 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Camera snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shower room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.cameraSnapshot" -msgstr "Instantánea de cámara" +msgid "editor.roomName.showerRoom" +msgstr "Cuarto de ducha" -# Source-Hash: 67d29724469fa8d3 +# Source-Hash: 5254168cc5712cb2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stairwell" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.clearSnapshot" -msgstr "Borrar instantánea" +msgid "editor.roomName.stairwell" +msgstr "Caja de escalera" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: d1596647cd84ade3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Storage" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.delete" -msgstr "Eliminar" +msgid "editor.roomName.storage" +msgstr "Almacenaje" -# Source-Hash: e2411929697b7ed4 +# Source-Hash: 7abc2dc6e39b1747 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete with contents" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Studio" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.deleteWithContents" -msgstr "Eliminar con el contenido" +msgid "editor.roomName.studio" +msgstr "Estudio" -# Source-Hash: 22ca3935e8754072 +# Source-Hash: ebe68e83e73021ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No zones on this level." -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Study" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.noZonesOnThisLevel" -msgstr "No hay zonas en esta planta." +msgid "editor.roomName.study" +msgstr "Estudio" -# Source-Hash: 941ea30f406dcfa2 +# Source-Hash: d69a0244649771ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Save to catalog" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sunroom" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.saveToCatalog" -msgstr "Guardar en el catálogo" +msgid "editor.roomName.sunroom" +msgstr "Solario" -# Source-Hash: 98662dfb371cac13 +# Source-Hash: 96281876ce53ba08 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select a level to view and create zones" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terrace" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.selectALevelToViewAnd" -msgstr "Selecciona una planta para ver y crear zonas" +msgid "editor.roomName.terrace" +msgstr "Terraza" -# Source-Hash: c40163620df24a76 +# Source-Hash: a0cb3e6f5cf4fbec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Take snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Toilet" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.takeSnapshot" -msgstr "Tomar instantánea" +msgid "editor.roomName.toilet" +msgstr "Aseo" -# Source-Hash: faecab10b69d4863 +# Source-Hash: 6c01526f89f3106b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Update snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Utility room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.updateSnapshot" -msgstr "Actualizar instantánea" +msgid "editor.roomName.utilityRoom" +msgstr "Cuarto de servicio" -# Source-Hash: 8a1fd8827a68f236 +# Source-Hash: fc42d89621ae7bac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "View snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx -#, fuzzy -msgid "editor.sidebar.panels.zonePanel.viewSnapshot" -msgstr "Ver instantánea" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Veranda" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.veranda" +msgstr "Veranda" -# Source-Hash: 58b05af5b5724efb +# Source-Hash: b45d7730e896fd99 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "\"{label}\" plugin crashed" -#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walk-in closet" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.usePluginPanels.labelPluginCrashed" -msgstr "El plugin “{label}” se ha bloqueado" +msgid "editor.roomName.walkInCloset" +msgstr "Vestidor" -# Source-Hash: 9e84d6d7b9885c4f +# Source-Hash: 399f27253ef956cb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Loading…" -#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Workshop" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.usePluginPanels.loading" -msgstr "Cargando…" +msgid "editor.roomName.workshop" +msgstr "Taller" -# Source-Hash: 9fc7a39bc32f287a +# Source-Hash: 83909f82446ee9c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Plugins" -#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Settings" +#: packages/editor/src/components/ui/sidebar/icon-rail.tsx #, fuzzy -msgid "editor.sidebar.usePluginPanels.plugins" -msgstr "Complementos" +msgid "editor.sidebar.iconRail.settings" +msgstr "Ajustes" -# Source-Hash: c6312309378aaaea +# Source-Hash: 91f90818d42a984e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "This panel hit an error and was unloaded for this session. The rest of the editor is unaffected — reload to try again." -#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Site" +#: packages/editor/src/components/ui/sidebar/icon-rail.tsx #, fuzzy -msgid "editor.sidebar.usePluginPanels.thisPanelHitAnErrorAnd" -msgstr "Este panel ha tenido un error y se ha descargado durante esta sesión. El resto del editor no se ve afectado: recarga para volver a intentarlo." +msgid "editor.sidebar.iconRail.site" +msgstr "Parcela" +# Source-Hash: 663175a9c461a96d # Review: required -# Source-Hash: 2ab3b6983e384ecc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling attachment" -#: packages/editor/src/components/ui/snap-target-badge.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx #, fuzzy -msgid "editor.snapTarget.ceiling" -msgstr "Fijación al techo" +msgid "editor.sidebar.panels.itemsPanel.all" +msgstr "Todo" +# Source-Hash: fce9814c289e6b71 # Review: required -# Source-Hash: 54a00bbb699e3778 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof attachment" -#: packages/editor/src/components/ui/snap-target-badge.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Community" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx #, fuzzy -msgid "editor.snapTarget.roof" -msgstr "Fijación a la cubierta" +msgid "editor.sidebar.panels.itemsPanel.community" +msgstr "Comunidad" +# Source-Hash: 663175a9c461a96d # Review: required -# Source-Hash: e45fee9c27f6ae69 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall attachment" -#: packages/editor/src/components/ui/snap-target-badge.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx #, fuzzy -msgid "editor.snapTarget.wall" -msgstr "Fijación a la pared" +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.all" +msgstr "Todo" -# Source-Hash: 834de1a7027c4da1 +# Source-Hash: fce9814c289e6b71 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The editor scene failed to render" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Community" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx #, fuzzy -msgid "editor.theEditorSceneFailedToRender" -msgstr "No se pudo mostrar la escena del editor" +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.community" +msgstr "Comunidad" -# Source-Hash: 151f7c7e4110016f +# Source-Hash: 8d211c78417ed1b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A curtain wall takes no corner window" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Library" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx #, fuzzy -msgid "editor.toolHint.aCurtainWallTakesNoCorner.1qxjv5i" -msgstr "Un muro cortina no admite ventana de esquina" +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.library" +msgstr "Biblioteca" -# Source-Hash: 97f5e044d46501fb +# Source-Hash: a0b7adfdfdec7307 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A curved wall takes no corner window" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mine" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx #, fuzzy -msgid "editor.toolHint.aCurvedWallTakesNoCorner.1vdnaw5" -msgstr "Un muro curvo no admite ventana de esquina" +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.mine" +msgstr "Míos" -# Source-Hash: 776d8ebece7fe1bb +# Source-Hash: 6024b7778b392ec3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add a corner · click the first to close" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No results for “{search}”" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx #, fuzzy -msgid "editor.toolHint.addACornerClickTheFirst.o4r67t" -msgstr "Añadir esquina · haz clic en la primera para cerrar" +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.noResultsForSearch" +msgstr "No hay resultados para “{search}”" -# Source-Hash: 6a0745dd047b149a +# Source-Hash: 4ceb6dcb7827db7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Another opening is in the way at the corner" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Search..." +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx #, fuzzy -msgid "editor.toolHint.anotherOpeningIsInTheWay.11l9dd0" -msgstr "Otra abertura estorba en la esquina" +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.search" +msgstr "Buscar..." -# Source-Hash: 441124187e7da2fc +# Source-Hash: 8d211c78417ed1b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Library" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx #, fuzzy -msgid "editor.toolHint.autoHangers.10554ka" -msgstr "Colgadores automáticos" +msgid "editor.sidebar.panels.itemsPanel.library" +msgstr "Biblioteca" -# Source-Hash: 47a7f9a6a81156c3 +# Source-Hash: a0b7adfdfdec7307 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers - click or press H to toggle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mine" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx #, fuzzy -msgid "editor.toolHint.autoHangersClickOrPressH.rwa3ka" -msgstr "Colgadores automáticos: haz clic o pulsa H para alternar" +msgid "editor.sidebar.panels.itemsPanel.mine" +msgstr "Míos" -# Source-Hash: d7944f31cba90e26 +# Source-Hash: 6024b7778b392ec3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers: Off" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No results for “{search}”" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx #, fuzzy -msgid "editor.toolHint.autoHangersOff.7yx01x" -msgstr "Colgadores automáticos: desactivados" +msgid "editor.sidebar.panels.itemsPanel.noResultsForSearch" +msgstr "No hay resultados para “{search}”" -# Source-Hash: 295882d015d08742 +# Source-Hash: 4ceb6dcb7827db7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers: On" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Search..." +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx #, fuzzy -msgid "editor.toolHint.autoHangersOn.10b1umh" -msgstr "Colgadores automáticos: activados" +msgid "editor.sidebar.panels.itemsPanel.search" +msgstr "Buscar..." -# Source-Hash: 8c039e5182b01c4d +# Source-Hash: fb66c49eee49a3bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bypass snapping" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Build Tools" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.bypassSnapping.w5lmdv" -msgstr "Omitir el ajuste" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.buildTools" +msgstr "Herramientas de construcción" -# Source-Hash: c0774c185060fc13 +# Source-Hash: 14622745dbf93f4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.cancel.ew9em3" -msgstr "Cancelar" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.camera" +msgstr "Cámara" -# Source-Hash: 5b33b576fd30b74e +# Source-Hash: 677783232bea72a2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel move" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Direct Manipulation" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.cancelMove.lvp31c" -msgstr "Cancelar movimiento" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.directManipulation" +msgstr "Manipulación directa" -# Source-Hash: 136fa29b9ae419bf +# Source-Hash: 8e67947d43b76596 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel run / exit" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawing Tools" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.cancelRunExit.zqjf3h" -msgstr "Cancelar tramo / salir" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.drawingTools" +msgstr "Herramientas de dibujo" -# Source-Hash: 75b406824be91ac2 +# Source-Hash: 8cdda30f3be2bac2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel start point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Editor Navigation" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.cancelStartPoint.1xbq2lh" -msgstr "Cancelar punto inicial" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.editorNavigation" +msgstr "Navegación del editor" -# Source-Hash: ffa5aaa1746303c4 +# Source-Hash: 9a996e3570d615ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner window" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Item Placement" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.cornerWindow.1avkzpo" -msgstr "Ventana de esquina" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.itemPlacement" +msgstr "Colocación de elementos" -# Source-Hash: b0afdd855a02e4a7 +# Source-Hash: fc18926f9bd9eebd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cuts" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keyboard shortcuts" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.cuts.1y0axps" -msgstr "Cortes" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.keyboardShortcuts" +msgstr "Atajos de teclado" -# Source-Hash: dc9fe7601cc525f8 +# Source-Hash: cbb4c3e007d70aa0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cuts: {value}" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modes & History" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.cutsValue.ouzhvb" -msgstr "Cortes: {value}" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.modesHistory" +msgstr "Modos e historial" -# Source-Hash: a2e13bc4dc82624c +# Source-Hash: 170b2049ef0f9131 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cuts: {value}, even" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selection" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.cutsValueEven.1ngsz3" -msgstr "Cortes: {value}, uniformes" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.selection" +msgstr "Selección" -# Source-Hash: 04152b4cec726f34 +# Source-Hash: 0da1c4d163df2953 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cycle mono / gable / butterfly" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shortcuts are context-aware. Snapping is a visible mode: tap Shift to cycle it, hold Alt during a gesture to place freely." +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.cycleMonoGableButterfly.1poga3m" -msgstr "Cambiar un agua / dos aguas / mariposa" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.shortcutsAreContextAwareGuidedConstraints" +msgstr "Los atajos dependen del contexto. El ajuste es un modo visible: pulsa Mayús para cambiarlo y mantén Alt durante un gesto para colocar libremente." -# Source-Hash: 4fb6c83edb6652b5 +# Source-Hash: 3c67cde0578ac829 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cycle snapping mode" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.cycleSnappingMode.1ct0gn6" -msgstr "Cambiar el modo de ajuste" +msgid "editor.sidebar.panels.sitePanel.addLevel" +msgstr "Añadir planta" -# Source-Hash: 5d550a3ac76279de +# Source-Hash: 9a56d90d461b4bca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door style — click or press L to cycle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add point" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.doorStyleClickOrPressL.33pe65" -msgstr "Estilo de puerta: haz clic o pulsa L para cambiar" +msgid "editor.sidebar.panels.sitePanel.addPoint" +msgstr "Añadir punto" -# Source-Hash: 3272a7df5d7c6a9a +# Source-Hash: fedccec504a9ae33 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door type — click or press O to cycle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Area:" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.doorTypeClickOrPressO.1hhh8gt" -msgstr "Tipo de puerta: haz clic o pulsa O para cambiar" +msgid "editor.sidebar.panels.sitePanel.area" +msgstr "Área:" -# Source-Hash: 366222b4435eefda +# Source-Hash: 87b6880f6de7a45a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drop downspout from outlet" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base elevation" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.dropDownspoutFromOutlet.1k4h1m4" -msgstr "Bajar la bajante desde la salida" +msgid "editor.sidebar.panels.sitePanel.baseElevation" +msgstr "Cota base" -# Source-Hash: 03f306371f345007 +# Source-Hash: d42f7d29e3fc4af7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct diameter down / up" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Building" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.ductDiameterDownUp.1wdz5vq" -msgstr "Diámetro del conducto menos / más" +msgid "editor.sidebar.panels.sitePanel.building" +msgstr "Edificio" -# Source-Hash: 7b4137e27f8327d9 +# Source-Hash: 7c90f458259d5cd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End run / cancel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add new level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx #, fuzzy -msgid "editor.toolHint.endRunCancel.59dh2w" -msgstr "Terminar tramo / cancelar" +msgid "editor.sidebar.panels.sitePanel.buildingTreeNode.addNewLevel" +msgstr "Añadir nueva planta" -# Source-Hash: 938aacb119b29dc1 +# Source-Hash: d42f7d29e3fc4af7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Exit" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Building" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx #, fuzzy -msgid "editor.toolHint.exit.engmg5" -msgstr "Salir" +msgid "editor.sidebar.panels.sitePanel.buildingTreeNode.building" +msgstr "Edificio" -# Source-Hash: 7cb4e0688cabcb00 +# Source-Hash: bbc65c039ae86e11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Exit drawing" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.exitDrawing.9noxyb" -msgstr "Salir del dibujo" +msgid "editor.sidebar.panels.sitePanel.cameraSnapshot" +msgstr "Instantánea de cámara" -# Source-Hash: 47025a103c456125 +# Source-Hash: 3a0701ebcb9f26cb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish and continue" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Capture" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.finishAndContinue.1gpfsks" -msgstr "Terminar y continuar" +msgid "editor.sidebar.panels.sitePanel.capture" +msgstr "Captura" -# Source-Hash: 000918429b74128f +# Source-Hash: 71f2343818c55e0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish ceiling" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear selection" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.finishCeiling.1c1lfel" -msgstr "Terminar el techo" +msgid "editor.sidebar.panels.sitePanel.clearSelection" +msgstr "Borrar selección" -# Source-Hash: 51a80a0dba5a6f30 +# Source-Hash: 67d29724469fa8d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish grid axis" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.finishGridAxis.1wvrfhr" -msgstr "Terminar el eje" +msgid "editor.sidebar.panels.sitePanel.clearSnapshot" +msgstr "Borrar instantánea" -# Source-Hash: 87c7b98fc2e010e1 +# Source-Hash: def517c77fda49ea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish measurement" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close walls around a space to make a room." +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.finishMeasurement.1e4gv16" -msgstr "Terminar la medida" +msgid "editor.sidebar.panels.sitePanel.closeWallsAroundASpaceTo" +msgstr "Cierra muros alrededor de un espacio para crear una estancia." -# Source-Hash: 5e1a0af7dc506826 +# Source-Hash: 2b9af8da4b34cbfa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish multi-point witnesses" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collection colour" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx #, fuzzy -msgid "editor.toolHint.finishMultiPointWitnesses.8wzskz" -msgstr "Terminar los testigos de varios puntos" +msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.collectionColour" +msgstr "Color de la colección" -# Source-Hash: 30fc0862501ba2e8 +# Source-Hash: 135af27a14a4cda7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish slab" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collections" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx #, fuzzy -msgid "editor.toolHint.finishSlab.xmnm8e" -msgstr "Terminar el forjado" +msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.collections" +msgstr "Colecciones" -# Source-Hash: 66ed7c7598d3aa29 +# Source-Hash: 6f4751c26f12aef9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip side" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete collection" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx #, fuzzy -msgid "editor.toolHint.flipSide.172xku9" -msgstr "Invertir el lado" +msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.deleteCollection" +msgstr "Eliminar colección" -# Source-Hash: f5717f6a0905ffab +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follow: trace a lineset" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.followTraceALineset.mgquwe" -msgstr "Seguir: trazar junto a una línea frigorífica" +msgid "editor.sidebar.panels.sitePanel.delete" +msgstr "Eliminar" -# Source-Hash: ed7f3d8417a3e074 +# Source-Hash: 8e29375893d63408 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Force place" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.forcePlace.1hq1nr" -msgstr "Forzar colocación" +msgid "editor.sidebar.panels.sitePanel.deleteLevel" +msgstr "Eliminar planta" -# Source-Hash: cc0c14065951444d +# Source-Hash: 6552e45eecc0a227 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Free placement" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw a zone" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.freePlacement.1nztdac" -msgstr "Colocación libre" +msgid "editor.sidebar.panels.sitePanel.drawAZone" +msgstr "Dibujar una zona" -# Source-Hash: f098a27096a9c1ea +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Go vertical ↕, click to place" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.goVerticalClickToPlace.dg8g6m" -msgstr "Pasar a vertical ↕, haz clic para colocar" +msgid "editor.sidebar.panels.sitePanel.duplicate" +msgstr "Duplicar" -# Source-Hash: fd47f1820d8799c8 +# Source-Hash: 933177338f5a03ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Highlight outlet" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.highlightOutlet.65hoq8" -msgstr "Resaltar la salida" +msgid "editor.sidebar.panels.sitePanel.duplicateLevel" +msgstr "Duplicar planta" -# Source-Hash: eb90058d0f856f67 +# Source-Hash: c038947f317cabba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Join as a corner window" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate level with options" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.joinAsACornerWindow.jvdp4j" -msgstr "Unir como ventana de esquina" +msgid "editor.sidebar.panels.sitePanel.duplicateLevelWithOptions" +msgstr "Duplicar planta con opciones" -# Source-Hash: 225b3161f2e59757 +# Source-Hash: 9614c6825a7c67bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Alt + drag" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate with options..." +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.altDrag.ai3wn9" -msgstr "Alt + arrastrar" +msgid "editor.sidebar.panels.sitePanel.duplicateWithOptions" +msgstr "Duplicar con opciones..." -# Source-Hash: dd66f883b173fc72 +# Source-Hash: 7c4196b9e791c195 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Backspace" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elements" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.backspace.qy6qx8" -msgstr "Retroceso" +msgid "editor.sidebar.panels.sitePanel.elements" +msgstr "Elementos" -# Source-Hash: a18387bc0be54c32 +# Source-Hash: 1344ea2602e3aa9e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guide" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.click.m8sun" -msgstr "Clic" +msgid "editor.sidebar.panels.sitePanel.guide" +msgstr "Guía" -# Source-Hash: db9e60c1d30b8499 +# Source-Hash: 591087ea83a48ead # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click again" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.clickAgain.190ws9j" -msgstr "Volver a hacer clic" +msgid "editor.sidebar.panels.sitePanel.hide" +msgstr "Ocultar" -# Source-Hash: f400330b9c9c12e8 +# Source-Hash: 0608743fc1736d86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Command" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.command.1j2mkia" -msgstr "Comando" +msgid "editor.sidebar.panels.sitePanel.level" +msgstr "Planta" -# Source-Hash: 976c63285a510b09 +# Source-Hash: 13b3e6a6afe319d1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Control" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New unit" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.control.10fbl8e" -msgstr "Control" +msgid "editor.sidebar.panels.sitePanel.newUnit" +msgstr "Nueva unidad" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 0192748d50f0e5f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No buildings yet" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.delete.oay2cq" -msgstr "Eliminar" +msgid "editor.sidebar.panels.sitePanel.noBuildingsYet" +msgstr "Aún no hay edificios" -# Source-Hash: 88888c9d2719fa92 +# Source-Hash: 1be310702a12e433 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double click" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No elements on this level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.doubleClick.vlma6o" -msgstr "Doble clic" +msgid "editor.sidebar.panels.sitePanel.noElementsOnThisLevel" +msgstr "No hay elementos en esta planta" -# Source-Hash: dfb85b2addb7b9fa +# Source-Hash: 0956af88ced36992 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No levels yet" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.drag.8pwtpf" -msgstr "Arrastrar" +msgid "editor.sidebar.panels.sitePanel.noLevelsYet" +msgstr "Aún no hay plantas" -# Source-Hash: ed9140d42148c99b +# Source-Hash: 45c41bfb2ae19627 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Enter" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# object selected} other {# objects selected}}" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.enter.1ctpui5" -msgstr "Intro" +msgid "editor.sidebar.panels.sitePanel.objectsSelected" +msgstr "{count, plural, one {# objeto seleccionado} many {# objetos seleccionados} other {# objetos seleccionados}}" -# Source-Hash: 9195fa8b9c8ebdfb +# Source-Hash: a5434e26e5cb1b26 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Other zones" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.hover.6xw79p" -msgstr "Pasar el cursor" +msgid "editor.sidebar.panels.sitePanel.otherZones" +msgstr "Otras zonas" -# Source-Hash: 2d78441b741bc562 +# Source-Hash: 2aa38d84079d4dba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a duct end" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Perimeter:" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.hoverADuctEnd.19axr3b" -msgstr "Pasa el cursor por un extremo del conducto" +msgid "editor.sidebar.panels.sitePanel.perimeter" +msgstr "Perímetro:" -# Source-Hash: 6083405086f61c76 +# Source-Hash: 4004b9a8e4f8c9d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a pipe end" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Property Line" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.hoverAPipeEnd.1jbum5f" -msgstr "Pasa el cursor por un extremo de la tubería" +msgid "editor.sidebar.panels.sitePanel.propertyLine" +msgstr "Lindero" -# Source-Hash: a5a337eb76fdb066 +# Source-Hash: 3e7408ed44676176 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover gutter" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rooms" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.hoverGutter.1dwcsno" -msgstr "Pasa el cursor por el canalón" +msgid "editor.sidebar.panels.sitePanel.rooms" +msgstr "Estancias" -# Source-Hash: a58533594411e088 +# Source-Hash: ca39c0581c7318e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left click" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select a level to view content" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.leftClick.s4gwfc" -msgstr "Clic izquierdo" +msgid "editor.sidebar.panels.sitePanel.selectALevelToViewContent" +msgstr "Selecciona una planta para ver su contenido" -# Source-Hash: bc4ab608ec3d3b4f +# Source-Hash: 827e0c6ac9936b69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Middle click" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.middleClick.1jbaan4" -msgstr "Clic central" +msgid "editor.sidebar.panels.sitePanel.show" +msgstr "Mostrar" -# Source-Hash: 6791879c651108c7 +# Source-Hash: 91f90818d42a984e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right click" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Site" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.rightClick.1ovld0h" -msgstr "Clic derecho" +msgid "editor.sidebar.panels.sitePanel.site" +msgstr "Parcela" -# Source-Hash: c836b21b42198868 +# Source-Hash: c40163620df24a76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R / Shift+R" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Take snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.rShiftR.13bnobh" -msgstr "R / Mayús+R" +msgid "editor.sidebar.panels.sitePanel.takeSnapshot" +msgstr "Tomar instantánea" -# Source-Hash: 9812aa06d8bb7544 +# Source-Hash: d6b381247066a7aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scroll" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The ground level cannot be deleted" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.scroll.ai6wr0" -msgstr "Desplazar" +msgid "editor.sidebar.panels.sitePanel.theGroundLevelCannotBeDeleted" +msgstr "La planta baja no se puede eliminar" -# Source-Hash: f2174536230657c8 +# Source-Hash: bbc65c039ae86e11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scroll wheel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.toolHint.key.scrollWheel.18j0ix7" -msgstr "Rueda del ratón" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.cameraSnapshot" +msgstr "Instantánea de cámara" -# Source-Hash: 82dd231086d87f3b +# Source-Hash: 67d29724469fa8d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Space" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.toolHint.key.space.1hrh82t" -msgstr "Espacio" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.clearSnapshot" +msgstr "Borrar instantánea" -# Source-Hash: 9e68aa2f472cad56 +# Source-Hash: 591087ea83a48ead # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tab" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.toolHint.key.tab.1xsal0s" -msgstr "Tab" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.hide" +msgstr "Ocultar" -# Source-Hash: 4b221b73f9496a49 +# Source-Hash: 827e0c6ac9936b69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mount: floor / ceiling / wall" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.toolHint.mountFloorCeilingWall.32dxpv" -msgstr "Montaje: suelo / techo / muro" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.show" +msgstr "Mostrar" -# Source-Hash: 225edfb1e45aed95 +# Source-Hash: c40163620df24a76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No room for the matching window on the other wall" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Take snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.toolHint.noRoomForTheMatchingWindow.1755948" -msgstr "No hay espacio para la ventana correspondiente en el otro muro" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.takeSnapshot" +msgstr "Tomar instantánea" -# Source-Hash: a7045d6b678bcd13 +# Source-Hash: faecab10b69d4863 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No wall meets here" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Update snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.toolHint.noWallMeetsHere.19n99yc" -msgstr "Aquí no se une ningún muro" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.updateSnapshot" +msgstr "Actualizar instantánea" -# Source-Hash: a639341dc21fed2c +# Source-Hash: 8a1fd8827a68f236 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Number of cuts — scroll or click to change" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "View snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.toolHint.numberOfCutsScrollOrClick.1kqe84b" -msgstr "Número de cortes: desplaza o haz clic para cambiar" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.viewSnapshot" +msgstr "Ver instantánea" -# Source-Hash: af01bde3ae4b7e59 +# Source-Hash: b404dded35241274 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick witness point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Units" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.pickWitnessPoint.k3hgh1" -msgstr "Elegir punto testigo" +msgid "editor.sidebar.panels.sitePanel.units" +msgstr "Unidades" -# Source-Hash: ecfd58576b28a9f6 +# Source-Hash: 149fec3fd1f08042 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pipe size down / up" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete unit" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.toolHint.pipeSizeDownUp.wp04og" -msgstr "Diámetro de tubería menos / más" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.deleteUnit" +msgstr "Eliminar unidad" -# Source-Hash: 7a1eb7b64f06bad0 +# Source-Hash: 930399d3fb247a7c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place and continue" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Focused" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.toolHint.placeAndContinue.qfwkrq" -msgstr "Colocar y continuar" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.focused" +msgstr "Enfocada" -# Source-Hash: c6cda39e2e4b5d3a +# Source-Hash: 41ac9dd23bb558d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place block" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove from unit" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.toolHint.placeBlock.1aylwrx" -msgstr "Colocar bloque" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.removeFromUnit" +msgstr "Quitar de la unidad" -# Source-Hash: 45a743c52a1d72de +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place box vent on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.toolHint.placeBoxVentOnRoof.kf88e5" -msgstr "Colocar aireador en la cubierta" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.room" +msgstr "Estancia" -# Source-Hash: 75142dd1d557efe2 +# Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place cabinet" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.toolHint.placeCabinet.b0ouyk" -msgstr "Colocar mueble" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.zone" +msgstr "Zona" -# Source-Hash: da603a713d4c9909 +# Source-Hash: faecab10b69d4863 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place canopy or set the next run point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Update snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeCanopyOrSetTheNext.12l7zf8" -msgstr "Colocar la marquesina o el siguiente punto" +msgid "editor.sidebar.panels.sitePanel.updateSnapshot" +msgstr "Actualizar instantánea" -# Source-Hash: 8b3a30c6b7a5612d +# Source-Hash: 28a12e6806c091b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place chimney on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{assetType, select, guide {Uploading guide... {progress}%} other {Uploading scan... {progress}%}}" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeChimneyOnRoof.19dbqu" -msgstr "Colocar chimenea en la cubierta" +msgid "editor.sidebar.panels.sitePanel.uploadingProgress" +msgstr "{assetType, select, guide {Subiendo guía... {progress}%} other {Subiendo escaneo 3D... {progress}%}}" -# Source-Hash: 710d41e4e2f259fa +# Source-Hash: de389a2a46d53384 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place column" -#: packages/nodes/src/i18n/definition-messages.ts -#, fuzzy -msgid "editor.toolHint.placeColumn.1w2vq86" -msgstr "Colocar pilar" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Upload scan/floorplan" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.uploadScanFloorplan" +msgstr "Subir escaneo 3D o plano" -# Source-Hash: ee1da4e12a71d9a9 +# Source-Hash: 8a1fd8827a68f236 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place cupola on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "View snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeCupolaOnRoof.ofx3bn" -msgstr "Colocar linterna en la cubierta" +msgid "editor.sidebar.panels.sitePanel.viewSnapshot" +msgstr "Ver instantánea" -# Source-Hash: 19c1fe8c46d213a5 +# Source-Hash: ba9f809cb032ee57 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place dimension line when needed" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "In {unitName}" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/zone-membership-checkbox.tsx #, fuzzy -msgid "editor.toolHint.placeDimensionLineWhenNeeded.bjw2cj" -msgstr "Colocar la línea de cota cuando haga falta" +msgid "editor.sidebar.panels.sitePanel.zoneMembershipCheckbox.inUnitname" +msgstr "En {unitName}" -# Source-Hash: 58f3e7efb6ea120b +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place door on wall" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeDoorOnWall.1jwadf" -msgstr "Colocar puerta en el muro" +msgid "editor.sidebar.panels.zonePanel.actions" +msgstr "Acciones" -# Source-Hash: de04e9d03d937c97 +# Source-Hash: fcc43f22937d1536 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place dormer on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add one" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeDormerOnRoof.1w518a6" -msgstr "Colocar buhardilla en la cubierta" +msgid "editor.sidebar.panels.zonePanel.addOne" +msgstr "Añadir una" -# Source-Hash: c581645f2ee447c2 +# Source-Hash: bbc65c039ae86e11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place elevator" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeElevator.1f65zva" -msgstr "Colocar ascensor" +msgid "editor.sidebar.panels.zonePanel.cameraSnapshot" +msgstr "Instantánea de cámara" -# Source-Hash: 096b8d6482717358 +# Source-Hash: 67d29724469fa8d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place eyebrow vent on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeEyebrowVentOnRoof.1h1tqxn" -msgstr "Colocar respiradero de ceja en la cubierta" +msgid "editor.sidebar.panels.zonePanel.clearSnapshot" +msgstr "Borrar instantánea" -# Source-Hash: e8d42c1c8370773f +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place fitting" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeFitting.1pmx3vn" -msgstr "Colocar accesorio" +msgid "editor.sidebar.panels.zonePanel.delete" +msgstr "Eliminar" -# Source-Hash: 2340a4b70cb0d9ad +# Source-Hash: e2411929697b7ed4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place gutter on roof eave" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete with contents" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeGutterOnRoofEave.llwzf9" -msgstr "Colocar canalón en el alero" +msgid "editor.sidebar.panels.zonePanel.deleteWithContents" +msgstr "Eliminar con el contenido" -# Source-Hash: 706a8eafb6212833 +# Source-Hash: 22ca3935e8754072 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place item" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No zones on this level." +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeItem.teynf" -msgstr "Colocar elemento" +msgid "editor.sidebar.panels.zonePanel.noZonesOnThisLevel" +msgstr "No hay zonas en esta planta." -# Source-Hash: 1815c482e249932e +# Source-Hash: 941ea30f406dcfa2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place it (locked to 45°)" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Save to catalog" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeItLockedTo45.16e4csk" -msgstr "Colocar (bloqueado a 45°)" +msgid "editor.sidebar.panels.zonePanel.saveToCatalog" +msgstr "Guardar en el catálogo" -# Source-Hash: 4a14340657532838 +# Source-Hash: 98662dfb371cac13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place measurement point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select a level to view and create zones" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeMeasurementPoint.bsatli" -msgstr "Colocar punto de medida" +msgid "editor.sidebar.panels.zonePanel.selectALevelToViewAnd" +msgstr "Selecciona una planta para ver y crear zonas" -# Source-Hash: b3be684ac62fbf53 +# Source-Hash: c40163620df24a76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Take snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placement.13lcvts" -msgstr "Colocación" +msgid "editor.sidebar.panels.zonePanel.takeSnapshot" +msgstr "Tomar instantánea" -# Source-Hash: 2bb2ce6276c69b1e +# Source-Hash: faecab10b69d4863 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement: Auto" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Update snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placementAuto.1caa52d" -msgstr "Colocación: automática" +msgid "editor.sidebar.panels.zonePanel.updateSnapshot" +msgstr "Actualizar instantánea" -# Source-Hash: ed78ac5354a1dcd8 +# Source-Hash: 8a1fd8827a68f236 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement: Ground" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "View snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placementGround.1ruz145" -msgstr "Colocación: suelo" +msgid "editor.sidebar.panels.zonePanel.viewSnapshot" +msgstr "Ver instantánea" -# Source-Hash: a066a2c9d5e65a1a +# Source-Hash: 58b05af5b5724efb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement: Roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "\"{label}\" plugin crashed" +#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx #, fuzzy -msgid "editor.toolHint.placementRoof.renkw8" -msgstr "Colocación: cubierta" +msgid "editor.sidebar.usePluginPanels.labelPluginCrashed" +msgstr "El plugin “{label}” se ha bloqueado" -# Source-Hash: 8f74dbe5064c4c66 +# Source-Hash: 9e84d6d7b9885c4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement surface - click or press P to cycle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Loading…" +#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx #, fuzzy -msgid "editor.toolHint.placementSurfaceClickOrPressP.w56h19" -msgstr "Superficie de colocación: haz clic o pulsa P para cambiar" +msgid "editor.sidebar.usePluginPanels.loading" +msgstr "Cargando…" -# Source-Hash: fe119955c925feaf +# Source-Hash: 9fc7a39bc32f287a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement type" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plugins" +#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx #, fuzzy -msgid "editor.toolHint.placementType.1mdpl60" -msgstr "Tipo de colocación" +msgid "editor.sidebar.usePluginPanels.plugins" +msgstr "Complementos" -# Source-Hash: 33043a35500168f5 +# Source-Hash: c6312309378aaaea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement type — click or press I to toggle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This panel hit an error and was unloaded for this session. The rest of the editor is unaffected — reload to try again." +#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx #, fuzzy -msgid "editor.toolHint.placementTypeClickOrPressI.10cgxh2" -msgstr "Tipo de colocación: haz clic o pulsa I para alternar" +msgid "editor.sidebar.usePluginPanels.thisPanelHitAnErrorAnd" +msgstr "Este panel ha tenido un error y se ha descargado durante esta sesión. El resto del editor no se ve afectado: recarga para volver a intentarlo." -# Source-Hash: 9945f412e6a9a446 +# Source-Hash: 2ab3b6983e384ecc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place on a fence" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling attachment" +#: packages/editor/src/components/ui/snap-target-badge.tsx #, fuzzy -msgid "editor.toolHint.placeOnAFence.1dptstr" -msgstr "Colocar en una valla" +msgid "editor.snapTarget.ceiling" +msgstr "Fijación al techo" -# Source-Hash: 6708118775a7da7f +# Source-Hash: 54a00bbb699e3778 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place register" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof attachment" +#: packages/editor/src/components/ui/snap-target-badge.tsx #, fuzzy -msgid "editor.toolHint.placeRegister.1uebycd" -msgstr "Colocar rejilla" +msgid "editor.snapTarget.roof" +msgstr "Fijación a la cubierta" -# Source-Hash: ebd2731f5c79306e +# Source-Hash: e45fee9c27f6ae69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place ridge vent on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall attachment" +#: packages/editor/src/components/ui/snap-target-badge.tsx #, fuzzy -msgid "editor.toolHint.placeRidgeVentOnRoof.2tpd8r" -msgstr "Colocar ventilación de cumbrera en la cubierta" +msgid "editor.snapTarget.wall" +msgstr "Fijación a la pared" -# Source-Hash: 9b3c66a867c23326 +# Source-Hash: 834de1a7027c4da1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place shelf" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The editor scene failed to render" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.toolHint.placeShelf.y4l3iw" -msgstr "Colocar estantería" +msgid "editor.theEditorSceneFailedToRender" +msgstr "No se pudo mostrar la escena del editor" -# Source-Hash: f11cf5c1c9fe862d +# Source-Hash: 151f7c7e4110016f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place skylight on roof" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A curtain wall takes no corner window" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeSkylightOnRoof.e215pe" -msgstr "Colocar claraboya en la cubierta" +msgid "editor.toolHint.aCurtainWallTakesNoCorner.1qxjv5i" +msgstr "Un muro cortina no admite ventana de esquina" -# Source-Hash: e989a58d6709cc16 +# Source-Hash: 97f5e044d46501fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place solar panel array on roof" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A curved wall takes no corner window" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeSolarPanelArrayOnRoof.kk11fn" -msgstr "Colocar paneles solares en la cubierta" +msgid "editor.toolHint.aCurvedWallTakesNoCorner.1vdnaw5" +msgstr "Un muro curvo no admite ventana de esquina" -# Source-Hash: b67f7036d5180cf5 +# Source-Hash: 776d8ebece7fe1bb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place spawn point" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add a corner · click the first to close" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeSpawnPoint.205o25" -msgstr "Colocar punto de aparición" +msgid "editor.toolHint.addACornerClickTheFirst.o4r67t" +msgstr "Añadir esquina · haz clic en la primera para cerrar" -# Source-Hash: 6c7f32a17e5636c3 +# Source-Hash: 6a0745dd047b149a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place stairs" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Another opening is in the way at the corner" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeStairs.zwxxu2" -msgstr "Colocar escalera" +msgid "editor.toolHint.anotherOpeningIsInTheWay.11l9dd0" +msgstr "Otra abertura estorba en la esquina" -# Source-Hash: 641c0d3debd798a8 +# Source-Hash: 441124187e7da2fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place trap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeTrap.1gxemn3" -msgstr "Colocar sifón" +msgid "editor.toolHint.autoHangers.10554ka" +msgstr "Colgadores automáticos" -# Source-Hash: 6f0a6f6c4b7588a0 +# Source-Hash: 47a7f9a6a81156c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place turbine vent on roof" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers - click or press H to toggle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeTurbineVentOnRoof.1iqeluf" -msgstr "Colocar extractor eólico en la cubierta" +msgid "editor.toolHint.autoHangersClickOrPressH.rwa3ka" +msgstr "Colgadores automáticos: haz clic o pulsa H para alternar" -# Source-Hash: e65cf5edb4f51ed5 +# Source-Hash: d7944f31cba90e26 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place unit" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers: Off" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeUnit.8zkx4q" -msgstr "Colocar equipo" +msgid "editor.toolHint.autoHangersOff.7yx01x" +msgstr "Colgadores automáticos: desactivados" -# Source-Hash: 86ce1c730154f68b +# Source-Hash: 295882d015d08742 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place window on wall" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers: On" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeWindowOnWall.1k3qnfb" -msgstr "Colocar ventana en el muro" +msgid "editor.toolHint.autoHangersOn.10b1umh" +msgstr "Colgadores automáticos: activados" -# Source-Hash: 2b612180a7617901 +# Source-Hash: 8c039e5182b01c4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place without the corner snap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bypass snapping" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeWithoutTheCornerSnap.1nifqew" -msgstr "Colocar sin el ajuste a la esquina" +msgid "editor.toolHint.bypassSnapping.w5lmdv" +msgstr "Omitir el ajuste" -# Source-Hash: 0dc6d121791696f7 +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove last point" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.removeLastPoint.2dmdcx" -msgstr "Quitar el último punto" +msgid "editor.toolHint.cancel.ew9em3" +msgstr "Cancelar" -# Source-Hash: 8b74b1d962be10fc +# Source-Hash: 5b33b576fd30b74e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove last witness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel move" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.removeLastWitness.1b6vvzw" -msgstr "Quitar el último testigo" +msgid "editor.toolHint.cancelMove.lvp31c" +msgstr "Cancelar movimiento" -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: 136fa29b9ae419bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel run / exit" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.rotate.1thqa0a" -msgstr "Girar" +msgid "editor.toolHint.cancelRunExit.zqjf3h" +msgstr "Cancelar tramo / salir" -# Source-Hash: 8a665ecaeffa9308 +# Source-Hash: 75b406824be91ac2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ±45°" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel start point" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.rotate45.9zq68u" -msgstr "Girar ±45°" +msgid "editor.toolHint.cancelStartPoint.1xbq2lh" +msgstr "Cancelar punto inicial" -# Source-Hash: be2240289aa74df5 +# Source-Hash: ffa5aaa1746303c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ±45° (floor / ceiling)" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner window" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.rotate45FloorCeiling.m9t57d" -msgstr "Girar ±45° (suelo / techo)" +msgid "editor.toolHint.cornerWindow.1avkzpo" +msgstr "Ventana de esquina" -# Source-Hash: d5fb78b07c0f8138 +# Source-Hash: b0afdd855a02e4a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ghost ±15°" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cuts" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.rotateGhost15.rsa52c" -msgstr "Girar la vista previa ±15°" +msgid "editor.toolHint.cuts.1y0axps" +msgstr "Cortes" -# Source-Hash: 912d340cd16e27fa +# Source-Hash: dc9fe7601cc525f8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate or flip the run side" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cuts: {value}" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.rotateOrFlipTheRunSide.t5ior7" -msgstr "Girar o invertir el lado de la línea" +msgid "editor.toolHint.cutsValue.ouzhvb" +msgstr "Cortes: {value}" -# Source-Hash: ad1dc0b5536cceef +# Source-Hash: a2e13bc4dc82624c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate roof direction 90°" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cuts: {value}, even" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.rotateRoofDirection90.tvbji2" -msgstr "Girar la orientación de la cubierta 90°" +msgid "editor.toolHint.cutsValueEven.1ngsz3" +msgstr "Cortes: {value}, uniformes" -# Source-Hash: fa24651e9e5f595a +# Source-Hash: 04152b4cec726f34 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate spawn point" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cycle mono / gable / butterfly" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.rotateSpawnPoint.1opcuu7" -msgstr "Girar el punto de aparición" +msgid "editor.toolHint.cycleMonoGableButterfly.1poga3m" +msgstr "Cambiar un agua / dos aguas / mariposa" -# Source-Hash: 2d693d87fe9b59e6 +# Source-Hash: 4fb6c83edb6652b5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round / rectangular / oval" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cycle snapping mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.roundRectangularOval.e4nh6x" -msgstr "Redondo / rectangular / ovalado" +msgid "editor.toolHint.cycleSnappingMode.1ct0gn6" +msgstr "Cambiar el modo de ajuste" -# Source-Hash: f7d2c9cdcc637c97 +# Source-Hash: 5d550a3ac76279de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set fence start / end" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door style — click or press L to cycle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.setFenceStartEnd.1phbwsq" -msgstr "Fijar inicio / fin de la valla" +msgid "editor.toolHint.doorStyleClickOrPressL.33pe65" +msgstr "Estilo de puerta: haz clic o pulsa L para cambiar" -# Source-Hash: c93ae898b4d59f6f +# Source-Hash: 3272a7df5d7c6a9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set one corner, then the opposite" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door type — click or press O to cycle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.setOneCornerThenTheOpposite.8tsl49" -msgstr "Fija una esquina y luego la opuesta" +msgid "editor.toolHint.doorTypeClickOrPressO.1hhh8gt" +msgstr "Tipo de puerta: haz clic o pulsa O para cambiar" -# Source-Hash: 4f55171f10c6ceeb +# Source-Hash: 366222b4435eefda # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set roof footprint" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drop downspout from outlet" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.setRoofFootprint.p50n0o" -msgstr "Fijar la planta de la cubierta" +msgid "editor.toolHint.dropDownspoutFromOutlet.1k4h1m4" +msgstr "Bajar la bajante desde la salida" -# Source-Hash: 0243859b1d64c21e +# Source-Hash: 03f306371f345007 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set wall start / end" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct diameter down / up" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.setWallStartEnd.1r8ubcx" -msgstr "Fijar inicio / fin del muro" +msgid "editor.toolHint.ductDiameterDownUp.1wdz5vq" +msgstr "Diámetro del conducto menos / más" -# Source-Hash: c2806cce9612fa50 +# Source-Hash: 7b4137e27f8327d9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slope / level" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End run / cancel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.slopeLevel.ftqp67" -msgstr "Pendiente / horizontal" +msgid "editor.toolHint.endRunCancel.59dh2w" +msgstr "Terminar tramo / cancelar" -# Source-Hash: 06c0ec40606db679 +# Source-Hash: b714e91c31108a71 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snap onto the run" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End the run" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.snapOntoTheRun.86yhmp" -msgstr "Ajustar al tramo" +msgid "editor.toolHint.endTheRun.1c1raig" +msgstr "Terminar el tramo" -# Source-Hash: e214cccbac9c4fd2 +# Source-Hash: 938aacb119b29dc1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Split at the marks" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Exit" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.splitAtTheMarks.x5tpdd" -msgstr "Dividir en las marcas" +msgid "editor.toolHint.exit.engmg5" +msgstr "Salir" -# Source-Hash: 94455c35bfeac6b4 +# Source-Hash: 7cb4e0688cabcb00 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start grid axis" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Exit drawing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.startGridAxis.k92yza" -msgstr "Iniciar el eje" +msgid "editor.toolHint.exitDrawing.9noxyb" +msgstr "Salir del dibujo" -# Source-Hash: 2edb4c29bbe7c513 +# Source-Hash: 47025a103c456125 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start lineset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish and continue" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.startLineset.23q8dh" -msgstr "Iniciar la línea frigorífica" +msgid "editor.toolHint.finishAndContinue.1gpfsks" +msgstr "Terminar y continuar" -# Source-Hash: 9e50f1b30e325208 +# Source-Hash: 000918429b74128f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start liquid line" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish ceiling" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.startLiquidLine.1rlxsgd" -msgstr "Iniciar la línea de líquido" +msgid "editor.toolHint.finishCeiling.1c1lfel" +msgstr "Terminar el techo" -# Source-Hash: 877ddcb778c211cc +# Source-Hash: 51a80a0dba5a6f30 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start run" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish grid axis" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.startRun.r6fc5u" -msgstr "Iniciar el tramo" +msgid "editor.toolHint.finishGridAxis.1wvrfhr" +msgstr "Terminar el eje" -# Source-Hash: 8a62bee64174bbc0 +# Source-Hash: 87c7b98fc2e010e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start segment" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish measurement" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.startSegment.rolym6" -msgstr "Iniciar el segmento" +msgid "editor.toolHint.finishMeasurement.1e4gv16" +msgstr "Terminar la medida" -# Source-Hash: 6cc5dc51a8e66779 +# Source-Hash: 5e1a0af7dc506826 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Step back or cancel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish multi-point witnesses" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.stepBackOrCancel.zbfdkn" -msgstr "Retroceder o cancelar" +msgid "editor.toolHint.finishMultiPointWitnesses.8wzskz" +msgstr "Terminar los testigos de varios puntos" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: 30fc0862501ba2e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish slab" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.style.nf3vcm" -msgstr "Estilo" +msgid "editor.toolHint.finishSlab.xmnm8e" +msgstr "Terminar el forjado" -# Source-Hash: 81f595b1c47c0080 +# Source-Hash: 66ed7c7598d3aa29 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Barn" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip side" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleBarn.k9n1x" -msgstr "Estilo: granero" +msgid "editor.toolHint.flipSide.172xku9" +msgstr "Invertir el lado" -# Source-Hash: 3a82c718fe215273 +# Source-Hash: f5717f6a0905ffab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Casement" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow: trace a lineset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleCasement.ziklec" -msgstr "Estilo: abatible" +msgid "editor.toolHint.followTraceALineset.mgquwe" +msgstr "Seguir: trazar junto a una línea frigorífica" -# Source-Hash: 072e3331d1d105c0 +# Source-Hash: ed7f3d8417a3e074 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Craftsman" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Force place" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleCraftsman.52e6a9" -msgstr "Estilo: artesano" +msgid "editor.toolHint.forcePlace.1hq1nr" +msgstr "Forzar colocación" -# Source-Hash: b64d07557dec1714 +# Source-Hash: 64b4ac6d3da25183 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Double-hung" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleDoubleHung.1lg8pkg" -msgstr "Estilo: guillotina doble" +msgid "editor.toolHint.freeAngle.1ptblho" +msgstr "Ángulo libre" -# Source-Hash: 55ef8761a537637f +# Source-Hash: 446b8aac1e5e8422 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: French" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free place" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleFrench.1ue3j64" -msgstr "Estilo: francesa" +msgid "editor.toolHint.freePlace.1s1uusw" +msgstr "Colocación libre" -# Source-Hash: bc8a751d87536dc3 +# Source-Hash: cc0c14065951444d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Glass" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free placement" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleGlass.qudnb4" -msgstr "Estilo: vidrio" +msgid "editor.toolHint.freePlacement.1nztdac" +msgstr "Colocación libre" -# Source-Hash: 40c1eb0bc83e207d +# Source-Hash: f098a27096a9c1ea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Grid" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Go vertical ↕, click to place" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleGrid.1vuq4po" -msgstr "Estilo: cuadrícula" +msgid "editor.toolHint.goVerticalClickToPlace.dg8g6m" +msgstr "Pasar a vertical ↕, haz clic para colocar" -# Source-Hash: f516886bab2e7f10 +# Source-Hash: fd47f1820d8799c8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Half-louvered" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Highlight outlet" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleHalfLouvered.13b1few" -msgstr "Estilo: media lama" +msgid "editor.toolHint.highlightOutlet.65hoq8" +msgstr "Resaltar la salida" -# Source-Hash: 64e4389a695371a2 +# Source-Hash: eb90058d0f856f67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Horizontal bands" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Join as a corner window" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleHorizontalBands.12ethxk" -msgstr "Estilo: bandas horizontales" +msgid "editor.toolHint.joinAsACornerWindow.jvdp4j" +msgstr "Unir como ventana de esquina" -# Source-Hash: ff6d226a425b00c0 +# Source-Hash: 225b3161f2e59757 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Modern" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Alt + drag" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleModern.1fh8hhn" -msgstr "Estilo: moderno" +msgid "editor.toolHint.key.altDrag.ai3wn9" +msgstr "Alt + arrastrar" -# Source-Hash: c6d17ba078ff47e7 +# Source-Hash: dd66f883b173fc72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Backspace" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.stylePanel.922jze" -msgstr "Estilo: panel" +msgid "editor.toolHint.key.backspace.qy6qx8" +msgstr "Retroceso" -# Source-Hash: 5e6baad0d2ce3a62 +# Source-Hash: a18387bc0be54c32 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Paneled glass" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.stylePaneledGlass.17a17en" -msgstr "Estilo: vidrio con paneles" +msgid "editor.toolHint.key.click.m8sun" +msgstr "Clic" -# Source-Hash: 6314388e6832c252 +# Source-Hash: db9e60c1d30b8499 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Shaker" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click again" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleShaker.49z17k" -msgstr "Estilo: shaker" +msgid "editor.toolHint.key.clickAgain.190ws9j" +msgstr "Volver a hacer clic" -# Source-Hash: a0f8e524f3ca121f +# Source-Hash: f400330b9c9c12e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Single" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Command" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleSingle.6f3cm0" -msgstr "Estilo: simple" +msgid "editor.toolHint.key.command.1j2mkia" +msgstr "Comando" -# Source-Hash: 368279df3a472c86 +# Source-Hash: 976c63285a510b09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Six-panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Control" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleSixPanel.u49laj" -msgstr "Estilo: seis paneles" +msgid "editor.toolHint.key.control.10fbl8e" +msgstr "Control" -# Source-Hash: 8f3c2571d8168fee +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Sliding" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleSliding.q81s0i" -msgstr "Estilo: corredera" +msgid "editor.toolHint.key.delete.oay2cq" +msgstr "Eliminar" -# Source-Hash: aa9d9eb137ca38d4 +# Source-Hash: 88888c9d2719fa92 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Tall grid" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double click" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleTallGrid.1eotg3x" -msgstr "Estilo: cuadrícula alta" +msgid "editor.toolHint.key.doubleClick.vlma6o" +msgstr "Doble clic" -# Source-Hash: bc164648722b63e5 +# Source-Hash: dfb85b2addb7b9fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Transom" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleTransom.kb9bh6" -msgstr "Estilo: montante" +msgid "editor.toolHint.key.drag.8pwtpf" +msgstr "Arrastrar" -# Source-Hash: 9a218f0c9ceb4697 +# Source-Hash: ed9140d42148c99b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Triple-hung" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Enter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleTripleHung.pxnqi3" -msgstr "Estilo: guillotina triple" +msgid "editor.toolHint.key.enter.1ctpui5" +msgstr "Intro" -# Source-Hash: 9f6df1344bd3d694 +# Source-Hash: 9195fa8b9c8ebdfb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Wide grid" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleWideGrid.12n27et" -msgstr "Estilo: cuadrícula ancha" +msgid "editor.toolHint.key.hover.6xw79p" +msgstr "Pasar el cursor" -# Source-Hash: 711d4050c0cb95d7 +# Source-Hash: 2d78441b741bc562 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Switch rotation axis (Y → X → Z)" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a duct end" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.switchRotationAxisYXZ.15lohm6" -msgstr "Cambiar el eje de giro (Y → X → Z)" +msgid "editor.toolHint.key.hoverADuctEnd.19axr3b" +msgstr "Pasa el cursor por un extremo del conducto" -# Source-Hash: d650c71e042c2598 +# Source-Hash: 6083405086f61c76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The walls meet at too sharp or too flat an angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a pipe end" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.theWallsMeetAtTooSharp.kh3wi3" -msgstr "Los muros se unen en un ángulo demasiado agudo o demasiado plano" +msgid "editor.toolHint.key.hoverAPipeEnd.1jbum5f" +msgstr "Pasa el cursor por un extremo de la tubería" -# Source-Hash: ab206ac56e65f190 +# Source-Hash: a5a337eb76fdb066 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The window waiting there is taller than this wall" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover gutter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.theWindowWaitingThereIsTaller.1tqwez4" -msgstr "La ventana prevista ahí es más alta que este muro" +msgid "editor.toolHint.key.hoverGutter.1dwcsno" +msgstr "Pasa el cursor por el canalón" -# Source-Hash: 9c1f47138ed5c7ee +# Source-Hash: a58533594411e088 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Three or more walls meet here" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left click" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.threeOrMoreWallsMeetHere.rgifif" -msgstr "Aquí se unen tres o más muros" +msgid "editor.toolHint.key.leftClick.s4gwfc" +msgstr "Clic izquierdo" -# Source-Hash: c3ca56fa28e15f07 +# Source-Hash: bc4ab608ec3d3b4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trace ceiling outline" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Middle click" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.traceCeilingOutline.1b639wv" -msgstr "Trazar el contorno del techo" +msgid "editor.toolHint.key.middleClick.1jbaan4" +msgstr "Clic central" -# Source-Hash: bdf71499d30a29de +# Source-Hash: 6791879c651108c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trace slab outline" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right click" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.traceSlabOutline.z0j2lc" -msgstr "Trazar el contorno del forjado" +msgid "editor.toolHint.key.rightClick.1ovld0h" +msgstr "Clic derecho" -# Source-Hash: c44f7ab8bbd24858 +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.type.1m2zofh" -msgstr "Tipo" +msgid "editor.toolHint.key.room.1f3jkpm" +msgstr "Estancia" -# Source-Hash: b54eaaff3349dcb1 +# Source-Hash: c836b21b42198868 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Awning" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R / Shift+R" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeAwning.1cj59al" -msgstr "Tipo: proyectante" +msgid "editor.toolHint.key.rShiftR.13bnobh" +msgstr "R / Mayús+R" -# Source-Hash: f399572a27417c66 +# Source-Hash: 9812aa06d8bb7544 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Barn" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scroll" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeBarn.sbnygq" -msgstr "Tipo: granero" +msgid "editor.toolHint.key.scroll.ai6wr0" +msgstr "Desplazar" -# Source-Hash: a1df9782200b5f1e +# Source-Hash: f2174536230657c8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Bay" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scroll wheel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeBay.1200hc1" -msgstr "Tipo: mirador" +msgid "editor.toolHint.key.scrollWheel.18j0ix7" +msgstr "Rueda del ratón" -# Source-Hash: ff069a390e8e3f66 +# Source-Hash: 82dd231086d87f3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Bow" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Space" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeBow.14s2t9p" -msgstr "Tipo: mirador curvo" +msgid "editor.toolHint.key.space.1hrh82t" +msgstr "Espacio" -# Source-Hash: bdac5f3f2ea70fff +# Source-Hash: 9e68aa2f472cad56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Cabinet" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tab" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeCabinet.1r68je5" -msgstr "Tipo: armario" +msgid "editor.toolHint.key.tab.1xsal0s" +msgstr "Tab" -# Source-Hash: e0754fc03997cbf9 +# Source-Hash: 4b221b73f9496a49 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Casement" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mount: floor / ceiling / wall" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeCasement.176uo9j" -msgstr "Tipo: abatible" +msgid "editor.toolHint.mountFloorCeilingWall.32dxpv" +msgstr "Montaje: suelo / techo / muro" -# Source-Hash: 47d873446d6e173b +# Source-Hash: 225edfb1e45aed95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Double" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No room for the matching window on the other wall" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeDouble.af7w4i" -msgstr "Tipo: doble" +msgid "editor.toolHint.noRoomForTheMatchingWindow.1755948" +msgstr "No hay espacio para la ventana correspondiente en el otro muro" -# Source-Hash: 5942e484513aaab5 +# Source-Hash: e367d28a655f1cca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Double Hung" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not a rectangle: draw this roof instead" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeDoubleHung.t482fu" -msgstr "Tipo: guillotina doble" +msgid "editor.toolHint.notARectangleDrawThisRoof.100pa5g" +msgstr "No es un rectángulo: dibuja esta cubierta en su lugar" -# Source-Hash: f9497fbfceefda27 +# Source-Hash: a7045d6b678bcd13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Fixed" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No wall meets here" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeFixed.v1cjez" -msgstr "Tipo: fija" +msgid "editor.toolHint.noWallMeetsHere.19n99yc" +msgstr "Aquí no se une ningún muro" -# Source-Hash: 0dcf07acc9cbf000 +# Source-Hash: a639341dc21fed2c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Folding" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Number of cuts — scroll or click to change" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeFolding.sxxyng" -msgstr "Tipo: plegable" +msgid "editor.toolHint.numberOfCutsScrollOrClick.1kqe84b" +msgstr "Número de cortes: desplaza o haz clic para cambiar" -# Source-Hash: bff7331f87f279aa +# Source-Hash: af01bde3ae4b7e59 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: French" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick witness point" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeFrench.1y57z1b" -msgstr "Tipo: francesa" +msgid "editor.toolHint.pickWitnessPoint.k3hgh1" +msgstr "Elegir punto testigo" -# Source-Hash: 9d2c3b82079eb769 +# Source-Hash: ecfd58576b28a9f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Hinged" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pipe size down / up" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeHinged.1xrcfju" -msgstr "Tipo: batiente" +msgid "editor.toolHint.pipeSizeDownUp.wp04og" +msgstr "Diámetro de tubería menos / más" -# Source-Hash: b8001b90ff522838 +# Source-Hash: 7a1eb7b64f06bad0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Island" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place and continue" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeIsland.ufr3ce" -msgstr "Tipo: isla" +msgid "editor.toolHint.placeAndContinue.qfwkrq" +msgstr "Colocar y continuar" -# Source-Hash: 516833c5160d412e +# Source-Hash: c6cda39e2e4b5d3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Louvered" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place block" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeLouvered.oxl1cz" -msgstr "Tipo: de lamas" +msgid "editor.toolHint.placeBlock.1aylwrx" +msgstr "Colocar bloque" -# Source-Hash: 291272bf848ad6ab +# Source-Hash: 45a743c52a1d72de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Pocket" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place box vent on roof" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typePocket.hc65x9" -msgstr "Tipo: corredera empotrada" +msgid "editor.toolHint.placeBoxVentOnRoof.kf88e5" +msgstr "Colocar aireador en la cubierta" -# Source-Hash: 46d0e53d6ae07c72 +# Source-Hash: 75142dd1d557efe2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Single Hung" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place cabinet" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeSingleHung.p53pyl" -msgstr "Tipo: guillotina simple" +msgid "editor.toolHint.placeCabinet.b0ouyk" +msgstr "Colocar mueble" -# Source-Hash: b11115b50df8faac +# Source-Hash: da603a713d4c9909 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Sliding" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place canopy or set the next run point" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeSliding.nwmr3f" -msgstr "Tipo: corredera" +msgid "editor.toolHint.placeCanopyOrSetTheNext.12l7zf8" +msgstr "Colocar la marquesina o el siguiente punto" -# Source-Hash: bff0c1694ee0a37e +# Source-Hash: 8b3a30c6b7a5612d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical stack ↕, click to place" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place chimney on roof" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.verticalStackClickToPlace.ijcn4q" -msgstr "Montante vertical ↕, haz clic para colocar" +msgid "editor.toolHint.placeChimneyOnRoof.19dbqu" +msgstr "Colocar chimenea en la cubierta" -# Source-Hash: bac471ee67af6412 +# Source-Hash: 710d41e4e2f259fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waste / vent" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place column" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.wasteVent.1hvi3vj" -msgstr "Desagüe / ventilación" +msgid "editor.toolHint.placeColumn.1w2vq86" +msgstr "Colocar pilar" -# Source-Hash: 1c744b7e24fc786e +# Source-Hash: ee1da4e12a71d9a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Window style — click or press L to cycle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place cupola on roof" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.windowStyleClickOrPressL.ah7qm9" -msgstr "Estilo de ventana: haz clic o pulsa L para cambiar" +msgid "editor.toolHint.placeCupolaOnRoof.ofx3bn" +msgstr "Colocar linterna en la cubierta" -# Source-Hash: dd6f0ab314fea26c +# Source-Hash: 19c1fe8c46d213a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Window type — click or press O to cycle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place dimension line when needed" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.windowTypeClickOrPressO.wv4x35" -msgstr "Tipo de ventana: haz clic o pulsa O para cambiar" +msgid "editor.toolHint.placeDimensionLineWhenNeeded.bjw2cj" +msgstr "Colocar la línea de cota cuando haga falta" +# Source-Hash: 58f3e7efb6ea120b # Review: required -# Source-Hash: a48c4b2e4d71b08d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length: {field} m" -#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place door on wall" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.tools.distribution.distributionRunTool.lengthField" -msgstr "Longitud: {field} m" +msgid "editor.toolHint.placeDoorOnWall.1jwadf" +msgstr "Colocar puerta en el muro" +# Source-Hash: de04e9d03d937c97 # Review: required -# Source-Hash: e53695d6669245c7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tab: direction" -#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place dormer on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.tools.distribution.distributionRunTool.tabDirection" -msgstr "Tab: dirección" +msgid "editor.toolHint.placeDormerOnRoof.1w518a6" +msgstr "Colocar buhardilla en la cubierta" +# Source-Hash: c581645f2ee447c2 # Review: required -# Source-Hash: abb1d8c8bfb41acf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "type a length" -#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place elevator" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.tools.distribution.distributionRunTool.typeALength" -msgstr "escribe una longitud" +msgid "editor.toolHint.placeElevator.1f65zva" +msgstr "Colocar ascensor" -# Source-Hash: 9fc7a39bc32f287a +# Source-Hash: 096b8d6482717358 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Plugins" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place eyebrow vent on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.plugins" -msgstr "Complementos" +msgid "editor.toolHint.placeEyebrowVentOnRoof.1h1tqxn" +msgstr "Colocar respiradero de ceja en la cubierta" -# Source-Hash: c54f9bac358893d8 +# Source-Hash: e8d42c1c8370773f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "2D" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place fitting" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.view2d" -msgstr "2D" +msgid "editor.toolHint.placeFitting.1pmx3vn" +msgstr "Colocar accesorio" -# Source-Hash: f78f2fa035f25f85 +# Source-Hash: 2340a4b70cb0d9ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "3D" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place gutter on roof eave" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.view3d" -msgstr "3D" +msgid "editor.toolHint.placeGutterOnRoofEave.llwzf9" +msgstr "Colocar canalón en el alero" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: 706a8eafb6212833 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place item" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.auto" -msgstr "Auto" +msgid "editor.toolHint.placeItem.teynf" +msgstr "Colocar elemento" -# Source-Hash: 7890c110650ad1e5 +# Source-Hash: 1815c482e249932e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Browse plugins" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place it (locked to 45°)" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.browsePlugins" -msgstr "Explorar complementos" +msgid "editor.toolHint.placeItLockedTo45.16e4csk" +msgstr "Colocar (bloqueado a 45°)" -# Source-Hash: 3b11e7af681a9dcd +# Source-Hash: 4a14340657532838 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close {label}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place measurement point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.closeLabel" -msgstr "Cerrar {label}" +msgid "editor.toolHint.placeMeasurementPoint.bsatli" +msgstr "Colocar punto de medida" -# Source-Hash: 3f00e92517e3f4a5 +# Source-Hash: b3be684ac62fbf53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close split (\\)" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.closeSplit" -msgstr "Cerrar vista dividida (\\)" +msgid "editor.toolHint.placement.13lcvts" +msgstr "Colocación" -# Source-Hash: 94cc8e9f1ee16edb +# Source-Hash: 2bb2ce6276c69b1e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement: Auto" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.ground" -msgstr "Terreno" +msgid "editor.toolHint.placementAuto.1caa52d" +msgstr "Colocación: automática" -# Source-Hash: 0d472502a4d36e86 +# Source-Hash: ed78ac5354a1dcd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{standing, select, partly {Partly below grade · ground solid} below {Below grade · ground solid} other {Ground solid}}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement: Ground" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.groundSolid" -msgstr "{standing, select, partly {Parcialmente bajo rasante · terreno sólido} below {Bajo rasante · terreno sólido} other {Terreno sólido}}" +msgid "editor.toolHint.placementGround.1ruz145" +msgstr "Colocación: suelo" -# Source-Hash: 1b6798c307ac1b96 +# Source-Hash: a066a2c9d5e65a1a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{standing, select, partly {Partly below grade · ground veiled} below {Below grade · ground veiled} other {Ground veiled}}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement: Roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.groundVeiled" -msgstr "{standing, select, partly {Parcialmente bajo rasante · terreno velado} below {Bajo rasante · terreno velado} other {Terreno velado}}" +msgid "editor.toolHint.placementRoof.renkw8" +msgstr "Colocación: cubierta" -# Source-Hash: ebdc976a98e82626 +# Source-Hash: 8f74dbe5064c4c66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Keep the ground solid" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement surface - click or press P to cycle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.keepTheGroundSolid" -msgstr "Mantener el terreno sólido" +msgid "editor.toolHint.placementSurfaceClickOrPressP.w56h19" +msgstr "Superficie de colocación: haz clic o pulsa P para cambiar" -# Source-Hash: 5f827686a006d88c +# Source-Hash: fe119955c925feaf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "More views" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement type" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.moreViews" -msgstr "Más vistas" +msgid "editor.toolHint.placementType.1mdpl60" +msgstr "Tipo de colocación" -# Source-Hash: f175bbcf457ab73c +# Source-Hash: 33043a35500168f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pane {pane} views" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement type — click or press I to toggle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.paneViews" -msgstr "Vistas del panel {pane}" +msgid "editor.toolHint.placementTypeClickOrPressI.10cgxh2" +msgstr "Tipo de colocación: haz clic o pulsa I para alternar" -# Source-Hash: 33c20cc33dce9a9b +# Source-Hash: 9945f412e6a9a446 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pin {label}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place on a fence" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.pinLabel" -msgstr "Fijar {label}" +msgid "editor.toolHint.placeOnAFence.1dptstr" +msgstr "Colocar en una valla" -# Source-Hash: 3f7231b1eb2f93f3 +# Source-Hash: 6708118775a7da7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pin to the view bar" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place register" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.pinToTheViewBar" -msgstr "Fijar a la barra de vistas" +msgid "editor.toolHint.placeRegister.1uebycd" +msgstr "Colocar rejilla" -# Source-Hash: ef3e765e692faf4c +# Source-Hash: ebd2731f5c79306e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place ridge vent on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.solid" -msgstr "Sólido" +msgid "editor.toolHint.placeRidgeVentOnRoof.2tpd8r" +msgstr "Colocar ventilación de cumbrera en la cubierta" -# Source-Hash: 98f22f3f89f17686 +# Source-Hash: 9b3c66a867c23326 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Split (\\)" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place shelf" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.split" -msgstr "Vista dividida (\\)" +msgid "editor.toolHint.placeShelf.y4l3iw" +msgstr "Colocar estantería" -# Source-Hash: e4cd64b1680ac0d2 +# Source-Hash: f11cf5c1c9fe862d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Split" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place skylight on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.split2" -msgstr "Dividir" +msgid "editor.toolHint.placeSkylightOnRoof.e215pe" +msgstr "Colocar claraboya en la cubierta" -# Source-Hash: 15b0adc705923a27 +# Source-Hash: e989a58d6709cc16 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swap panes" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place solar panel array on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.swapPanes" -msgstr "Intercambiar paneles" +msgid "editor.toolHint.placeSolarPanelArrayOnRoof.kk11fn" +msgstr "Colocar paneles solares en la cubierta" -# Source-Hash: 9781bcdb7a8549e2 +# Source-Hash: b67f7036d5180cf5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unpin from the view bar" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place spawn point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.unpinFromTheViewBar" -msgstr "Quitar de la barra de vistas" +msgid "editor.toolHint.placeSpawnPoint.205o25" +msgstr "Colocar punto de aparición" -# Source-Hash: f667358dec4abdea +# Source-Hash: 6c7f32a17e5636c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unpin {label}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place stairs" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.unpinLabel" -msgstr "Dejar de fijar {label}" +msgid "editor.toolHint.placeStairs.zwxxu2" +msgstr "Colocar escalera" -# Source-Hash: e96581f0bbf9fa91 +# Source-Hash: 641c0d3debd798a8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Veil the ground over a level below grade" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place trap" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.veilTheGroundOverALevel" -msgstr "Velar el terreno sobre una planta bajo rasante" +msgid "editor.toolHint.placeTrap.1gxemn3" +msgstr "Colocar sifón" -# Source-Hash: fb82f09f8ed3059e +# Source-Hash: 6f0a6f6c4b7588a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Views" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place turbine vent on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.views" -msgstr "Vistas" +msgid "editor.toolHint.placeTurbineVentOnRoof.1iqeluf" +msgstr "Colocar extractor eólico en la cubierta" -# Source-Hash: fdece5c2158dfe88 +# Source-Hash: e65cf5edb4f51ed5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "You can retry the scene or return home without reloading the whole app shell." -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place unit" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.youCanRetryTheSceneOr" -msgstr "Puedes reintentar la escena o volver al inicio sin recargar toda la aplicación." +msgid "editor.toolHint.placeUnit.8zkx4q" +msgstr "Colocar equipo" -# Source-Hash: a273dacdf51b26f2 +# Source-Hash: 86ce1c730154f68b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A topology-backed solid edited directly in the canvas." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place window on wall" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.block.description" -msgstr "Sólido con topología que se edita directamente en el lienzo." +msgid "editor.toolHint.placeWindowOnWall.1k3qnfb" +msgstr "Colocar ventana en el muro" -# Source-Hash: 279f456ebb2f5da0 +# Source-Hash: 2b612180a7617901 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Block" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place without the corner snap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.block.label" -msgstr "Bloque" +msgid "editor.toolHint.placeWithoutTheCornerSnap.1nifqew" +msgstr "Colocar sin el ajuste a la esquina" -# Source-Hash: b2a371b4041b5e38 +# Source-Hash: dd2ea442152dca5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Small louvered exhaust vent that sits on a roof slope." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Point inside a room, porch or deck" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.description" -msgstr "Pequeño respiradero de extracción con lamas sobre un faldón." +msgid "editor.toolHint.pointInsideARoomPorchOr.58w64l" +msgstr "Sitúa el cursor dentro de una estancia, un porche o una tarima" -# Source-Hash: f736ca24e84825c3 +# Source-Hash: 0dc6d121791696f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box Vent" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove last point" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.label" -msgstr "Aireador de cubierta" +msgid "editor.toolHint.removeLastPoint.2dmdcx" +msgstr "Quitar el último punto" +# Source-Hash: 8b74b1d962be10fc # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove last witness" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.actions" -msgstr "Acciones" +msgid "editor.toolHint.removeLastWitness.1b6vvzw" +msgstr "Quitar el último testigo" +# Source-Hash: 1185bd2407dd9172 # Review: required -# Source-Hash: c0e9837e67038e92 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base Flange" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge direction" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.baseFlange" -msgstr "Brida de base" +msgid "editor.toolHint.ridgeDirection.5m1369" +msgstr "Dirección de la cumbrera" +# Source-Hash: 4352028e50450055 # Review: required -# Source-Hash: fa9118f6f4f020d7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base Height" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge direction - click or press R to turn it 90°" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.baseHeight" -msgstr "Altura de la base" +msgid "editor.toolHint.ridgeDirectionClickOrPressR.1t14dyk" +msgstr "Dirección de la cumbrera: haz clic o pulsa R para girarla 90°" +# Source-Hash: 96c889f047db9de5 # Review: required -# Source-Hash: 0869f5a92dabb4e1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base Inset" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge: Long side" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.baseInset" -msgstr "Retranqueo de la base" +msgid "editor.toolHint.ridgeLongSide.ew0euv" +msgstr "Cumbrera: lado largo" +# Source-Hash: 58143198d3f2a265 # Review: required -# Source-Hash: e9a89a5e4ac8cd61 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge: Short side" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.box" -msgstr "Caja" +msgid "editor.toolHint.ridgeShortSide.gye8pb" +msgstr "Cumbrera: lado corto" +# Source-Hash: 306d409f8a1cf480 # Review: required -# Source-Hash: f736ca24e84825c3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box Vent" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.boxVent" -msgstr "Aireador de cubierta" +msgid "editor.toolHint.rotate.1thqa0a" +msgstr "Girar" +# Source-Hash: 8a665ecaeffa9308 # Review: required -# Source-Hash: d52b53241789ee63 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ±45°" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.cap" -msgstr "Remate" +msgid "editor.toolHint.rotate45.9zq68u" +msgstr "Girar ±45°" +# Source-Hash: be2240289aa74df5 # Review: required -# Source-Hash: 0ce3b53766b550e7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap Height" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ±45° (floor / ceiling)" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.capHeight" -msgstr "Altura del sombrerete" +msgid "editor.toolHint.rotate45FloorCeiling.m9t57d" +msgstr "Girar ±45° (suelo / techo)" +# Source-Hash: d5fb78b07c0f8138 # Review: required -# Source-Hash: 89eba9f077fba348 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner Bevel" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ghost ±15°" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.cornerBevel" -msgstr "Chaflán de esquina" +msgid "editor.toolHint.rotateGhost15.rsa52c" +msgstr "Girar la vista previa ±15°" +# Source-Hash: 912d340cd16e27fa # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate or flip the run side" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.delete" -msgstr "Eliminar" +msgid "editor.toolHint.rotateOrFlipTheRunSide.t5ior7" +msgstr "Girar o invertir el lado de la línea" +# Source-Hash: fa24651e9e5f595a # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate spawn point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.depth" -msgstr "Profundidad" +msgid "editor.toolHint.rotateSpawnPoint.1opcuu7" +msgstr "Girar el punto de aparición" +# Source-Hash: 2d693d87fe9b59e6 # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round / rectangular / oval" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.dimensions" -msgstr "Dimensiones" +msgid "editor.toolHint.roundRectangularOval.e4nh6x" +msgstr "Redondo / rectangular / ovalado" +# Source-Hash: ee4ca2612f1ea085 # Review: required -# Source-Hash: de47e23eb81efe02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dome" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set beam start / end; the next beam starts there" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.dome" -msgstr "Cúpula" +msgid "editor.toolHint.setBeamStartEndTheNext.di3bzj" +msgstr "Fijar inicio / fin de la viga; la siguiente viga empieza ahí" +# Source-Hash: f7d2c9cdcc637c97 # Review: required -# Source-Hash: 1c5c81aa21193d07 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dome Curvature" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set fence start / end" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.domeCurvature" -msgstr "Curvatura de la cúpula" +msgid "editor.toolHint.setFenceStartEnd.1phbwsq" +msgstr "Fijar inicio / fin de la valla" +# Source-Hash: c93ae898b4d59f6f # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set one corner, then the opposite" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.duplicate" -msgstr "Duplicar" +msgid "editor.toolHint.setOneCornerThenTheOpposite.8tsl49" +msgstr "Fija una esquina y luego la opuesta" +# Source-Hash: 4f55171f10c6ceeb # Review: required -# Source-Hash: 8cac057f7ae6804d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap Height" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set roof footprint" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.gapHeight" -msgstr "Altura de la holgura" +msgid "editor.toolHint.setRoofFootprint.p50n0o" +msgstr "Fijar la planta de la cubierta" +# Source-Hash: 0243859b1d64c21e # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set wall start / end" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.height" -msgstr "Altura" +msgid "editor.toolHint.setWallStartEnd.1r8ubcx" +msgstr "Fijar inicio / fin del muro" +# Source-Hash: c2806cce9612fa50 # Review: required -# Source-Hash: 8a9c2ea0783a0e53 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hood Overhang" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slope / level" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.hoodOverhang" -msgstr "Vuelo de la caperuza" +msgid "editor.toolHint.slopeLevel.ftqp67" +msgstr "Pendiente / horizontal" +# Source-Hash: 06c0ec40606db679 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snap onto the run" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.move" -msgstr "Mover" +msgid "editor.toolHint.snapOntoTheRun.86yhmp" +msgstr "Ajustar al tramo" +# Source-Hash: e214cccbac9c4fd2 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Split at the marks" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.position" -msgstr "Posición" +msgid "editor.toolHint.splitAtTheMarks.x5tpdd" +msgstr "Dividir en las marcas" +# Source-Hash: 94455c35bfeac6b4 # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start grid axis" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.rotation" -msgstr "Rotación" +msgid "editor.toolHint.startGridAxis.k92yza" +msgstr "Iniciar el eje" +# Source-Hash: 2edb4c29bbe7c513 # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start lineset" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.style" -msgstr "Estilo" +msgid "editor.toolHint.startLineset.23q8dh" +msgstr "Iniciar la línea frigorífica" +# Source-Hash: 9e50f1b30e325208 # Review: required -# Source-Hash: 71d82d47e11d2564 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Taper" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start liquid line" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.topTaper" -msgstr "Estrechamiento superior" +msgid "editor.toolHint.startLiquidLine.1rlxsgd" +msgstr "Iniciar la línea de líquido" +# Source-Hash: 877ddcb778c211cc # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start run" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.width" -msgstr "Ancho" +msgid "editor.toolHint.startRun.r6fc5u" +msgstr "Iniciar el tramo" -# Source-Hash: f49d8836ae037dde +# Source-Hash: 8a62bee64174bbc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A building container holding one or more levels." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start segment" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.building.description" -msgstr "Contenedor de edificio con una o varias plantas." +msgid "editor.toolHint.startSegment.rolym6" +msgstr "Iniciar el segmento" -# Source-Hash: d42f7d29e3fc4af7 +# Source-Hash: 6cc5dc51a8e66779 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Building" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Step back or cancel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.building.label" -msgstr "Edificio" +msgid "editor.toolHint.stepBackOrCancel.zbfdkn" +msgstr "Retroceder o cancelar" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: 5a8274cbe3034558 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Baskets" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.baskets" -msgstr "Cestas" +msgid "editor.toolHint.style.nf3vcm" +msgstr "Estilo" +# Source-Hash: 81f595b1c47c0080 # Review: required -# Source-Hash: b3a163b453896bef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Barn" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.bottom" -msgstr "Inferior" +msgid "editor.toolHint.styleBarn.k9n1x" +msgstr "Estilo: granero" +# Source-Hash: 3a82c718fe215273 # Review: required -# Source-Hash: 486501f027037732 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Freezer" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Casement" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.bottomFreezer" -msgstr "Congelador inferior" +msgid "editor.toolHint.styleCasement.ziklec" +msgstr "Estilo: abatible" +# Source-Hash: 072e3331d1d105c0 # Review: required -# Source-Hash: 375acc0016b3aa14 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bowls" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Craftsman" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.bowls" -msgstr "Senos" +msgid "editor.toolHint.styleCraftsman.52e6a9" +msgstr "Estilo: artesano" +# Source-Hash: b64d07557dec1714 # Review: required -# Source-Hash: 8449b59bf054c27d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Burners on" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Double-hung" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.burnersOn" -msgstr "Fuegos encendidos" +msgid "editor.toolHint.styleDoubleHung.1lg8pkg" +msgstr "Estilo: guillotina doble" +# Source-Hash: 55ef8761a537637f # Review: required -# Source-Hash: 95169058fec6db14 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Chimney" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: French" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.chimney" -msgstr "Chimenea" +msgid "editor.toolHint.styleFrench.1ue3j64" +msgstr "Estilo: francesa" +# Source-Hash: bc8a751d87536dc3 # Review: required -# Source-Hash: a6b76187db231ae7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Decrease {label}" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Glass" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.decrease" -msgstr "Reducir {label}" +msgid "editor.toolHint.styleGlass.qudnb4" +msgstr "Estilo: vidrio" +# Source-Hash: 40c1eb0bc83e207d # Review: required -# Source-Hash: 787e10f5db16904e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Grid" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.door" -msgstr "Puerta" +msgid "editor.toolHint.styleGrid.1vuq4po" +msgstr "Estilo: cuadrícula" +# Source-Hash: f516886bab2e7f10 # Review: required -# Source-Hash: 3cd71355956a1821 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Half-louvered" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.double" -msgstr "Doble" +msgid "editor.toolHint.styleHalfLouvered.13b1few" +msgstr "Estilo: media lama" +# Source-Hash: 64e4389a695371a2 # Review: required -# Source-Hash: 63fe49d73892aac8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawer" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Horizontal bands" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.drawer" -msgstr "Cajón" +msgid "editor.toolHint.styleHorizontalBands.12ethxk" +msgstr "Estilo: bandas horizontales" +# Source-Hash: ff6d226a425b00c0 # Review: required -# Source-Hash: f98242a5dacd33f3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawers" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Modern" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.drawers" -msgstr "Cajones" +msgid "editor.toolHint.styleModern.1fh8hhn" +msgstr "Estilo: moderno" +# Source-Hash: c6d17ba078ff47e7 # Review: required -# Source-Hash: 3af5347c94ae6443 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip hinge" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Panel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.flipHinge" -msgstr "Invertir bisagra" +msgid "editor.toolHint.stylePanel.922jze" +msgstr "Estilo: panel" +# Source-Hash: 5e6baad0d2ce3a62 # Review: required -# Source-Hash: c930f681e61c029c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip the door hinge to the opposite side" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Paneled glass" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.flipTheDoorHingeToThe" -msgstr "Pasar la bisagra de la puerta al lado opuesto" +msgid "editor.toolHint.stylePaneledGlass.17a17en" +msgstr "Estilo: vidrio con paneles" +# Source-Hash: 6314388e6832c252 # Review: required -# Source-Hash: 85724031c91952a3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fridge" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Shaker" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.fridge" -msgstr "Frigorífico" +msgid "editor.toolHint.styleShaker.49z17k" +msgstr "Estilo: shaker" +# Source-Hash: a0f8e524f3ca121f # Review: required -# Source-Hash: e67f11024d683ea9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gas" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Single" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.gas" -msgstr "Gas" +msgid "editor.toolHint.styleSingle.6f3cm0" +msgstr "Estilo: simple" +# Source-Hash: 368279df3a472c86 # Review: required -# Source-Hash: 8ab91094cf650204 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Six-panel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.glass" -msgstr "Vidrio" +msgid "editor.toolHint.styleSixPanel.u49laj" +msgstr "Estilo: seis paneles" +# Source-Hash: 8f3c2571d8168fee # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Sliding" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.height" -msgstr "Altura" +msgid "editor.toolHint.styleSliding.q81s0i" +msgstr "Estilo: corredera" +# Source-Hash: aa9d9eb137ca38d4 # Review: required -# Source-Hash: 6f434b84c8b59b8c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hob" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Tall grid" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.hob" -msgstr "Placa" +msgid "editor.toolHint.styleTallGrid.1eotg3x" +msgstr "Estilo: cuadrícula alta" +# Source-Hash: bc164648722b63e5 # Review: required -# Source-Hash: d52570d41b4df776 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Increase {label}" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Transom" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.increase" -msgstr "Aumentar {label}" +msgid "editor.toolHint.styleTransom.kb9bh6" +msgstr "Estilo: montante" +# Source-Hash: 9a218f0c9ceb4697 # Review: required -# Source-Hash: d298f259163e868e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Induction" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Triple-hung" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.induction" -msgstr "Inducción" +msgid "editor.toolHint.styleTripleHung.pxnqi3" +msgstr "Estilo: guillotina triple" +# Source-Hash: 9f6df1344bd3d694 # Review: required -# Source-Hash: 54800340a0eeab23 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Layout" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Wide grid" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.layout" -msgstr "Distribución" +msgid "editor.toolHint.styleWideGrid.12n27et" +msgstr "Estilo: cuadrícula ancha" +# Source-Hash: 711d4050c0cb95d7 # Review: required -# Source-Hash: f365c6b6dd9ebab9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Switch rotation axis (Y → X → Z)" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.left" -msgstr "Izquierda" +msgid "editor.toolHint.switchRotationAxisYXZ.15lohm6" +msgstr "Cambiar el eje de giro (Y → X → Z)" +# Source-Hash: d650c71e042c2598 # Review: required -# Source-Hash: 12ade82be3830a0b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Micro" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The walls meet at too sharp or too flat an angle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.micro" -msgstr "Microondas" +msgid "editor.toolHint.theWallsMeetAtTooSharp.kh3wi3" +msgstr "Los muros se unen en un ángulo demasiado agudo o demasiado plano" +# Source-Hash: ab206ac56e65f190 # Review: required -# Source-Hash: a06a50e63f0c240e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move down" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The window waiting there is taller than this wall" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.moveDown" -msgstr "Bajar" +msgid "editor.toolHint.theWindowWaitingThereIsTaller.1tqwez4" +msgstr "La ventana prevista ahí es más alta que este muro" +# Source-Hash: 9c1f47138ed5c7ee # Review: required -# Source-Hash: d49ea60a2312df2f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move up" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Three or more walls meet here" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.moveUp" -msgstr "Subir" +msgid "editor.toolHint.threeOrMoreWallsMeetHere.rgifif" +msgstr "Aquí se unen tres o más muros" +# Source-Hash: c3ca56fa28e15f07 # Review: required -# Source-Hash: 596023c8b9a8f2e4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Oven" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trace ceiling outline" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.oven" -msgstr "Horno" +msgid "editor.toolHint.traceCeilingOutline.1b639wv" +msgstr "Trazar el contorno del techo" +# Source-Hash: bdf71499d30a29de # Review: required -# Source-Hash: 83b20797fb0a01a0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pullout" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trace slab outline" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.pullout" -msgstr "Extraíble" +msgid "editor.toolHint.traceSlabOutline.z0j2lc" +msgstr "Trazar el contorno del forjado" +# Source-Hash: c44f7ab8bbd24858 # Review: required -# Source-Hash: 43c251f465b647ce -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rack" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.rack" -msgstr "Estante" +msgid "editor.toolHint.type.1m2zofh" +msgstr "Tipo" +# Source-Hash: b54eaaff3349dcb1 # Review: required -# Source-Hash: 3c2b3026d37cbcc2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove compartment" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Awning" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.removeCompartment" -msgstr "Quitar compartimento" +msgid "editor.toolHint.typeAwning.1cj59al" +msgstr "Tipo: proyectante" +# Source-Hash: f399572a27417c66 # Review: required -# Source-Hash: b34d5ee0f218221d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Barn" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.right" -msgstr "Derecha" +msgid "editor.toolHint.typeBarn.sbnygq" +msgstr "Tipo: granero" +# Source-Hash: a1df9782200b5f1e # Review: required -# Source-Hash: d7145f84f8e0e3fe -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shelf" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Bay" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.shelf" -msgstr "Estantería" +msgid "editor.toolHint.typeBay.1200hc1" +msgstr "Tipo: mirador" +# Source-Hash: ff069a390e8e3f66 # Review: required -# Source-Hash: 5fbb88f1f079b6db -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shelves" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Bow" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.shelves" -msgstr "Baldas" +msgid "editor.toolHint.typeBow.14s2t9p" +msgstr "Tipo: mirador curvo" +# Source-Hash: bdac5f3f2ea70fff # Review: required -# Source-Hash: 47173085127029f0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shelves inside" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Cabinet" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.shelvesInside" -msgstr "Baldas interiores" +msgid "editor.toolHint.typeCabinet.1r68je5" +msgstr "Tipo: armario" +# Source-Hash: e0754fc03997cbf9 # Review: required -# Source-Hash: 62ab2eb3c775da95 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Casement" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.single" -msgstr "Simple" +msgid "editor.toolHint.typeCasement.176uo9j" +msgstr "Tipo: abatible" +# Source-Hash: 47d873446d6e173b # Review: required -# Source-Hash: 522a7535fc93fb4f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sink" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Double" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.sink" -msgstr "Fregadero" +msgid "editor.toolHint.typeDouble.af7w4i" +msgstr "Tipo: doble" +# Source-Hash: 5942e484513aaab5 # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Double Hung" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.style" -msgstr "Estilo" +msgid "editor.toolHint.typeDoubleHung.t482fu" +msgstr "Tipo: guillotina doble" +# Source-Hash: f9497fbfceefda27 # Review: required -# Source-Hash: 78a454b7ac7a3cd9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Fixed" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.surface" -msgstr "Superficie" +msgid "editor.toolHint.typeFixed.v1cjez" +msgstr "Tipo: fija" +# Source-Hash: 0dcf07acc9cbf000 # Review: required -# Source-Hash: 27644f0497fd9849 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Folding" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.top" -msgstr "Superior" +msgid "editor.toolHint.typeFolding.sxxyng" +msgstr "Tipo: plegable" +# Source-Hash: bff7331f87f279aa # Review: required -# Source-Hash: eaadfd2d19b27d87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Freezer" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: French" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.topFreezer" -msgstr "Congelador superior" +msgid "editor.toolHint.typeFrench.1y57z1b" +msgstr "Tipo: francesa" +# Source-Hash: 9d2c3b82079eb769 # Review: required -# Source-Hash: 04f3a3462ef5d247 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top grate" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Hinged" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.topGrate" -msgstr "Parrilla superior" +msgid "editor.toolHint.typeHinged.1xrcfju" +msgstr "Tipo: batiente" +# Source-Hash: b8001b90ff522838 # Review: required -# Source-Hash: 4a616e1d2ca55bd5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tray" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Island" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.tray" -msgstr "Bandeja" +msgid "editor.toolHint.typeIsland.ufr3ce" +msgstr "Tipo: isla" +# Source-Hash: 516833c5160d412e # Review: required -# Source-Hash: c44f7ab8bbd24858 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Louvered" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.type" -msgstr "Tipo" +msgid "editor.toolHint.typeLouvered.oxl1cz" +msgstr "Tipo: de lamas" +# Source-Hash: 291272bf848ad6ab # Review: required -# Source-Hash: 6c4de540d19316ab -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Washer" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Pocket" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.washer" -msgstr "Lavavajillas" +msgid "editor.toolHint.typePocket.hc65x9" +msgstr "Tipo: corredera empotrada" +# Source-Hash: 46d0e53d6ae07c72 # Review: required -# Source-Hash: 5211a0caf3518125 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wire" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Single Hung" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.wire" -msgstr "Alambre" +msgid "editor.toolHint.typeSingleHung.p53pyl" +msgstr "Tipo: guillotina simple" -# Source-Hash: 693a0d8896f5cc43 +# Source-Hash: b11115b50df8faac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A configurable parametric base cabinet." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Sliding" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.description" -msgstr "Mueble bajo paramétrico configurable." +msgid "editor.toolHint.typeSliding.nwmr3f" +msgstr "Tipo: corredera" +# Source-Hash: bff0c1694ee0a37e # Review: required -# Source-Hash: b0568ea943addd5b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom freezer" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical stack ↕, click to place" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.essentialControls.bottomFreezer" -msgstr "Congelador inferior" +msgid "editor.toolHint.verticalStackClickToPlace.ijcn4q" +msgstr "Montante vertical ↕, haz clic para colocar" +# Source-Hash: bac471ee67af6412 # Review: required -# Source-Hash: da78819903ae0863 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cooktop type" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waste / vent" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.essentialControls.cooktopType" -msgstr "Tipo de placa" +msgid "editor.toolHint.wasteVent.1hvi3vj" +msgstr "Desagüe / ventilación" +# Source-Hash: 1c744b7e24fc786e # Review: required -# Source-Hash: c608188f58ed1cfc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door direction" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Window style — click or press L to cycle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.essentialControls.doorDirection" -msgstr "Sentido de apertura" +msgid "editor.toolHint.windowStyleClickOrPressL.ah7qm9" +msgstr "Estilo de ventana: haz clic o pulsa L para cambiar" +# Source-Hash: dd6f0ab314fea26c # Review: required -# Source-Hash: 3cd71355956a1821 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Window type — click or press O to cycle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.essentialControls.double" -msgstr "Doble" +msgid "editor.toolHint.windowTypeClickOrPressO.wv4x35" +msgstr "Tipo de ventana: haz clic o pulsa O para cambiar" +# Source-Hash: a48c4b2e4d71b08d # Review: required -# Source-Hash: f7fb8f6393cc4cfc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fridge type" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length: {field} m" +#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx #, fuzzy -msgid "node.cabinet.essentialControls.fridgeType" -msgstr "Tipo de frigorífico" +msgid "editor.tools.distribution.distributionRunTool.lengthField" +msgstr "Longitud: {field} m" +# Source-Hash: e53695d6669245c7 # Review: required -# Source-Hash: e67f11024d683ea9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gas" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tab: direction" +#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx #, fuzzy -msgid "node.cabinet.essentialControls.gas" -msgstr "Gas" +msgid "editor.tools.distribution.distributionRunTool.tabDirection" +msgstr "Tab: dirección" +# Source-Hash: abb1d8c8bfb41acf # Review: required -# Source-Hash: 8ab91094cf650204 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "type a length" +#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx #, fuzzy -msgid "node.cabinet.essentialControls.glass" -msgstr "Vidrio" +msgid "editor.tools.distribution.distributionRunTool.typeALength" +msgstr "escribe una longitud" +# Source-Hash: 9fc7a39bc32f287a # Review: required -# Source-Hash: d298f259163e868e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Induction" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plugins" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.essentialControls.induction" -msgstr "Inducción" +msgid "editor.views.plugins" +msgstr "Complementos" +# Source-Hash: c54f9bac358893d8 # Review: required -# Source-Hash: 76df477d42cec629 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Item options" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "2D" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.essentialControls.itemOptions" -msgstr "Opciones del elemento" +msgid "editor.views.view2d" +msgstr "2D" +# Source-Hash: f78f2fa035f25f85 # Review: required -# Source-Hash: bca1b184af1c0c4b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left hinge" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "3D" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.essentialControls.leftHinge" -msgstr "Bisagra izquierda" +msgid "editor.views.view3d" +msgstr "3D" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: e32da7429c85f1a5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right hinge" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.essentialControls.rightHinge" -msgstr "Bisagra derecha" +msgid "editor.views.viewBar.auto" +msgstr "Auto" +# Source-Hash: 7890c110650ad1e5 # Review: required -# Source-Hash: 62ab2eb3c775da95 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Browse plugins" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.essentialControls.single" -msgstr "Simple" +msgid "editor.views.viewBar.browsePlugins" +msgstr "Explorar complementos" +# Source-Hash: 3b11e7af681a9dcd # Review: required -# Source-Hash: 4bc3042055df1e85 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sink layout" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close {label}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.essentialControls.sinkLayout" -msgstr "Distribución del fregadero" +msgid "editor.views.viewBar.closeLabel" +msgstr "Cerrar {label}" +# Source-Hash: 3f00e92517e3f4a5 # Review: required -# Source-Hash: 29cffe75281dbea6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top freezer" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close split (\\)" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.essentialControls.topFreezer" -msgstr "Congelador superior" +msgid "editor.views.viewBar.closeSplit" +msgstr "Cerrar vista dividida (\\)" +# Source-Hash: 94cc8e9f1ee16edb # Review: required -# Source-Hash: 09c2cb2ea7b1be3c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose {label}" -#: packages/nodes/src/cabinet/kitchen-collection.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenCollection.chooseLabel" -msgstr "Elegir {label}" +msgid "editor.views.viewBar.ground" +msgstr "Terreno" +# Source-Hash: 0d472502a4d36e86 # Review: required -# Source-Hash: 1dd2cac6488ddc30 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No kitchen items match. Try “fridge”, “sink”, or “cabinet”." -#: packages/nodes/src/cabinet/kitchen-collection.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{standing, select, partly {Partly below grade · ground solid} below {Below grade · ground solid} other {Ground solid}}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenCollection.noKitchenItemsMatchTryFridge" -msgstr "Ningún elemento de cocina coincide. Prueba «frigorífico», «fregadero» o «mueble»." +msgid "editor.views.viewBar.groundSolid" +msgstr "{standing, select, partly {Parcialmente bajo rasante · terreno sólido} below {Bajo rasante · terreno sólido} other {Terreno sólido}}" +# Source-Hash: 1b6798c307ac1b96 # Review: required -# Source-Hash: 6752675ca6280ddd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Search fridge, sink, cabinets…" -#: packages/nodes/src/cabinet/kitchen-collection.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{standing, select, partly {Partly below grade · ground veiled} below {Below grade · ground veiled} other {Ground veiled}}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenCollection.searchFridgeSinkCabinets" -msgstr "Buscar frigorífico, fregadero, muebles…" +msgid "editor.views.viewBar.groundVeiled" +msgstr "{standing, select, partly {Parcialmente bajo rasante · terreno velado} below {Bajo rasante · terreno velado} other {Terreno velado}}" +# Source-Hash: ebdc976a98e82626 # Review: required -# Source-Hash: fe3c6d57a07c323d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Search kitchen items" -#: packages/nodes/src/cabinet/kitchen-collection.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keep the ground solid" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenCollection.searchKitchenItems" -msgstr "Buscar elementos de cocina" +msgid "editor.views.viewBar.keepTheGroundSolid" +msgstr "Mantener el terreno sólido" +# Source-Hash: 5f827686a006d88c # Review: required -# Source-Hash: d44a46146db2e44c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Appliances & fixtures" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "More views" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenGroup.appliances" -msgstr "Electrodomésticos y equipamiento" +msgid "editor.views.viewBar.moreViews" +msgstr "Más vistas" +# Source-Hash: f175bbcf457ab73c # Review: required -# Source-Hash: d4d3ad7c099b6513 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinets" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pane {pane} views" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenGroup.cabinets" -msgstr "Muebles" +msgid "editor.views.viewBar.paneViews" +msgstr "Vistas del panel {pane}" +# Source-Hash: 33c20cc33dce9a9b # Review: required -# Source-Hash: 465db52f98c2d94f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add beside" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pin {label}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.addBeside" -msgstr "Añadir al lado" +msgid "editor.views.viewBar.pinLabel" +msgstr "Fijar {label}" +# Source-Hash: 3f7231b1eb2f93f3 # Review: required -# Source-Hash: 9733e2ad85deb6d5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add beside selected item" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pin to the view bar" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.addBesideSelectedItem" -msgstr "Añadir junto al elemento seleccionado" +msgid "editor.views.viewBar.pinToTheViewBar" +msgstr "Fijar a la barra de vistas" +# Source-Hash: ef3e765e692faf4c # Review: required -# Source-Hash: 4b2f676fb4c9ec63 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add {label}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.addLabel" -msgstr "Añadir {label}" +msgid "editor.views.viewBar.solid" +msgstr "Sólido" +# Source-Hash: 98f22f3f89f17686 # Review: required -# Source-Hash: 5122b8e9b4ec6a00 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "An upper cabinet attached to this item will be removed to make room." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Split (\\)" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.anUpperCabinetAttachedToThis" -msgstr "Se quitará un mueble alto unido a este elemento para dejar espacio." +msgid "editor.views.viewBar.split" +msgstr "Vista dividida (\\)" +# Source-Hash: e4cd64b1680ac0d2 # Review: required -# Source-Hash: 5737c4567e0f6863 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Split" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.cabinet" -msgstr "Mueble" +msgid "editor.views.viewBar.split2" +msgstr "Dividir" +# Source-Hash: 15b0adc705923a27 # Review: required -# Source-Hash: c0774c185060fc13 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap panes" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.cancel" -msgstr "Cancelar" +msgid "editor.views.viewBar.swapPanes" +msgstr "Intercambiar paneles" +# Source-Hash: 9781bcdb7a8549e2 # Review: required -# Source-Hash: f42912b116015f58 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "This {width} item cannot fit within the current run and its wall or corner limits. Move an end cabinet or free space, then try again." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unpin from the view bar" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.cannotFit" -msgstr "Este elemento de {width} no cabe en el tramo actual ni en sus límites de pared o esquina. Mueve un mueble del extremo o libera espacio y vuelve a intentarlo." +msgid "editor.views.viewBar.unpinFromTheViewBar" +msgstr "Quitar de la barra de vistas" +# Source-Hash: f667358dec4abdea # Review: required -# Source-Hash: b7eeb26a356d03c3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{side, select, left {Inserts on the left of the selected item.} other {Inserts on the right of the selected item.}}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unpin {label}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.insertsBeside" -msgstr "{side, select, left {Se inserta a la izquierda del elemento seleccionado.} other {Se inserta a la derecha del elemento seleccionado.}}" - +msgid "editor.views.viewBar.unpinLabel" +msgstr "Dejar de fijar {label}" + +# Source-Hash: e96581f0bbf9fa91 # Review: required -# Source-Hash: f65332177316d11d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The kitchen changed. Select an item again to refresh the preview." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Veil the ground over a level below grade" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.kitchenChanged" -msgstr "La cocina ha cambiado. Vuelve a seleccionar un elemento para actualizar la vista previa." +msgid "editor.views.viewBar.veilTheGroundOverALevel" +msgstr "Velar el terreno sobre una planta bajo rasante" +# Source-Hash: fb82f09f8ed3059e # Review: required -# Source-Hash: 5b6990b17111fd6b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchen run preview, highlighted item is the proposed change" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Views" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.kitchenRunPreviewHighlightedItemIs" -msgstr "Vista previa del tramo de cocina; el elemento resaltado es el cambio propuesto" +msgid "editor.views.viewBar.views" +msgstr "Vistas" +# Source-Hash: 57c1428fe2d28745 # Review: required -# Source-Hash: cb59562ba7eb1d25 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left side" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "List the layers from the outside in, around one framing core. The type is saved with the project and applied to this wall; other walls keep their layers." +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.leftSide" -msgstr "Lado izquierdo" +msgid "editor.wallTypeEditorDialog.listTheLayersAppliedToThisWall" +msgstr "Enumera las capas de fuera hacia dentro, en torno a un único núcleo estructural. El tipo se guarda con el proyecto y se aplica a este muro; los demás muros conservan sus capas." +# Source-Hash: 9e9715d52410c86f # Review: required -# Source-Hash: 766354d53f17d78c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{name}: moves {distance}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.moved" -msgstr "{name}: se mueve {distance}" +msgid "editor.wallTypeMenu.custom" +msgstr "Personalizado" +# Source-Hash: 0e2a2a8b90ba9c7e # Review: required -# Source-Hash: df1083d9ffc2c59d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{name}: {width}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall types: new, edit or duplicate {label}" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.previewItem" -msgstr "{name}: {width}" +msgid "editor.wallTypeMenu.wallTypesOf" +msgstr "Tipos de muro: crear, editar o duplicar {label}" +# Source-Hash: fdece5c2158dfe88 # Review: required -# Source-Hash: ada7fbece9ca9e3c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace selected item" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "You can retry the scene or return home without reloading the whole app shell." +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.replaceSelectedItem" -msgstr "Reemplazar el elemento seleccionado" +msgid "editor.youCanRetryTheSceneOr" +msgstr "Puedes reintentar la escena o volver al inicio sin recargar toda la aplicación." +# Source-Hash: bafa390e07160f3c # Review: required -# Source-Hash: ab8b52d2704537d2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replaces only the selected item." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A framing beam drawn end to end: a porch header, a deck beam, a girder." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.kitchenModuleActions.replacesOnlyTheSelectedItem" -msgstr "Solo reemplaza el elemento seleccionado." +msgid "node.beam.description" +msgstr "Una viga de entramado dibujada de extremo a extremo: un dintel de porche, una viga de tarima, una jácena." +# Source-Hash: e14858b33b6e2623 # Review: required -# Source-Hash: 03cb6dea6e4a4c5e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace with…" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.kitchenModuleActions.replaceWith" -msgstr "Reemplazar por…" +msgid "node.beam.label" +msgstr "Viga" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 948fe657641f298c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace with {label}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.replaceWithLabel" -msgstr "Reemplazar por {label}" +msgid "node.beam.panel.actions" +msgstr "Acciones" +# Source-Hash: 59f845b250e0df6f # Review: required -# Source-Hash: 154f9fa86b7670ba -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{name}: {before} → {after}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add posts" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.resized" -msgstr "{name}: {before} → {after}" +msgid "node.beam.panel.addPosts" +msgstr "Añadir postes" +# Source-Hash: e14858b33b6e2623 # Review: required -# Source-Hash: 4ecc493400fb6aa2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right side" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.rightSide" -msgstr "Lado derecho" +msgid "node.beam.panel.beam" +msgstr "Viga" +# Source-Hash: 26e977da636cc882 # Review: required -# Source-Hash: f2c30e7e21cf27e6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unable to update this kitchen." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam {size}" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.unableToUpdateThisKitchen" -msgstr "No se puede actualizar esta cocina." +msgid "node.beam.panel.beamSize" +msgstr "Viga {size}" -# Source-Hash: 2e6d8cda361c648d +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Modular Cabinet" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.label" -msgstr "Mueble modular" +msgid "node.beam.panel.delete" +msgstr "Eliminar" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: 740e0a4e4afa78ea -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finished height extends {overflow} mm above the ceiling." -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.aboveCeiling" -msgstr "La altura acabada sobrepasa el techo en {overflow} mm." +msgid "node.beam.panel.depth" +msgstr "Canto" +# Source-Hash: 73694f3f45cf2ee1 # Review: required -# Source-Hash: e3b4d2ed4f6f5efb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add chimney" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dropped" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.addChimney" -msgstr "Añadir campana" +msgid "node.beam.panel.dropped" +msgstr "Descolgada" +# Source-Hash: eaaa20f3b603140f # Review: required -# Source-Hash: 90bdc92c0a91d060 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add compartment" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flush" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.addCompartment" -msgstr "Añadir compartimento" +msgid "node.beam.panel.flush" +msgstr "Enrasada" +# Source-Hash: 0ee3edea19fd153e # Review: required -# Source-Hash: ece05d9b6f4b616d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add wall cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow the ceiling plane" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.addWallCabinet" -msgstr "Añadir mueble alto" +msgid "node.beam.panel.followTheCeilingPlane" +msgstr "Seguir el plano del techo" +# Source-Hash: 193b75ac869c251d # Review: required -# Source-Hash: f571cb2d06ae01ae -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Advanced" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{length} long; its underside {underside} over the floor, the ceiling plane {plane}." +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.advanced" -msgstr "Avanzado" +msgid "node.beam.panel.lengthLongItsUnderside" +msgstr "{length} de largo; su cara inferior a {underside} sobre el suelo y el plano del techo a {plane}." +# Source-Hash: 964b86ae1474ff98 # Review: required -# Source-Hash: 7f4dcb90defe1ac2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Appliance" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Material" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.appliance" -msgstr "Electrodoméstico" +msgid "node.beam.panel.material" +msgstr "Material" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: bd5e3f533412ff6a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Appliance front" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.applianceFront" -msgstr "Frente de electrodoméstico" +msgid "node.beam.panel.move" +msgstr "Mover" +# Source-Hash: fa876c632c284d81 # Review: required -# Source-Hash: 05b65242d8c48791 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "1 ply" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.auto" -msgstr "Auto" +msgid "node.beam.panel.n1Ply" +msgstr "1 pieza" +# Source-Hash: b3be684ac62fbf53 # Review: required -# Source-Hash: 9cf3754f15467c50 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.bar" -msgstr "Barra" +msgid "node.beam.panel.placement" +msgstr "Colocación" +# Source-Hash: 6ac7987d650b9742 # Review: required -# Source-Hash: 133893b177bd05d6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base Cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{plies} plies" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.baseCabinet" -msgstr "Mueble bajo" +msgid "node.beam.panel.pliesPlies" +msgstr "{plies} piezas" +# Source-Hash: 60bb3338e0ad558c # Review: required -# Source-Hash: d63f16df2c754126 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet construction, compartments, and opening preview." -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Size" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.cabinetConstructionCompartmentsAndOpeningPreview" -msgstr "Construcción del mueble, compartimentos y vista previa de apertura." +msgid "node.beam.panel.size" +msgstr "Tamaño" +# Source-Hash: 27644f0497fd9849 # Review: required -# Source-Hash: d62dc35dac835228 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet panel" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.cabinetPanel" -msgstr "Panel del mueble" +msgid "node.beam.panel.top" +msgstr "Cara superior" +# Source-Hash: 5b4c960036b3d05b # Review: required -# Source-Hash: 81caf4809d58b5f5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet Type" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top elevation" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.cabinetType" -msgstr "Tipo de mueble" +msgid "node.beam.panel.topElevation" +msgstr "Cota superior" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: 5211341ed18f33f6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.center" -msgstr "Centro" +msgid "node.beam.panel.width" +msgstr "Ancho" +# Source-Hash: a273dacdf51b26f2 # Review: required -# Source-Hash: d7cf5045c01b2eb9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A topology-backed solid edited directly in the canvas." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.panel.close" -msgstr "Cerrar" +msgid "node.block.description" +msgstr "Sólido con topología que se edita directamente en el lienzo." +# Source-Hash: 279f456ebb2f5da0 # Review: required -# Source-Hash: cf29134333e47184 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Block" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.panel.closeCabinet" -msgstr "Cerrar mueble" +msgid "node.block.label" +msgstr "Bloque" +# Source-Hash: b2a371b4041b5e38 # Review: required -# Source-Hash: b1ab1ba948bb77b0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Common wall-cabinet heights. Use the slider below for a custom height." -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Small louvered exhaust vent that sits on a roof slope." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.panel.commonWallCabinetHeightsUseThe" -msgstr "Alturas habituales de muebles altos. Usa el control deslizante de abajo para una altura personalizada." +msgid "node.boxVent.description" +msgstr "Pequeño respiradero de extracción con lamas sobre un faldón." +# Source-Hash: f736ca24e84825c3 # Review: required -# Source-Hash: fe9e63d5c5087386 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Compartments" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box Vent" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.panel.compartments" -msgstr "Compartimentos" +msgid "node.boxVent.label" +msgstr "Aireador de cubierta" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 7984b1c42abd9c02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cutout" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.cutout" -msgstr "Recorte" +msgid "node.boxVent.panel.actions" +msgstr "Acciones" +# Source-Hash: c0e9837e67038e92 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base Flange" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.depth" -msgstr "Profundidad" +msgid "node.boxVent.panel.baseFlange" +msgstr "Brida de base" +# Source-Hash: fa9118f6f4f020d7 # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base Height" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.dimensions" -msgstr "Dimensiones" +msgid "node.boxVent.panel.baseHeight" +msgstr "Altura de la base" +# Source-Hash: 0869f5a92dabb4e1 # Review: required -# Source-Hash: 82c9ea6f403fc934 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit kitchen run" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base Inset" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.editKitchenRun" -msgstr "Editar tramo de cocina" +msgid "node.boxVent.panel.baseInset" +msgstr "Retranqueo de la base" +# Source-Hash: e9a89a5e4ac8cd61 # Review: required -# Source-Hash: 7e9bbeb035fc73e2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fill to ceiling" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.fillToCeiling" -msgstr "Hasta el techo" +msgid "node.boxVent.panel.box" +msgstr "Caja" +# Source-Hash: f736ca24e84825c3 # Review: required -# Source-Hash: b3907da0ad234f10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box Vent" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.finish" -msgstr "Terminar" +msgid "node.boxVent.panel.boxVent" +msgstr "Aireador de cubierta" +# Source-Hash: d52b53241789ee63 # Review: required -# Source-Hash: c1796152935221ef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front construction" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.frontConstruction" -msgstr "Construcción del frente" +msgid "node.boxVent.panel.cap" +msgstr "Remate" +# Source-Hash: 0ce3b53766b550e7 # Review: required -# Source-Hash: 58884f99d64e6d00 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handles" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap Height" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.handles" -msgstr "Tiradores" +msgid "node.boxVent.panel.capHeight" +msgstr "Altura del sombrerete" +# Source-Hash: 89eba9f077fba348 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner Bevel" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.height" -msgstr "Altura" +msgid "node.boxVent.panel.cornerBevel" +msgstr "Chaflán de esquina" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: d73589d7c04b1121 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height preset" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.heightPreset" -msgstr "Altura predefinida" +msgid "node.boxVent.panel.delete" +msgstr "Eliminar" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: 590bfdd02dcdb857 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hole" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.hole" -msgstr "Orificio" +msgid "node.boxVent.panel.depth" +msgstr "Profundidad" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: 3db1dea825785a30 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inset" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.inset" -msgstr "Empotrado" +msgid "node.boxVent.panel.dimensions" +msgstr "Dimensiones" +# Source-Hash: de47e23eb81efe02 # Review: required -# Source-Hash: 1176d2568d093bf1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchen" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dome" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.kitchen" -msgstr "Cocina" +msgid "node.boxVent.panel.dome" +msgstr "Cúpula" +# Source-Hash: 1c5c81aa21193d07 # Review: required -# Source-Hash: a74f10dadc92c8bb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchen run" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dome Curvature" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.kitchenRun" -msgstr "Tramo de cocina" +msgid "node.boxVent.panel.domeCurvature" +msgstr "Curvatura de la cúpula" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: 103e15b39c909210 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Knob" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.knob" -msgstr "Pomo" +msgid "node.boxVent.panel.duplicate" +msgstr "Duplicar" +# Source-Hash: 8cac057f7ae6804d # Review: required -# Source-Hash: 81d365ccef73068c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap Height" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.mounting" -msgstr "Montaje" +msgid "node.boxVent.panel.gapHeight" +msgstr "Altura de la holgura" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: f2953d2931e36d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.none" -msgstr "Ninguno" +msgid "node.boxVent.panel.height" +msgstr "Altura" +# Source-Hash: 8a9c2ea0783a0e53 # Review: required -# Source-Hash: 3e52f04f92e08070 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hood Overhang" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.open" -msgstr "Abrir" +msgid "node.boxVent.panel.hoodOverhang" +msgstr "Vuelo de la caperuza" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: b8ecc16c07d66f42 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open Animation" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.openAnimation" -msgstr "Animación de apertura" +msgid "node.boxVent.panel.move" +msgstr "Mover" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: 2d4adbbd70c3ae6a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.openCabinet" -msgstr "Abrir mueble" +msgid "node.boxVent.panel.position" +msgstr "Posición" +# Source-Hash: 01989595ee7c1dc0 # Review: required -# Source-Hash: 9c215dc512e57fa4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overlay" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.overlay" -msgstr "Superpuesta" +msgid "node.boxVent.panel.rotation" +msgstr "Rotación" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: a35b7357943a5cae -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel-ready" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.panelReady" -msgstr "Panelable" +msgid "node.boxVent.panel.style" +msgstr "Estilo" +# Source-Hash: 71d82d47e11d2564 # Review: required -# Source-Hash: 3d0d4eee59177824 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Planning checks" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Taper" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.planningChecks" -msgstr "Comprobaciones de diseño" +msgid "node.boxVent.panel.topTaper" +msgstr "Estrechamiento superior" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: c7b10382e01914ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Play" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.play" -msgstr "Reproducir" +msgid "node.boxVent.panel.width" +msgstr "Ancho" +# Source-Hash: f49d8836ae037dde # Review: required -# Source-Hash: c530f8af9dfd846f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Play animation" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A building container holding one or more levels." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.panel.playAnimation" -msgstr "Reproducir animación" +msgid "node.building.description" +msgstr "Contenedor de edificio con una o varias plantas." +# Source-Hash: d42f7d29e3fc4af7 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Building" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.panel.position" -msgstr "Posición" +msgid "node.building.label" +msgstr "Edificio" +# Source-Hash: 5a8274cbe3034558 # Review: required -# Source-Hash: efca749fc4463623 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised Arch" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Baskets" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.raisedArch" -msgstr "Arco en relieve" +msgid "node.cabinet.compartmentCard.baskets" +msgstr "Cestas" +# Source-Hash: b3a163b453896bef # Review: required -# Source-Hash: a8639a97ab07cd59 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove wall cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.removeWallCabinet" -msgstr "Quitar mueble alto" +msgid "node.cabinet.compartmentCard.bottom" +msgstr "Inferior" +# Source-Hash: 486501f027037732 # Review: required -# Source-Hash: 03cb6dea6e4a4c5e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace with…" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Freezer" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.replaceWith" -msgstr "Reemplazar por…" +msgid "node.cabinet.compartmentCard.bottomFreezer" +msgstr "Congelador inferior" +# Source-Hash: 375acc0016b3aa14 # Review: required -# Source-Hash: 5d6956c21fde6418 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reveal gap" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bowls" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.revealGap" -msgstr "Holgura entre frentes" +msgid "node.cabinet.compartmentCard.bowls" +msgstr "Senos" +# Source-Hash: 8449b59bf054c27d # Review: required -# Source-Hash: 5b68e435b7210876 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaker" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Burners on" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.shaker" -msgstr "Shaker" +msgid "node.cabinet.compartmentCard.burnersOn" +msgstr "Fuegos encendidos" +# Source-Hash: 95169058fec6db14 # Review: required -# Source-Hash: c378ed346bf83375 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shared countertop, plinth, and finishes" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Chimney" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.sharedCountertopPlinthAndFinishes" -msgstr "Encimera, zócalo y acabados compartidos" +msgid "node.cabinet.compartmentCard.chimney" +msgstr "Chimenea" +# Source-Hash: a6b76187db231ae7 # Review: required -# Source-Hash: 8775bc8dc9593964 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Decrease {label}" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.slab" -msgstr "Forjado" +msgid "node.cabinet.compartmentCard.decrease" +msgstr "Reducir {label}" +# Source-Hash: 787e10f5db16904e # Review: required -# Source-Hash: 8606fe2c60764a95 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid matching front between the cabinet and wall. Countertop and toe-kick continue across this filler." -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.solidMatchingFrontBetweenTheCabinet" -msgstr "Frente macizo a juego entre el mueble y la pared. La encimera y el zócalo continúan sobre este relleno." +msgid "node.cabinet.compartmentCard.door" +msgstr "Puerta" +# Source-Hash: 3cd71355956a1821 # Review: required -# Source-Hash: 5a4d5353cc496a63 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard width" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.standardWidth" -msgstr "Ancho estándar" +msgid "node.cabinet.compartmentCard.double" +msgstr "Doble" +# Source-Hash: 63fe49d73892aac8 # Review: required -# Source-Hash: 4a784e3e95a08715 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stop" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawer" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.stop" -msgstr "Detener" +msgid "node.cabinet.compartmentCard.drawer" +msgstr "Cajón" +# Source-Hash: f98242a5dacd33f3 # Review: required -# Source-Hash: 72c9fcd7a0eb5380 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stop animation" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawers" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.stopAnimation" -msgstr "Detener animación" +msgid "node.cabinet.compartmentCard.drawers" +msgstr "Cajones" +# Source-Hash: 3af5347c94ae6443 # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip hinge" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.style" -msgstr "Estilo" +msgid "node.cabinet.compartmentCard.flipHinge" +msgstr "Invertir bisagra" +# Source-Hash: c930f681e61c029c # Review: required -# Source-Hash: bfd618690e0c2f24 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tall Cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip the door hinge to the opposite side" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.tallCabinet" -msgstr "Columna" +msgid "node.cabinet.compartmentCard.flipTheDoorHingeToThe" +msgstr "Pasar la bisagra de la puerta al lado opuesto" +# Source-Hash: 85724031c91952a3 # Review: required -# Source-Hash: 27644f0497fd9849 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fridge" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.top" -msgstr "Superior" +msgid "node.cabinet.compartmentCard.fridge" +msgstr "Frigorífico" +# Source-Hash: e67f11024d683ea9 # Review: required -# Source-Hash: d09654ebd12a538a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gas" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.topCabinet" -msgstr "Mueble superior" +msgid "node.cabinet.compartmentCard.gas" +msgstr "Gas" +# Source-Hash: 8ab91094cf650204 # Review: required -# Source-Hash: bc19e7805b3e3703 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top / Ceiling" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.topCeiling" -msgstr "Superior / Techo" +msgid "node.cabinet.compartmentCard.glass" +msgstr "Vidrio" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 29ea8a68eed99925 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top depth" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.topDepth" -msgstr "Fondo superior" +msgid "node.cabinet.compartmentCard.height" +msgstr "Altura" +# Source-Hash: 6f434b84c8b59b8c # Review: required -# Source-Hash: 2d40f591e7dcbf5a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top height" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hob" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.topHeight" -msgstr "Altura superior" +msgid "node.cabinet.compartmentCard.hob" +msgstr "Placa" +# Source-Hash: d52570d41b4df776 # Review: required -# Source-Hash: 3b878d6015c03945 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trim / Soffit" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Increase {label}" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.trimSoffit" -msgstr "Remate / Plafón" +msgid "node.cabinet.compartmentCard.increase" +msgstr "Aumentar {label}" +# Source-Hash: d298f259163e868e # Review: required -# Source-Hash: a6e5be20001e8d26 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Uses the cabinet front style, reveal, handle, and front material settings below." -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Induction" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.usesTheCabinetFrontStyleReveal" -msgstr "Usa el estilo de frente, la holgura, el tirador y el material de frente definidos abajo." +msgid "node.cabinet.compartmentCard.induction" +msgstr "Inducción" +# Source-Hash: 54800340a0eeab23 # Review: required -# Source-Hash: cd55643590c64a42 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall filler" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layout" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.wallFiller" -msgstr "Relleno de pared" +msgid "node.cabinet.compartmentCard.layout" +msgstr "Distribución" +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.width" -msgstr "Ancho" +msgid "node.cabinet.compartmentCard.left" +msgstr "Izquierda" +# Source-Hash: 12ade82be3830a0b # Review: required -# Source-Hash: 4ef03cfd6782316b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base cabinet" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Micro" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.preset.baseCabinet" -msgstr "Mueble bajo" +msgid "node.cabinet.compartmentCard.micro" +msgstr "Microondas" +# Source-Hash: a06a50e63f0c240e # Review: required -# Source-Hash: d353fff221a78228 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dishwasher" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move down" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.preset.dishwasher" -msgstr "Lavavajillas" +msgid "node.cabinet.compartmentCard.moveDown" +msgstr "Bajar" +# Source-Hash: d49ea60a2312df2f # Review: required -# Source-Hash: ecb596567b8b7179 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawer cabinet" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move up" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.preset.drawerCabinet" -msgstr "Mueble de cajones" +msgid "node.cabinet.compartmentCard.moveUp" +msgstr "Subir" +# Source-Hash: 596023c8b9a8f2e4 # Review: required -# Source-Hash: 85724031c91952a3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fridge" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Oven" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.preset.fridge" -msgstr "Frigorífico" +msgid "node.cabinet.compartmentCard.oven" +msgstr "Horno" +# Source-Hash: 83b20797fb0a01a0 # Review: required -# Source-Hash: 72d587d58b645a81 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gas cooktop" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pullout" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.preset.gasCooktop" -msgstr "Placa de gas" +msgid "node.cabinet.compartmentCard.pullout" +msgstr "Extraíble" +# Source-Hash: 43c251f465b647ce # Review: required -# Source-Hash: 6b02c36e6aac2cd6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Induction cooktop" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rack" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.preset.inductionCooktop" -msgstr "Placa de inducción" +msgid "node.cabinet.compartmentCard.rack" +msgstr "Estante" +# Source-Hash: 3c2b3026d37cbcc2 # Review: required -# Source-Hash: d5fcb790aef707bf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Oven Tower" -#: packages/nodes/src/cabinet/kitchen-catalog.ts -#, fuzzy -msgid "node.cabinet.preset.ovenTower" -msgstr "Columna de horno" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove compartment" +#: packages/nodes/src/cabinet/compartment-card.tsx +#, fuzzy +msgid "node.cabinet.compartmentCard.removeCompartment" +msgstr "Quitar compartimento" +# Source-Hash: b34d5ee0f218221d # Review: required -# Source-Hash: edd4d1ab7525dcaa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sink cabinet" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.preset.sinkCabinet" -msgstr "Mueble de fregadero" +msgid "node.cabinet.compartmentCard.right" +msgstr "Derecha" +# Source-Hash: d7145f84f8e0e3fe # Review: required -# Source-Hash: 9b7427a8954f618b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tall Pantry" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shelf" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.preset.tallPantry" -msgstr "Despensero alto" +msgid "node.cabinet.compartmentCard.shelf" +msgstr "Estantería" +# Source-Hash: 5fbb88f1f079b6db # Review: required -# Source-Hash: 3bd9629eb17cc572 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall cabinet" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shelves" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.preset.wallCabinet" -msgstr "Mueble alto" +msgid "node.cabinet.compartmentCard.shelves" +msgstr "Baldas" +# Source-Hash: 47173085127029f0 # Review: required -# Source-Hash: 7c40d26770eede82 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add left" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shelves inside" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.addLeft" -msgstr "Añadir a la izquierda" +msgid "node.cabinet.compartmentCard.shelvesInside" +msgstr "Baldas interiores" +# Source-Hash: 62ab2eb3c775da95 # Review: required -# Source-Hash: 25082cdf77e219c3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add right" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.addRight" -msgstr "Añadir a la derecha" +msgid "node.cabinet.compartmentCard.single" +msgstr "Simple" +# Source-Hash: 522a7535fc93fb4f # Review: required -# Source-Hash: 4b1204c1b706f618 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Align cabinets & handles" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sink" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.alignCabinetsHandles" -msgstr "Alinear muebles y tiradores" +msgid "node.cabinet.compartmentCard.sink" +msgstr "Fregadero" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: 8c73c7a9406db5ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Applies depth, carcass, plinth, and countertop thickness to this run." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.appliesDepthCarcassPlinthAndCountertop" -msgstr "Aplica a este tramo el fondo, el casco, el zócalo y el grosor de la encimera." +msgid "node.cabinet.compartmentCard.style" +msgstr "Estilo" +# Source-Hash: 78a454b7ac7a3cd9 # Review: required -# Source-Hash: ef576e6c8f9ebe5f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {Create {number} module copy} other {Create {number} module copies}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.arrayCreate" -msgstr "{count, plural, one {Crear {number} copia del módulo} many {Crear {number} copias del módulo} other {Crear {number} copias del módulo}}" +msgid "node.cabinet.compartmentCard.surface" +msgstr "Superficie" +# Source-Hash: 27644f0497fd9849 # Review: required -# Source-Hash: 0eec3888096306a1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {Create {number} {name} copy} other {Create {number} {name} copies}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.arrayCreateNamed" -msgstr "{count, plural, one {Crear {number} copia de {name}} many {Crear {number} copias de {name}} other {Crear {number} copias de {name}}}" +msgid "node.cabinet.compartmentCard.top" +msgstr "Superior" +# Source-Hash: eaadfd2d19b27d87 # Review: required -# Source-Hash: 8cdc0b808b551d3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a copy count from 1 to 20 and spacing from 0 to 2 m" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Freezer" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.arrayInvalidOptions" -msgstr "Elige un número de copias de 1 a 20 y una separación de 0 a 2 m" +msgid "node.cabinet.compartmentCard.topFreezer" +msgstr "Congelador superior" +# Source-Hash: 04f3a3462ef5d247 # Review: required -# Source-Hash: cb89fe4161e87d68 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "There is not enough room in this run for the requested array" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top grate" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.arrayNoRoom" -msgstr "No hay espacio suficiente en este tramo para la serie solicitada" +msgid "node.cabinet.compartmentCard.topGrate" +msgstr "Parrilla superior" +# Source-Hash: 4a616e1d2ca55bd5 # Review: required -# Source-Hash: 075d027345689724 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a standard or appliance module as the source" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tray" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.arrayNoSource" -msgstr "Elige un módulo estándar o de electrodoméstico como origen" +msgid "node.cabinet.compartmentCard.tray" +msgstr "Bandeja" +# Source-Hash: c44f7ab8bbd24858 # Review: required -# Source-Hash: 05b65242d8c48791 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.auto" -msgstr "Auto" +msgid "node.cabinet.compartmentCard.type" +msgstr "Tipo" +# Source-Hash: 6c4de540d19316ab # Review: required -# Source-Hash: 7ceade8f25b58fe9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Washer" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.back" -msgstr "Volver" +msgid "node.cabinet.compartmentCard.washer" +msgstr "Lavavajillas" +# Source-Hash: 5211a0caf3518125 # Review: required -# Source-Hash: b2c3a03bf67a97a7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Balances standard base cabinets while keeping appliance and corner-filler widths fixed." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wire" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.balancesStandardBaseCabinetsWhileKeeping" -msgstr "Equilibra los muebles bajos estándar manteniendo fijos los anchos de electrodomésticos y rellenos de esquina." +msgid "node.cabinet.compartmentCard.wire" +msgstr "Alambre" +# Source-Hash: 693a0d8896f5cc43 # Review: required -# Source-Hash: 9cf3754f15467c50 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A configurable parametric base cabinet." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.runPanel.bar" -msgstr "Barra" +msgid "node.cabinet.description" +msgstr "Mueble bajo paramétrico configurable." +# Source-Hash: b0568ea943addd5b # Review: required -# Source-Hash: ccec5da17ca39eee -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar counter" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom freezer" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.barCounter" -msgstr "Barra de bar" +msgid "node.cabinet.essentialControls.bottomFreezer" +msgstr "Congelador inferior" +# Source-Hash: da78819903ae0863 # Review: required -# Source-Hash: 97c1605fff221752 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar depth" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cooktop type" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.barDepth" -msgstr "Fondo de la barra" +msgid "node.cabinet.essentialControls.cooktopType" +msgstr "Tipo de placa" +# Source-Hash: c608188f58ed1cfc # Review: required -# Source-Hash: 9514a6ddebdca34e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar height" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door direction" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.barHeight" -msgstr "Altura de la barra" +msgid "node.cabinet.essentialControls.doorDirection" +msgstr "Sentido de apertura" +# Source-Hash: 3cd71355956a1821 # Review: required -# Source-Hash: 7af3b69b4b5aeb19 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Carcass height" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.carcassHeight" -msgstr "Altura del casco" +msgid "node.cabinet.essentialControls.double" +msgstr "Doble" +# Source-Hash: f7fb8f6393cc4cfc # Review: required -# Source-Hash: 5211341ed18f33f6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fridge type" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.center" -msgstr "Centro" +msgid "node.cabinet.essentialControls.fridgeType" +msgstr "Tipo de frigorífico" +# Source-Hash: e67f11024d683ea9 # Review: required -# Source-Hash: b1ab1ba948bb77b0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Common wall-cabinet heights. Use the slider below for a custom height." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gas" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.commonWallCabinetHeightsUseThe" -msgstr "Alturas habituales de muebles altos. Usa el control deslizante de abajo para una altura personalizada." +msgid "node.cabinet.essentialControls.gas" +msgstr "Gas" +# Source-Hash: 8ab91094cf650204 # Review: required -# Source-Hash: 88ccc87b9b45a464 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Copies" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.copies" -msgstr "Copias" +msgid "node.cabinet.essentialControls.glass" +msgstr "Vidrio" +# Source-Hash: d298f259163e868e # Review: required -# Source-Hash: d215c489b8385d9f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Copies include the source cabinet structure and any attached wall cabinet. Existing modules stay fixed; the requested array must fit in the available run space." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Induction" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.copiesIncludeTheSourceCabinetStructure" -msgstr "Las copias incluyen la estructura del mueble de origen y cualquier mueble alto unido. Los módulos existentes no se mueven; la serie solicitada debe caber en el espacio disponible del tramo." +msgid "node.cabinet.essentialControls.induction" +msgstr "Inducción" +# Source-Hash: 76df477d42cec629 # Review: required -# Source-Hash: 221d1b64649b08f8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner fillers cannot be used as array sources" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Item options" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.cornerFillersCannotBeUsedAs" -msgstr "Los rellenos de esquina no pueden ser origen de una serie" +msgid "node.cabinet.essentialControls.itemOptions" +msgstr "Opciones del elemento" +# Source-Hash: bca1b184af1c0c4b # Review: required -# Source-Hash: d8d1bc5a0f9fa0cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Countertop depth" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left hinge" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.countertopDepth" -msgstr "Fondo de la encimera" +msgid "node.cabinet.essentialControls.leftHinge" +msgstr "Bisagra izquierda" +# Source-Hash: e32da7429c85f1a5 # Review: required -# Source-Hash: 10bba4a11996c84b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Countertop height" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right hinge" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.countertopHeight" -msgstr "Altura de la encimera" +msgid "node.cabinet.essentialControls.rightHinge" +msgstr "Bisagra derecha" +# Source-Hash: 62ab2eb3c775da95 # Review: required -# Source-Hash: 8abdfbc1798d9eaa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Create array" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.createArray" -msgstr "Crear serie" +msgid "node.cabinet.essentialControls.single" +msgstr "Simple" +# Source-Hash: 4bc3042055df1e85 # Review: required -# Source-Hash: 7984b1c42abd9c02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cutout" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sink layout" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.cutout" -msgstr "Recorte" +msgid "node.cabinet.essentialControls.sinkLayout" +msgstr "Distribución del fregadero" +# Source-Hash: 29cffe75281dbea6 # Review: required -# Source-Hash: 555240ffcca44233 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete {name}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top freezer" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.deleteModule" -msgstr "Eliminar {name}" +msgid "node.cabinet.essentialControls.topFreezer" +msgstr "Congelador superior" +# Source-Hash: 09c2cb2ea7b1be3c # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose {label}" +#: packages/nodes/src/cabinet/kitchen-collection.tsx #, fuzzy -msgid "node.cabinet.runPanel.depth" -msgstr "Profundidad" +msgid "node.cabinet.kitchenCollection.chooseLabel" +msgstr "Elegir {label}" +# Source-Hash: 1dd2cac6488ddc30 # Review: required -# Source-Hash: 76cd03300faa9b2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Direction" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No kitchen items match. Try “fridge”, “sink”, or “cabinet”." +#: packages/nodes/src/cabinet/kitchen-collection.tsx #, fuzzy -msgid "node.cabinet.runPanel.direction" -msgstr "Dirección" +msgid "node.cabinet.kitchenCollection.noKitchenItemsMatchTryFridge" +msgstr "Ningún elemento de cocina coincide. Prueba «frigorífico», «fregadero» o «mueble»." +# Source-Hash: 6752675ca6280ddd # Review: required -# Source-Hash: 5ca5884d3ff7edf4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate along run" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Search fridge, sink, cabinets…" +#: packages/nodes/src/cabinet/kitchen-collection.tsx #, fuzzy -msgid "node.cabinet.runPanel.duplicateAlongRun" -msgstr "Duplicar a lo largo del tramo" +msgid "node.cabinet.kitchenCollection.searchFridgeSinkCabinets" +msgstr "Buscar frigorífico, fregadero, muebles…" +# Source-Hash: fe3c6d57a07c323d # Review: required -# Source-Hash: a834f687290afc10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equalize all resizeable standard base cabinets in this run" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Search kitchen items" +#: packages/nodes/src/cabinet/kitchen-collection.tsx #, fuzzy -msgid "node.cabinet.runPanel.equalizeAll" -msgstr "Igualar todos los muebles bajos estándar redimensionables de este tramo" +msgid "node.cabinet.kitchenCollection.searchKitchenItems" +msgstr "Buscar elementos de cocina" +# Source-Hash: d44a46146db2e44c # Review: required -# Source-Hash: 24da8a2de2c6e345 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The resizeable cabinet widths are already equal" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Appliances & fixtures" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.runPanel.equalizeAlreadyEqual" -msgstr "Los anchos de los muebles redimensionables ya son iguales" +msgid "node.cabinet.kitchenGroup.appliances" +msgstr "Electrodomésticos y equipamiento" +# Source-Hash: d4d3ad7c099b6513 # Review: required -# Source-Hash: c38a4faef2097b73 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "At least two standard base cabinets are required" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinets" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.runPanel.equalizeNeedsTwo" -msgstr "Se necesitan al menos dos muebles bajos estándar" +msgid "node.cabinet.kitchenGroup.cabinets" +msgstr "Muebles" +# Source-Hash: 465db52f98c2d94f # Review: required -# Source-Hash: 61f15ae24419430c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The available run width cannot satisfy the cabinet width limits" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add beside" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.equalizeNoFit" -msgstr "El ancho disponible del tramo no cumple los límites de ancho de los muebles" +msgid "node.cabinet.kitchenModuleActions.addBeside" +msgstr "Añadir al lado" +# Source-Hash: 9733e2ad85deb6d5 # Review: required -# Source-Hash: 7617bb3b455dcdda -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equalize widths" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add beside selected item" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.equalizeWidths" -msgstr "Igualar anchos" +msgid "node.cabinet.kitchenModuleActions.addBesideSelectedItem" +msgstr "Añadir junto al elemento seleccionado" +# Source-Hash: 4b2f676fb4c9ec63 # Review: required -# Source-Hash: ad8c948d883a0c9d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{side, select, left {Left: {width} mm} other {Right: {width} mm}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add {label}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.fillerPlanSide" -msgstr "{side, select, left {Izquierda: {width} mm} other {Derecha: {width} mm}}" +msgid "node.cabinet.kitchenModuleActions.addLabel" +msgstr "Añadir {label}" +# Source-Hash: 5122b8e9b4ec6a00 # Review: required -# Source-Hash: 47ccd8c8b04475cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish & align" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An upper cabinet attached to this item will be removed to make room." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.finishAlign" -msgstr "Acabado y alineación" +msgid "node.cabinet.kitchenModuleActions.anUpperCabinetAttachedToThis" +msgstr "Se quitará un mueble alto unido a este elemento para dejar espacio." +# Source-Hash: 5737c4567e0f6863 # Review: required -# Source-Hash: 855892e18c74153a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finished back" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.finishedBack" -msgstr "Trasera acabada" +msgid "node.cabinet.kitchenModuleActions.cabinet" +msgstr "Mueble" +# Source-Hash: c0774c185060fc13 # Review: required -# Source-Hash: 7ab47aea30c73663 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finished exposed ends" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.finishedExposedEnds" -msgstr "Laterales vistos acabados" +msgid "node.cabinet.kitchenModuleActions.cancel" +msgstr "Cancelar" +# Source-Hash: f42912b116015f58 # Review: required -# Source-Hash: c9356f25caf33eec -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fits 50–150 mm gaps at run ends beside perpendicular walls." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This {width} item cannot fit within the current run and its wall or corner limits. Move an end cabinet or free space, then try again." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.fits50150MmGapsAt" -msgstr "Cubre huecos de 50–150 mm en los extremos del tramo junto a paredes perpendiculares." +msgid "node.cabinet.kitchenModuleActions.cannotFit" +msgstr "Este elemento de {width} no cabe en el tramo actual ni en sus límites de pared o esquina. Mueve un mueble del extremo o libera espacio y vuelve a intentarlo." +# Source-Hash: b7eeb26a356d03c3 # Review: required -# Source-Hash: b6f541bc28e38d2f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fit wall fillers" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{side, select, left {Inserts on the left of the selected item.} other {Inserts on the right of the selected item.}}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.fitWallFillers" -msgstr "Ajustar rellenos de pared" +msgid "node.cabinet.kitchenModuleActions.insertsBeside" +msgstr "{side, select, left {Se inserta a la izquierda del elemento seleccionado.} other {Se inserta a la derecha del elemento seleccionado.}}" +# Source-Hash: f65332177316d11d # Review: required -# Source-Hash: 2af738f010ce28f0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fronts" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The kitchen changed. Select an item again to refresh the preview." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.fronts" -msgstr "Frentes" +msgid "node.cabinet.kitchenModuleActions.kitchenChanged" +msgstr "La cocina ha cambiado. Vuelve a seleccionar un elemento para actualizar la vista previa." +# Source-Hash: 5b6990b17111fd6b # Review: required -# Source-Hash: 58884f99d64e6d00 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handles" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchen run preview, highlighted item is the proposed change" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.handles" -msgstr "Tiradores" +msgid "node.cabinet.kitchenModuleActions.kitchenRunPreviewHighlightedItemIs" +msgstr "Vista previa del tramo de cocina; el elemento resaltado es el cambio propuesto" +# Source-Hash: cb59562ba7eb1d25 # Review: required -# Source-Hash: d73589d7c04b1121 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height preset" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left side" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.heightPreset" -msgstr "Altura predefinida" +msgid "node.cabinet.kitchenModuleActions.leftSide" +msgstr "Lado izquierdo" +# Source-Hash: 766354d53f17d78c # Review: required -# Source-Hash: 590bfdd02dcdb857 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hole" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{name}: moves {distance}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.hole" -msgstr "Orificio" +msgid "node.cabinet.kitchenModuleActions.moved" +msgstr "{name}: se mueve {distance}" +# Source-Hash: df1083d9ffc2c59d # Review: required -# Source-Hash: 3db1dea825785a30 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inset" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{name}: {width}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.inset" -msgstr "Empotrado" +msgid "node.cabinet.kitchenModuleActions.previewItem" +msgstr "{name}: {width}" +# Source-Hash: ada7fbece9ca9e3c # Review: required -# Source-Hash: 2997c230c529590d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Island & Bar" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace selected item" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.islandBar" -msgstr "Isla y barra" +msgid "node.cabinet.kitchenModuleActions.replaceSelectedItem" +msgstr "Reemplazar el elemento seleccionado" +# Source-Hash: ab8b52d2704537d2 # Review: required -# Source-Hash: a74f10dadc92c8bb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchen run" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replaces only the selected item." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.kitchenRun" -msgstr "Tramo de cocina" +msgid "node.cabinet.kitchenModuleActions.replacesOnlyTheSelectedItem" +msgstr "Solo reemplaza el elemento seleccionado." +# Source-Hash: 03cb6dea6e4a4c5e # Review: required -# Source-Hash: 103e15b39c909210 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Knob" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace with…" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.knob" -msgstr "Pomo" +msgid "node.cabinet.kitchenModuleActions.replaceWith" +msgstr "Reemplazar por…" +# Source-Hash: 948fe657641f298c # Review: required -# Source-Hash: f365c6b6dd9ebab9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace with {label}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.left" -msgstr "Izquierda" +msgid "node.cabinet.kitchenModuleActions.replaceWithLabel" +msgstr "Reemplazar por {label}" +# Source-Hash: 154f9fa86b7670ba # Review: required -# Source-Hash: 3c88a1840043e15a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match base heights, backs, reveals and handles. Align upper cabinets; preserve tall appliances and custom compartments." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{name}: {before} → {after}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.matchBaseHeightsBacksRevealsAnd" -msgstr "Iguala alturas de muebles bajos, traseras, holguras y tiradores. Alinea los muebles altos; conserva los electrodomésticos altos y los compartimentos personalizados." +msgid "node.cabinet.kitchenModuleActions.resized" +msgstr "{name}: {before} → {after}" +# Source-Hash: 4ecc493400fb6aa2 # Review: required -# Source-Hash: b112e31fe44cc94b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Metric · 600 mm" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right side" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.metricProfile" -msgstr "Métrico · 600 mm" +msgid "node.cabinet.kitchenModuleActions.rightSide" +msgstr "Lado derecho" +# Source-Hash: f2c30e7e21cf27e6 # Review: required -# Source-Hash: 4739f6315c5e8680 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Module {number}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unable to update this kitchen." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.moduleNumber" -msgstr "Módulo {number}" +msgid "node.cabinet.kitchenModuleActions.unableToUpdateThisKitchen" +msgstr "No se puede actualizar esta cocina." +# Source-Hash: 2e6d8cda361c648d # Review: required -# Source-Hash: b8801184e07e4815 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Modules" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modular Cabinet" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.runPanel.modules" -msgstr "Módulos" +msgid "node.cabinet.label" +msgstr "Mueble modular" +# Source-Hash: 740e0a4e4afa78ea # Review: required -# Source-Hash: 81d365ccef73068c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finished height extends {overflow} mm above the ceiling." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.mounting" -msgstr "Montaje" +msgid "node.cabinet.panel.aboveCeiling" +msgstr "La altura acabada sobrepasa el techo en {overflow} mm." +# Source-Hash: e3b4d2ed4f6f5efb # Review: required -# Source-Hash: a3914bd96488175c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No eligible module" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add chimney" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.noEligibleModule" -msgstr "Ningún módulo válido" +msgid "node.cabinet.panel.addChimney" +msgstr "Añadir campana" +# Source-Hash: 90bdc92c0a91d060 # Review: required -# Source-Hash: f2953d2931e36d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add compartment" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.none" -msgstr "Ninguno" +msgid "node.cabinet.panel.addCompartment" +msgstr "Añadir compartimento" +# Source-Hash: ece05d9b6f4b616d # Review: required -# Source-Hash: 9c215dc512e57fa4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overlay" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add wall cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.overlay" -msgstr "Superpuesta" +msgid "node.cabinet.panel.addWallCabinet" +msgstr "Añadir mueble alto" +# Source-Hash: f571cb2d06ae01ae # Review: required -# Source-Hash: 49fb05dfafd6001d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Plinth height" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Advanced" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.plinthHeight" -msgstr "Altura del zócalo" +msgid "node.cabinet.panel.advanced" +msgstr "Avanzado" +# Source-Hash: 7f4dcb90defe1ac2 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Appliance" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.position" -msgstr "Posición" +msgid "node.cabinet.panel.appliance" +msgstr "Electrodoméstico" +# Source-Hash: bd5e3f533412ff6a # Review: required -# Source-Hash: efca749fc4463623 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised Arch" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Appliance front" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.raisedArch" -msgstr "Arco en relieve" +msgid "node.cabinet.panel.applianceFront" +msgstr "Frente de electrodoméstico" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: 5d6956c21fde6418 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reveal gap" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.revealGap" -msgstr "Holgura entre frentes" +msgid "node.cabinet.panel.auto" +msgstr "Auto" +# Source-Hash: 9cf3754f15467c50 # Review: required -# Source-Hash: b34d5ee0f218221d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.right" -msgstr "Derecha" +msgid "node.cabinet.panel.bar" +msgstr "Barra" +# Source-Hash: 133893b177bd05d6 # Review: required -# Source-Hash: e022da49ae8b4aef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Seating overhang" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base Cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.seatingOverhang" -msgstr "Voladizo para asientos" +msgid "node.cabinet.panel.baseCabinet" +msgstr "Mueble bajo" +# Source-Hash: d63f16df2c754126 # Review: required -# Source-Hash: 5b68e435b7210876 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaker" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet construction, compartments, and opening preview." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.shaker" -msgstr "Shaker" +msgid "node.cabinet.panel.cabinetConstructionCompartmentsAndOpeningPreview" +msgstr "Construcción del mueble, compartimentos y vista previa de apertura." +# Source-Hash: d62dc35dac835228 # Review: required -# Source-Hash: cba29b18ce666b0a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shared Plinth & Countertop" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet panel" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.sharedPlinthCountertop" -msgstr "Zócalo y encimera compartidos" +msgid "node.cabinet.panel.cabinetPanel" +msgstr "Panel del mueble" +# Source-Hash: 81caf4809d58b5f5 # Review: required -# Source-Hash: f7d577c4064c16ff -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show countertop" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet Type" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.showCountertop" -msgstr "Mostrar encimera" +msgid "node.cabinet.panel.cabinetType" +msgstr "Tipo de mueble" +# Source-Hash: 5211341ed18f33f6 # Review: required -# Source-Hash: 5d98e04dfd2e0a83 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show plinth" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.showPlinth" -msgstr "Mostrar zócalo" +msgid "node.cabinet.panel.center" +msgstr "Centro" +# Source-Hash: d7cf5045c01b2eb9 # Review: required -# Source-Hash: 8775bc8dc9593964 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.slab" -msgstr "Forjado" +msgid "node.cabinet.panel.close" +msgstr "Cerrar" +# Source-Hash: cf29134333e47184 # Review: required -# Source-Hash: 5bdc0a959203c52e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Source module" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.sourceModule" -msgstr "Módulo de origen" +msgid "node.cabinet.panel.closeCabinet" +msgstr "Cerrar mueble" +# Source-Hash: b1ab1ba948bb77b0 # Review: required -# Source-Hash: e4698e83d02beb6c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spacing" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Common wall-cabinet heights. Use the slider below for a custom height." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.spacing" -msgstr "Separación" +msgid "node.cabinet.panel.commonWallCabinetHeightsUseThe" +msgstr "Alturas habituales de muebles altos. Usa el control deslizante de abajo para una altura personalizada." +# Source-Hash: fe9e63d5c5087386 # Review: required -# Source-Hash: 40e3105cbe68d163 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard dimensions" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Compartments" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.standardDimensions" -msgstr "Dimensiones estándar" +msgid "node.cabinet.panel.compartments" +msgstr "Compartimentos" +# Source-Hash: 7984b1c42abd9c02 # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cutout" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.style" -msgstr "Estilo" +msgid "node.cabinet.panel.cutout" +msgstr "Recorte" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: e9d7ad9851d476d9 +# Source-Hash: 99ac4d03c3061f3a # Review: required -# English: "{type, select, shelf {Shelf} drawer {Drawer} door {Door} oven {Oven} microwave {Microwave} dishwasher {Dishwasher} sink {Sink} cooktop_gas {Gas cooktop} cooktop_induction {Induction cooktop} pull_out_pantry {Pull-out pantry} fridge_single {Fridge} fridge_double {Double fridge} fridge_top_freezer {Top-freezer fridge} fridge_bottom_freezer {Bottom-freezer fridge} hood_pyramid {Pyramid hood} hood_curved_glass {Curved glass hood} other {{raw}}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.summaryCompartment" -msgstr "{type, select, shelf {Balda} drawer {Cajón} door {Puerta} oven {Horno} microwave {Microondas} dishwasher {Lavavajillas} sink {Fregadero} cooktop_gas {Placa de gas} cooktop_induction {Placa de inducción} pull_out_pantry {Despensero extraíble} fridge_single {Frigorífico} fridge_double {Frigorífico doble} fridge_top_freezer {Frigorífico con congelador superior} fridge_bottom_freezer {Frigorífico con congelador inferior} hood_pyramid {Campana piramidal} hood_curved_glass {Campana de vidrio curvo} other {{raw}}}" +msgid "node.cabinet.panel.depth" +msgstr "Profundidad" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: 98582c257f149d44 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {{number} compartment} other {{number} compartments}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.summaryCompartments" -msgstr "{count, plural, one {{number} compartimento} many {{number} compartimentos} other {{number} compartimentos}}" +msgid "node.cabinet.panel.dimensions" +msgstr "Dimensiones" +# Source-Hash: 82c9ea6f403fc934 # Review: required -# Source-Hash: 65b1cbba3b92c5b2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Empty" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit kitchen run" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.summaryEmpty" -msgstr "Vacío" +msgid "node.cabinet.panel.editKitchenRun" +msgstr "Editar tramo de cocina" +# Source-Hash: 7e9bbeb035fc73e2 # Review: required -# Source-Hash: 5db8b868684cf9f3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tall cabinet" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fill to ceiling" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.summaryTall" -msgstr "Columna" +msgid "node.cabinet.panel.fillToCeiling" +msgstr "Hasta el techo" +# Source-Hash: b3907da0ad234f10 # Review: required -# Source-Hash: 27644f0497fd9849 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.top" -msgstr "Superior" +msgid "node.cabinet.panel.finish" +msgstr "Terminar" +# Source-Hash: c1796152935221ef # Review: required -# Source-Hash: 88c85283afe0c0bc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unable to finish this kitchen run." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front construction" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.unableToFinish" -msgstr "No se puede terminar este tramo de cocina." +msgid "node.cabinet.panel.frontConstruction" +msgstr "Construcción del frente" +# Source-Hash: 58884f99d64e6d00 # Review: required -# Source-Hash: 8f668fb3e1a1696a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use {name} as array source" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handles" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.useAsArraySource" -msgstr "Usar {name} como origen de la serie" +msgid "node.cabinet.panel.handles" +msgstr "Tiradores" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 9308a109d017dcd6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use this module as the array source" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.useThisModuleAsTheArray" -msgstr "Usar este módulo como origen de la serie" +msgid "node.cabinet.panel.height" +msgstr "Altura" +# Source-Hash: d73589d7c04b1121 # Review: required -# Source-Hash: 1ce253a4d11bfa68 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "US · 24 in" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height preset" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.usProfile" -msgstr "EE. UU. · 24 in" +msgid "node.cabinet.panel.heightPreset" +msgstr "Altura predefinida" +# Source-Hash: 590bfdd02dcdb857 # Review: required -# Source-Hash: a2d852b2c5629796 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waterfall ends" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hole" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.waterfallEnds" -msgstr "Laterales en cascada" +msgid "node.cabinet.panel.hole" +msgstr "Orificio" -# Source-Hash: ffc8d80e438f40b7 +# Source-Hash: 3db1dea825785a30 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "An editable module inside a modular cabinet run." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inset" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinetModule.description" -msgstr "Módulo editable dentro de una línea de muebles modulares." +msgid "node.cabinet.panel.inset" +msgstr "Empotrado" -# Source-Hash: d5c19ec529e26a98 +# Source-Hash: 1176d2568d093bf1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet Module" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchen" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinetModule.label" -msgstr "Módulo de mueble" +msgid "node.cabinet.panel.kitchen" +msgstr "Cocina" -# Source-Hash: 4d6d5e9439f40e9b +# Source-Hash: a74f10dadc92c8bb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A polygon-bounded ceiling surface that hosts ceiling-mounted items." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchen run" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.description" -msgstr "Superficie de techo delimitada por un polígono que aloja elementos de techo." +msgid "node.cabinet.panel.kitchenRun" +msgstr "Tramo de cocina" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: 103e15b39c909210 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Knob" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.label" -msgstr "Techo" +msgid "node.cabinet.panel.knob" +msgstr "Pomo" -# Source-Hash: 659e6b799ad7c27d +# Source-Hash: 81d365ccef73068c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Hole" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.addHole" -msgstr "Añadir hueco" +msgid "node.cabinet.panel.mounting" +msgstr "Montaje" -# Source-Hash: 8332ab41e22958f1 +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Area" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.area" -msgstr "Área" +msgid "node.cabinet.panel.none" +msgstr "Ninguno" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.auto" -msgstr "Auto" +msgid "node.cabinet.panel.open" +msgstr "Abrir" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: b8ecc16c07d66f42 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open Animation" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.ceiling" -msgstr "Techo" +msgid "node.cabinet.panel.openAnimation" +msgstr "Animación de apertura" -# Source-Hash: b2a1b3bc9676fe05 +# Source-Hash: 2d4adbbd70c3ae6a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom height" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.customHeight" -msgstr "Altura personalizada" +msgid "node.cabinet.panel.openCabinet" +msgstr "Abrir mueble" -# Source-Hash: 4e4f1a24e4a9d61e +# Source-Hash: 9c215dc512e57fa4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut opening" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overlay" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.cutOpening" -msgstr "Abrir hueco" +msgid "node.cabinet.panel.overlay" +msgstr "Superpuesta" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: a35b7357943a5cae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel-ready" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.done" -msgstr "Hecho" +msgid "node.cabinet.panel.panelReady" +msgstr "Panelable" -# Source-Hash: a5c2353769b603d5 +# Source-Hash: 3d0d4eee59177824 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows level" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Planning checks" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.followsLevel" -msgstr "Sigue la planta" +msgid "node.cabinet.panel.planningChecks" +msgstr "Comprobaciones de diseño" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: c7b10382e01914ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Play" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.height" -msgstr "Altura" +msgid "node.cabinet.panel.play" +msgstr "Reproducir" -# Source-Hash: 703f56131ac45e60 +# Source-Hash: c530f8af9dfd846f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High (3.0m)" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Play animation" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.high30m" -msgstr "Alto (3,0 m)" +msgid "node.cabinet.panel.playAnimation" +msgstr "Reproducir animación" -# Source-Hash: 4ed40bdab397fe22 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High (9'0\")" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.high90" -msgstr "Alto (9'0\")" +msgid "node.cabinet.panel.position" +msgstr "Posición" -# Source-Hash: 34504c6ca6445e76 +# Source-Hash: efca749fc4463623 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Holes" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised Arch" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.holes" -msgstr "Huecos" +msgid "node.cabinet.panel.raisedArch" +msgstr "Arco en relieve" -# Source-Hash: 6e68b62d2aa611a4 +# Source-Hash: a8639a97ab07cd59 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Info" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove wall cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.info" -msgstr "Info" +msgid "node.cabinet.panel.removeWallCabinet" +msgstr "Quitar mueble alto" -# Source-Hash: 6925a008b1924062 +# Source-Hash: 03cb6dea6e4a4c5e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Limited by the level to {height} — raise the level height for a taller ceiling." -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace with…" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.limitedByLevel" -msgstr "Limitado por la planta a {height}: sube la altura de la planta para un techo más alto." +msgid "node.cabinet.panel.replaceWith" +msgstr "Reemplazar por…" -# Source-Hash: c7410ff087be3a61 +# Source-Hash: 5d6956c21fde6418 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low (2.4m)" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reveal gap" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.low24m" -msgstr "Bajo (2,4 m)" +msgid "node.cabinet.panel.revealGap" +msgstr "Holgura entre frentes" -# Source-Hash: a59425761b7c9084 +# Source-Hash: 5b68e435b7210876 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low (8'0\")" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaker" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.low80" -msgstr "Bajo (8'0\")" +msgid "node.cabinet.panel.shaker" +msgstr "Shaker" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: c378ed346bf83375 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shared countertop, plinth, and finishes" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.move" -msgstr "Mover" +msgid "node.cabinet.panel.sharedCountertopPlinthAndFinishes" +msgstr "Encimera, zócalo y acabados compartidos" -# Source-Hash: 1d2dafb0d8f26ed5 +# Source-Hash: 8775bc8dc9593964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No holes" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.noHoles" -msgstr "Sin huecos" +msgid "node.cabinet.panel.slab" +msgstr "Forjado" -# Source-Hash: 24f5fbd158798197 +# Source-Hash: 8606fe2c60764a95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard (2.5m)" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid matching front between the cabinet and wall. Countertop and toe-kick continue across this filler." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.standard25m" -msgstr "Estándar (2,5 m)" +msgid "node.cabinet.panel.solidMatchingFrontBetweenTheCabinet" +msgstr "Frente macizo a juego entre el mueble y la pared. La encimera y el zócalo continúan sobre este relleno." -# Source-Hash: 73cf00cf1900c22b +# Source-Hash: 5a4d5353cc496a63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard (8'6\")" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard width" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.standard86" -msgstr "Estándar (8'6\")" +msgid "node.cabinet.panel.standardWidth" +msgstr "Ancho estándar" -# Source-Hash: 065626498678bc5d +# Source-Hash: 4a784e3e95a08715 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Taller than this level ({available} available). Raise the level height first." -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stop" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.tallerThanLevel" -msgstr "Más alto que esta planta ({available} disponibles). Sube primero la altura de la planta." +msgid "node.cabinet.panel.stop" +msgstr "Detener" -# Source-Hash: ea12ce3c2b3588e7 +# Source-Hash: 72c9fcd7a0eb5380 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical masonry stack on a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stop animation" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.description" -msgstr "Chimenea vertical de obra sobre un faldón." +msgid "node.cabinet.panel.stopAnimation" +msgstr "Detener animación" -# Source-Hash: 95169058fec6db14 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Chimney" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.label" -msgstr "Chimenea" +msgid "node.cabinet.panel.style" +msgstr "Estilo" +# Source-Hash: bfd618690e0c2f24 # Review: required -# Source-Hash: dc393661f0038c2d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Above Ridge" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tall Cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.panel.aboveRidge" -msgstr "Sobre la cumbrera" +msgid "node.cabinet.panel.tallCabinet" +msgstr "Columna" +# Source-Hash: 27644f0497fd9849 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.panel.actions" -msgstr "Acciones" +msgid "node.cabinet.panel.top" +msgstr "Superior" +# Source-Hash: d09654ebd12a538a # Review: required -# Source-Hash: 7ceade8f25b58fe9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.panel.back" -msgstr "Volver" +msgid "node.cabinet.panel.topCabinet" +msgstr "Mueble superior" +# Source-Hash: bc19e7805b3e3703 # Review: required -# Source-Hash: 0d42509b34b05dec -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bands" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top / Ceiling" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.panel.bands" -msgstr "Bandas" +msgid "node.cabinet.panel.topCeiling" +msgstr "Superior / Techo" +# Source-Hash: 29ea8a68eed99925 # Review: required -# Source-Hash: d52b53241789ee63 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap" -#: packages/nodes/src/chimney/panel.tsx -#, fuzzy -msgid "node.chimney.panel.cap" -msgstr "Remate" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top depth" +#: packages/nodes/src/cabinet/panel.tsx +#, fuzzy +msgid "node.cabinet.panel.topDepth" +msgstr "Fondo superior" +# Source-Hash: 2d40f591e7dcbf5a # Review: required -# Source-Hash: 95169058fec6db14 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Chimney" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top height" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.panel.chimney" -msgstr "Chimenea" +msgid "node.cabinet.panel.topHeight" +msgstr "Altura superior" +# Source-Hash: 3b878d6015c03945 # Review: required -# Source-Hash: b619f366d2a1dfda -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Chimney Type" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trim / Soffit" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.panel.chimneyType" -msgstr "Tipo de chimenea" +msgid "node.cabinet.panel.trimSoffit" +msgstr "Remate / Plafón" +# Source-Hash: a6e5be20001e8d26 # Review: required -# Source-Hash: 6786ac75cbe9af57 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corbeled" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Uses the cabinet front style, reveal, handle, and front material settings below." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.panel.corbeled" -msgstr "Con ménsulas" +msgid "node.cabinet.panel.usesTheCabinetFrontStyleReveal" +msgstr "Usa el estilo de frente, la holgura, el tirador y el material de frente definidos abajo." +# Source-Hash: cd55643590c64a42 # Review: required -# Source-Hash: 89eba9f077fba348 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner Bevel" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall filler" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.panel.cornerBevel" -msgstr "Chaflán de esquina" +msgid "node.cabinet.panel.wallFiller" +msgstr "Relleno de pared" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: 8a4beb9a57edc26e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Count" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.panel.count" -msgstr "Cantidad" +msgid "node.cabinet.panel.width" +msgstr "Ancho" +# Source-Hash: 4ef03cfd6782316b # Review: required -# Source-Hash: f8ba7d73d3006d57 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base cabinet" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.cricket" -msgstr "Caballete desviador" +msgid "node.cabinet.preset.baseCabinet" +msgstr "Mueble bajo" +# Source-Hash: d353fff221a78228 # Review: required -# Source-Hash: 14144df9e1364eea -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cutout Offset" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dishwasher" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.cutoutOffset" -msgstr "Desfase del recorte" +msgid "node.cabinet.preset.dishwasher" +msgstr "Lavavajillas" +# Source-Hash: ecb596567b8b7179 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawer cabinet" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.delete" -msgstr "Eliminar" +msgid "node.cabinet.preset.drawerCabinet" +msgstr "Mueble de cajones" +# Source-Hash: 85724031c91952a3 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fridge" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.depth" -msgstr "Profundidad" +msgid "node.cabinet.preset.fridge" +msgstr "Frigorífico" +# Source-Hash: 72d587d58b645a81 # Review: required -# Source-Hash: 016d8e70618916d4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diameter" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gas cooktop" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.diameter" -msgstr "Diámetro" +msgid "node.cabinet.preset.gasCooktop" +msgstr "Placa de gas" +# Source-Hash: 6b02c36e6aac2cd6 # Review: required -# Source-Hash: 3cd71355956a1821 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Induction cooktop" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.double" -msgstr "Doble" +msgid "node.cabinet.preset.inductionCooktop" +msgstr "Placa de inducción" +# Source-Hash: d5fcb790aef707bf # Review: required -# Source-Hash: 150340cd05f4a6dd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Extent" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Oven Tower" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.extent" -msgstr "Extensión" +msgid "node.cabinet.preset.ovenTower" +msgstr "Columna de horno" +# Source-Hash: edd4d1ab7525dcaa # Review: required -# Source-Hash: 9cab4d4c95f63cdd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sink cabinet" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.flat" -msgstr "Plana" +msgid "node.cabinet.preset.sinkCabinet" +msgstr "Mueble de fregadero" +# Source-Hash: 9b7427a8954f618b # Review: required -# Source-Hash: f817c09ef0bb6d69 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flues" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tall Pantry" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.flues" -msgstr "Conductos" +msgid "node.cabinet.preset.tallPantry" +msgstr "Despensero alto" +# Source-Hash: 3bd9629eb17cc572 # Review: required -# Source-Hash: a3c10560fa3c1612 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Footprint" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall cabinet" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.footprint" -msgstr "Huella" +msgid "node.cabinet.preset.wallCabinet" +msgstr "Mueble alto" +# Source-Hash: 7c40d26770eede82 # Review: required -# Source-Hash: e360f89d3c0ec456 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add left" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.front" -msgstr "Frente" +msgid "node.cabinet.runPanel.addLeft" +msgstr "Añadir a la izquierda" +# Source-Hash: 25082cdf77e219c3 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add right" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.height" -msgstr "Altura" +msgid "node.cabinet.runPanel.addRight" +msgstr "Añadir a la derecha" +# Source-Hash: 4b1204c1b706f618 # Review: required -# Source-Hash: 5b490bc19dddf201 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hollow Depth" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Align cabinets & handles" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.hollowDepth" -msgstr "Profundidad del hueco" +msgid "node.cabinet.runPanel.alignCabinetsHandles" +msgstr "Alinear muebles y tiradores" +# Source-Hash: 8c73c7a9406db5ad # Review: required -# Source-Hash: 643687bc3adaac76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Applies depth, carcass, plinth, and countertop thickness to this run." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.length" -msgstr "Longitud" +msgid "node.cabinet.runPanel.appliesDepthCarcassPlinthAndCountertop" +msgstr "Aplica a este tramo el fondo, el casco, el zócalo y el grosor de la encimera." +# Source-Hash: ef576e6c8f9ebe5f # Review: required -# Source-Hash: f2953d2931e36d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {Create {number} module copy} other {Create {number} module copies}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.none" -msgstr "Ninguno" +msgid "node.cabinet.runPanel.arrayCreate" +msgstr "{count, plural, one {Crear {number} copia del módulo} many {Crear {number} copias del módulo} other {Crear {number} copias del módulo}}" +# Source-Hash: 0eec3888096306a1 # Review: required -# Source-Hash: 0f0e13abf9b2bb67 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Offset" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {Create {number} {name} copy} other {Create {number} {name} copies}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.offset" -msgstr "Desfase" +msgid "node.cabinet.runPanel.arrayCreateNamed" +msgstr "{count, plural, one {Crear {number} copia de {name}} many {Crear {number} copias de {name}} other {Crear {number} copias de {name}}}" +# Source-Hash: 8cdc0b808b551d3a # Review: required -# Source-Hash: 88540def2ce16ac5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overhang" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a copy count from 1 to 20 and spacing from 0 to 2 m" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.overhang" -msgstr "Vuelo" +msgid "node.cabinet.runPanel.arrayInvalidOptions" +msgstr "Elige un número de copias de 1 a 20 y una separación de 0 a 2 m" +# Source-Hash: cb89fe4161e87d68 # Review: required -# Source-Hash: 6ce059aee1386f72 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panels" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "There is not enough room in this run for the requested array" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.panels" -msgstr "Paneles" +msgid "node.cabinet.runPanel.arrayNoRoom" +msgstr "No hay espacio suficiente en este tramo para la serie solicitada" +# Source-Hash: 075d027345689724 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a standard or appliance module as the source" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.position" -msgstr "Posición" +msgid "node.cabinet.runPanel.arrayNoSource" +msgstr "Elige un módulo estándar o de electrodoméstico como origen" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: f29fef1beeb25f22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangular" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.rectangular" -msgstr "Rectangular" +msgid "node.cabinet.runPanel.auto" +msgstr "Auto" +# Source-Hash: 7ceade8f25b58fe9 # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.rotation" -msgstr "Rotación" +msgid "node.cabinet.runPanel.back" +msgstr "Volver" +# Source-Hash: b2c3a03bf67a97a7 # Review: required -# Source-Hash: ad0457800a1f0eb4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Balances standard base cabinets while keeping appliance and corner-filler widths fixed." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.round" -msgstr "Redondo" +msgid "node.cabinet.runPanel.balancesStandardBaseCabinetsWhileKeeping" +msgstr "Equilibra los muebles bajos estándar manteniendo fijos los anchos de electrodomésticos y rellenos de esquina." +# Source-Hash: 9cf3754f15467c50 # Review: required -# Source-Hash: 8c6e3985459dacf9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.shoulder" -msgstr "Hombro" +msgid "node.cabinet.runPanel.bar" +msgstr "Barra" +# Source-Hash: ccec5da17ca39eee # Review: required -# Source-Hash: 84b9195c73dd7a67 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Side Margin" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar counter" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.sideMargin" -msgstr "Margen lateral" +msgid "node.cabinet.runPanel.barCounter" +msgstr "Barra de bar" +# Source-Hash: 97c1605fff221752 # Review: required -# Source-Hash: a05a390ae205fdd8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Simple" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar depth" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.simple" -msgstr "Sencillo" +msgid "node.cabinet.runPanel.barDepth" +msgstr "Fondo de la barra" +# Source-Hash: 9514a6ddebdca34e # Review: required -# Source-Hash: 62ab2eb3c775da95 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar height" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.single" -msgstr "Simple" +msgid "node.cabinet.runPanel.barHeight" +msgstr "Altura de la barra" +# Source-Hash: 7af3b69b4b5aeb19 # Review: required -# Source-Hash: f6998707123fe72d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sloped" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Carcass height" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.sloped" -msgstr "Inclinado" +msgid "node.cabinet.runPanel.carcassHeight" +msgstr "Altura del casco" +# Source-Hash: 5211341ed18f33f6 # Review: required -# Source-Hash: e4698e83d02beb6c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spacing" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.spacing" -msgstr "Separación" +msgid "node.cabinet.runPanel.center" +msgstr "Centro" +# Source-Hash: b1ab1ba948bb77b0 # Review: required -# Source-Hash: 39287346366fc206 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Common wall-cabinet heights. Use the slider below for a custom height." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.square" -msgstr "Cuadrado" +msgid "node.cabinet.runPanel.commonWallCabinetHeightsUseThe" +msgstr "Alturas habituales de muebles altos. Usa el control deslizante de abajo para una altura personalizada." +# Source-Hash: 88ccc87b9b45a464 # Review: required -# Source-Hash: 2c6b1cf17a973d67 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stepped" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Copies" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.stepped" -msgstr "Escalonado" +msgid "node.cabinet.runPanel.copies" +msgstr "Copias" +# Source-Hash: d215c489b8385d9f # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Copies include the source cabinet structure and any attached wall cabinet. Existing modules stay fixed; the requested array must fit in the available run space." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.style" -msgstr "Estilo" +msgid "node.cabinet.runPanel.copiesIncludeTheSourceCabinetStructure" +msgstr "Las copias incluyen la estructura del mueble de origen y cualquier mueble alto unido. Los módulos existentes no se mueven; la serie solicitada debe caber en el espacio disponible del tramo." +# Source-Hash: 221d1b64649b08f8 # Review: required -# Source-Hash: f86f1f22230596b7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tapered" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner fillers cannot be used as array sources" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.tapered" -msgstr "Ahusado" +msgid "node.cabinet.runPanel.cornerFillersCannotBeUsedAs" +msgstr "Los rellenos de esquina no pueden ser origen de una serie" +# Source-Hash: d8d1bc5a0f9fa0cd # Review: required -# Source-Hash: fdbb503f0941bd56 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Countertop depth" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.thickness" -msgstr "Espesor" +msgid "node.cabinet.runPanel.countertopDepth" +msgstr "Fondo de la encimera" +# Source-Hash: 10bba4a11996c84b # Review: required -# Source-Hash: 14b162761ce18fe9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Offset" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Countertop height" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.topOffset" -msgstr "Desfase superior" +msgid "node.cabinet.runPanel.countertopHeight" +msgstr "Altura de la encimera" +# Source-Hash: 8abdfbc1798d9eaa # Review: required -# Source-Hash: 1a5ccd607c400d76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Thickness" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Create array" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.wallThickness" -msgstr "Grosor de pared" +msgid "node.cabinet.runPanel.createArray" +msgstr "Crear serie" +# Source-Hash: 7984b1c42abd9c02 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cutout" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.width" -msgstr "Ancho" +msgid "node.cabinet.runPanel.cutout" +msgstr "Recorte" +# Source-Hash: 555240ffcca44233 # Review: required -# Source-Hash: abff67400a76e5eb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Brick" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete {name}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.preset.brick" -msgstr "Ladrillo" +msgid "node.cabinet.runPanel.deleteModule" +msgstr "Eliminar {name}" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: f6cbdaa17e989b91 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Modern" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.preset.modern" -msgstr "Moderno" +msgid "node.cabinet.runPanel.depth" +msgstr "Profundidad" +# Source-Hash: 76cd03300faa9b2b # Review: required -# Source-Hash: ad0457800a1f0eb4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Direction" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.preset.round" -msgstr "Redondo" +msgid "node.cabinet.runPanel.direction" +msgstr "Dirección" -# Source-Hash: 6a06e628257f3393 +# Source-Hash: 5ca5884d3ff7edf4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A parametric column with configurable cross-section, base, and capital." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate along run" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.description" -msgstr "Pilar paramétrico con sección, basa y capitel configurables." +msgid "node.cabinet.runPanel.duplicateAlongRun" +msgstr "Duplicar a lo largo del tramo" -# Source-Hash: 3530ac1f4046cd22 +# Source-Hash: a834f687290afc10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Column" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equalize all resizeable standard base cabinets in this run" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.label" -msgstr "Pilar" +msgid "node.cabinet.runPanel.equalizeAll" +msgstr "Igualar todos los muebles bajos estándar redimensionables de este tramo" +# Source-Hash: 24da8a2de2c6e345 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The resizeable cabinet widths are already equal" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.actions" -msgstr "Acciones" +msgid "node.cabinet.runPanel.equalizeAlreadyEqual" +msgstr "Los anchos de los muebles redimensionables ya son iguales" +# Source-Hash: c38a4faef2097b73 # Review: required -# Source-Hash: 14b21685d375581a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A-Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "At least two standard base cabinets are required" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.aFrame" -msgstr "Marco en A" +msgid "node.cabinet.runPanel.equalizeNeedsTwo" +msgstr "Se necesitan al menos dos muebles bajos estándar" +# Source-Hash: 61f15ae24419430c # Review: required -# Source-Hash: 4007d88108e25c2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Apply preset..." -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The available run width cannot satisfy the cabinet width limits" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.applyPreset" -msgstr "Aplicar ajuste predefinido…" +msgid "node.cabinet.runPanel.equalizeNoFit" +msgstr "El ancho disponible del tramo no cumple los límites de ancho de los muebles" +# Source-Hash: 7617bb3b455dcdda # Review: required -# Source-Hash: dbfe7c561383c964 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Apply proportion..." -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equalize widths" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.applyProportion" -msgstr "Aplicar proporción…" +msgid "node.cabinet.runPanel.equalizeWidths" +msgstr "Igualar anchos" +# Source-Hash: ad8c948d883a0c9d # Review: required -# Source-Hash: 1f3fd938f0b26c9f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Depth" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{side, select, left {Left: {width} mm} other {Right: {width} mm}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.bottomDepth" -msgstr "Fondo inferior" +msgid "node.cabinet.runPanel.fillerPlanSide" +msgstr "{side, select, left {Izquierda: {width} mm} other {Derecha: {width} mm}}" +# Source-Hash: 47ccd8c8b04475cd # Review: required -# Source-Hash: 85576e19cd3da914 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Height" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish & align" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.bottomHeight" -msgstr "Altura inferior" +msgid "node.cabinet.runPanel.finishAlign" +msgstr "Acabado y alineación" +# Source-Hash: 855892e18c74153a # Review: required -# Source-Hash: 4df0bbb04744a810 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finished back" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.bottomSpread" -msgstr "Apertura inferior" +msgid "node.cabinet.runPanel.finishedBack" +msgstr "Trasera acabada" +# Source-Hash: 7ab47aea30c73663 # Review: required -# Source-Hash: 67479fecb980a441 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Step Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finished exposed ends" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.bottomStepSpread" -msgstr "Separación de escalones inferiores" +msgid "node.cabinet.runPanel.finishedExposedEnds" +msgstr "Laterales vistos acabados" +# Source-Hash: c9356f25caf33eec # Review: required -# Source-Hash: 6ea977c42202ca24 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Tiers" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fits 50–150 mm gaps at run ends beside perpendicular walls." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.bottomTiers" -msgstr "Escalones inferiores" +msgid "node.cabinet.runPanel.fits50150MmGapsAt" +msgstr "Cubre huecos de 50–150 mm en los extremos del tramo junto a paredes perpendiculares." +# Source-Hash: b6f541bc28e38d2f # Review: required -# Source-Hash: 709ca788827f8a94 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit wall fillers" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.bottomWidth" -msgstr "Ancho inferior" +msgid "node.cabinet.runPanel.fitWallFillers" +msgstr "Ajustar rellenos de pared" +# Source-Hash: 2af738f010ce28f0 # Review: required -# Source-Hash: 39d33008c81fc075 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fronts" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.boxFrame" -msgstr "Marco cerrado" +msgid "node.cabinet.runPanel.fronts" +msgstr "Frentes" +# Source-Hash: 58884f99d64e6d00 # Review: required -# Source-Hash: 381b1f481f747677 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Brace Depth" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handles" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.braceDepth" -msgstr "Fondo del arriostramiento" +msgid "node.cabinet.runPanel.handles" +msgstr "Tiradores" +# Source-Hash: d73589d7c04b1121 # Review: required -# Source-Hash: 8509b09b4ecdd6b6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Brace Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height preset" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.braceWidth" -msgstr "Ancho del arriostramiento" +msgid "node.cabinet.runPanel.heightPreset" +msgstr "Altura predefinida" +# Source-Hash: 590bfdd02dcdb857 # Review: required -# Source-Hash: 08558dd786f45281 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bulge" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hole" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.bulge" -msgstr "Abombamiento" +msgid "node.cabinet.runPanel.hole" +msgstr "Orificio" +# Source-Hash: 3db1dea825785a30 # Review: required -# Source-Hash: 663b9a9e6a469b02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bulged" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inset" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.bulged" -msgstr "Abombada" +msgid "node.cabinet.runPanel.inset" +msgstr "Empotrado" +# Source-Hash: 2997c230c529590d # Review: required -# Source-Hash: 3530ac1f4046cd22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Column" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Island & Bar" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.column" -msgstr "Pilar" +msgid "node.cabinet.runPanel.islandBar" +msgstr "Isla y barra" +# Source-Hash: a74f10dadc92c8bb # Review: required -# Source-Hash: ca0a856f04460bd5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connector Plates" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchen run" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.connectorPlates" -msgstr "Placas de unión" +msgid "node.cabinet.runPanel.kitchenRun" +msgstr "Tramo de cocina" +# Source-Hash: 103e15b39c909210 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Knob" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.delete" -msgstr "Eliminar" +msgid "node.cabinet.runPanel.knob" +msgstr "Pomo" +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.depth" -msgstr "Profundidad" +msgid "node.cabinet.runPanel.left" +msgstr "Izquierda" +# Source-Hash: 3c88a1840043e15a # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match base heights, backs, reveals and handles. Align upper cabinets; preserve tall appliances and custom compartments." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.dimensions" -msgstr "Dimensiones" +msgid "node.cabinet.runPanel.matchBaseHeightsBacksRevealsAnd" +msgstr "Iguala alturas de muebles bajos, traseras, holguras y tiradores. Alinea los muebles altos; conserva los electrodomésticos altos y los compartimentos personalizados." +# Source-Hash: b112e31fe44cc94b # Review: required -# Source-Hash: b963a08f0d540014 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edge Softness" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Metric · 600 mm" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.edgeSoftness" -msgstr "Suavizado de aristas" +msgid "node.cabinet.runPanel.metricProfile" +msgstr "Métrico · 600 mm" +# Source-Hash: 4739f6315c5e8680 # Review: required -# Source-Hash: 82b3db356639ef92 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ends" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Module {number}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.ends" -msgstr "Extremos" +msgid "node.cabinet.runPanel.moduleNumber" +msgstr "Módulo {number}" +# Source-Hash: b8801184e07e4815 # Review: required -# Source-Hash: 646c3cd99df3e285 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modules" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.endWidth" -msgstr "Ancho del extremo" +msgid "node.cabinet.runPanel.modules" +msgstr "Módulos" +# Source-Hash: 81d365ccef73068c # Review: required -# Source-Hash: 02e229bca2a2b5f1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fork Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.forkSpread" -msgstr "Apertura de la horquilla" +msgid "node.cabinet.runPanel.mounting" +msgstr "Montaje" +# Source-Hash: a3914bd96488175c # Review: required -# Source-Hash: fdebfac05413abcf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Heavy" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No eligible module" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.heavy" -msgstr "Robusta" +msgid "node.cabinet.runPanel.noEligibleModule" +msgstr "Ningún módulo válido" +# Source-Hash: f2953d2931e36d0c # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.height" -msgstr "Altura" +msgid "node.cabinet.runPanel.none" +msgstr "Ninguno" +# Source-Hash: 9c215dc512e57fa4 # Review: required -# Source-Hash: 957fae84ed52a2e3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height and footprint are controlled by the lean-to extension. Rotate or change the support style here; resize from the parent lean-to." -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overlay" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.heightAndFootprintAreControlledBy" -msgstr "La altura y la huella las controla la extensión de un agua. Gira o cambia el estilo de soporte aquí; cambia el tamaño desde la extensión principal." +msgid "node.cabinet.runPanel.overlay" +msgstr "Superpuesta" +# Source-Hash: 49fb05dfafd6001d # Review: required -# Source-Hash: bb851e93088b73a2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hourglass" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plinth height" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.hourglass" -msgstr "Reloj de arena" +msgid "node.cabinet.runPanel.plinthHeight" +msgstr "Altura del zócalo" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: 9cc75129edee59ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "K Brace" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.kBrace" -msgstr "Arriostramiento en K" +msgid "node.cabinet.runPanel.position" +msgstr "Posición" +# Source-Hash: efca749fc4463623 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised Arch" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.move" -msgstr "Mover" +msgid "node.cabinet.runPanel.raisedArch" +msgstr "Arco en relieve" +# Source-Hash: 5d6956c21fde6418 # Review: required -# Source-Hash: 6dc190abd3f22787 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Neck Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reveal gap" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.neckWidth" -msgstr "Ancho del cuello" +msgid "node.cabinet.runPanel.revealGap" +msgstr "Holgura entre frentes" +# Source-Hash: b34d5ee0f218221d # Review: required -# Source-Hash: 7dba7ed55eeba18f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.noBottom" -msgstr "Sin base" +msgid "node.cabinet.runPanel.right" +msgstr "Derecha" +# Source-Hash: e022da49ae8b4aef # Review: required -# Source-Hash: 682d71815bb20e94 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No Top" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Seating overhang" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.noTop" -msgstr "Sin capitel" +msgid "node.cabinet.runPanel.seatingOverhang" +msgstr "Voladizo para asientos" +# Source-Hash: 5b68e435b7210876 # Review: required -# Source-Hash: 4da8688437f64db8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Plinth Thickness" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaker" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.plinthThickness" -msgstr "Grosor del plinto" +msgid "node.cabinet.runPanel.shaker" +msgstr "Shaker" +# Source-Hash: cba29b18ce666b0a # Review: required -# Source-Hash: 0bf453b4882c663c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Portal Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shared Plinth & Countertop" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.portalFrame" -msgstr "Pórtico" +msgid "node.cabinet.runPanel.sharedPlinthCountertop" +msgstr "Zócalo y encimera compartidos" +# Source-Hash: f7d577c4064c16ff # Review: required -# Source-Hash: 441f7f652ea6a0d8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preset" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show countertop" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.preset" -msgstr "Preajuste" +msgid "node.cabinet.runPanel.showCountertop" +msgstr "Mostrar encimera" +# Source-Hash: 5d98e04dfd2e0a83 # Review: required -# Source-Hash: f29fef1beeb25f22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangular" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show plinth" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.rectangular" -msgstr "Rectangular" +msgid "node.cabinet.runPanel.showPlinth" +msgstr "Mostrar zócalo" +# Source-Hash: 8775bc8dc9593964 # Review: required -# Source-Hash: 23b9d290b165cd49 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ring Pairs" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.ringPairs" -msgstr "Pares de anillos" +msgid "node.cabinet.runPanel.slab" +msgstr "Forjado" +# Source-Hash: 5bdc0a959203c52e # Review: required -# Source-Hash: 8db82d731a19651e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ring Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Source module" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.ringSpread" -msgstr "Separación de anillos" +msgid "node.cabinet.runPanel.sourceModule" +msgstr "Módulo de origen" +# Source-Hash: e4698e83d02beb6c # Review: required -# Source-Hash: bdb524a15d9e1509 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ring Thickness" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spacing" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.ringThickness" -msgstr "Grosor de anillos" +msgid "node.cabinet.runPanel.spacing" +msgstr "Separación" +# Source-Hash: 40e3105cbe68d163 # Review: required -# Source-Hash: ad0457800a1f0eb4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard dimensions" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.round" -msgstr "Redondo" +msgid "node.cabinet.runPanel.standardDimensions" +msgstr "Dimensiones estándar" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: baa84a2d17095dcf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round Band Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.roundBandWidth" -msgstr "Ancho de la banda redonda" +msgid "node.cabinet.runPanel.style" +msgstr "Estilo" +# Source-Hash: e9d7ad9851d476d9 # Review: required -# Source-Hash: 5f1f67fb0ca59a6d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rounded Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{type, select, shelf {Shelf} drawer {Drawer} door {Door} oven {Oven} microwave {Microwave} dishwasher {Dishwasher} sink {Sink} cooktop_gas {Gas cooktop} cooktop_induction {Induction cooktop} pull_out_pantry {Pull-out pantry} fridge_single {Fridge} fridge_double {Double fridge} fridge_top_freezer {Top-freezer fridge} fridge_bottom_freezer {Bottom-freezer fridge} hood_pyramid {Pyramid hood} hood_curved_glass {Curved glass hood} other {{raw}}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.roundedBottom" -msgstr "Base redondeada" +msgid "node.cabinet.runPanel.summaryCompartment" +msgstr "{type, select, shelf {Balda} drawer {Cajón} door {Puerta} oven {Horno} microwave {Microondas} dishwasher {Lavavajillas} sink {Fregadero} cooktop_gas {Placa de gas} cooktop_induction {Placa de inducción} pull_out_pantry {Despensero extraíble} fridge_single {Frigorífico} fridge_double {Frigorífico doble} fridge_top_freezer {Frigorífico con congelador superior} fridge_bottom_freezer {Frigorífico con congelador inferior} hood_pyramid {Campana piramidal} hood_curved_glass {Campana de vidrio curvo} other {{raw}}}" +# Source-Hash: 98582c257f149d44 # Review: required -# Source-Hash: 446816980ed0da27 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rounded Top" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {{number} compartment} other {{number} compartments}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.roundedTop" -msgstr "Capitel redondeado" +msgid "node.cabinet.runPanel.summaryCompartments" +msgstr "{count, plural, one {{number} compartimento} many {{number} compartimentos} other {{number} compartimentos}}" +# Source-Hash: 65b1cbba3b92c5b2 # Review: required -# Source-Hash: 9e554c26be80f0d0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segment Twist" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Empty" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.segmentTwist" -msgstr "Torsión de segmentos" +msgid "node.cabinet.runPanel.summaryEmpty" +msgstr "Vacío" +# Source-Hash: 5db8b868684cf9f3 # Review: required -# Source-Hash: 4fc63ad21de30103 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tall cabinet" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.shaft" -msgstr "Hueco" +msgid "node.cabinet.runPanel.summaryTall" +msgstr "Columna" +# Source-Hash: 27644f0497fd9849 # Review: required -# Source-Hash: 9bc3a704a9a96b3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Corner Radius" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.shaftCornerRadius" -msgstr "Radio de esquina del fuste" +msgid "node.cabinet.runPanel.top" +msgstr "Superior" +# Source-Hash: 88c85283afe0c0bc # Review: required -# Source-Hash: 3dab61aeb47e504d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unable to finish this kitchen run." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.shaftWidth" -msgstr "Ancho del fuste" +msgid "node.cabinet.runPanel.unableToFinish" +msgstr "No se puede terminar este tramo de cocina." +# Source-Hash: 8f668fb3e1a1696a # Review: required -# Source-Hash: 85ea1d3c8b749680 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use {name} as array source" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.shape" -msgstr "Forma" +msgid "node.cabinet.runPanel.useAsArraySource" +msgstr "Usar {name} como origen de la serie" +# Source-Hash: 9308a109d017dcd6 # Review: required -# Source-Hash: 49a2ce13016d4073 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Short / Stout" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use this module as the array source" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.shortStout" -msgstr "Corta / Gruesa" +msgid "node.cabinet.runPanel.useThisModuleAsTheArray" +msgstr "Usar este módulo como origen de la serie" +# Source-Hash: 1ce253a4d11bfa68 # Review: required -# Source-Hash: 4637a9a61638cc66 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Simple Block Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "US · 24 in" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.simpleBlockBottom" -msgstr "Base de bloque simple" +msgid "node.cabinet.runPanel.usProfile" +msgstr "EE. UU. · 24 in" +# Source-Hash: a2d852b2c5629796 # Review: required -# Source-Hash: 9278f9b4a48208b0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Simple Top" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waterfall ends" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.simpleTop" -msgstr "Capitel simple" +msgid "node.cabinet.runPanel.waterfallEnds" +msgstr "Laterales en cascada" +# Source-Hash: ffc8d80e438f40b7 # Review: required -# Source-Hash: 9099890734ae1238 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single Strut" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An editable module inside a modular cabinet run." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.panel.singleStrut" -msgstr "Puntal único" +msgid "node.cabinetModule.description" +msgstr "Módulo editable dentro de una línea de muebles modulares." +# Source-Hash: d5c19ec529e26a98 # Review: required -# Source-Hash: d87ce271009ce063 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slender" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet Module" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.panel.slender" -msgstr "Esbelta" +msgid "node.cabinetModule.label" +msgstr "Módulo de mueble" +# Source-Hash: 25be6d614ec09df9 # Review: required -# Source-Hash: 39287346366fc206 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom chord" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.square" -msgstr "Cuadrado" +msgid "node.ceiling.buildUpSection.bottomChord" +msgstr "Cordón inferior" +# Source-Hash: a0c71abc0f146a2b # Review: required -# Source-Hash: 2dc84759d8df709d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square Plinth Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling joists" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.squarePlinthBottom" -msgstr "Base de plinto cuadrado" +msgid "node.ceiling.buildUpSection.ceilingJoists" +msgstr "Viguetas de techo" +# Source-Hash: 7d286c87375d417e # Review: required -# Source-Hash: d998c212030bc7c2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Decking" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.standard" -msgstr "Estándar" +msgid "node.ceiling.buildUpSection.decking" +msgstr "Entablado" +# Source-Hash: b3907da0ad234f10 # Review: required -# Source-Hash: 01a6393135e0fb10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stepped Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.steppedBottom" -msgstr "Base escalonada" +msgid "node.ceiling.buildUpSection.finish" +msgstr "Acabado" +# Source-Hash: c7e72beff9fe4b37 # Review: required -# Source-Hash: 3d7e443797d4146e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stepped Top" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framing" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.steppedTop" -msgstr "Capitel escalonado" +msgid "node.ceiling.buildUpSection.framing" +msgstr "Entramado" +# Source-Hash: c7aa596536ceeecb # Review: required -# Source-Hash: 4ee35f740730ae87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Joists" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.straight" -msgstr "Recto" +msgid "node.ceiling.buildUpSection.joists" +msgstr "Viguetas" +# Source-Hash: 4ccd2fc1a471fca5 # Review: required -# Source-Hash: 6063ae2877faa35d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Taper" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layers" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.taper" -msgstr "Ahusamiento" +msgid "node.ceiling.buildUpSection.layers" +msgstr "Capas" +# Source-Hash: f2953d2931e36d0c # Review: required -# Source-Hash: f86f1f22230596b7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tapered" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.tapered" -msgstr "Ahusado" +msgid "node.ceiling.buildUpSection.none" +msgstr "Ninguno" +# Source-Hash: 441f7f652ea6a0d8 # Review: required -# Source-Hash: 3e7ec47626ee3f22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Depth" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preset" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.topDepth" -msgstr "Fondo superior" +msgid "node.ceiling.buildUpSection.preset" +msgstr "Preajuste" +# Source-Hash: 2bc7b44c217cb8fb # Review: required -# Source-Hash: 0ca9047731784f56 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Height" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The height is the finished underside; the layers rise from it." +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.topHeight" -msgstr "Altura superior" +msgid "node.ceiling.buildUpSection.theHeightIsTheFinishedUnderside" +msgstr "La altura es la cara inferior acabada; las capas suben desde ella." +# Source-Hash: fdbb503f0941bd56 # Review: required -# Source-Hash: 3d8a2be83b5b536a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.topSpread" -msgstr "Apertura superior" +msgid "node.ceiling.buildUpSection.thickness" +msgstr "Espesor" +# Source-Hash: 2cf52770d658d006 # Review: required -# Source-Hash: f4ae0dc639dbc220 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Step Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Truss bottom chords" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.topStepSpread" -msgstr "Separación de escalones superiores" +msgid "node.ceiling.buildUpSection.trussBottomChords" +msgstr "Cordones inferiores de cercha" +# Source-Hash: 4d6d5e9439f40e9b # Review: required -# Source-Hash: 8acc4e843934b086 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Tiers" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A polygon-bounded ceiling surface that hosts ceiling-mounted items." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.panel.topTiers" -msgstr "Escalones superiores" +msgid "node.ceiling.description" +msgstr "Superficie de techo delimitada por un polígono que aloja elementos de techo." +# Source-Hash: 4275c05172abd7fb # Review: required -# Source-Hash: a50eb6400611a57c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.panel.topWidth" -msgstr "Ancho superior" +msgid "node.ceiling.label" +msgstr "Techo" +# Source-Hash: 659e6b799ad7c27d # Review: required -# Source-Hash: f425799b82e085ed -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transform" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Hole" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.transform" -msgstr "Transformación" +msgid "node.ceiling.panel.addHole" +msgstr "Añadir hueco" +# Source-Hash: 8332ab41e22958f1 # Review: required -# Source-Hash: 952fd1ef187c6646 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trestle" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Area" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.trestle" -msgstr "Caballete" +msgid "node.ceiling.panel.area" +msgstr "Área" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: 7430dad59aaf98f4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tripod" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.tripod" -msgstr "Trípode" +msgid "node.ceiling.panel.auto" +msgstr "Auto" +# Source-Hash: 4275c05172abd7fb # Review: required -# Source-Hash: 0db559f22647ec73 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Twist Segments" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.twistSegments" -msgstr "Segmentos de torsión" +msgid "node.ceiling.panel.ceiling" +msgstr "Techo" +# Source-Hash: b2a1b3bc9676fe05 # Review: required -# Source-Hash: 8038a34ffebf4932 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom height" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.vertical" -msgstr "Vertical" +msgid "node.ceiling.panel.customHeight" +msgstr "Altura personalizada" +# Source-Hash: 4e4f1a24e4a9d61e # Review: required -# Source-Hash: f24cc343d79acc10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "V Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut opening" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.vSupport" -msgstr "Soporte en V" +msgid "node.ceiling.panel.cutOpening" +msgstr "Abrir hueco" +# Source-Hash: 16552c2580bbe8b8 # Review: required -# Source-Hash: 44dda7136b93c8ee -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.waist" -msgstr "Losa" +msgid "node.ceiling.panel.done" +msgstr "Hecho" +# Source-Hash: a5c2353769b603d5 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows level" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.width" -msgstr "Ancho" +msgid "node.ceiling.panel.followsLevel" +msgstr "Sigue la planta" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 4e6640dfff42cea4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "X Brace" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.xBrace" -msgstr "Cruz de San Andrés" +msgid "node.ceiling.panel.height" +msgstr "Altura" +# Source-Hash: 703f56131ac45e60 # Review: required -# Source-Hash: fefc9b1cfb26b5a8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Yaw" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High (3.0m)" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.yaw" -msgstr "Guiñada" +msgid "node.ceiling.panel.high30m" +msgstr "Alto (3,0 m)" +# Source-Hash: 4ed40bdab397fe22 # Review: required -# Source-Hash: 86259690e332b66d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Y Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High (9'0\")" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.ySupport" -msgstr "Soporte en Y" +msgid "node.ceiling.panel.high90" +msgstr "Alto (9'0\")" +# Source-Hash: 34504c6ca6445e76 # Review: required -# Source-Hash: bf2baf3d7b55f0df -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A-Frame Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Holes" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.aFrameSupport" -msgstr "Soporte en A" +msgid "node.ceiling.panel.holes" +msgstr "Huecos" +# Source-Hash: 6e68b62d2aa611a4 # Review: required -# Source-Hash: 51cf77bb359cee43 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight Round" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Info" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.basicPillar" -msgstr "Redonda recta" +msgid "node.ceiling.panel.info" +msgstr "Info" +# Source-Hash: 6925a008b1924062 # Review: required -# Source-Hash: 39d33008c81fc075 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Limited by the level to {height} — raise the level height for a taller ceiling." +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.boxFrameSupport" -msgstr "Marco cerrado" +msgid "node.ceiling.panel.limitedByLevel" +msgstr "Limitado por la planta a {height}: sube la altura de la planta para un techo más alto." +# Source-Hash: c7410ff087be3a61 # Review: required -# Source-Hash: 4f22058e862d1f81 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Soft Bulged" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low (2.4m)" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.bulgedPillar" -msgstr "Ligeramente abombada" +msgid "node.ceiling.panel.low24m" +msgstr "Bajo (2,4 m)" +# Source-Hash: a59425761b7c9084 # Review: required -# Source-Hash: bb851e93088b73a2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hourglass" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low (8'0\")" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.hourglassPillar" -msgstr "Reloj de arena" +msgid "node.ceiling.panel.low80" +msgstr "Bajo (8'0\")" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: 9cc75129edee59ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "K Brace" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.kBraceSupport" -msgstr "Arriostramiento en K" +msgid "node.ceiling.panel.move" +msgstr "Mover" +# Source-Hash: 1d2dafb0d8f26ed5 # Review: required -# Source-Hash: 0bf453b4882c663c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Portal Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No holes" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.portalFrameSupport" -msgstr "Pórtico" +msgid "node.ceiling.panel.noHoles" +msgstr "Sin huecos" +# Source-Hash: 24f5fbd158798197 # Review: required -# Source-Hash: 9099890734ae1238 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single Strut" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard (2.5m)" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.singleStrutSupport" -msgstr "Puntal único" +msgid "node.ceiling.panel.standard25m" +msgstr "Estándar (2,5 m)" +# Source-Hash: 73cf00cf1900c22b # Review: required -# Source-Hash: 0c13af329b9b57cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square Block" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard (8'6\")" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.squarePillar" -msgstr "Bloque cuadrado" +msgid "node.ceiling.panel.standard86" +msgstr "Estándar (8'6\")" +# Source-Hash: 065626498678bc5d # Review: required -# Source-Hash: 4c294bad84924665 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tapered Round" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Taller than this level ({available} available). Raise the level height first." +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.taperedPillar" -msgstr "Redonda ahusada" +msgid "node.ceiling.panel.tallerThanLevel" +msgstr "Más alto que esta planta ({available} disponibles). Sube primero la altura de la planta." +# Source-Hash: ea12ce3c2b3588e7 # Review: required -# Source-Hash: 360e405bfd74a379 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trestle Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical masonry stack on a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.preset.trestleSupport" -msgstr "Marco de caballete" +msgid "node.chimney.description" +msgstr "Chimenea vertical de obra sobre un faldón." +# Source-Hash: 95169058fec6db14 # Review: required -# Source-Hash: 4589103259b4fc4d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tripod Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Chimney" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.preset.tripodSupport" -msgstr "Soporte trípode" +msgid "node.chimney.label" +msgstr "Chimenea" +# Source-Hash: dc393661f0038c2d # Review: required -# Source-Hash: f24cc343d79acc10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "V Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Above Ridge" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.column.preset.vFrameSupport" -msgstr "Soporte en V" +msgid "node.chimney.panel.aboveRidge" +msgstr "Sobre la cumbrera" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 4e6640dfff42cea4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "X Brace" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.column.preset.xBraceSupport" -msgstr "Cruz de San Andrés" +msgid "node.chimney.panel.actions" +msgstr "Acciones" +# Source-Hash: 7ceade8f25b58fe9 # Review: required -# Source-Hash: 86259690e332b66d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Y Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.column.preset.yFrameSupport" -msgstr "Soporte en Y" +msgid "node.chimney.panel.back" +msgstr "Volver" -# Source-Hash: 895766ad1b766c2e +# Source-Hash: 0d42509b34b05dec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Associative linear, curved, circular, angular, or coordinate plan dimension." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bands" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.constructionDimension.description" -msgstr "Cota de plano asociativa: lineal, curva, circular, angular o de coordenadas." - -# Source-Hash: 6875b60ee8a7cc3b -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Construction Dimension" -#: packages/nodes/src/i18n/definition-messages.ts -#, fuzzy -msgid "node.constructionDimension.label" -msgstr "Cota de construcción" +msgid "node.chimney.panel.bands" +msgstr "Bandas" -# Source-Hash: 61a6c6b9bc29c4f8 +# Source-Hash: d52b53241789ee63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Left" -#: packages/nodes/src/window/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cornerRadius.bottomLeft" -msgstr "Inferior izquierda" +msgid "node.chimney.panel.cap" +msgstr "Remate" -# Source-Hash: c5368accab136fa6 +# Source-Hash: 95169058fec6db14 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Right" -#: packages/nodes/src/window/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Chimney" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cornerRadius.bottomRight" -msgstr "Inferior derecha" +msgid "node.chimney.panel.chimney" +msgstr "Chimenea" -# Source-Hash: c8f86af3f03af6c7 +# Source-Hash: b619f366d2a1dfda # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Left" -#: packages/nodes/src/door/panel.tsx -#: packages/nodes/src/window/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Chimney Type" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cornerRadius.topLeft" -msgstr "Superior izquierda" +msgid "node.chimney.panel.chimneyType" +msgstr "Tipo de chimenea" -# Source-Hash: 0ead7f1ffdbbd892 +# Source-Hash: 6786ac75cbe9af57 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Right" -#: packages/nodes/src/door/panel.tsx -#: packages/nodes/src/window/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corbeled" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cornerRadius.topRight" -msgstr "Superior derecha" +msgid "node.chimney.panel.corbeled" +msgstr "Con ménsulas" -# Source-Hash: a276c9693f01dec7 +# Source-Hash: 89eba9f077fba348 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Louvered roof lantern with a dome or pyramid cap and optional finial." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner Bevel" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.description" -msgstr "Linterna de cubierta con lamas, remate en cúpula o pirámide y pináculo opcional." +msgid "node.chimney.panel.cornerBevel" +msgstr "Chaflán de esquina" -# Source-Hash: e679dd19f96eba0a +# Source-Hash: 8a4beb9a57edc26e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cupola" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Count" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.label" -msgstr "Linterna" +msgid "node.chimney.panel.count" +msgstr "Cantidad" +# Source-Hash: f8ba7d73d3006d57 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.actions" -msgstr "Acciones" +msgid "node.chimney.panel.cricket" +msgstr "Caballete desviador" +# Source-Hash: 14144df9e1364eea # Review: required -# Source-Hash: e679dd19f96eba0a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cupola" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cutout Offset" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.cupola" -msgstr "Linterna" +msgid "node.chimney.panel.cutoutOffset" +msgstr "Desfase del recorte" -# Review: required # Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" -#: packages/nodes/src/cupola/panel.tsx +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.delete" +msgid "node.chimney.panel.delete" msgstr "Eliminar" -# Review: required # Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Depth" -#: packages/nodes/src/cupola/panel.tsx +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.depth" +msgid "node.chimney.panel.depth" msgstr "Profundidad" +# Source-Hash: 016d8e70618916d4 # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diameter" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.dimensions" -msgstr "Dimensiones" +msgid "node.chimney.panel.diameter" +msgstr "Diámetro" +# Source-Hash: 3cd71355956a1821 # Review: required -# Source-Hash: de47e23eb81efe02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dome" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.dome" -msgstr "Cúpula" +msgid "node.chimney.panel.double" +msgstr "Doble" +# Source-Hash: 150340cd05f4a6dd # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Extent" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.duplicate" -msgstr "Duplicar" +msgid "node.chimney.panel.extent" +msgstr "Extensión" +# Source-Hash: 9cab4d4c95f63cdd # Review: required -# Source-Hash: 1cfe33235b30b1d8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finial" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.finial" -msgstr "Remate" +msgid "node.chimney.panel.flat" +msgstr "Plana" +# Source-Hash: f817c09ef0bb6d69 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flues" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.height" -msgstr "Altura" +msgid "node.chimney.panel.flues" +msgstr "Conductos" +# Source-Hash: a3c10560fa3c1612 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Footprint" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.move" -msgstr "Mover" +msgid "node.chimney.panel.footprint" +msgstr "Huella" +# Source-Hash: e360f89d3c0ec456 # Review: required -# Source-Hash: b5e0cb318d484d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No Finial" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.noFinial" -msgstr "Sin remate" +msgid "node.chimney.panel.front" +msgstr "Frente" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.position" -msgstr "Posición" +msgid "node.chimney.panel.height" +msgstr "Altura" +# Source-Hash: 5b490bc19dddf201 # Review: required -# Source-Hash: 47587b825e9a696b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pyramid" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hollow Depth" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.pyramid" -msgstr "Pirámide" +msgid "node.chimney.panel.hollowDepth" +msgstr "Profundidad del hueco" +# Source-Hash: 643687bc3adaac76 # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.rotation" -msgstr "Rotación" +msgid "node.chimney.panel.length" +msgstr "Longitud" +# Source-Hash: f2953d2931e36d0c # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.style" -msgstr "Estilo" +msgid "node.chimney.panel.none" +msgstr "Ninguno" +# Source-Hash: 0f0e13abf9b2bb67 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Offset" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.width" -msgstr "Ancho" +msgid "node.chimney.panel.offset" +msgstr "Desfase" -# Source-Hash: 5d4ccdf13668fab4 +# Source-Hash: 88540def2ce16ac5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto elevator cutout" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overhang" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cutout.autoElevator" -msgstr "Recorte automático de ascensor" +msgid "node.chimney.panel.overhang" +msgstr "Vuelo" -# Source-Hash: 78aa03576e02dda7 +# Source-Hash: 6ce059aee1386f72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto stair cutout" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panels" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cutout.autoStair" -msgstr "Recorte automático de escalera" +msgid "node.chimney.panel.panels" +msgstr "Paneles" -# Source-Hash: e04298381837252f +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cutout.opening" -msgstr "Abertura" +msgid "node.chimney.panel.position" +msgstr "Posición" -# Source-Hash: ce37dbd7a309940b +# Source-Hash: f29fef1beeb25f22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room cutout" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangular" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cutout.room" -msgstr "Recorte de estancia" +msgid "node.chimney.panel.rectangular" +msgstr "Rectangular" -# Source-Hash: 6123b20edb9569de +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A door cut into a wall. Animated open/close state." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.description" -msgstr "Puerta abierta en un muro, con apertura y cierre animados." +msgid "node.chimney.panel.rotation" +msgstr "Rotación" -# Source-Hash: 787e10f5db16904e +# Source-Hash: ad0457800a1f0eb4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.label" -msgstr "Puerta" +msgid "node.chimney.panel.round" +msgstr "Redondo" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 8c6e3985459dacf9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.actions" -msgstr "Acciones" +msgid "node.chimney.panel.shoulder" +msgstr "Hombro" -# Source-Hash: 8337b3213849faca +# Source-Hash: 84b9195c73dd7a67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "+ Add Segment" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Side Margin" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.addSegment" -msgstr "+ Añadir segmento" +msgid "node.chimney.panel.sideMargin" +msgstr "Margen lateral" -# Source-Hash: 663175a9c461a96d +# Source-Hash: a05a390ae205fdd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Simple" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.all" -msgstr "Todo" +msgid "node.chimney.panel.simple" +msgstr "Sencillo" -# Source-Hash: 710261f5ffb32617 +# Source-Hash: 62ab2eb3c775da95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arch" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.arch" -msgstr "Arco" +msgid "node.chimney.panel.single" +msgstr "Simple" -# Source-Hash: 3715cd54e4775087 +# Source-Hash: f6998707123fe72d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arch Height" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sloped" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.archHeight" -msgstr "Altura del arco" +msgid "node.chimney.panel.sloped" +msgstr "Inclinado" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: e4698e83d02beb6c # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 -# English: "Auto" -#: packages/nodes/src/door/panel.tsx +# AI-Model: claude-opus-5-5 +# English: "Spacing" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.auto" -msgstr "Auto" +msgid "node.chimney.panel.spacing" +msgstr "Separación" -# Source-Hash: 8a04486ba122ea7d +# Source-Hash: 39287346366fc206 # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 -# English: "Auto follows the wall" -#: packages/nodes/src/door/panel.tsx +# AI-Model: claude-opus-5-5 +# English: "Square" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.autoFollowsTheWall" -msgstr "Auto sigue el muro" +msgid "node.chimney.panel.square" +msgstr "Cuadrado" -# Source-Hash: 387773c8aa2820a4 +# Source-Hash: 2c6b1cf17a973d67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar Height" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stepped" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.barHeight" -msgstr "Altura de la barra" +msgid "node.chimney.panel.stepped" +msgstr "Escalonado" -# Source-Hash: 30edd1c180aac9b4 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Columns" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.columns" -msgstr "Columnas" +msgid "node.chimney.panel.style" +msgstr "Estilo" -# Source-Hash: f533584833a4a7bb +# Source-Hash: f86f1f22230596b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Content Padding" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tapered" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.contentPadding" -msgstr "Relleno del contenido" +msgid "node.chimney.panel.tapered" +msgstr "Ahusado" -# Source-Hash: 7a90a42b578f2435 +# Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner Radius" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.cornerRadius" -msgstr "Radio de esquina" +msgid "node.chimney.panel.thickness" +msgstr "Espesor" -# Source-Hash: aa0e8e02212091e4 +# Source-Hash: 14b162761ce18fe9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom: the segments match no style." -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Offset" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.customTheSegmentsMatchNoStyle" -msgstr "Personalizado: los segmentos no coinciden con ningún estilo." +msgid "node.chimney.panel.topOffset" +msgstr "Desfase superior" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 1a5ccd607c400d76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall Thickness" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.delete" -msgstr "Eliminar" +msgid "node.chimney.panel.wallThickness" +msgstr "Grosor de pared" -# Source-Hash: 99ac4d03c3061f3a +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.depth" -msgstr "Profundidad" +msgid "node.chimney.panel.width" +msgstr "Ancho" -# Source-Hash: 12df69f42beb0643 +# Source-Hash: abff67400a76e5eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brick" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.dimensions" -msgstr "Dimensiones" +msgid "node.chimney.preset.brick" +msgstr "Ladrillo" -# Source-Hash: 76cd03300faa9b2b +# Source-Hash: f6cbdaa17e989b91 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Direction" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modern" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.direction" -msgstr "Dirección" +msgid "node.chimney.preset.modern" +msgstr "Moderno" -# Source-Hash: c53c3307e2a2a32a +# Source-Hash: ad0457800a1f0eb4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Divider" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.divider" -msgstr "Divisor" +msgid "node.chimney.preset.round" +msgstr "Redondo" -# Source-Hash: 787e10f5db16904e +# Source-Hash: 6a06e628257f3393 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A parametric column with configurable cross-section, base, and capital." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.door" -msgstr "Puerta" +msgid "node.column.description" +msgstr "Pilar paramétrico con sección, basa y capitel configurables." -# Source-Hash: 4a0aa7f647e6461b +# Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Closer" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Column" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.doorCloser" -msgstr "Cierrapuertas" +msgid "node.column.label" +msgstr "Pilar" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.duplicate" -msgstr "Duplicar" +msgid "node.column.panel.actions" +msgstr "Acciones" -# Source-Hash: 65b1cbba3b92c5b2 +# Source-Hash: 14b21685d375581a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Empty" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A-Frame" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.empty" -msgstr "Vacío" +msgid "node.column.panel.aFrame" +msgstr "Marco en A" -# Source-Hash: 6982301da2dbe186 +# Source-Hash: 4007d88108e25c2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Enable Handle" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Apply preset..." +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.enableHandle" -msgstr "Activar manilla" +msgid "node.column.panel.applyPreset" +msgstr "Aplicar ajuste predefinido…" -# Source-Hash: 2e96ebf9c6e7fe49 +# Source-Hash: dbfe7c561383c964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Enable Threshold" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Apply proportion..." +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.enableThreshold" -msgstr "Activar umbral" +msgid "node.column.panel.applyProportion" +msgstr "Aplicar proporción…" -# Source-Hash: 61f9413d3bbabde7 +# Source-Hash: 1f3fd938f0b26c9f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip Side" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Depth" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.flipSide" -msgstr "Invertir lado" +msgid "node.column.panel.bottomDepth" +msgstr "Fondo inferior" -# Source-Hash: 7e8fdd28f9d54d1f +# Source-Hash: 85576e19cd3da914 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fold" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Height" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.fold" -msgstr "Pliegue" +msgid "node.column.panel.bottomHeight" +msgstr "Altura inferior" -# Source-Hash: ce3a6c03765dbbd8 +# Source-Hash: 4df0bbb04744a810 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.frame" -msgstr "Marco" +msgid "node.column.panel.bottomSpread" +msgstr "Apertura inferior" -# Source-Hash: 0cce8ae784f78478 +# Source-Hash: 67479fecb980a441 # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 -# English: "Depth (auto)" -#: packages/nodes/src/door/panel.tsx +# AI-Model: claude-opus-5-5 +# English: "Bottom Step Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.frameDepthAuto" -msgstr "Profundidad (auto)" +msgid "node.column.panel.bottomStepSpread" +msgstr "Separación de escalones inferiores" -# Source-Hash: 53aa825a4737190a +# Source-Hash: 6ea977c42202ca24 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Garage" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Tiers" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.garage" -msgstr "Garaje" +msgid "node.column.panel.bottomTiers" +msgstr "Escalones inferiores" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: 709ca788827f8a94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.glass" -msgstr "Vidrio" +msgid "node.column.panel.bottomWidth" +msgstr "Ancho inferior" -# Source-Hash: 41483b645efc0c65 +# Source-Hash: 39d33008c81fc075 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handle" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box Frame" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.handle" -msgstr "Manilla" +msgid "node.column.panel.boxFrame" +msgstr "Marco cerrado" -# Source-Hash: b4a496a904640583 +# Source-Hash: 381b1f481f747677 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handle Side" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brace Depth" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.handleSide" -msgstr "Lado de la manilla" +msgid "node.column.panel.braceDepth" +msgstr "Fondo del arriostramiento" -# Source-Hash: 8c1bc3a078056ff7 +# Source-Hash: 8509b09b4ecdd6b6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hardware" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brace Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.hardware" -msgstr "Herrajes" +msgid "node.column.panel.braceWidth" +msgstr "Ancho del arriostramiento" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: 08558dd786f45281 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bulge" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.height" -msgstr "Altura" +msgid "node.column.panel.bulge" +msgstr "Abombamiento" -# Source-Hash: 7c8f079bbefe86c9 +# Source-Hash: 663b9a9e6a469b02 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hinges Side" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bulged" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.hingesSide" -msgstr "Lado de las bisagras" +msgid "node.column.panel.bulged" +msgstr "Abombada" -# Source-Hash: ac9c79f08ef130a1 +# Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Horizontal" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Column" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.horizontal" -msgstr "Horizontal" +msgid "node.column.panel.column" +msgstr "Pilar" -# Source-Hash: 42824e50de26bc14 +# Source-Hash: ca0a856f04460bd5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Individual" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connector Plates" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.individual" -msgstr "Individual" +msgid "node.column.panel.connectorPlates" +msgstr "Placas de unión" -# Source-Hash: 3db1dea825785a30 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inset" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.inset" -msgstr "Empotrado" +msgid "node.column.panel.delete" +msgstr "Eliminar" -# Source-Hash: 1f4ad5ad3e1be222 +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inward" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.inward" -msgstr "Hacia dentro" +msgid "node.column.panel.depth" +msgstr "Profundidad" -# Source-Hash: f365c6b6dd9ebab9 +# Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.left" -msgstr "Izquierda" +msgid "node.column.panel.dimensions" +msgstr "Dimensiones" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: b963a08f0d540014 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edge Softness" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.move" -msgstr "Mover" +msgid "node.column.panel.edgeSoftness" +msgstr "Suavizado de aristas" -# Source-Hash: 3e52f04f92e08070 +# Source-Hash: 82b3db356639ef92 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ends" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.open" -msgstr "Abrir" +msgid "node.column.panel.ends" +msgstr "Extremos" -# Source-Hash: e04298381837252f +# Source-Hash: 646c3cd99df3e285 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.opening" -msgstr "Abertura" +msgid "node.column.panel.endWidth" +msgstr "Ancho del extremo" -# Source-Hash: ecb81bd3eefa6a47 +# Source-Hash: 02e229bca2a2b5f1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening Shape" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fork Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.openingShape" -msgstr "Forma del hueco" +msgid "node.column.panel.forkSpread" +msgstr "Apertura de la horquilla" -# Source-Hash: ccd8f06b8f8d27c9 +# Source-Hash: fdebfac05413abcf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Outward" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Heavy" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.outward" -msgstr "Hacia fuera" +msgid "node.column.panel.heavy" +msgstr "Robusta" -# Source-Hash: 482469f5a0873f73 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.panel" -msgstr "Panel" +msgid "node.column.panel.height" +msgstr "Altura" -# Source-Hash: 6ce059aee1386f72 +# Source-Hash: 957fae84ed52a2e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panels" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height and footprint are controlled by the lean-to extension. Rotate or change the support style here; resize from the parent lean-to." +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.panels" -msgstr "Paneles" +msgid "node.column.panel.heightAndFootprintAreControlledBy" +msgstr "La altura y la huella las controla la extensión de un agua. Gira o cambia el estilo de soporte aquí; cambia el tamaño desde la extensión principal." -# Source-Hash: ad56a8ab82ff1a77 +# Source-Hash: bb851e93088b73a2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panic Bar" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hourglass" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.panicBar" -msgstr "Barra antipánico" +msgid "node.column.panel.hourglass" +msgstr "Reloj de arena" -# Source-Hash: ade6246634d93054 +# Source-Hash: 9cc75129edee59ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pocket" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "K Brace" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.pocket" -msgstr "Corredera empotrada" +msgid "node.column.panel.kBrace" +msgstr "Arriostramiento en K" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.position" -msgstr "Posición" +msgid "node.column.panel.move" +msgstr "Mover" -# Source-Hash: 947eacd2689daced +# Source-Hash: 6dc190abd3f22787 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rail" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Neck Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.rail" -msgstr "Travesaño" +msgid "node.column.panel.neckWidth" +msgstr "Ancho del cuello" -# Source-Hash: 3b6f225112035fde +# Source-Hash: 7dba7ed55eeba18f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rect" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.rect" -msgstr "Rect." +msgid "node.column.panel.noBottom" +msgstr "Sin base" -# Source-Hash: c05172113af5a2b8 +# Source-Hash: 682d71815bb20e94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "- Remove" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No Top" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.remove" -msgstr "- Quitar" +msgid "node.column.panel.noTop" +msgstr "Sin capitel" -# Source-Hash: 59236bd016c6b904 +# Source-Hash: 4da8688437f64db8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reveal Radius" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plinth Thickness" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.revealRadius" -msgstr "Radio del derrame" +msgid "node.column.panel.plinthThickness" +msgstr "Grosor del plinto" -# Source-Hash: b34d5ee0f218221d +# Source-Hash: 0bf453b4882c663c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Portal Frame" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.right" -msgstr "Derecha" +msgid "node.column.panel.portalFrame" +msgstr "Pórtico" -# Source-Hash: fc826da6c99303e6 +# Source-Hash: 441f7f652ea6a0d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rounded" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preset" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.rounded" -msgstr "Redondeado" +msgid "node.column.panel.preset" +msgstr "Preajuste" -# Source-Hash: 505d8419cf4cc5e1 +# Source-Hash: f29fef1beeb25f22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segments" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangular" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.segments" -msgstr "Segmentos" +msgid "node.column.panel.rectangular" +msgstr "Rectangular" -# Source-Hash: a8096eb4beaadeef +# Source-Hash: 23b9d290b165cd49 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Size is limited to the wall, including clearance for the opening frame." -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ring Pairs" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.sizeIsLimitedToTheWall" -msgstr "El tamaño está limitado al muro, incluida la holgura del marco del hueco." +msgid "node.column.panel.ringPairs" +msgstr "Pares de anillos" -# Source-Hash: c00de0e2c9b0ddcb +# Source-Hash: 8db82d731a19651e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slide" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ring Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.slide" -msgstr "Deslizar" +msgid "node.column.panel.ringSpread" +msgstr "Separación de anillos" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: bdb524a15d9e1509 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ring Thickness" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.style" -msgstr "Estilo" +msgid "node.column.panel.ringThickness" +msgstr "Grosor de anillos" -# Source-Hash: e48604b5f7b2a5f4 +# Source-Hash: ad0457800a1f0eb4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swing" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.swing" -msgstr "Abatir" +msgid "node.column.panel.round" +msgstr "Redondo" -# Source-Hash: fdbb503f0941bd56 +# Source-Hash: baa84a2d17095dcf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round Band Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.thickness" -msgstr "Espesor" +msgid "node.column.panel.roundBandWidth" +msgstr "Ancho de la banda redonda" -# Source-Hash: f165d6c05be2b651 +# Source-Hash: 5f1f67fb0ca59a6d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Threshold" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rounded Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.threshold" -msgstr "Umbral" +msgid "node.column.panel.roundedBottom" +msgstr "Base redondeada" -# Source-Hash: 7e2505dd1d5e3513 +# Source-Hash: 446816980ed0da27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Shape" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rounded Top" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.topShape" -msgstr "Forma superior" +msgid "node.column.panel.roundedTop" +msgstr "Capitel redondeado" -# Source-Hash: c44f7ab8bbd24858 +# Source-Hash: 9e554c26be80f0d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segment Twist" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.type" -msgstr "Tipo" +msgid "node.column.panel.segmentTwist" +msgstr "Torsión de segmentos" -# Source-Hash: 8038a34ffebf4932 +# Source-Hash: 4fc63ad21de30103 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.vertical" -msgstr "Vertical" +msgid "node.column.panel.shaft" +msgstr "Hueco" -# Source-Hash: 63d6b766151965f9 +# Source-Hash: 9bc3a704a9a96b3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "wall" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Corner Radius" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.wall" -msgstr "muro" +msgid "node.column.panel.shaftCornerRadius" +msgstr "Radio de esquina del fuste" -# Source-Hash: 3a0ccd6c46877a87 +# Source-Hash: 3dab61aeb47e504d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.width" -msgstr "Ancho" +msgid "node.column.panel.shaftWidth" +msgstr "Ancho del fuste" -# Source-Hash: 8421deea35cb5afc +# Source-Hash: 85ea1d3c8b749680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Barn" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.barn" -msgstr "Granero" +msgid "node.column.panel.shape" +msgstr "Forma" -# Source-Hash: f747fbe71717772e +# Source-Hash: 49a2ce13016d4073 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Craftsman" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Short / Stout" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.craftsman" -msgstr "Craftsman" +msgid "node.column.panel.shortStout" +msgstr "Corta / Gruesa" -# Source-Hash: 092033938ca2debb +# Source-Hash: 4637a9a61638cc66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "French" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Simple Block Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.french" -msgstr "Francesa" +msgid "node.column.panel.simpleBlockBottom" +msgstr "Base de bloque simple" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: 9278f9b4a48208b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Simple Top" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.glass" -msgstr "Vidrio" +msgid "node.column.panel.simpleTop" +msgstr "Capitel simple" -# Source-Hash: 6ab8b98b38eb2e65 +# Source-Hash: 9099890734ae1238 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Half-louvered" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single Strut" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.halfLouvered" -msgstr "Media persiana" +msgid "node.column.panel.singleStrut" +msgstr "Puntal único" -# Source-Hash: f6cbdaa17e989b91 +# Source-Hash: d87ce271009ce063 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Modern" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slender" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.modern" -msgstr "Moderno" +msgid "node.column.panel.slender" +msgstr "Esbelta" -# Source-Hash: 482469f5a0873f73 +# Source-Hash: 39287346366fc206 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.panel" -msgstr "Panel" +msgid "node.column.panel.square" +msgstr "Cuadrado" -# Source-Hash: ac42c328610a0edd +# Source-Hash: 2dc84759d8df709d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paneled glass" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square Plinth Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.paneledGlass" -msgstr "Cuarterones con vidrio" +msgid "node.column.panel.squarePlinthBottom" +msgstr "Base de plinto cuadrado" -# Source-Hash: 5b68e435b7210876 +# Source-Hash: d998c212030bc7c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaker" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.shaker" -msgstr "Shaker" +msgid "node.column.panel.standard" +msgstr "Estándar" -# Source-Hash: 9ad6ac42b4152b64 +# Source-Hash: 01a6393135e0fb10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Six-panel" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stepped Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.sixPanel" -msgstr "Seis cuarterones" +msgid "node.column.panel.steppedBottom" +msgstr "Base escalonada" -# Source-Hash: 8421deea35cb5afc +# Source-Hash: 3d7e443797d4146e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Barn" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stepped Top" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.barn" -msgstr "Granero" +msgid "node.column.panel.steppedTop" +msgstr "Capitel escalonado" -# Source-Hash: 3cd71355956a1821 +# Source-Hash: 4ee35f740730ae87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.double" -msgstr "Doble" +msgid "node.column.panel.straight" +msgstr "Recto" -# Source-Hash: 29ff60e662b789fb +# Source-Hash: 6063ae2877faa35d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Folding" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Taper" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.folding" -msgstr "Plegable" +msgid "node.column.panel.taper" +msgstr "Ahusamiento" -# Source-Hash: 092033938ca2debb +# Source-Hash: f86f1f22230596b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "French" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tapered" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.french" -msgstr "Francesa" +msgid "node.column.panel.tapered" +msgstr "Ahusado" -# Source-Hash: c86309fefe89699b +# Source-Hash: 3e7ec47626ee3f22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roll-up" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Depth" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.garageRollup" -msgstr "Enrollable" +msgid "node.column.panel.topDepth" +msgstr "Fondo superior" -# Source-Hash: fb6a868430547544 +# Source-Hash: 0ca9047731784f56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sectional" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Height" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.garageSectional" -msgstr "Seccional" +msgid "node.column.panel.topHeight" +msgstr "Altura superior" -# Source-Hash: 0b5eb64b569db837 +# Source-Hash: 3d8a2be83b5b536a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilt-up" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.garageTiltup" -msgstr "Basculante" +msgid "node.column.panel.topSpread" +msgstr "Apertura superior" -# Source-Hash: e744be60baad6abc +# Source-Hash: f4ae0dc639dbc220 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hinged" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Step Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.hinged" -msgstr "Abatible" +msgid "node.column.panel.topStepSpread" +msgstr "Separación de escalones superiores" -# Source-Hash: ade6246634d93054 +# Source-Hash: 8acc4e843934b086 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pocket" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Tiers" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.pocket" -msgstr "Corredera empotrada" +msgid "node.column.panel.topTiers" +msgstr "Escalones superiores" -# Source-Hash: 18cbc73c5e1590aa +# Source-Hash: a50eb6400611a57c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sliding" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.sliding" -msgstr "Corredera" +msgid "node.column.panel.topWidth" +msgstr "Ancho superior" -# Source-Hash: 387e57242c8d110a +# Source-Hash: f425799b82e085ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "House-shaped protrusion on a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transform" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.description" -msgstr "Saliente con forma de casa en un faldón." +msgid "node.column.panel.transform" +msgstr "Transformación" -# Source-Hash: 6b6f8068bbc4c902 +# Source-Hash: 952fd1ef187c6646 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dormer" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trestle" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.label" -msgstr "Buhardilla" +msgid "node.column.panel.trestle" +msgstr "Caballete" +# Source-Hash: 7430dad59aaf98f4 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tripod" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.depth" -msgstr "Profundidad" +msgid "node.column.panel.tripod" +msgstr "Trípode" +# Source-Hash: 0db559f22647ec73 # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Twist Segments" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.dimensions" -msgstr "Dimensiones" +msgid "node.column.panel.twistSegments" +msgstr "Segmentos de torsión" +# Source-Hash: 8038a34ffebf4932 # Review: required -# Source-Hash: 6b6f8068bbc4c902 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dormer" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.dormer" -msgstr "Buhardilla" +msgid "node.column.panel.vertical" +msgstr "Vertical" +# Source-Hash: f24cc343d79acc10 # Review: required -# Source-Hash: 6949d667043bee0b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "V Support" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.dutch" -msgstr "Holandesa" +msgid "node.column.panel.vSupport" +msgstr "Soporte en V" +# Source-Hash: 44dda7136b93c8ee # Review: required -# Source-Hash: 9cab4d4c95f63cdd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.flat" -msgstr "Plana" +msgid "node.column.panel.waist" +msgstr "Losa" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: deaffa095d126dfe -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.gable" -msgstr "Dos aguas" +msgid "node.column.panel.width" +msgstr "Ancho" +# Source-Hash: 4e6640dfff42cea4 # Review: required -# Source-Hash: 7f53d9ffca39984a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "X Brace" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.gambrel" -msgstr "Holandés de buhardilla" +msgid "node.column.panel.xBrace" +msgstr "Cruz de San Andrés" +# Source-Hash: fefc9b1cfb26b5a8 # Review: required -# Source-Hash: 9eda0ea8d447066d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hip" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Yaw" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.hip" -msgstr "Cuatro aguas" +msgid "node.column.panel.yaw" +msgstr "Guiñada" +# Source-Hash: 86259690e332b66d # Review: required -# Source-Hash: 7f7bb0e875af3260 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Y Support" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.mansard" -msgstr "Mansarda" +msgid "node.column.panel.ySupport" +msgstr "Soporte en Y" +# Source-Hash: 4d3a89de7073d38d # Review: required -# Source-Hash: 53af9efc7eca6594 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pitch Direction" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A {size} deck post stands no taller than {limit} (IRC Table R507.4, by species and the area it carries): check it, or use the next size up." +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.pitchDirection" -msgstr "Dirección de la pendiente" +msgid "node.column.postSection.aSizeDeckPostStandsNo" +msgstr "Un poste de tarima {size} no debe superar {limit} de altura (tabla R507.4 del IRC, según la especie y el área que soporta): compruébalo o usa el tamaño superior." +# Source-Hash: 9e9715d52410c86f # Review: required -# Source-Hash: 6c39ef7125494c4a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pitch Rise" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.pitchRise" -msgstr "Altura de la pendiente" +msgid "node.column.postSection.custom" +msgstr "Personalizado" +# Source-Hash: 31f74f6b8e7f077e # Review: required -# Source-Hash: 96336d4b0820b977 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rise Back" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit to the beam over it ({height})" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.riseBack" -msgstr "Sube hacia atrás" +msgid "node.column.postSection.fitToTheBeamOverIt" +msgstr "Ajustar a la viga superior ({height})" +# Source-Hash: f09c0bf0ea50fc47 # Review: required -# Source-Hash: ee3d45f8b756d029 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rise Front" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit to the ceiling plane ({height})" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.riseFront" -msgstr "Sube hacia delante" +msgid "node.column.postSection.fitToTheCeilingPlane" +msgstr "Ajustar al plano del techo ({height})" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 5e0622f3b09c9326 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Height" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.roofHeight" -msgstr "Altura de cubierta" +msgid "node.column.postSection.height" +msgstr "Altura" +# Source-Hash: b1778491849d76d6 # Review: required -# Source-Hash: 19ab9527ae7889f4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Type" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keep its shape and style it as a column" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.roofType" -msgstr "Tipo de cubierta" +msgid "node.column.postSection.keepItsShapeAndStyleIt" +msgstr "Conservar su forma y darle estilo de pilar" +# Source-Hash: 151f47e85cf7cc8b # Review: required -# Source-Hash: dba6a7b56cf7083f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Section" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Make it a column" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.section" -msgstr "Sección" +msgid "node.column.postSection.makeItAColumn" +msgstr "Convertir en pilar" +# Source-Hash: 5cc981e79d737694 # Review: required -# Source-Hash: c8d0df27faa3feaa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.shed" -msgstr "Un agua" +msgid "node.column.postSection.post" +msgstr "Poste" +# Source-Hash: 64ed304f3773f93d # Review: required -# Source-Hash: e0f973edce3e4ca8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Height" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Treated" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.wallHeight" -msgstr "Altura del muro" +msgid "node.column.postSection.treated" +msgstr "Tratado" +# Source-Hash: 5c362de43a2cbac1 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Untreated" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.width" -msgstr "Ancho" +msgid "node.column.postSection.untreated" +msgstr "Sin tratar" +# Source-Hash: bf2baf3d7b55f0df # Review: required -# Source-Hash: 0b1d1e9a36456a50 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Windows" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A-Frame Support" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.windows" -msgstr "Ventanas" +msgid "node.column.preset.aFrameSupport" +msgstr "Soporte en A" +# Source-Hash: 51cf77bb359cee43 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/dormer/panel-actions-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight Round" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelActionsSection.actions" -msgstr "Acciones" +msgid "node.column.preset.basicPillar" +msgstr "Redonda recta" +# Source-Hash: 39d33008c81fc075 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/dormer/panel-actions-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box Frame" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelActionsSection.delete" -msgstr "Eliminar" +msgid "node.column.preset.boxFrameSupport" +msgstr "Marco cerrado" +# Source-Hash: 4f22058e862d1f81 # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/dormer/panel-actions-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Soft Bulged" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelActionsSection.duplicate" -msgstr "Duplicar" +msgid "node.column.preset.bulgedPillar" +msgstr "Ligeramente abombada" +# Source-Hash: bb851e93088b73a2 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/dormer/panel-actions-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hourglass" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelActionsSection.move" -msgstr "Mover" +msgid "node.column.preset.hourglassPillar" +msgstr "Reloj de arena" +# Source-Hash: 9cc75129edee59ad # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/dormer/panel-position-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "K Brace" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelPositionSection.position" -msgstr "Posición" +msgid "node.column.preset.kBraceSupport" +msgstr "Arriostramiento en K" +# Source-Hash: 0bf453b4882c663c # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/dormer/panel-position-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Portal Frame" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelPositionSection.rotation" -msgstr "Rotación" +msgid "node.column.preset.portalFrameSupport" +msgstr "Pórtico" +# Source-Hash: 9099890734ae1238 # Review: required -# Source-Hash: 7b19d21b9ad868c7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Window" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single Strut" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.addWindow" -msgstr "Añadir ventana" +msgid "node.column.preset.singleStrutSupport" +msgstr "Puntal único" +# Source-Hash: 0c13af329b9b57cd # Review: required -# Source-Hash: 70d7cc5a6422feaa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit {name}" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square Block" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.editNamed" -msgstr "Editar {name}" +msgid "node.column.preset.squarePillar" +msgstr "Bloque cuadrado" +# Source-Hash: 4c294bad84924665 # Review: required -# Source-Hash: b6648f023e6c83dc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit window" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tapered Round" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.editWindow" -msgstr "Editar ventana" +msgid "node.column.preset.taperedPillar" +msgstr "Redonda ahusada" +# Source-Hash: 360e405bfd74a379 # Review: required -# Source-Hash: 4649baf9753aeb74 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Increase the dormer width to add another window." -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trestle Frame" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.increaseTheDormerWidthToAdd" -msgstr "Aumenta el ancho de la buhardilla para añadir otra ventana." +msgid "node.column.preset.trestleSupport" +msgstr "Marco de caballete" +# Source-Hash: 4589103259b4fc4d # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tripod Support" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.move" -msgstr "Mover" +msgid "node.column.preset.tripodSupport" +msgstr "Soporte trípode" +# Source-Hash: f24cc343d79acc10 # Review: required -# Source-Hash: c24226954309d83e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move {name}" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "V Support" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.moveNamed" -msgstr "Mover {name}" +msgid "node.column.preset.vFrameSupport" +msgstr "Soporte en V" +# Source-Hash: 4e6640dfff42cea4 # Review: required -# Source-Hash: f07faaf0d5e43eef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move window" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "X Brace" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.moveWindow" -msgstr "Mover ventana" +msgid "node.column.preset.xBraceSupport" +msgstr "Cruz de San Andrés" +# Source-Hash: 86259690e332b66d # Review: required -# Source-Hash: d2816490ea93d363 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No windows" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Y Support" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.noWindows" -msgstr "Sin ventanas" +msgid "node.column.preset.yFrameSupport" +msgstr "Soporte en Y" +# Source-Hash: 895766ad1b766c2e # Review: required -# Source-Hash: 5cbb24f8b1ce7fb7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Window {number}" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Associative linear, curved, circular, angular, or coordinate plan dimension." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.dormer.panelWindowsSection.windowNumber" -msgstr "Ventana {number}" +msgid "node.constructionDimension.description" +msgstr "Cota de plano asociativa: lineal, curva, circular, angular o de coordenadas." +# Source-Hash: 6875b60ee8a7cc3b # Review: required -# Source-Hash: 9ca7d951240907cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Windows ({length})" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Construction Dimension" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.dormer.panelWindowsSection.windowsLength" -msgstr "Ventanas ({length})" +msgid "node.constructionDimension.label" +msgstr "Cota de construcción" +# Source-Hash: 61a6c6b9bc29c4f8 # Review: required -# Source-Hash: f975c4759607806a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{face, select, back {Back} left {Left} right {Right} other {Front}} · {width} × {height} m" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Left" +#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.windowSummary" -msgstr "{face, select, back {Trasera} left {Izquierda} right {Derecha} other {Frontal}} · {width} × {height} m" +msgid "node.cornerRadius.bottomLeft" +msgstr "Inferior izquierda" -# Source-Hash: b46392d2ea865760 +# Source-Hash: c5368accab136fa6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical drop pipe from a gutter outlet to the ground." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Right" +#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.downspout.description" -msgstr "Tubo vertical desde la salida del canalón hasta el suelo." +msgid "node.cornerRadius.bottomRight" +msgstr "Inferior derecha" +# Source-Hash: c8f86af3f03af6c7 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/downspout/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Left" +#: packages/nodes/src/door/panel.tsx +#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.downspout.inspectorEditors.position" -msgstr "Posición" +msgid "node.cornerRadius.topLeft" +msgstr "Superior izquierda" -# Source-Hash: 1a1ec08a311f1b35 +# Source-Hash: 0ead7f1ffdbbd892 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspout" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Right" +#: packages/nodes/src/door/panel.tsx +#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.downspout.label" -msgstr "Bajante" +msgid "node.cornerRadius.topRight" +msgstr "Superior derecha" -# Source-Hash: 29eadb8c84ae9632 +# Source-Hash: a276c9693f01dec7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elbow, tee, reducer, or square-to-round transition connecting duct runs." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Louvered roof lantern with a dome or pyramid cap and optional finial." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.ductFitting.description" -msgstr "Codo, T, reducción o transición cuadrado-redondo que une conductos." +msgid "node.cupola.description" +msgstr "Linterna de cubierta con lamas, remate en cúpula o pirámide y pináculo opcional." +# Source-Hash: e679dd19f96eba0a # Review: required -# Source-Hash: 7323a0fc9efb077f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swap W/H" -#: packages/nodes/src/duct-fitting/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cupola" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.ductFitting.inspectorEditors.swapWH" -msgstr "Intercambiar An/Al" +msgid "node.cupola.label" +msgstr "Linterna" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 064b36c4fc5deb87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swap width and height" -#: packages/nodes/src/duct-fitting/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductFitting.inspectorEditors.swapWidthAndHeight" -msgstr "Intercambiar ancho y alto" +msgid "node.cupola.panel.actions" +msgstr "Acciones" -# Source-Hash: 6d0c3833d87535e4 +# Source-Hash: e679dd19f96eba0a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct Fitting" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cupola" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductFitting.label" -msgstr "Accesorio de conducto" - +msgid "node.cupola.panel.cupola" +msgstr "Linterna" + +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: dd86efcab72fc5c7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Axis" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductFitting.tool.axis" -msgstr "Eje" +msgid "node.cupola.panel.delete" +msgstr "Eliminar" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: 5232a826549f915e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "⌥ axis" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductFitting.tool.axis2" -msgstr "⌥ eje" +msgid "node.cupola.panel.depth" +msgstr "Profundidad" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: 880b34f6fc0ae854 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a duct face that fits the door" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductFitting.tool.hoverADuctFaceThatFits" -msgstr "Pasa sobre una cara de conducto donde quepa la trampilla" +msgid "node.cupola.panel.dimensions" +msgstr "Dimensiones" +# Source-Hash: de47e23eb81efe02 # Review: required -# Source-Hash: 706f5b43a1d4a84a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place access door" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dome" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductFitting.tool.placeAccessDoor" -msgstr "Colocar trampilla de acceso" +msgid "node.cupola.panel.dome" +msgstr "Cúpula" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductFitting.tool.rTRotate" -msgstr "R/T girar" +msgid "node.cupola.panel.duplicate" +msgstr "Duplicar" -# Source-Hash: 09eb45a9b35d1a9f +# Source-Hash: 1cfe33235b30b1d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "HVAC duct run — polyline of round, rect, or flat-oval sections." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finial" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductSegment.description" -msgstr "Conducto de climatización: polilínea de secciones redondas, rectangulares u ovaladas planas." +msgid "node.cupola.panel.finial" +msgstr "Remate" -# Source-Hash: e971d82044e2f48e +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductSegment.label" -msgstr "Conducto" +msgid "node.cupola.panel.height" +msgstr "Altura" -# Source-Hash: 33181d0f42421013 +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct terminal — supply register, ceiling diffuser, or return grille. Duct runs end at its collar." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductTerminal.description" -msgstr "Terminal de conducto: rejilla de impulsión, difusor de techo o rejilla de retorno. Los conductos terminan en su collarín." +msgid "node.cupola.panel.move" +msgstr "Mover" -# Source-Hash: 161e5386b939e1bc +# Source-Hash: b5e0cb318d484d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Register" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No Finial" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductTerminal.label" -msgstr "Rejilla" +msgid "node.cupola.panel.noFinial" +msgstr "Sin remate" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: 83c665eafcf43a68 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{mount, select, floor {Mount Floor} ceiling {Mount Ceiling} wall {Mount Wall} other {Mount {label}}}" -#: packages/nodes/src/duct-terminal/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductTerminal.tool.mount" -msgstr "{mount, select, floor {Montaje en suelo} ceiling {Montaje en techo} wall {Montaje en pared} other {Montaje {label}}}" +msgid "node.cupola.panel.position" +msgstr "Posición" +# Source-Hash: 47587b825e9a696b # Review: required -# Source-Hash: f067dd52ea051385 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "M surface" -#. Key hint: pressing M switches the mounting surface. -#: packages/nodes/src/duct-terminal/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pyramid" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductTerminal.tool.mSurface" -msgstr "M superficie" +msgid "node.cupola.panel.pyramid" +msgstr "Pirámide" +# Source-Hash: 01989595ee7c1dc0 # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/duct-terminal/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductTerminal.tool.rTRotate" -msgstr "R/T girar" +msgid "node.cupola.panel.rotation" +msgstr "Rotación" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: 98446855908ee71d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapped to duct" -#: packages/nodes/src/duct-terminal/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductTerminal.tool.snappedToDuct" -msgstr "Ajustado al conducto" +msgid "node.cupola.panel.style" +msgstr "Estilo" -# Source-Hash: d0afa386e65cd3a4 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A multi-level elevator shaft with configurable openings per level." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.elevator.description" -msgstr "Hueco de ascensor de varias plantas con aberturas configurables por planta." +msgid "node.cupola.panel.width" +msgstr "Ancho" -# Source-Hash: ab5cbab7be160a1c +# Source-Hash: 5d4ccdf13668fab4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevator" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto elevator cutout" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.elevator.label" -msgstr "Ascensor" +msgid "node.cutout.autoElevator" +msgstr "Recorte automático de ascensor" +# Source-Hash: 78aa03576e02dda7 # Review: required -# Source-Hash: 7e6d5f138e315bdb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Access" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto stair cutout" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.elevator.panel.access" -msgstr "Acceso" +msgid "node.cutout.autoStair" +msgstr "Recorte automático de escalera" +# Source-Hash: e04298381837252f # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.elevator.panel.actions" -msgstr "Acciones" +msgid "node.cutout.opening" +msgstr "Abertura" +# Source-Hash: ce37dbd7a309940b # Review: required -# Source-Hash: fdf7108a011bd94b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cab" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room cutout" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.elevator.panel.cab" -msgstr "Cabina" +msgid "node.cutout.room" +msgstr "Recorte de estancia" +# Source-Hash: b1757d76048706b7 # Review: required -# Source-Hash: 2d0ab44f3820f22c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cab Height" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap hinge side" +#: packages/nodes/src/door/actions.tsx #, fuzzy -msgid "node.elevator.panel.cabHeight" -msgstr "Altura de cabina" +msgid "node.door.actions.swapHingeSide" +msgstr "Cambiar el lado de las bisagras" +# Source-Hash: d8bbb9fdf69726ca # Review: required -# Source-Hash: 65f410261609060b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center opening" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap swing side" +#: packages/nodes/src/door/actions.tsx +#, fuzzy +msgid "node.door.actions.swapSwingSide" +msgstr "Cambiar el sentido de apertura" + +# Source-Hash: 6123b20edb9569de +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A door cut into a wall. Animated open/close state." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.door.description" +msgstr "Puerta abierta en un muro, con apertura y cierre animados." + +# Source-Hash: 787e10f5db16904e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.door.label" +msgstr "Puerta" + +# Source-Hash: aa6d82bdb3cc1d9a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.actions" +msgstr "Acciones" + +# Source-Hash: 8337b3213849faca +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "+ Add Segment" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.addSegment" +msgstr "+ Añadir segmento" + +# Source-Hash: 663175a9c461a96d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.all" +msgstr "Todo" + +# Source-Hash: 710261f5ffb32617 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arch" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.arch" +msgstr "Arco" + +# Source-Hash: 3715cd54e4775087 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arch Height" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.archHeight" +msgstr "Altura del arco" + +# Source-Hash: 05b65242d8c48791 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.auto" +msgstr "Auto" + +# Source-Hash: 8a04486ba122ea7d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto follows the wall" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.autoFollowsTheWall" +msgstr "Auto sigue el muro" + +# Source-Hash: 387773c8aa2820a4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar Height" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.barHeight" +msgstr "Altura de la barra" + +# Source-Hash: 30edd1c180aac9b4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Columns" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.columns" +msgstr "Columnas" + +# Source-Hash: f533584833a4a7bb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Content Padding" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.contentPadding" +msgstr "Relleno del contenido" + +# Source-Hash: 7a90a42b578f2435 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner Radius" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.cornerRadius" +msgstr "Radio de esquina" + +# Source-Hash: aa0e8e02212091e4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom: the segments match no style." +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.customTheSegmentsMatchNoStyle" +msgstr "Personalizado: los segmentos no coinciden con ningún estilo." + +# Source-Hash: b26de372b4b0eaac +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.delete" +msgstr "Eliminar" + +# Source-Hash: 99ac4d03c3061f3a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.depth" +msgstr "Profundidad" + +# Source-Hash: 12df69f42beb0643 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.dimensions" +msgstr "Dimensiones" + +# Source-Hash: 76cd03300faa9b2b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Direction" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.direction" +msgstr "Dirección" + +# Source-Hash: c53c3307e2a2a32a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divider" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.divider" +msgstr "Divisor" + +# Source-Hash: 787e10f5db16904e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.door" +msgstr "Puerta" + +# Source-Hash: 4a0aa7f647e6461b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Closer" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.doorCloser" +msgstr "Cierrapuertas" + +# Source-Hash: 34dc96fe77a31e51 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.duplicate" +msgstr "Duplicar" + +# Source-Hash: 65b1cbba3b92c5b2 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Empty" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.empty" +msgstr "Vacío" + +# Source-Hash: 6982301da2dbe186 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Enable Handle" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.enableHandle" +msgstr "Activar manilla" + +# Source-Hash: 2e96ebf9c6e7fe49 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Enable Threshold" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.enableThreshold" +msgstr "Activar umbral" + +# Source-Hash: 61f9413d3bbabde7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip Side" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.flipSide" +msgstr "Invertir lado" + +# Source-Hash: 7e8fdd28f9d54d1f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fold" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.fold" +msgstr "Pliegue" + +# Source-Hash: ce3a6c03765dbbd8 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.frame" +msgstr "Marco" + +# Source-Hash: 0cce8ae784f78478 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth (auto)" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.frameDepthAuto" +msgstr "Profundidad (auto)" + +# Source-Hash: 53aa825a4737190a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Garage" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.garage" +msgstr "Garaje" + +# Source-Hash: 8ab91094cf650204 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.glass" +msgstr "Vidrio" + +# Source-Hash: 41483b645efc0c65 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handle" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.handle" +msgstr "Manilla" + +# Source-Hash: b4a496a904640583 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handle Side" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.handleSide" +msgstr "Lado de la manilla" + +# Source-Hash: 8c1bc3a078056ff7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hardware" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.hardware" +msgstr "Herrajes" + +# Source-Hash: 646ef0fbcbc58edf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.height" +msgstr "Altura" + +# Source-Hash: 7c8f079bbefe86c9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hinges Side" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.hingesSide" +msgstr "Lado de las bisagras" + +# Source-Hash: ac9c79f08ef130a1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Horizontal" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.horizontal" +msgstr "Horizontal" + +# Source-Hash: 42824e50de26bc14 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Individual" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.individual" +msgstr "Individual" + +# Source-Hash: 3db1dea825785a30 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inset" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.inset" +msgstr "Empotrado" + +# Source-Hash: 1f4ad5ad3e1be222 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inward" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.inward" +msgstr "Hacia dentro" + +# Source-Hash: f365c6b6dd9ebab9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.left" +msgstr "Izquierda" + +# Source-Hash: bd02c614454fbd2b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.move" +msgstr "Mover" + +# Source-Hash: 3e52f04f92e08070 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.open" +msgstr "Abrir" + +# Source-Hash: e04298381837252f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.opening" +msgstr "Abertura" + +# Source-Hash: ecb81bd3eefa6a47 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening Shape" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.openingShape" +msgstr "Forma del hueco" + +# Source-Hash: ccd8f06b8f8d27c9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outward" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.outward" +msgstr "Hacia fuera" + +# Source-Hash: 482469f5a0873f73 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.panel" +msgstr "Panel" + +# Source-Hash: 6ce059aee1386f72 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panels" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.panels" +msgstr "Paneles" + +# Source-Hash: ad56a8ab82ff1a77 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panic Bar" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.panicBar" +msgstr "Barra antipánico" + +# Source-Hash: ade6246634d93054 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pocket" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.pocket" +msgstr "Corredera empotrada" + +# Source-Hash: 9da0cbfad144d737 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.position" +msgstr "Posición" + +# Source-Hash: 947eacd2689daced +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rail" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.rail" +msgstr "Travesaño" + +# Source-Hash: 3b6f225112035fde +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rect" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.rect" +msgstr "Rect." + +# Source-Hash: c05172113af5a2b8 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "- Remove" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.remove" +msgstr "- Quitar" + +# Source-Hash: 59236bd016c6b904 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reveal Radius" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.revealRadius" +msgstr "Radio del derrame" + +# Source-Hash: b34d5ee0f218221d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.right" +msgstr "Derecha" + +# Source-Hash: fc826da6c99303e6 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rounded" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.rounded" +msgstr "Redondeado" + +# Source-Hash: 505d8419cf4cc5e1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segments" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.segments" +msgstr "Segmentos" + +# Source-Hash: a8096eb4beaadeef +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Size is limited to the wall, including clearance for the opening frame." +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.sizeIsLimitedToTheWall" +msgstr "El tamaño está limitado al muro, incluida la holgura del marco del hueco." + +# Source-Hash: c00de0e2c9b0ddcb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slide" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.slide" +msgstr "Deslizar" + +# Source-Hash: 1a79a485d91f3f28 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.style" +msgstr "Estilo" + +# Source-Hash: e48604b5f7b2a5f4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swing" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.swing" +msgstr "Abatir" + +# Source-Hash: fdbb503f0941bd56 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.thickness" +msgstr "Espesor" + +# Source-Hash: f165d6c05be2b651 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Threshold" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.threshold" +msgstr "Umbral" + +# Source-Hash: 7e2505dd1d5e3513 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Shape" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.topShape" +msgstr "Forma superior" + +# Source-Hash: c44f7ab8bbd24858 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.type" +msgstr "Tipo" + +# Source-Hash: 8038a34ffebf4932 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.vertical" +msgstr "Vertical" + +# Source-Hash: 63d6b766151965f9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "wall" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.wall" +msgstr "muro" + +# Source-Hash: 3a0ccd6c46877a87 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.width" +msgstr "Ancho" + +# Source-Hash: 8421deea35cb5afc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Barn" +#: packages/nodes/src/shared/opening-labels.ts +#, fuzzy +msgid "node.door.style.barn" +msgstr "Granero" + +# Source-Hash: f747fbe71717772e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Craftsman" +#: packages/nodes/src/shared/opening-labels.ts +#, fuzzy +msgid "node.door.style.craftsman" +msgstr "Craftsman" + +# Source-Hash: 092033938ca2debb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "French" +#: packages/nodes/src/shared/opening-labels.ts +#, fuzzy +msgid "node.door.style.french" +msgstr "Francesa" + +# Source-Hash: 8ab91094cf650204 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/shared/opening-labels.ts +#, fuzzy +msgid "node.door.style.glass" +msgstr "Vidrio" + +# Source-Hash: 6ab8b98b38eb2e65 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Half-louvered" +#: packages/nodes/src/shared/opening-labels.ts +#, fuzzy +msgid "node.door.style.halfLouvered" +msgstr "Media persiana" + +# Source-Hash: f6cbdaa17e989b91 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modern" +#: packages/nodes/src/shared/opening-labels.ts +#, fuzzy +msgid "node.door.style.modern" +msgstr "Moderno" + +# Source-Hash: 482469f5a0873f73 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel" +#: packages/nodes/src/shared/opening-labels.ts +#, fuzzy +msgid "node.door.style.panel" +msgstr "Panel" + +# Source-Hash: ac42c328610a0edd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paneled glass" +#: packages/nodes/src/shared/opening-labels.ts +#, fuzzy +msgid "node.door.style.paneledGlass" +msgstr "Cuarterones con vidrio" + +# Source-Hash: 5b68e435b7210876 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaker" +#: packages/nodes/src/shared/opening-labels.ts +#, fuzzy +msgid "node.door.style.shaker" +msgstr "Shaker" + +# Source-Hash: 9ad6ac42b4152b64 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Six-panel" +#: packages/nodes/src/shared/opening-labels.ts +#, fuzzy +msgid "node.door.style.sixPanel" +msgstr "Seis cuarterones" + +# Source-Hash: 8421deea35cb5afc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Barn" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.type.barn" +msgstr "Granero" + +# Source-Hash: 3cd71355956a1821 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.type.double" +msgstr "Doble" + +# Source-Hash: 29ff60e662b789fb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Folding" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.type.folding" +msgstr "Plegable" + +# Source-Hash: 092033938ca2debb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "French" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.type.french" +msgstr "Francesa" + +# Source-Hash: c86309fefe89699b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roll-up" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.type.garageRollup" +msgstr "Enrollable" + +# Source-Hash: fb6a868430547544 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sectional" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.type.garageSectional" +msgstr "Seccional" + +# Source-Hash: 0b5eb64b569db837 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilt-up" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.type.garageTiltup" +msgstr "Basculante" + +# Source-Hash: e744be60baad6abc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hinged" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.type.hinged" +msgstr "Abatible" + +# Source-Hash: ade6246634d93054 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pocket" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.type.pocket" +msgstr "Corredera empotrada" + +# Source-Hash: 18cbc73c5e1590aa +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sliding" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.type.sliding" +msgstr "Corredera" + +# Source-Hash: 387e57242c8d110a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "House-shaped protrusion on a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.dormer.description" +msgstr "Saliente con forma de casa en un faldón." + +# Source-Hash: 6b6f8068bbc4c902 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dormer" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.dormer.label" +msgstr "Buhardilla" + +# Source-Hash: 99ac4d03c3061f3a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.depth" +msgstr "Profundidad" + +# Source-Hash: 12df69f42beb0643 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.dimensions" +msgstr "Dimensiones" + +# Source-Hash: 6b6f8068bbc4c902 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dormer" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.dormer" +msgstr "Buhardilla" + +# Source-Hash: 6949d667043bee0b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.dutch" +msgstr "Holandesa" + +# Source-Hash: 9cab4d4c95f63cdd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.flat" +msgstr "Plana" + +# Source-Hash: deaffa095d126dfe +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.gable" +msgstr "Dos aguas" + +# Source-Hash: 7f53d9ffca39984a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.gambrel" +msgstr "Holandés de buhardilla" + +# Source-Hash: 9eda0ea8d447066d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hip" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.hip" +msgstr "Cuatro aguas" + +# Source-Hash: 7f7bb0e875af3260 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.mansard" +msgstr "Mansarda" + +# Source-Hash: 53af9efc7eca6594 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pitch Direction" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.pitchDirection" +msgstr "Dirección de la pendiente" + +# Source-Hash: 6c39ef7125494c4a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pitch Rise" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.pitchRise" +msgstr "Altura de la pendiente" + +# Source-Hash: 96336d4b0820b977 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rise Back" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.riseBack" +msgstr "Sube hacia atrás" + +# Source-Hash: ee3d45f8b756d029 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rise Front" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.riseFront" +msgstr "Sube hacia delante" + +# Source-Hash: 5e0622f3b09c9326 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Height" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.roofHeight" +msgstr "Altura de cubierta" + +# Source-Hash: 19ab9527ae7889f4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Type" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.roofType" +msgstr "Tipo de cubierta" + +# Source-Hash: dba6a7b56cf7083f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Section" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.section" +msgstr "Sección" + +# Source-Hash: c8d0df27faa3feaa +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.shed" +msgstr "Un agua" + +# Source-Hash: e0f973edce3e4ca8 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall Height" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.wallHeight" +msgstr "Altura del muro" + +# Source-Hash: 3a0ccd6c46877a87 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.width" +msgstr "Ancho" + +# Source-Hash: 0b1d1e9a36456a50 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Windows" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.windows" +msgstr "Ventanas" + +# Source-Hash: aa6d82bdb3cc1d9a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/dormer/panel-actions-section.tsx +#, fuzzy +msgid "node.dormer.panelActionsSection.actions" +msgstr "Acciones" + +# Source-Hash: b26de372b4b0eaac +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/dormer/panel-actions-section.tsx +#, fuzzy +msgid "node.dormer.panelActionsSection.delete" +msgstr "Eliminar" + +# Source-Hash: 34dc96fe77a31e51 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/dormer/panel-actions-section.tsx +#, fuzzy +msgid "node.dormer.panelActionsSection.duplicate" +msgstr "Duplicar" + +# Source-Hash: bd02c614454fbd2b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/dormer/panel-actions-section.tsx +#, fuzzy +msgid "node.dormer.panelActionsSection.move" +msgstr "Mover" + +# Source-Hash: 9da0cbfad144d737 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/dormer/panel-position-section.tsx +#, fuzzy +msgid "node.dormer.panelPositionSection.position" +msgstr "Posición" + +# Source-Hash: 01989595ee7c1dc0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/dormer/panel-position-section.tsx +#, fuzzy +msgid "node.dormer.panelPositionSection.rotation" +msgstr "Rotación" + +# Source-Hash: 7b19d21b9ad868c7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Window" +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.addWindow" +msgstr "Añadir ventana" + +# Source-Hash: 70d7cc5a6422feaa +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit {name}" +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.editNamed" +msgstr "Editar {name}" + +# Source-Hash: b6648f023e6c83dc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit window" +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.editWindow" +msgstr "Editar ventana" + +# Source-Hash: 4649baf9753aeb74 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Increase the dormer width to add another window." +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.increaseTheDormerWidthToAdd" +msgstr "Aumenta el ancho de la buhardilla para añadir otra ventana." + +# Source-Hash: bd02c614454fbd2b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.move" +msgstr "Mover" + +# Source-Hash: c24226954309d83e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move {name}" +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.moveNamed" +msgstr "Mover {name}" + +# Source-Hash: f07faaf0d5e43eef +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move window" +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.moveWindow" +msgstr "Mover ventana" + +# Source-Hash: d2816490ea93d363 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No windows" +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.noWindows" +msgstr "Sin ventanas" + +# Source-Hash: 5cbb24f8b1ce7fb7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Window {number}" +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.windowNumber" +msgstr "Ventana {number}" + +# Source-Hash: 9ca7d951240907cd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Windows ({length})" +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.windowsLength" +msgstr "Ventanas ({length})" + +# Source-Hash: f975c4759607806a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{face, select, back {Back} left {Left} right {Right} other {Front}} · {width} × {height} m" +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.windowSummary" +msgstr "{face, select, back {Trasera} left {Izquierda} right {Derecha} other {Frontal}} · {width} × {height} m" + +# Source-Hash: b46392d2ea865760 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical drop pipe from a gutter outlet to the ground." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.downspout.description" +msgstr "Tubo vertical desde la salida del canalón hasta el suelo." + +# Source-Hash: 9da0cbfad144d737 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/downspout/inspector-editors.tsx +#, fuzzy +msgid "node.downspout.inspectorEditors.position" +msgstr "Posición" + +# Source-Hash: 1a1ec08a311f1b35 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspout" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.downspout.label" +msgstr "Bajante" + +# Source-Hash: 29eadb8c84ae9632 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elbow, tee, reducer, or square-to-round transition connecting duct runs." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.ductFitting.description" +msgstr "Codo, T, reducción o transición cuadrado-redondo que une conductos." + +# Source-Hash: 7323a0fc9efb077f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap W/H" +#: packages/nodes/src/duct-fitting/inspector-editors.tsx +#, fuzzy +msgid "node.ductFitting.inspectorEditors.swapWH" +msgstr "Intercambiar An/Al" + +# Source-Hash: 064b36c4fc5deb87 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap width and height" +#: packages/nodes/src/duct-fitting/inspector-editors.tsx +#, fuzzy +msgid "node.ductFitting.inspectorEditors.swapWidthAndHeight" +msgstr "Intercambiar ancho y alto" + +# Source-Hash: 6d0c3833d87535e4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct Fitting" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.ductFitting.label" +msgstr "Accesorio de conducto" + +# Source-Hash: dd86efcab72fc5c7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Axis" +#: packages/nodes/src/duct-fitting/tool.tsx +#, fuzzy +msgid "node.ductFitting.tool.axis" +msgstr "Eje" + +# Source-Hash: 5232a826549f915e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "⌥ axis" +#: packages/nodes/src/duct-fitting/tool.tsx +#, fuzzy +msgid "node.ductFitting.tool.axis2" +msgstr "⌥ eje" + +# Source-Hash: 880b34f6fc0ae854 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a duct face that fits the door" +#: packages/nodes/src/duct-fitting/tool.tsx +#, fuzzy +msgid "node.ductFitting.tool.hoverADuctFaceThatFits" +msgstr "Pasa sobre una cara de conducto donde quepa la trampilla" + +# Source-Hash: 706f5b43a1d4a84a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place access door" +#: packages/nodes/src/duct-fitting/tool.tsx +#, fuzzy +msgid "node.ductFitting.tool.placeAccessDoor" +msgstr "Colocar trampilla de acceso" + +# Source-Hash: 8fb180251a321cef +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/duct-fitting/tool.tsx +#, fuzzy +msgid "node.ductFitting.tool.rTRotate" +msgstr "R/T girar" + +# Source-Hash: 09eb45a9b35d1a9f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "HVAC duct run — polyline of round, rect, or flat-oval sections." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.ductSegment.description" +msgstr "Conducto de climatización: polilínea de secciones redondas, rectangulares u ovaladas planas." + +# Source-Hash: e971d82044e2f48e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.ductSegment.label" +msgstr "Conducto" + +# Source-Hash: 33181d0f42421013 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct terminal — supply register, ceiling diffuser, or return grille. Duct runs end at its collar." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.ductTerminal.description" +msgstr "Terminal de conducto: rejilla de impulsión, difusor de techo o rejilla de retorno. Los conductos terminan en su collarín." + +# Source-Hash: 161e5386b939e1bc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Register" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.ductTerminal.label" +msgstr "Rejilla" + +# Source-Hash: 83c665eafcf43a68 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{mount, select, floor {Mount Floor} ceiling {Mount Ceiling} wall {Mount Wall} other {Mount {label}}}" +#: packages/nodes/src/duct-terminal/tool.tsx +#, fuzzy +msgid "node.ductTerminal.tool.mount" +msgstr "{mount, select, floor {Montaje en suelo} ceiling {Montaje en techo} wall {Montaje en pared} other {Montaje {label}}}" + +# Source-Hash: f067dd52ea051385 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "M surface" +#. Key hint: pressing M switches the mounting surface. +#: packages/nodes/src/duct-terminal/tool.tsx +#, fuzzy +msgid "node.ductTerminal.tool.mSurface" +msgstr "M superficie" + +# Source-Hash: 8fb180251a321cef +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/duct-terminal/tool.tsx +#, fuzzy +msgid "node.ductTerminal.tool.rTRotate" +msgstr "R/T girar" + +# Source-Hash: 98446855908ee71d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapped to duct" +#: packages/nodes/src/duct-terminal/tool.tsx +#, fuzzy +msgid "node.ductTerminal.tool.snappedToDuct" +msgstr "Ajustado al conducto" + +# Source-Hash: d0afa386e65cd3a4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A multi-level elevator shaft with configurable openings per level." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.elevator.description" +msgstr "Hueco de ascensor de varias plantas con aberturas configurables por planta." + +# Source-Hash: ab5cbab7be160a1c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevator" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.elevator.label" +msgstr "Ascensor" + +# Source-Hash: 7e6d5f138e315bdb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Access" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.access" +msgstr "Acceso" + +# Source-Hash: aa6d82bdb3cc1d9a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.actions" +msgstr "Acciones" + +# Source-Hash: fdf7108a011bd94b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cab" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.cab" +msgstr "Cabina" + +# Source-Hash: 2d0ab44f3820f22c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cab Height" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.cabHeight" +msgstr "Altura de cabina" + +# Source-Hash: 65f410261609060b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center opening" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.centerOpening" +msgstr "Apertura central" + +# Source-Hash: c5433f4d3ea8a8a7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default Floor" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.defaultFloor" +msgstr "Planta predeterminada" + +# Source-Hash: b26de372b4b0eaac +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.delete" +msgstr "Eliminar" + +# Source-Hash: 99ac4d03c3061f3a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.depth" +msgstr "Profundidad" + +# Source-Hash: 748877ae309c313c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Destination" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.destination" +msgstr "Destino" + +# Source-Hash: 3bff69bd74544339 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Disabled" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.disabled" +msgstr "Desactivado" + +# Source-Hash: d8baf402fa9c52f0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Height" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.doorHeight" +msgstr "Altura de puerta" + +# Source-Hash: 20f60b98de67849b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Doors" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.doors" +msgstr "Puertas" + +# Source-Hash: eb0d4023a513b16c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Time" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.doorTime" +msgstr "Tiempo de puerta" + +# Source-Hash: b3e001acdb1f869d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Type" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.doorType" +msgstr "Tipo de puerta" + +# Source-Hash: c6203a69fdf44065 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Width" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.doorWidth" +msgstr "Ancho de puerta" + +# Source-Hash: 34dc96fe77a31e51 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.duplicate" +msgstr "Duplicar" + +# Source-Hash: eb3abe5340b26138 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dwell" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.dwell" +msgstr "Tiempo de parada" + +# Source-Hash: ab5cbab7be160a1c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevator" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.elevator" +msgstr "Ascensor" + +# Source-Hash: 702140636ff3977a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "From" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.from" +msgstr "Desde" + +# Source-Hash: 8ab91094cf650204 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.glass" +msgstr "Vidrio" + +# Source-Hash: 88810658a2b97bc6 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass frame" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.glassFrame" +msgstr "Marco de vidrio" + +# Source-Hash: c0ff16d77ebc9593 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Motion" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.motion" +msgstr "Movimiento" + +# Source-Hash: bd02c614454fbd2b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.move" +msgstr "Mover" + +# Source-Hash: 825ac8855353a4e1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening Style" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.openingStyle" +msgstr "Tipo de apertura" + +# Source-Hash: 9da0cbfad144d737 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.position" +msgstr "Posición" + +# Source-Hash: 01989595ee7c1dc0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.rotation" +msgstr "Rotación" + +# Source-Hash: f9a95d8407fafda4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segmented panel" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.segmentedPanel" +msgstr "Panel segmentado" + +# Source-Hash: aa7b49b13f96057f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Service" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.service" +msgstr "Servicio" + +# Source-Hash: 4fc63ad21de30103 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.shaft" +msgstr "Hueco" + +# Source-Hash: 6605ade39317cd42 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Depth" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.shaftDepth" +msgstr "Fondo del hueco" + +# Source-Hash: b28db5a3a48fe52e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Style" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.shaftStyle" +msgstr "Estilo del hueco" + +# Source-Hash: 3dab61aeb47e504d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Width" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.shaftWidth" +msgstr "Ancho del hueco" + +# Source-Hash: aee3b2bd78c87d0b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single left" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.singleLeft" +msgstr "Simple izquierda" + +# Source-Hash: cc43ffbef4ac7ae0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single right" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.singleRight" +msgstr "Simple derecha" + +# Source-Hash: ef3e765e692faf4c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.solid" +msgstr "Sólido" + +# Source-Hash: 8008b6f17089beaf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid panel" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.solidPanel" +msgstr "Panel opaco" + +# Source-Hash: 3b006be0b1f0493f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Speed" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.speed" +msgstr "Velocidad" + +# Source-Hash: 6d37a1679fa3708e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stop {stopOrder}" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.stopStoporder" +msgstr "Parada {stopOrder}" + +# Source-Hash: b3214a20e45a7aed +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "To" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.to" +msgstr "Hasta" + +# Source-Hash: 1a5ccd607c400d76 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall Thickness" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.wallThickness" +msgstr "Grosor de pared" + +# Source-Hash: 3a0ccd6c46877a87 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.width" +msgstr "Ancho" + +# Source-Hash: fefc9b1cfb26b5a8 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Yaw" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.yaw" +msgstr "Guiñada" + +# Source-Hash: 7b22c91cf520e161 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low curved lens-shaped roof vent with a louvered front." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.eyebrowVent.description" +msgstr "Respiradero de cubierta bajo, curvo y lenticular con frente de lamas." + +# Source-Hash: 654b29319185ac66 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eyebrow Vent" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.eyebrowVent.label" +msgstr "Respiradero de ceja" + +# Source-Hash: aa6d82bdb3cc1d9a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.actions" +msgstr "Acciones" + +# Source-Hash: abc97377800a8333 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back height" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.backHeight" +msgstr "Altura trasera" + +# Source-Hash: b26de372b4b0eaac +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.delete" +msgstr "Eliminar" + +# Source-Hash: 99ac4d03c3061f3a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.depth" +msgstr "Profundidad" + +# Source-Hash: 12df69f42beb0643 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.dimensions" +msgstr "Dimensiones" + +# Source-Hash: 34dc96fe77a31e51 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.duplicate" +msgstr "Duplicar" + +# Source-Hash: 654b29319185ac66 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eyebrow Vent" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.eyebrowVent" +msgstr "Respiradero de ceja" + +# Source-Hash: a2d107a5deaa01f4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Half-round" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.halfRound" +msgstr "Media caña" + +# Source-Hash: 646ef0fbcbc58edf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.height" +msgstr "Altura" + +# Source-Hash: 318192f27a774fb7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Louvers" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.louvers" +msgstr "Lamas" + +# Source-Hash: bd02c614454fbd2b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.move" +msgstr "Mover" + +# Source-Hash: 9da0cbfad144d737 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.position" +msgstr "Posición" + +# Source-Hash: 01989595ee7c1dc0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.rotation" +msgstr "Rotación" + +# Source-Hash: e16f85e4bebfefb1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scoop" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.scoop" +msgstr "Cuchara" + +# Source-Hash: ec53d40877e11b62 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slant-box" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.slantBox" +msgstr "Caja inclinada" + +# Source-Hash: 1a79a485d91f3f28 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.style" +msgstr "Estilo" + +# Source-Hash: 3a0ccd6c46877a87 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.width" +msgstr "Ancho" + +# Source-Hash: 20032fe9430f610d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A straight or curved fence segment with configurable posts and infill." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.fence.description" +msgstr "Tramo de valla recto o curvo con postes y relleno configurables." + +# Source-Hash: 6f84b85097bc1ffc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add point after" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.addPointAfter" +msgstr "Añadir punto después" + +# Source-Hash: 1a15ab3101e2d166 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a slab or shaped surface on this level." +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.chooseASlabOrShapedSurface" +msgstr "Elige una losa o una superficie modelada en esta planta." + +# Source-Hash: 78a5625401384000 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a surface" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.chooseASurface" +msgstr "Elegir una superficie" + +# Source-Hash: 2ee121dca87bb64a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.corner" +msgstr "Esquina" + +# Source-Hash: f08fbb462e9afc0e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curve" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.curve" +msgstr "Curva" + +# Source-Hash: a028e08962c388e0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curved" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.curved" +msgstr "Curvo" + +# Source-Hash: 81b75058b7843a0c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{style, select, picket {Distribution controls pickets in each bay between posts.} horizontal {Distribution controls posts along the full fence.} other {Distribution controls infill pieces between the two end posts.}} Spacing is measured between centers. The available width limits the count so pieces do not overlap." +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.distributionInfo" +msgstr "{style, select, picket {La distribución controla los listones de cada tramo entre postes.} horizontal {La distribución controla los postes a lo largo de toda la valla.} other {La distribución controla las piezas de relleno entre los dos postes extremos.}} La separación se mide entre centros. El ancho disponible limita la cantidad para que las piezas no se solapen." + +# Source-Hash: fbc8f54b0e3fdeb1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit path" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.editPath" +msgstr "Editar trazado" + +# Source-Hash: 55686db44529c013 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Extend path" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.extendPath" +msgstr "Prolongar trazado" + +# Source-Hash: 0bf0f27e631aa98d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow highest surface" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.followHighestSurface" +msgstr "Seguir la superficie más alta" + +# Source-Hash: e0b381fcb05a65c4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow selected surface" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.followSelectedSurface" +msgstr "Seguir la superficie seleccionada" + +# Source-Hash: c418d97f803af8dd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hold starting height" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.holdStartingHeight" +msgstr "Mantener la altura inicial" + +# Source-Hash: 295ca9336dc1935b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Join" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.join" +msgstr "Unir" + +# Source-Hash: 643687bc3adaac76 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.length" +msgstr "Longitud" + +# Source-Hash: 1fedc8a2f2ea6887 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {{number} point} other {{number} points}} · {length} m" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.pathSummary" +msgstr "{count, plural, one {{number} punto} many {{number} puntos} other {{number} puntos}} · {length} m" + +# Source-Hash: c96d499e11181429 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket rail projection" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.picketRailProjection" +msgstr "Saliente de los listones sobre el travesaño" + +# Source-Hash: a1880fca8372d06f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Point" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.point" +msgstr "Punto" + +# Source-Hash: 39bc6254b5307f53 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove point" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.removePoint" +msgstr "Quitar punto" + +# Source-Hash: ea56af3a0d7a65e4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set each span to straight or curved, then drag its points and curve handles in either view." +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.setEachSpanToStraightOr" +msgstr "Haz que cada tramo sea recto o curvo y luego arrastra sus puntos y tiradores de curva en cualquiera de las vistas." + +# Source-Hash: 354c8bc5c8da5a6e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Smooth" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.smooth" +msgstr "Suavizar" + +# Source-Hash: 3c700cc1299a150f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Span to point {number}" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.spanToPointNumber" +msgstr "Tramo hasta el punto {number}" + +# Source-Hash: 4ee35f740730ae87 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.straight" +msgstr "Recto" + +# Source-Hash: 78a454b7ac7a3cd9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.surface" +msgstr "Superficie" + +# Source-Hash: ab2de0428c093018 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface behavior" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.surfaceBehavior" +msgstr "Comportamiento en la superficie" + +# Source-Hash: 02042fde61b5aa11 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fence" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.elevator.panel.centerOpening" -msgstr "Apertura central" +msgid "node.fence.label" +msgstr "Valla" +# Source-Hash: 3e07a9889c1bd7f9 # Review: required -# Source-Hash: c5433f4d3ea8a8a7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default Floor" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Detach endpoint" +#: packages/nodes/src/fence/move-endpoint-tool.tsx #, fuzzy -msgid "node.elevator.panel.defaultFloor" -msgstr "Planta predeterminada" +msgid "node.fence.moveEndpointTool.detachEndpoint" +msgstr "Separar extremo" +# Source-Hash: 7a3ce9fec6370e3e # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag endpoint" +#: packages/nodes/src/fence/move-endpoint-tool.tsx #, fuzzy -msgid "node.elevator.panel.delete" -msgstr "Eliminar" +msgid "node.fence.moveEndpointTool.dragEndpoint" +msgstr "Arrastrar extremo" +# Source-Hash: d7cf5045c01b2eb9 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close" +#: packages/nodes/src/fence-feature/actions.tsx #, fuzzy -msgid "node.elevator.panel.depth" -msgstr "Profundidad" +msgid "node.fenceFeature.actions.close" +msgstr "Cerrar" +# Source-Hash: 3e52f04f92e08070 # Review: required -# Source-Hash: 748877ae309c313c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Destination" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/fence-feature/actions.tsx #, fuzzy -msgid "node.elevator.panel.destination" -msgstr "Destino" +msgid "node.fenceFeature.actions.open" +msgstr "Abrir" +# Source-Hash: fc4cf2bc034fc547 # Review: required -# Source-Hash: 3bff69bd74544339 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Disabled" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Board width" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.disabled" -msgstr "Desactivado" +msgid "node.fenceFeature.inspector.boardWidth" +msgstr "Ancho de tabla" +# Source-Hash: f3b11e5b2dd3b25f # Review: required -# Source-Hash: d8baf402fa9c52f0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Height" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bracing" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.doorHeight" -msgstr "Altura de puerta" +msgid "node.fenceFeature.inspector.bracing" +msgstr "Arriostramiento" +# Source-Hash: d09ec3d9565734c3 # Review: required -# Source-Hash: 20f60b98de67849b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Doors" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Distance from start" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.doors" -msgstr "Puertas" +msgid "node.fenceFeature.inspector.distanceFromStart" +msgstr "Distancia desde el inicio" +# Source-Hash: dcd803eaf3796298 # Review: required -# Source-Hash: eb0d4023a513b16c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Time" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fence unavailable." +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.doorTime" -msgstr "Tiempo de puerta" +msgid "node.fenceFeature.inspector.fenceUnavailable" +msgstr "Valla no disponible." +# Source-Hash: 3519d91b7bda18a5 # Review: required -# Source-Hash: b3e001acdb1f869d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Type" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame width" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.doorType" -msgstr "Tipo de puerta" +msgid "node.fenceFeature.inspector.frameWidth" +msgstr "Ancho del marco" +# Source-Hash: cb18554b2420e700 # Review: required -# Source-Hash: c6203a69fdf44065 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Width" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gate height" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.doorWidth" -msgstr "Ancho de puerta" +msgid "node.fenceFeature.inspector.gateHeight" +msgstr "Altura de la puerta" +# Source-Hash: 54098b5ee574737a # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gate style" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.duplicate" -msgstr "Duplicar" +msgid "node.fenceFeature.inspector.gateStyle" +msgstr "Estilo de puerta de valla" +# Source-Hash: 4fc3e60be28f60d5 # Review: required -# Source-Hash: eb3abe5340b26138 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dwell" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground clearance" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.dwell" -msgstr "Tiempo de parada" +msgid "node.fenceFeature.inspector.groundClearance" +msgstr "Separación al suelo" +# Source-Hash: 916f2e07bf082795 # Review: required -# Source-Hash: ab5cbab7be160a1c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevator" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hinges and latch" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.elevator" -msgstr "Ascensor" +msgid "node.fenceFeature.inspector.hingesAndLatch" +msgstr "Bisagras y pestillo" +# Source-Hash: 5bd2e597fbb2a2c9 # Review: required -# Source-Hash: 702140636ff3977a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "From" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hinge side" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.from" -msgstr "Desde" +msgid "node.fenceFeature.inspector.hingeSide" +msgstr "Lado de las bisagras" +# Source-Hash: 8fec7e969045a8e7 # Review: required -# Source-Hash: 8ab91094cf650204 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Horizontal boards" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.glass" -msgstr "Vidrio" +msgid "node.fenceFeature.inspector.horizontalBoards" +msgstr "Tablas horizontales" +# Source-Hash: f4addad87cc4223e # Review: required -# Source-Hash: 88810658a2b97bc6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass frame" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Infill spacing" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.glassFrame" -msgstr "Marco de vidrio" +msgid "node.fenceFeature.inspector.infillSpacing" +msgstr "Separación del relleno" +# Source-Hash: cdec08b292742b20 # Review: required -# Source-Hash: c0ff16d77ebc9593 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Motion" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Jamb posts" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.motion" -msgstr "Movimiento" +msgid "node.fenceFeature.inspector.jambPosts" +msgstr "Postes de jamba" +# Source-Hash: ef88410453ee7414 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keep the opening inside the fence and clear of other gates or passages." +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.move" -msgstr "Mover" +msgid "node.fenceFeature.inspector.keepTheOpeningInsideTheFence" +msgstr "Mantén la abertura dentro de la valla y lejos de otras puertas o pasos." +# Source-Hash: 67cd0171b226fedb # Review: required -# Source-Hash: 825ac8855353a4e1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening Style" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Leaf thickness" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.openingStyle" -msgstr "Tipo de apertura" +msgid "node.fenceFeature.inspector.leafThickness" +msgstr "Grosor de la hoja" +# Source-Hash: c390ba248e629b9e # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Leaves" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.position" -msgstr "Posición" +msgid "node.fenceFeature.inspector.leaves" +msgstr "Hojas" +# Source-Hash: d7bb934589475512 # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left leaf proportion" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.rotation" -msgstr "Rotación" +msgid "node.fenceFeature.inspector.leftLeafProportion" +msgstr "Proporción de la hoja izquierda" +# Source-Hash: aa9fe0ebace8957d # Review: required -# Source-Hash: f9a95d8407fafda4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segmented panel" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match fence height" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.segmentedPanel" -msgstr "Panel segmentado" +msgid "node.fenceFeature.inspector.matchFenceHeight" +msgstr "Igualar altura de la valla" +# Source-Hash: c15c1af69ec5c1eb # Review: required -# Source-Hash: aa7b49b13f96057f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Service" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match fence style" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.service" -msgstr "Servicio" +msgid "node.fenceFeature.inspector.matchFenceStyle" +msgstr "Igualar el estilo de la valla" +# Source-Hash: 51b7ab6a0a78d90a # Review: required -# Source-Hash: 4fc63ad21de30103 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening angle" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.shaft" -msgstr "Hueco" +msgid "node.fenceFeature.inspector.openingAngle" +msgstr "Ángulo de apertura" +# Source-Hash: d2e20300c07aa722 # Review: required -# Source-Hash: 6605ade39317cd42 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Depth" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening width" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.shaftDepth" -msgstr "Fondo del hueco" +msgid "node.fenceFeature.inspector.openingWidth" +msgstr "Ancho de la abertura" +# Source-Hash: 6b108fb1d0eb8f9d # Review: required -# Source-Hash: b28db5a3a48fe52e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Style" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open rails" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.shaftStyle" -msgstr "Estilo del hueco" +msgid "node.fenceFeature.inspector.openRails" +msgstr "Barandas abiertas" +# Source-Hash: d500c4b7827d3390 # Review: required -# Source-Hash: 3dab61aeb47e504d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Width" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cross" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.shaftWidth" -msgstr "Ancho del hueco" +msgid "node.fenceFeature.inspector.option.cross" +msgstr "Cruz" +# Source-Hash: 7420c0d2caee1c22 # Review: required -# Source-Hash: aee3b2bd78c87d0b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single left" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diagonal" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.singleLeft" -msgstr "Simple izquierda" +msgid "node.fenceFeature.inspector.option.diagonal" +msgstr "Diagonal" +# Source-Hash: 7308869944020839 # Review: required -# Source-Hash: cc43ffbef4ac7ae0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single right" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double gate" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.singleRight" -msgstr "Simple derecha" +msgid "node.fenceFeature.inspector.option.doubleGate" +msgstr "Puerta doble" +# Source-Hash: 1f4ad5ad3e1be222 # Review: required -# Source-Hash: ef3e765e692faf4c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inward" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.solid" -msgstr "Sólido" +msgid "node.fenceFeature.inspector.option.inward" +msgstr "Hacia dentro" +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# Source-Hash: 8008b6f17089beaf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid panel" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.solidPanel" -msgstr "Panel opaco" +msgid "node.fenceFeature.inspector.option.left" +msgstr "Izquierda" +# Source-Hash: f2953d2931e36d0c # Review: required -# Source-Hash: 3b006be0b1f0493f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Speed" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.speed" -msgstr "Velocidad" +msgid "node.fenceFeature.inspector.option.none" +msgstr "Ninguno" +# Source-Hash: ccd8f06b8f8d27c9 # Review: required -# Source-Hash: 6d37a1679fa3708e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stop {stopOrder}" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outward" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.stopStoporder" -msgstr "Parada {stopOrder}" +msgid "node.fenceFeature.inspector.option.outward" +msgstr "Hacia fuera" +# Source-Hash: b34d5ee0f218221d # Review: required -# Source-Hash: b3214a20e45a7aed -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "To" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.to" -msgstr "Hasta" +msgid "node.fenceFeature.inspector.option.right" +msgstr "Derecha" +# Source-Hash: d327097d9ac1099f # Review: required -# Source-Hash: 1a5ccd607c400d76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Thickness" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single gate" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.wallThickness" -msgstr "Grosor de pared" +msgid "node.fenceFeature.inspector.option.singleGate" +msgstr "Puerta simple" +# Source-Hash: 9295ddc2805b21e2 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.width" -msgstr "Ancho" +msgid "node.fenceFeature.inspector.picket" +msgstr "Estacas" +# Source-Hash: 8dd5999b235f60ab # Review: required -# Source-Hash: fefc9b1cfb26b5a8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Yaw" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post height" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.yaw" -msgstr "Guiñada" +msgid "node.fenceFeature.inspector.postHeight" +msgstr "Altura de los postes" -# Source-Hash: 7b22c91cf520e161 +# Source-Hash: 90bcd7a8123ec343 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low curved lens-shaped roof vent with a louvered front." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove gate" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.eyebrowVent.description" -msgstr "Respiradero de cubierta bajo, curvo y lenticular con frente de lamas." +msgid "node.fenceFeature.inspector.removeGate" +msgstr "Quitar puerta" -# Source-Hash: 654b29319185ac66 +# Source-Hash: 7e3505710613543f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Eyebrow Vent" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove opening" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.eyebrowVent.label" -msgstr "Respiradero de ceja" +msgid "node.fenceFeature.inspector.removeOpening" +msgstr "Quitar abertura" +# Source-Hash: af6f8885fe0fa4e9 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid privacy" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.eyebrowVent.panel.actions" -msgstr "Acciones" +msgid "node.fenceFeature.inspector.solidPrivacy" +msgstr "Privacidad total" +# Source-Hash: 1a7048255c3bdfcb # Review: required -# Source-Hash: abc97377800a8333 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back height" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swing direction" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.eyebrowVent.panel.backHeight" -msgstr "Altura trasera" +msgid "node.fenceFeature.inspector.swingDirection" +msgstr "Sentido de apertura" +# Source-Hash: eba3df14a2de0812 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical slats" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.eyebrowVent.panel.delete" -msgstr "Eliminar" +msgid "node.fenceFeature.inspector.verticalSlats" +msgstr "Lamas verticales" +# Source-Hash: df61821ed00852d8 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A gate hosted by a fence." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.depth" -msgstr "Profundidad" +msgid "node.fenceGate.description" +msgstr "Puerta alojada en una valla." +# Source-Hash: 4a479aa23542d766 # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gate" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.dimensions" -msgstr "Dimensiones" +msgid "node.fenceGate.label" +msgstr "Puerta de valla" +# Source-Hash: 8f9c927d79796c26 # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An intentional opening in a fence." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.duplicate" -msgstr "Duplicar" +msgid "node.fenceOpening.description" +msgstr "Abertura intencionada en una valla." +# Source-Hash: ab67bb47e647d594 # Review: required -# Source-Hash: 654b29319185ac66 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Eyebrow Vent" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open Passage" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.eyebrowVent" -msgstr "Respiradero de ceja" +msgid "node.fenceOpening.label" +msgstr "Paso abierto" +# Source-Hash: dc3adf0c2d50dba6 # Review: required -# Source-Hash: a2d107a5deaa01f4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Half-round" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor opening" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.halfRound" -msgstr "Media caña" +msgid "node.floorOpening.label" +msgstr "Hueco de forjado" +# Source-Hash: 2f4fac2b1d39fdb1 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A measurement / reference annotation (linear, area, or arc)." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.height" -msgstr "Altura" +msgid "node.guide.description" +msgstr "Anotación de medida o referencia (lineal, área o arco)." +# Source-Hash: 1344ea2602e3aa9e # Review: required -# Source-Hash: 318192f27a774fb7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Louvers" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guide" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.louvers" -msgstr "Lamas" +msgid "node.guide.label" +msgstr "Guía" +# Source-Hash: 5402d634f40b2f97 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rain-water channel running along the eave of a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.move" -msgstr "Mover" +msgid "node.gutter.description" +msgstr "Canal de agua de lluvia a lo largo del alero de un faldón." +# Source-Hash: fc7d4ecf973db135 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Downspout" +#: packages/nodes/src/gutter/downspouts-panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.position" -msgstr "Posición" +msgid "node.gutter.downspoutsPanel.addDownspout" +msgstr "Añadir bajante" +# Source-Hash: 9b9929bac2c39bca # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspout {number}" +#: packages/nodes/src/gutter/downspouts-panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.rotation" -msgstr "Rotación" +msgid "node.gutter.downspoutsPanel.downspoutNumber" +msgstr "Bajante {number}" +# Source-Hash: fc34d45725838141 # Review: required -# Source-Hash: e16f85e4bebfefb1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scoop" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspouts" +#: packages/nodes/src/gutter/downspouts-panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.scoop" -msgstr "Cuchara" +msgid "node.gutter.downspoutsPanel.downspouts" +msgstr "Bajantes" +# Source-Hash: ac329c74056f0616 # Review: required -# Source-Hash: ec53d40877e11b62 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slant-box" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove downspout" +#: packages/nodes/src/gutter/downspouts-panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.slantBox" -msgstr "Caja inclinada" +msgid "node.gutter.downspoutsPanel.removeDownspout" +msgstr "Quitar bajante" +# Source-Hash: 14ba981da3627ae2 # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gutter" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.style" -msgstr "Estilo" +msgid "node.gutter.label" +msgstr "Canalón" +# Source-Hash: 387082cd5f118bed # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Manual" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.width" -msgstr "Ancho" +msgid "node.hole.manual" +msgstr "Manual" -# Source-Hash: 20032fe9430f610d +# Source-Hash: fffde6fa82e65ffc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A straight or curved fence segment with configurable posts and infill." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hole {number} (Editing)" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.fence.description" -msgstr "Tramo de valla recto o curvo con postes y relleno configurables." +msgid "node.holeEditing" +msgstr "Hueco {number} (editando)" +# Source-Hash: 0fe446c72451e4a5 # Review: required -# Source-Hash: 6f84b85097bc1ffc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add point after" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hole {number}" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.addPointAfter" -msgstr "Añadir punto después" +msgid "node.holeNumber" +msgstr "Hueco {number}" +# Source-Hash: 8eeeb79ff4221939 # Review: required -# Source-Hash: 1a15ab3101e2d166 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a slab or shaped surface on this level." -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} {unit} · {count, plural, one {{points} pt} other {{points} pts}} · {source}" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.chooseASlabOrShapedSurface" -msgstr "Elige una losa o una superficie modelada en esta planta." +msgid "node.holeSummary" +msgstr "{area} {unit} · {count, plural, one {{points} pto} many {{points} ptos} other {{points} ptos}} · {source}" +# Source-Hash: 50e9252d30f3fb4d # Review: required -# Source-Hash: 78a5625401384000 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a surface" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Furnace, air handler, or condenser — duct runs connect to its supply/return collars." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fence.inspectorEditors.chooseASurface" -msgstr "Elegir una superficie" +msgid "node.hvacEquipment.description" +msgstr "Caldera, climatizadora o condensadora: los conductos se conectan a sus collarines de impulsión y retorno." +# Source-Hash: 3bf1c1a8dbb93743 # Review: required -# Source-Hash: 2ee121dca87bb64a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "HVAC Unit" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fence.inspectorEditors.corner" -msgstr "Esquina" +msgid "node.hvacEquipment.label" +msgstr "Equipo de climatización" +# Source-Hash: 8fb180251a321cef # Review: required -# Source-Hash: f08fbb462e9afc0e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curve" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/hvac-equipment/tool.tsx #, fuzzy -msgid "node.fence.inspectorEditors.curve" -msgstr "Curva" +msgid "node.hvacEquipment.tool.rTRotate" +msgstr "R/T girar" +# Source-Hash: f24a1089d9256460 # Review: required -# Source-Hash: a028e08962c388e0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curved" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Geometry preserved from an imported model when no native Pascal shape exists." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fence.inspectorEditors.curved" -msgstr "Curvo" +msgid "node.importedMesh.description" +msgstr "Geometría conservada de un modelo importado cuando no existe una forma nativa de Pascal." +# Source-Hash: 9f9d11f287f722d7 # Review: required -# Source-Hash: 81b75058b7843a0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{style, select, picket {Distribution controls pickets in each bay between posts.} horizontal {Distribution controls posts along the full fence.} other {Distribution controls infill pieces between the two end posts.}} Spacing is measured between centers. The available width limits the count so pieces do not overlap." -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Imported Mesh" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fence.inspectorEditors.distributionInfo" -msgstr "{style, select, picket {La distribución controla los listones de cada tramo entre postes.} horizontal {La distribución controla los postes a lo largo de toda la valla.} other {La distribución controla las piezas de relleno entre los dos postes extremos.}} La separación se mide entre centros. El ancho disponible limita la cantidad para que las piezas no se solapen." +msgid "node.importedMesh.label" +msgstr "Malla importada" +# Source-Hash: 9cce89f94c673821 # Review: required -# Source-Hash: fbc8f54b0e3fdeb1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit path" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Couldn't rebuild with these values." +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.editPath" -msgstr "Editar trazado" +msgid "node.item.authoredParams.couldnTRebuildWithTheseValues" +msgstr "No se ha podido reconstruir con estos valores." +# Source-Hash: 373b929318436fe3 # Review: required -# Source-Hash: 55686db44529c013 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Extend path" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Parameters" +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.extendPath" -msgstr "Prolongar trazado" +msgid "node.item.authoredParams.parameters" +msgstr "Parámetros" +# Source-Hash: 558cb886dbe0babe # Review: required -# Source-Hash: 0bf0f27e631aa98d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follow highest surface" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rebuilding…" +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.followHighestSurface" -msgstr "Seguir la superficie más alta" +msgid "node.item.authoredParams.rebuilding" +msgstr "Reconstruyendo…" +# Source-Hash: a094c99dc8ad29a3 # Review: required -# Source-Hash: e0b381fcb05a65c4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follow selected surface" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rebuilding in Blender…" +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.followSelectedSurface" -msgstr "Seguir la superficie seleccionada" +msgid "node.item.authoredParams.rebuildingInBlender" +msgstr "Reconstruyendo en Blender…" +# Source-Hash: 1778f93ee143cd95 # Review: required -# Source-Hash: c418d97f803af8dd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hold starting height" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset {param}" +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.holdStartingHeight" -msgstr "Mantener la altura inicial" +msgid "node.item.authoredParams.resetParam" +msgstr "Restablecer {param}" +# Source-Hash: 5a28cf5f2402dd7a # Review: required -# Source-Hash: 295ca9336dc1935b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Join" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset parameters" +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.join" -msgstr "Unir" +msgid "node.item.authoredParams.resetParameters" +msgstr "Restablecer parámetros" +# Source-Hash: 6eb8025c60d6d3ca # Review: required -# Source-Hash: 643687bc3adaac76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset to default" +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.length" -msgstr "Longitud" +msgid "node.item.authoredParams.resetToDefault" +msgstr "Restablecer valores predeterminados" +# Source-Hash: 63f79b3c467177b3 # Review: required -# Source-Hash: 1fedc8a2f2ea6887 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {{number} point} other {{number} points}} · {length} m" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A catalog-backed item (furniture, fixtures, decorations)." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fence.inspectorEditors.pathSummary" -msgstr "{count, plural, one {{number} punto} many {{number} puntos} other {{number} puntos}} · {length} m" +msgid "node.item.description" +msgstr "Elemento del catálogo (muebles, equipamiento, decoración)." +# Source-Hash: 2743a0e9d2743807 # Review: required -# Source-Hash: c96d499e11181429 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket rail projection" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Item" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fence.inspectorEditors.picketRailProjection" -msgstr "Saliente de los listones sobre el travesaño" +msgid "node.item.label" +msgstr "Elemento" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: a1880fca8372d06f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Point" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.point" -msgstr "Punto" +msgid "node.item.panel.actions" +msgstr "Acciones" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: 39bc6254b5307f53 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove point" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.removePoint" -msgstr "Quitar punto" +msgid "node.item.panel.delete" +msgstr "Eliminar" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: ea56af3a0d7a65e4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set each span to straight or curved, then drag its points and curve handles in either view." -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.setEachSpanToStraightOr" -msgstr "Haz que cada tramo sea recto o curvo y luego arrastra sus puntos y tiradores de curva en cualquiera de las vistas." +msgid "node.item.panel.dimensions" +msgstr "Dimensiones" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: 354c8bc5c8da5a6e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Smooth" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.smooth" -msgstr "Suavizar" +msgid "node.item.panel.duplicate" +msgstr "Duplicar" +# Source-Hash: 6e68b62d2aa611a4 # Review: required -# Source-Hash: 3c700cc1299a150f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Span to point {number}" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Info" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.spanToPointNumber" -msgstr "Tramo hasta el punto {number}" +msgid "node.item.panel.info" +msgstr "Info" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: 4ee35f740730ae87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.straight" -msgstr "Recto" +msgid "node.item.panel.move" +msgstr "Mover" +# Source-Hash: 28fe6e9deddde6e8 # Review: required -# Source-Hash: 78a454b7ac7a3cd9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "pos" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.surface" -msgstr "Superficie" +msgid "node.item.panel.pos" +msgstr "pos" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: ab2de0428c093018 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface behavior" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.surfaceBehavior" -msgstr "Comportamiento en la superficie" +msgid "node.item.panel.position" +msgstr "Posición" -# Source-Hash: 02042fde61b5aa11 +# Source-Hash: 5f433581c8f404fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fence" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "rot" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.label" -msgstr "Valla" +msgid "node.item.panel.rot" +msgstr "rot" +# Source-Hash: 01989595ee7c1dc0 # Review: required -# Source-Hash: 3e07a9889c1bd7f9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Detach endpoint" -#: packages/nodes/src/fence/move-endpoint-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.moveEndpointTool.detachEndpoint" -msgstr "Separar extremo" +msgid "node.item.panel.rotation" +msgstr "Rotación" +# Source-Hash: 8210f376c0d29acc # Review: required -# Source-Hash: 7a3ce9fec6370e3e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag endpoint" -#: packages/nodes/src/fence/move-endpoint-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scale" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.moveEndpointTool.dragEndpoint" -msgstr "Arrastrar extremo" +msgid "node.item.panel.scale" +msgstr "Escala" +# Source-Hash: 58fee802997c811c # Review: required -# Source-Hash: d7cf5045c01b2eb9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close" -#: packages/nodes/src/fence-feature/actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "scale" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fenceFeature.actions.close" -msgstr "Cerrar" +msgid "node.item.panel.scale2" +msgstr "escala" +# Source-Hash: b0d264950558d50e # Review: required -# Source-Hash: 3e52f04f92e08070 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/fence-feature/actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Uniform Scale" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fenceFeature.actions.open" -msgstr "Abrir" +msgid "node.item.panel.uniformScale" +msgstr "Escala uniforme" +# Source-Hash: 4b8d7e52013d1691 # Review: required -# Source-Hash: fc4cf2bc034fc547 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Board width" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "XYZ" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.boardWidth" -msgstr "Ancho de tabla" +msgid "node.item.panel.xyz" +msgstr "XYZ" +# Source-Hash: a9e2d7b215696e2a # Review: required -# Source-Hash: f3b11e5b2dd3b25f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bracing" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An attached mono-pitch or freestanding mono, gable, or butterfly canopy with managed structure and drainage." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.bracing" -msgstr "Arriostramiento" +msgid "node.leanToExtension.description" +msgstr "Marquesina adosada a un agua o exenta (un agua, dos aguas o mariposa) con estructura y desagüe gestionados." +# Source-Hash: 8503bedfbafde9a3 # Review: required -# Source-Hash: d09ec3d9565734c3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Distance from start" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Canopy" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.distanceFromStart" -msgstr "Distancia desde el inicio" +msgid "node.leanToExtension.label" +msgstr "Marquesina" +# Source-Hash: 45673462f914d3df # Review: required -# Source-Hash: dcd803eaf3796298 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fence unavailable." -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A single floor of a building, holding walls / slabs / ceilings / items." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.fenceUnavailable" -msgstr "Valla no disponible." +msgid "node.level.description" +msgstr "Una planta de un edificio con muros, forjados, techos y elementos." +# Source-Hash: 0608743fc1736d86 # Review: required -# Source-Hash: 3519d91b7bda18a5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame width" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.frameWidth" -msgstr "Ancho del marco" +msgid "node.level.label" +msgstr "Planta" +# Source-Hash: 156bdee8fee5bec6 # Review: required -# Source-Hash: cb18554b2420e700 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gate height" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Refrigerant lineset — copper suction + liquid pair joining a condenser to the indoor coil." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.gateHeight" -msgstr "Altura de la puerta" +msgid "node.lineset.description" +msgstr "Línea frigorífica: par de cobre de aspiración y líquido que une la condensadora con la batería interior." +# Source-Hash: 362b03eba9d8234c # Review: required -# Source-Hash: 54098b5ee574737a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gate style" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lineset" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.gateStyle" -msgstr "Estilo de puerta de valla" +msgid "node.lineset.label" +msgstr "Línea frigorífica" +# Source-Hash: 2bd4a85bed158269 # Review: required -# Source-Hash: 4fc3e60be28f60d5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground clearance" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standalone refrigerant liquid line — a thin bare-copper run; Follow mode traces an existing lineset." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.groundClearance" -msgstr "Separación al suelo" +msgid "node.liquidLine.description" +msgstr "Línea de líquido frigorífico independiente: un tubo fino de cobre desnudo; el modo Seguir traza junto a una línea existente." +# Source-Hash: c34c9b36492c6e21 # Review: required -# Source-Hash: 916f2e07bf082795 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hinges and latch" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Liquid Line" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.hingesAndLatch" -msgstr "Bisagras y pestillo" +msgid "node.liquidLine.label" +msgstr "Línea de líquido" +# Source-Hash: 601aaf23ce5a9279 # Review: required -# Source-Hash: 5bd2e597fbb2a2c9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hinge side" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click to trace this lineset run" +#: packages/nodes/src/liquid-line/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.hingeSide" -msgstr "Lado de las bisagras" +msgid "node.liquidLine.tool.clickToTraceThisLinesetRun" +msgstr "Haz clic para seguir este tramo de línea frigorífica" +# Source-Hash: 77df017af9260468 # Review: required -# Source-Hash: 8fec7e969045a8e7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Horizontal boards" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow: hover a lineset" +#: packages/nodes/src/liquid-line/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.horizontalBoards" -msgstr "Tablas horizontales" +msgid "node.liquidLine.tool.followHoverALineset" +msgstr "Seguir: pasa sobre una línea frigorífica" -# Review: required -# Source-Hash: f4addad87cc4223e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Infill spacing" -#: packages/nodes/src/fence-feature/inspector.tsx +# Source-Hash: ff4e3bb72267859e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A persistent distance, angle, area, perimeter, or volume annotation." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.infillSpacing" -msgstr "Separación del relleno" +msgid "node.measurement.description" +msgstr "Anotación persistente de distancia, ángulo, área, perímetro o volumen." +# Source-Hash: ec3567fd058bab7c # Review: required -# Source-Hash: cdec08b292742b20 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Jamb posts" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Measurement" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.jambPosts" -msgstr "Postes de jamba" +msgid "node.measurement.label" +msgstr "Medida" +# Source-Hash: d71b38e990539364 # Review: required -# Source-Hash: ef88410453ee7414 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Keep the opening inside the fence and clear of other gates or passages." -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{kind} {number}" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.keepTheOpeningInsideTheFence" -msgstr "Mantén la abertura dentro de la valla y lejos de otras puertas o pasos." +msgid "node.numberedName" +msgstr "{kind} {number}" +# Source-Hash: 09865d8781ef8699 # Review: required -# Source-Hash: 67cd0171b226fedb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Leaf thickness" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Currently {value}" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/roof/panel.tsx +#: packages/nodes/src/stair/panel.tsx +#: packages/nodes/src/wall/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.leafThickness" -msgstr "Grosor de la hoja" +msgid "node.panel.currently" +msgstr "Actualmente {value}" +# Source-Hash: 7764b50334e9f71d # Review: required -# Source-Hash: c390ba248e629b9e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Leaves" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV joint — elbow bend, 45° wye, or sanitary tee." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.leaves" -msgstr "Hojas" +msgid "node.pipeFitting.description" +msgstr "Unión de desagüe: codo, Y a 45° o T sanitaria." +# Source-Hash: c040baa6ed4c7aa5 # Review: required -# Source-Hash: d7bb934589475512 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left leaf proportion" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pipe Fitting" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.leftLeafProportion" -msgstr "Proporción de la hoja izquierda" +msgid "node.pipeFitting.label" +msgstr "Accesorio de tubería" +# Source-Hash: dd86efcab72fc5c7 # Review: required -# Source-Hash: aa9fe0ebace8957d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match fence height" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Axis" +#: packages/nodes/src/pipe-fitting/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.matchFenceHeight" -msgstr "Igualar altura de la valla" +msgid "node.pipeFitting.tool.axis" +msgstr "Eje" +# Source-Hash: 5232a826549f915e # Review: required -# Source-Hash: c15c1af69ec5c1eb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match fence style" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "⌥ axis" +#: packages/nodes/src/pipe-fitting/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.matchFenceStyle" -msgstr "Igualar el estilo de la valla" +msgid "node.pipeFitting.tool.axis2" +msgstr "⌥ eje" +# Source-Hash: 8fb180251a321cef # Review: required -# Source-Hash: 51b7ab6a0a78d90a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening angle" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/pipe-fitting/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.openingAngle" -msgstr "Ángulo de apertura" +msgid "node.pipeFitting.tool.rTRotate" +msgstr "R/T girar" +# Source-Hash: a0bb4762aa66fa3e # Review: required -# Source-Hash: d2e20300c07aa722 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening width" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drain / waste / vent pipe run — draw level or toggle a ¼″ per foot fall with S." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.openingWidth" -msgstr "Ancho de la abertura" +msgid "node.pipeSegment.description" +msgstr "Tubería de desagüe y ventilación: dibújala horizontal o alterna una pendiente de ¼″ por pie con S." +# Source-Hash: 457155657704f7cc # Review: required -# Source-Hash: 6b108fb1d0eb8f9d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open rails" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV Pipe" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.openRails" -msgstr "Barandas abiertas" +msgid "node.pipeSegment.label" +msgstr "Tubería de desagüe" +# Source-Hash: 6d0cdd14d0675e05 # Review: required -# Source-Hash: d500c4b7827d3390 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cross" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV P-trap — water seal on the waste line. The trap arm runs to the vent." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.option.cross" -msgstr "Cruz" +msgid "node.pipeTrap.description" +msgstr "Sifón en P: cierre hidráulico en el desagüe. El brazo del sifón llega a la ventilación." +# Source-Hash: b778a315e82065a0 # Review: required -# Source-Hash: 7420c0d2caee1c22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diagonal" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trap" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.option.diagonal" -msgstr "Diagonal" +msgid "node.pipeTrap.label" +msgstr "Sifón" +# Source-Hash: 73078bc0f5d686fa # Review: required -# Source-Hash: 7308869944020839 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double gate" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{diameter}\" Trap" +#: packages/nodes/src/pipe-trap/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.doubleGate" -msgstr "Puerta doble" +msgid "node.pipeTrap.tool.diameterTrap" +msgstr "Sifón de {diameter}\"" +# Source-Hash: 8fb180251a321cef # Review: required -# Source-Hash: 1f4ad5ad3e1be222 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inward" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/pipe-trap/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.inward" -msgstr "Hacia dentro" +msgid "node.pipeTrap.tool.rTRotate" +msgstr "R/T girar" +# Source-Hash: 0efe82436b915f6d # Review: required -# Source-Hash: f365c6b6dd9ebab9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Experimental editable recipe" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.option.left" -msgstr "Izquierda" +msgid "node.proceduralItem.description" +msgstr "Receta editable experimental" +# Source-Hash: c8bbcc888cce7b8a # Review: required -# Source-Hash: f2953d2931e36d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Procedural item" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.option.none" -msgstr "Ninguno" +msgid "node.proceduralItem.label" +msgstr "Elemento procedural" +# Source-Hash: 356aa0ed69cb8ec5 # Review: required -# Source-Hash: ccd8f06b8f8d27c9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Outward" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ventilation strip running along the ridge of a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.option.outward" -msgstr "Hacia fuera" +msgid "node.ridgeVent.description" +msgstr "Banda de ventilación a lo largo de la cumbrera de un faldón." +# Source-Hash: 54b74080f33c8c4e # Review: required -# Source-Hash: b34d5ee0f218221d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge Vent" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.option.right" -msgstr "Derecha" +msgid "node.ridgeVent.label" +msgstr "Ventilación de cumbrera" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: d327097d9ac1099f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single gate" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.singleGate" -msgstr "Puerta simple" +msgid "node.ridgeVent.panel.actions" +msgstr "Acciones" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: 9295ddc2805b21e2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.picket" -msgstr "Estacas" +msgid "node.ridgeVent.panel.delete" +msgstr "Eliminar" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: 8dd5999b235f60ab -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post height" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.postHeight" -msgstr "Altura de los postes" +msgid "node.ridgeVent.panel.dimensions" +msgstr "Dimensiones" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: 90bcd7a8123ec343 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove gate" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.removeGate" -msgstr "Quitar puerta" +msgid "node.ridgeVent.panel.duplicate" +msgstr "Duplicar" +# Source-Hash: 18bf817325c1c537 # Review: required -# Source-Hash: 7e3505710613543f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove opening" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End Caps" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.removeOpening" -msgstr "Quitar abertura" +msgid "node.ridgeVent.panel.endCaps" +msgstr "Tapas de extremo" +# Source-Hash: 466f817a0102d4a5 # Review: required -# Source-Hash: af6f8885fe0fa4e9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid privacy" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flanged" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.solidPrivacy" -msgstr "Privacidad total" +msgid "node.ridgeVent.panel.flanged" +msgstr "Con brida" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 1a7048255c3bdfcb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swing direction" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.swingDirection" -msgstr "Sentido de apertura" +msgid "node.ridgeVent.panel.height" +msgstr "Altura" +# Source-Hash: 643687bc3adaac76 # Review: required -# Source-Hash: eba3df14a2de0812 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical slats" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.verticalSlats" -msgstr "Lamas verticales" +msgid "node.ridgeVent.panel.length" +msgstr "Longitud" -# Source-Hash: df61821ed00852d8 +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A gate hosted by a fence." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceGate.description" -msgstr "Puerta alojada en una valla." +msgid "node.ridgeVent.panel.move" +msgstr "Mover" -# Source-Hash: 4a479aa23542d766 +# Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gate" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceGate.label" -msgstr "Puerta de valla" +msgid "node.ridgeVent.panel.open" +msgstr "Abrir" -# Source-Hash: 8f9c927d79796c26 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "An intentional opening in a fence." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceOpening.description" -msgstr "Abertura intencionada en una valla." +msgid "node.ridgeVent.panel.position" +msgstr "Posición" -# Source-Hash: ab67bb47e647d594 +# Source-Hash: 54b74080f33c8c4e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open Passage" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge Vent" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceOpening.label" -msgstr "Paso abierto" +msgid "node.ridgeVent.panel.ridgeVent" +msgstr "Ventilación de cumbrera" -# Source-Hash: dc3adf0c2d50dba6 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor opening" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.floorOpening.label" -msgstr "Hueco de forjado" +msgid "node.ridgeVent.panel.rotation" +msgstr "Rotación" -# Source-Hash: 2f4fac2b1d39fdb1 +# Source-Hash: e9046e9823b400a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A measurement / reference annotation (linear, area, or arc)." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingled" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.guide.description" -msgstr "Anotación de medida o referencia (lineal, área o arco)." +msgid "node.ridgeVent.panel.shingled" +msgstr "Con tejas" -# Source-Hash: 1344ea2602e3aa9e +# Source-Hash: d998c212030bc7c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guide" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.guide.label" -msgstr "Guía" +msgid "node.ridgeVent.panel.standard" +msgstr "Estándar" -# Source-Hash: 5402d634f40b2f97 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rain-water channel running along the eave of a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.gutter.description" -msgstr "Canal de agua de lluvia a lo largo del alero de un faldón." +msgid "node.ridgeVent.panel.style" +msgstr "Estilo" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: fc7d4ecf973db135 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Downspout" -#: packages/nodes/src/gutter/downspouts-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.gutter.downspoutsPanel.addDownspout" -msgstr "Añadir bajante" +msgid "node.ridgeVent.panel.width" +msgstr "Ancho" +# Source-Hash: c6d3976b4eb80586 # Review: required -# Source-Hash: 9b9929bac2c39bca -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspout {number}" -#: packages/nodes/src/gutter/downspouts-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arch bays" +#: packages/nodes/src/roof/barrel-panel.tsx #, fuzzy -msgid "node.gutter.downspoutsPanel.downspoutNumber" -msgstr "Bajante {number}" +msgid "node.roof.barrelPanel.archBays" +msgstr "Vanos en arco" +# Source-Hash: 1cfdd5affedf153c # Review: required -# Source-Hash: fc34d45725838141 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspouts" -#: packages/nodes/src/gutter/downspouts-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Barrel arch" +#: packages/nodes/src/roof/barrel-panel.tsx #, fuzzy -msgid "node.gutter.downspoutsPanel.downspouts" -msgstr "Bajantes" +msgid "node.roof.barrelPanel.barrelArch" +msgstr "Bóveda de cañón" +# Source-Hash: b3e8929750d18f7b # Review: required -# Source-Hash: ac329c74056f0616 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove downspout" -#: packages/nodes/src/gutter/downspouts-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat panes follow a circular arch. Rise is measured from the eaves." +#: packages/nodes/src/roof/barrel-panel.tsx #, fuzzy -msgid "node.gutter.downspoutsPanel.removeDownspout" -msgstr "Quitar bajante" +msgid "node.roof.barrelPanel.flatPanesFollowACircularArch" +msgstr "Los paños planos siguen un arco circular. La flecha se mide desde el alero." -# Source-Hash: 14ba981da3627ae2 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gutter" -#: packages/nodes/src/i18n/definition-messages.ts +# Source-Hash: fe8c5b735495eb00 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rise" +#: packages/nodes/src/roof/barrel-panel.tsx #, fuzzy -msgid "node.gutter.label" -msgstr "Canalón" +msgid "node.roof.barrelPanel.rise" +msgstr "Altura" -# Source-Hash: 387082cd5f118bed +# Source-Hash: 6afeec8de7ed618d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Manual" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A pitched / hip / gable roof composed of one or more segments." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.hole.manual" -msgstr "Manual" +msgid "node.roof.description" +msgstr "Cubierta inclinada, a cuatro aguas o a dos aguas compuesta por uno o varios faldones." -# Source-Hash: fffde6fa82e65ffc +# Source-Hash: b5be04471fd3fb7a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hole {number} (Editing)" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arch bay {number}" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.holeEditing" -msgstr "Hueco {number} (editando)" +msgid "node.roof.glazing.face.archBay" +msgstr "Vano en arco {number}" -# Source-Hash: 0fe446c72451e4a5 +# Source-Hash: 93381b9024a75a99 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hole {number}" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back slope" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.holeNumber" -msgstr "Hueco {number}" +msgid "node.roof.glazing.face.back" +msgstr "Faldón trasero" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: fd26f8df9d087c6b +# Source-Hash: 08b00107b635e11d # Review: required -# English: "{area} m² · {count, plural, one {{points} pt} other {{points} pts}} · {source}" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left end" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.holeSummary" -msgstr "{area} m² · {count, plural, one {{points} pto} many {{points} ptos} other {{points} ptos}} · {source}" +msgid "node.roof.glazing.face.endLeft" +msgstr "Extremo izquierdo" -# Source-Hash: 50e9252d30f3fb4d +# Source-Hash: 821734ea5d17a693 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Furnace, air handler, or condenser — duct runs connect to its supply/return collars." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right end" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.hvacEquipment.description" -msgstr "Caldera, climatizadora o condensadora: los conductos se conectan a sus collarines de impulsión y retorno." +msgid "node.roof.glazing.face.endRight" +msgstr "Extremo derecho" -# Source-Hash: 3bf1c1a8dbb93743 +# Source-Hash: 40c9ef62055067e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "HVAC Unit" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front slope" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.hvacEquipment.label" -msgstr "Equipo de climatización" +msgid "node.roof.glazing.face.front" +msgstr "Faldón delantero" +# Source-Hash: 1a88da71d5e5f0d6 # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/hvac-equipment/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed slope" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.hvacEquipment.tool.rTRotate" -msgstr "R/T girar" +msgid "node.roof.glazing.face.slope" +msgstr "Faldón a un agua" -# Source-Hash: f24a1089d9256460 +# Source-Hash: 3bcc542295b4c61e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Geometry preserved from an imported model when no native Pascal shape exists." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Alignment" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.importedMesh.description" -msgstr "Geometría conservada de un modelo importado cuando no existe una forma nativa de Pascal." +msgid "node.roof.glazingControls.alignment" +msgstr "Alineación" -# Source-Hash: 9f9d11f287f722d7 +# Source-Hash: 5211341ed18f33f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Imported Mesh" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.importedMesh.label" -msgstr "Malla importada" +msgid "node.roof.glazingControls.center" +msgstr "Centro" -# Source-Hash: 9cce89f94c673821 +# Source-Hash: 512e47607a37af46 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Couldn't rebuild with these values." -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a layout to edit the grid." +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.couldnTRebuildWithTheseValues" -msgstr "No se ha podido reconstruir con estos valores." +msgid "node.roof.glazingControls.chooseALayoutToEditThe" +msgstr "Elige una distribución para editar la retícula." -# Source-Hash: 373b929318436fe3 +# Source-Hash: 65b1cbba3b92c5b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Parameters" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Empty" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.parameters" -msgstr "Parámetros" +msgid "node.roof.glazingControls.empty" +msgstr "Vacío" -# Source-Hash: 558cb886dbe0babe +# Source-Hash: 135874d189176d13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rebuilding…" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.rebuilding" -msgstr "Reconstruyendo…" +msgid "node.roof.glazingControls.end" +msgstr "Final" -# Source-Hash: a094c99dc8ad29a3 +# Source-Hash: 4fb65101d0b1a222 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rebuilding in Blender…" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fixed spacing" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.rebuildingInBlender" -msgstr "Reconstruyendo en Blender…" +msgid "node.roof.glazingControls.fixedSpacing" +msgstr "Separación fija" -# Source-Hash: 1778f93ee143cd95 +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset {param}" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.resetParam" -msgstr "Restablecer {param}" +msgid "node.roof.glazingControls.glass" +msgstr "Vidrio" -# Source-Hash: 5a28cf5f2402dd7a +# Source-Hash: 54800340a0eeab23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset parameters" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layout" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.resetParameters" -msgstr "Restablecer parámetros" +msgid "node.roof.glazingControls.layout" +msgstr "Distribución" -# Source-Hash: 6eb8025c60d6d3ca +# Source-Hash: 321ca5101ab61db7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset to default" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Maximum spacing" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.resetToDefault" -msgstr "Restablecer valores predeterminados" +msgid "node.roof.glazingControls.maximumSpacing" +msgstr "Separación máxima" -# Source-Hash: 63f79b3c467177b3 +# Source-Hash: d10743fce478d9f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A catalog-backed item (furniture, fixtures, decorations)." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Max spacing" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.description" -msgstr "Elemento del catálogo (muebles, equipamiento, decoración)." +msgid "node.roof.glazingControls.maxSpacing" +msgstr "Separación máx." -# Source-Hash: 2743a0e9d2743807 +# Source-Hash: 37d9f63758abdb67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Item" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mixed" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.label" -msgstr "Elemento" +msgid "node.roof.glazingControls.mixed" +msgstr "Mixto" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: b91302bf741c9fd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel count" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.actions" -msgstr "Acciones" +msgid "node.roof.glazingControls.panelCount" +msgstr "Número de paneles" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 6ce059aee1386f72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panels" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.delete" -msgstr "Eliminar" +msgid "node.roof.glazingControls.panels" +msgstr "Paneles" -# Source-Hash: 12df69f42beb0643 +# Source-Hash: ef3e765e692faf4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.dimensions" -msgstr "Dimensiones" +msgid "node.roof.glazingControls.solid" +msgstr "Sólido" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: e4698e83d02beb6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spacing" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.duplicate" -msgstr "Duplicar" +msgid "node.roof.glazingControls.spacing" +msgstr "Separación" -# Source-Hash: 6e68b62d2aa611a4 +# Source-Hash: 0a26a1e61c825660 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Info" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.info" -msgstr "Info" +msgid "node.roof.glazingControls.start" +msgstr "Inicio" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 095237e9e2df4d9c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{title} alignment" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.move" -msgstr "Mover" +msgid "node.roof.glazingControls.titleAlignment" +msgstr "Alineación de {title}" -# Source-Hash: 28fe6e9deddde6e8 +# Source-Hash: c98a4e6b28f05e0f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "pos" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Changes apply to all {length} roof segments." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.pos" -msgstr "pos" +msgid "node.roof.glazingPanel.changesApplyToAllLengthRoof" +msgstr "Los cambios se aplican a los {length} segmentos de cubierta." -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: c5d2ff7fda4787cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose one roof system to edit settings for all selected segments." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.position" -msgstr "Posición" +msgid "node.roof.glazingPanel.chooseOneRoofSystemToEdit" +msgstr "Elige un sistema de cubierta para editar los ajustes de todos los segmentos seleccionados." -# Source-Hash: 5f433581c8f404fa +# Source-Hash: 80e07a119b63187c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "rot" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close the roof ends" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.rot" -msgstr "rot" +msgid "node.roof.glazingPanel.closeTheRoofEnds" +msgstr "Cerrar los extremos de la cubierta" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: e28dd27d54aaa7ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default panel infill" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.rotation" -msgstr "Rotación" +msgid "node.roof.glazingPanel.defaultPanelInfill" +msgstr "Relleno predeterminado del panel" -# Source-Hash: 8210f376c0d29acc +# Source-Hash: 134d33e2465937e7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scale" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divides each roof face into columns." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.scale" -msgstr "Escala" +msgid "node.roof.glazingPanel.dividesEachRoofFaceIntoColumns" +msgstr "Divide cada faldón en columnas." -# Source-Hash: 58fee802997c811c +# Source-Hash: 896a6e4da3357c39 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "scale" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divides the length of each arch bay into columns." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.scale2" -msgstr "escala" +msgid "node.roof.glazingPanel.dividesTheLengthOfEachArch" +msgstr "Divide la longitud de cada vano en arco en columnas." -# Source-Hash: b0d264950558d50e +# Source-Hash: be9c810d28d1feb9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Uniform Scale" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End infill fills the space above the walls. Edit room walls and ceilings separately." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.uniformScale" -msgstr "Escala uniforme" +msgid "node.roof.glazingPanel.endInfillFillsTheSpaceAbove" +msgstr "El relleno de testero llena el espacio sobre los muros. Edita los muros y techos de las estancias por separado." -# Source-Hash: 4b8d7e52013d1691 +# Source-Hash: 0b8b27dbc57cca44 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "XYZ" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame color" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.xyz" -msgstr "XYZ" +msgid "node.roof.glazingPanel.frameColor" +msgstr "Color del marco" -# Source-Hash: a9e2d7b215696e2a +# Source-Hash: fd413477f1a9e5ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "An attached mono-pitch or freestanding mono, gable, or butterfly canopy with managed structure and drainage." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame depth" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.leanToExtension.description" -msgstr "Marquesina adosada a un agua o exenta (un agua, dos aguas o mariposa) con estructura y desagüe gestionados." +msgid "node.roof.glazingPanel.frameDepth" +msgstr "Profundidad del marco" -# Source-Hash: 8503bedfbafde9a3 +# Source-Hash: 3519d91b7bda18a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Canopy" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame width" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.leanToExtension.label" -msgstr "Marquesina" +msgid "node.roof.glazingPanel.frameWidth" +msgstr "Ancho del marco" -# Source-Hash: 45673462f914d3df +# Source-Hash: c7e72beff9fe4b37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A single floor of a building, holding walls / slabs / ceilings / items." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framing" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.level.description" -msgstr "Una planta de un edificio con muros, forjados, techos y elementos." +msgid "node.roof.glazingPanel.framing" +msgstr "Entramado" -# Source-Hash: 0608743fc1736d86 +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.level.label" -msgstr "Planta" +msgid "node.roof.glazingPanel.glass" +msgstr "Vidrio" -# Source-Hash: 156bdee8fee5bec6 +# Source-Hash: 9c38875c310547ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Refrigerant lineset — copper suction + liquid pair joining a condenser to the indoor coil." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass tint" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.lineset.description" -msgstr "Línea frigorífica: par de cobre de aspiración y líquido que une la condensadora con la batería interior." +msgid "node.roof.glazingPanel.glassTint" +msgstr "Tinte del vidrio" -# Source-Hash: 362b03eba9d8234c +# Source-Hash: dd330a94b3f7a65a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lineset" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glazed" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.lineset.label" -msgstr "Línea frigorífica" +msgid "node.roof.glazingPanel.glazed" +msgstr "Acristalado" -# Source-Hash: 2bd4a85bed158269 +# Source-Hash: e6be52df9197243a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standalone refrigerant liquid line — a thin bare-copper run; Follow mode traces an existing lineset." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glazing is available for gable, straight shed, and barrel roofs." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.liquidLine.description" -msgstr "Línea de líquido frigorífico independiente: un tubo fino de cobre desnudo; el modo Seguir traza junto a una línea existente." +msgid "node.roof.glazingPanel.glazingIsAvailableForGableStraight" +msgstr "El acristalamiento está disponible para cubiertas a dos aguas, a un agua rectas y abovedadas." -# Source-Hash: c34c9b36492c6e21 +# Source-Hash: a4e7ef2e31d7220b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Liquid Line" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid across the roof" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.liquidLine.label" -msgstr "Línea de líquido" +msgid "node.roof.glazingPanel.gridAcrossTheRoof" +msgstr "Retícula transversal a la cubierta" +# Source-Hash: 2f28a3b33fccf56b # Review: required -# Source-Hash: 601aaf23ce5a9279 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click to trace this lineset run" -#: packages/nodes/src/liquid-line/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid along the length" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.liquidLine.tool.clickToTraceThisLinesetRun" -msgstr "Haz clic para seguir este tramo de línea frigorífica" +msgid "node.roof.glazingPanel.gridAlongTheLength" +msgstr "Retícula a lo largo" +# Source-Hash: 1f701893dbf9d72b # Review: required -# Source-Hash: 77df017af9260468 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follow: hover a lineset" -#: packages/nodes/src/liquid-line/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid along the slope" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.liquidLine.tool.followHoverALineset" -msgstr "Seguir: pasa sobre una línea frigorífica" +msgid "node.roof.glazingPanel.gridAlongTheSlope" +msgstr "Retícula según la pendiente" -# Source-Hash: ff4e3bb72267859e +# Source-Hash: 20c8dfbadda20e3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A persistent distance, angle, area, perimeter, or volume annotation." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid within each arch bay" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.measurement.description" -msgstr "Anotación persistente de distancia, ángulo, área, perímetro o volumen." +msgid "node.roof.glazingPanel.gridWithinEachArchBay" +msgstr "Retícula en cada vano en arco" -# Source-Hash: ec3567fd058bab7c +# Source-Hash: 7c339a5fae55681d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Measurement" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Infill" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.measurement.label" -msgstr "Medida" +msgid "node.roof.glazingPanel.infill" +msgstr "Relleno" -# Source-Hash: d71b38e990539364 +# Source-Hash: 1c0b8a5503c5daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{kind} {number}" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opacity" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.numberedName" -msgstr "{kind} {number}" +msgid "node.roof.glazingPanel.opacity" +msgstr "Opacidad" -# Source-Hash: 09865d8781ef8699 +# Source-Hash: 4d412746658f2faf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Currently {value}" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/roof/panel.tsx -#: packages/nodes/src/stair/panel.tsx -#: packages/nodes/src/wall/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pane thickness" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.panel.currently" -msgstr "Actualmente {value}" +msgid "node.roof.glazingPanel.paneThickness" +msgstr "Espesor del paño" -# Source-Hash: 7764b50334e9f71d +# Source-Hash: 570136e723cb7d99 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV joint — elbow bend, 45° wye, or sanitary tee." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof system" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.pipeFitting.description" -msgstr "Unión de desagüe: codo, Y a 45° o T sanitaria." +msgid "node.roof.glazingPanel.roofSystem" +msgstr "Sistema de cubierta" -# Source-Hash: c040baa6ed4c7aa5 +# Source-Hash: a6a7a36d982b4911 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pipe Fitting" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roughness" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.pipeFitting.label" -msgstr "Accesorio de tubería" +msgid "node.roof.glazingPanel.roughness" +msgstr "Rugosidad" +# Source-Hash: 2fa6fbeda5d45949 # Review: required -# Source-Hash: dd86efcab72fc5c7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Axis" -#: packages/nodes/src/pipe-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spacing is measured on the slope, not its horizontal projection." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.pipeFitting.tool.axis" -msgstr "Eje" +msgid "node.roof.glazingPanel.spacingIsMeasuredOnTheSlope" +msgstr "La separación se mide sobre la pendiente, no en su proyección horizontal." +# Source-Hash: d998c212030bc7c2 # Review: required -# Source-Hash: 5232a826549f915e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "⌥ axis" -#: packages/nodes/src/pipe-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.pipeFitting.tool.axis2" -msgstr "⌥ eje" +msgid "node.roof.glazingPanel.standard" +msgstr "Estándar" +# Source-Hash: efbe1c4facf561f7 # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/pipe-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Subdivides each flat arch bay. Arch bays controls the divisions around the curve." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.pipeFitting.tool.rTRotate" -msgstr "R/T girar" +msgid "node.roof.glazingPanel.subdividesEachFlatArchBayArch" +msgstr "Subdivide cada vano plano en arco. Vanos en arco controla las divisiones a lo largo de la curva." -# Source-Hash: a0bb4762aa66fa3e +# Source-Hash: 1497eac9e4f63016 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drain / waste / vent pipe run — draw level or toggle a ¼″ per foot fall with S." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a panel to override its default infill." +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeSegment.description" -msgstr "Tubería de desagüe y ventilación: dibújala horizontal o alterna una pendiente de ¼″ por pie con S." +msgid "node.roof.glazingPanelEditor.chooseAPanelToOverrideIts" +msgstr "Elige un panel para sustituir su relleno predeterminado." -# Source-Hash: 457155657704f7cc +# Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV Pipe" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Column" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeSegment.label" -msgstr "Tubería de desagüe" +msgid "node.roof.glazingPanelEditor.column2" +msgstr "Pilar" -# Source-Hash: 6d0cdd14d0675e05 +# Source-Hash: 9e9715d52410c86f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV P-trap — water seal on the waste line. The trap arm runs to the vent." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeTrap.description" -msgstr "Sifón en P: cierre hidráulico en el desagüe. El brazo del sifón llega a la ventilación." +msgid "node.roof.glazingPanelEditor.custom" +msgstr "Personalizado" -# Source-Hash: b778a315e82065a0 +# Source-Hash: 4ca0e0e73229540c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trap" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeTrap.label" -msgstr "Sifón" +msgid "node.roof.glazingPanelEditor.default" +msgstr "Predeterminado" +# Source-Hash: 9ef92ad8ae49ed72 # Review: required -# Source-Hash: 73078bc0f5d686fa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{diameter}\" Trap" -#: packages/nodes/src/pipe-trap/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{columns, plural, one {{columnCount} column} other {{columnCount} columns}} · {rows, plural, one {{rowCount} row} other {{rowCount} rows}}" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeTrap.tool.diameterTrap" -msgstr "Sifón de {diameter}\"" +msgid "node.roof.glazingPanelEditor.grid" +msgstr "{columns, plural, one {{columnCount} columna} many {{columnCount} columnas} other {{columnCount} columnas}} · {rows, plural, one {{rowCount} fila} many {{rowCount} filas} other {{rowCount} filas}}" +# Source-Hash: 11624abbcfdd5506 # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/pipe-trap/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Individual panels" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeTrap.tool.rTRotate" -msgstr "R/T girar" +msgid "node.roof.glazingPanelEditor.individualPanels" +msgstr "Paneles individuales" -# Source-Hash: 0efe82436b915f6d +# Source-Hash: 3a019ce58d021431 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Experimental editable recipe" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel infill" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.proceduralItem.description" -msgstr "Receta editable experimental" +msgid "node.roof.glazingPanelEditor.panelInfill" +msgstr "Relleno del panel" -# Source-Hash: c8bbcc888cce7b8a +# Source-Hash: 6eb8025c60d6d3ca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Procedural item" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset to default" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.proceduralItem.label" -msgstr "Elemento procedural" +msgid "node.roof.glazingPanelEditor.resetToDefault" +msgstr "Restablecer valores predeterminados" -# Source-Hash: 356aa0ed69cb8ec5 +# Source-Hash: 6fba44f2bfd8af8e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ventilation strip running along the ridge of a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof face" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.ridgeVent.description" -msgstr "Banda de ventilación a lo largo de la cumbrera de un faldón." +msgid "node.roof.glazingPanelEditor.roofFace" +msgstr "Faldón" -# Source-Hash: 54b74080f33c8c4e +# Source-Hash: 03a22f6df69c47d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ridge Vent" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Row" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.ridgeVent.label" -msgstr "Ventilación de cumbrera" +msgid "node.roof.glazingPanelEditor.row2" +msgstr "Fila" +# Source-Hash: 6c2cc2d9cd778998 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selected panel infill" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.ridgeVent.panel.actions" -msgstr "Acciones" +msgid "node.roof.glazingPanelEditor.selectedPanelInfill" +msgstr "Relleno del panel seleccionado" +# Source-Hash: f5f730969df63d1d # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.ridgeVent.panel.delete" -msgstr "Eliminar" +msgid "node.roof.label" +msgstr "Cubierta" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.dimensions" -msgstr "Dimensiones" +msgid "node.roof.panel.actions" +msgstr "Acciones" +# Source-Hash: d60471ce3cd45348 # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Chimney" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.duplicate" -msgstr "Duplicar" +msgid "node.roof.panel.addChimney" +msgstr "Añadir chimenea" +# Source-Hash: 1ca6a1cf9cc6e3ed # Review: required -# Source-Hash: 18bf817325c1c537 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End Caps" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Cupola" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.endCaps" -msgstr "Tapas de extremo" +msgid "node.roof.panel.addCupola" +msgstr "Añadir cúpula" +# Source-Hash: 94dea147eeaac52b # Review: required -# Source-Hash: 466f817a0102d4a5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flanged" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Dormer" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.flanged" -msgstr "Con brida" +msgid "node.roof.panel.addDormer" +msgstr "Añadir buhardilla" +# Source-Hash: 5679acdd64484726 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Eyebrow Vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.height" -msgstr "Altura" +msgid "node.roof.panel.addEyebrowVent" +msgstr "Añadir ventilación de ceja" +# Source-Hash: 25a141dc0d7c4b44 # Review: required -# Source-Hash: 643687bc3adaac76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Gutter" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.length" -msgstr "Longitud" +msgid "node.roof.panel.addGutter" +msgstr "Añadir canalón" +# Source-Hash: 7230bdc8a2252626 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Skylight" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.move" -msgstr "Mover" +msgid "node.roof.panel.addSkylight" +msgstr "Añadir claraboya" +# Source-Hash: 0f220e2602b7ff24 # Review: required -# Source-Hash: 3e52f04f92e08070 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Solar Panel" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.open" -msgstr "Abrir" +msgid "node.roof.panel.addSolarPanel" +msgstr "Añadir panel solar" +# Source-Hash: 4d83a2e5a4d9e6b4 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.position" -msgstr "Posición" +msgid "node.roof.panel.addVent" +msgstr "Añadir ventilación" +# Source-Hash: e9a89a5e4ac8cd61 # Review: required -# Source-Hash: 54b74080f33c8c4e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ridge Vent" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.ridgeVent" -msgstr "Ventilación de cumbrera" +msgid "node.roof.panel.box" +msgstr "Caja" +# Source-Hash: 3bf078fe2560daca # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "box vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.rotation" -msgstr "Rotación" +msgid "node.roof.panel.boxVent" +msgstr "ventilación de caja" +# Source-Hash: 4986740251121471 # Review: required -# Source-Hash: e9046e9823b400a0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingled" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "chimney" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.shingled" -msgstr "Con tejas" +msgid "node.roof.panel.chimney" +msgstr "chimenea" +# Source-Hash: 9e9715d52410c86f # Review: required -# Source-Hash: d998c212030bc7c2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.standard" -msgstr "Estándar" +msgid "node.roof.panel.custom" +msgstr "Personalizado" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.style" -msgstr "Estilo" +msgid "node.roof.panel.delete" +msgstr "Eliminar" +# Source-Hash: 5169968a4b0c1840 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "dormer" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.width" -msgstr "Ancho" +msgid "node.roof.panel.dormer" +msgstr "buhardilla" -# Source-Hash: c6d3976b4eb80586 +# Source-Hash: 72e51c6e5e9c6c26 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arch bays" -#: packages/nodes/src/roof/barrel-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw Segment" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.barrelPanel.archBays" -msgstr "Vanos en arco" +msgid "node.roof.panel.drawSegment" +msgstr "Dibujar segmento" -# Source-Hash: 1cfdd5affedf153c +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Barrel arch" -#: packages/nodes/src/roof/barrel-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.barrelPanel.barrelArch" -msgstr "Bóveda de cañón" +msgid "node.roof.panel.duplicate" +msgstr "Duplicar" -# Source-Hash: b3e8929750d18f7b +# Source-Hash: 5c99a67253bfc02a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat panes follow a circular arch. Rise is measured from the eaves." -#: packages/nodes/src/roof/barrel-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eave overhang" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.barrelPanel.flatPanesFollowACircularArch" -msgstr "Los paños planos siguen un arco circular. La flecha se mide desde el alero." +msgid "node.roof.panel.eaveOverhang" +msgstr "Vuelo del alero" -# Source-Hash: fe8c5b735495eb00 +# Source-Hash: 34756c5ea718ccb5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rise" -#: packages/nodes/src/roof/barrel-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eaves" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.barrelPanel.rise" -msgstr "Altura" +msgid "node.roof.panel.eaves" +msgstr "Aleros" -# Source-Hash: 6afeec8de7ed618d +# Source-Hash: 7c4196b9e791c195 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A pitched / hip / gable roof composed of one or more segments." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elements" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.description" -msgstr "Cubierta inclinada, a cuatro aguas o a dos aguas compuesta por uno o varios faldones." +msgid "node.roof.panel.elements" +msgstr "Elementos" -# Source-Hash: b5be04471fd3fb7a +# Source-Hash: 6b8ba49aa355fe87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arch bay {number}" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows walls" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.archBay" -msgstr "Vano en arco {number}" +msgid "node.roof.panel.followsWalls" +msgstr "Sigue los muros" -# Source-Hash: 93381b9024a75a99 +# Source-Hash: dbd062efc7f4fd7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back slope" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable overhang" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.back" -msgstr "Faldón trasero" +msgid "node.roof.panel.gableOverhang" +msgstr "Vuelo del hastial" -# Source-Hash: 08b00107b635e11d +# Source-Hash: 23b434461c990711 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left end" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "gutter" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.endLeft" -msgstr "Extremo izquierdo" +msgid "node.roof.panel.gutter" +msgstr "canalón" -# Source-Hash: 821734ea5d17a693 +# Source-Hash: 0608743fc1736d86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right end" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.endRight" -msgstr "Extremo derecho" +msgid "node.roof.panel.level" +msgstr "Planta" -# Source-Hash: 40c9ef62055067e1 +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front slope" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.front" -msgstr "Faldón delantero" +msgid "node.roof.panel.move" +msgstr "Mover" -# Source-Hash: 1a88da71d5e5f0d6 +# Source-Hash: 39661f4827b0f435 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed slope" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move to {level}" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.slope" -msgstr "Faldón a un agua" +msgid "node.roof.panel.moveToLevel" +msgstr "Mover a {level}" -# Source-Hash: 3bcc542295b4c61e +# Source-Hash: c534093ff560a9f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Alignment" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move to the roof level" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.alignment" -msgstr "Alineación" +msgid "node.roof.panel.moveToTheRoofLevel" +msgstr "Mover a la planta de cubierta" -# Source-Hash: 5211341ed18f33f6 +# Source-Hash: 0939fad1cb1831f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On {storey} with its walls, so it hides that floor's plan in solo and exploded views.{roofs, plural, =0 {} =1 {} other { The floor's {roofCount} roofs move together.}}" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.center" -msgstr "Centro" +msgid "node.roof.panel.onStoreyWalls" +msgstr "En {storey} con sus muros, así que oculta el plano de esa planta en las vistas aislada y explosionada.{roofs, plural, =0 {} =1 {} one {} many { Las {roofCount} cubiertas de la planta se mueven juntas.} other { Las {roofCount} cubiertas de la planta se mueven juntas.}}" -# Source-Hash: 512e47607a37af46 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a layout to edit the grid." -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.chooseALayoutToEditThe" -msgstr "Elige una distribución para editar la retícula." +msgid "node.roof.panel.position" +msgstr "Posición" -# Source-Hash: 65b1cbba3b92c5b2 +# Source-Hash: e6ddc8a624465793 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Empty" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.empty" -msgstr "Vacío" +msgid "node.roof.panel.ridge" +msgstr "Cumbrera" -# Source-Hash: 135874d189176d13 +# Source-Hash: 83112cbc205e9972 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "ridge vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.end" -msgstr "Final" +msgid "node.roof.panel.ridgeVent" +msgstr "ventilación de cumbrera" -# Source-Hash: 4fb65101d0b1a222 +# Source-Hash: f5f730969df63d1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fixed spacing" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.fixedSpacing" -msgstr "Separación fija" +msgid "node.roof.panel.roof" +msgstr "Cubierta" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.glass" -msgstr "Vidrio" +msgid "node.roof.panel.rotation" +msgstr "Rotación" -# Source-Hash: 54800340a0eeab23 +# Source-Hash: 505d8419cf4cc5e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Layout" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segments" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.layout" -msgstr "Distribución" +msgid "node.roof.panel.segments" +msgstr "Segmentos" -# Source-Hash: 321ca5101ab61db7 +# Source-Hash: 0c084c517dbc153b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Maximum spacing" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{roofType, select, hip {Hip} gable {Gable} shed {Shed} gambrel {Gambrel} dutch {Dutch} mansard {Mansard} flat {Flat} conical {Conical} barrel {Barrel} other {Roof}}" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.maximumSpacing" -msgstr "Separación máxima" +msgid "node.roof.panel.segmentType" +msgstr "{roofType, select, hip {A cuatro aguas} gable {A dos aguas} shed {A un agua} gambrel {Holandesa} dutch {Mixta} mansard {Mansarda} flat {Plana} conical {Cónica} barrel {Abovedada} other {Cubierta}}" -# Source-Hash: d10743fce478d9f4 +# Source-Hash: 0c4c82caccb4775c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Max spacing" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "skylight" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.maxSpacing" -msgstr "Separación máx." +msgid "node.roof.panel.skylight" +msgstr "claraboya" -# Source-Hash: 37d9f63758abdb67 +# Source-Hash: b9f931508dd6ec70 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mixed" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "solar panel" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.mixed" -msgstr "Mixto" +msgid "node.roof.panel.solarPanel" +msgstr "panel solar" -# Source-Hash: b91302bf741c9fd6 +# Source-Hash: d2428b22f1757a4e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel count" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turbine" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.panelCount" -msgstr "Número de paneles" +msgid "node.roof.panel.turbine" +msgstr "Turbina" -# Source-Hash: 6ce059aee1386f72 +# Source-Hash: 86d02a3d3a3a7fa2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panels" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "turbine vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.panels" -msgstr "Paneles" +msgid "node.roof.panel.turbineVent" +msgstr "aireador de turbina" -# Source-Hash: ef3e765e692faf4c +# Source-Hash: 6df330bcfcaac604 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Apply to all planes of this roof" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.solid" -msgstr "Sólido" +msgid "node.roofSegment.buildUpSection.applyToAllPlanesOfThis" +msgstr "Aplicar a todos los faldones de esta cubierta" -# Source-Hash: e4698e83d02beb6c +# Source-Hash: 7254a3eb47471b8a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spacing" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Architectural shingle" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.spacing" -msgstr "Separación" +msgid "node.roofSegment.buildUpSection.architecturalShingle" +msgstr "Teja asfáltica arquitectónica" -# Source-Hash: 0a26a1e61c825660 +# Source-Hash: afd23a6d653689c6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Asphalt 3-tab" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.start" -msgstr "Inicio" +msgid "node.roofSegment.buildUpSection.asphalt3Tab" +msgstr "Teja asfáltica de 3 lengüetas" -# Source-Hash: 095237e9e2df4d9c +# Source-Hash: 2650e7c436297ef2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{title} alignment" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clay tile" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.titleAlignment" -msgstr "Alineación de {title}" +msgid "node.roofSegment.buildUpSection.clayTile" +msgstr "Teja cerámica" -# Source-Hash: c98a4e6b28f05e0f +# Source-Hash: 92af091c56892f25 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Changes apply to all {length} roof segments." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Concrete tile" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.changesApplyToAllLengthRoof" -msgstr "Los cambios se aplican a los {length} segmentos de cubierta." +msgid "node.roofSegment.buildUpSection.concreteTile" +msgstr "Teja de hormigón" -# Source-Hash: c5d2ff7fda4787cd +# Source-Hash: 75168c15633cbad3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose one roof system to edit settings for all selected segments." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Covering" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.chooseOneRoofSystemToEdit" -msgstr "Elige un sistema de cubierta para editar los ajustes de todos los segmentos seleccionados." +msgid "node.roofSegment.buildUpSection.covering" +msgstr "Cubrición" -# Source-Hash: 80e07a119b63187c +# Source-Hash: f3aa561772702108 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close the roof ends" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.closeTheRoofEnds" -msgstr "Cerrar los extremos de la cubierta" +msgid "node.roofSegment.buildUpSection.deck" +msgstr "Tarima" -# Source-Hash: e28dd27d54aaa7ae +# Source-Hash: 14187d972ce9e1de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default panel infill" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit layers" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.defaultPanelInfill" -msgstr "Relleno predeterminado del panel" +msgid "node.roofSegment.buildUpSection.editLayers" +msgstr "Editar capas" -# Source-Hash: 134d33e2465937e7 +# Source-Hash: 5aff5f630e4b18c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Divides each roof face into columns." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.dividesEachRoofFaceIntoColumns" -msgstr "Divide cada faldón en columnas." +msgid "node.roofSegment.buildUpSection.finishName" +msgstr "Nombre del acabado" -# Source-Hash: 896a6e4da3357c39 +# Source-Hash: b9ed3f21665672eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Divides the length of each arch bay into columns." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ice and water shield" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.dividesTheLengthOfEachArch" -msgstr "Divide la longitud de cada vano en arco en columnas." +msgid "node.roofSegment.buildUpSection.iceAndWaterShield" +msgstr "Barrera contra hielo y agua" -# Source-Hash: be9c810d28d1feb9 +# Source-Hash: 6d79431c0092abac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End infill fills the space above the walls. Edit room walls and ceilings separately." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.endInfillFillsTheSpaceAbove" -msgstr "El relleno de testero llena el espacio sobre los muros. Edita los muros y techos de las estancias por separado." +msgid "node.roofSegment.buildUpSection.insulationName" +msgstr "Nombre del aislamiento" -# Source-Hash: 0b8b27dbc57cca44 +# Source-Hash: e4e9305964238fda # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame color" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Interior finish" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.frameColor" -msgstr "Color del marco" +msgid "node.roofSegment.buildUpSection.interiorFinish" +msgstr "Acabado interior" -# Source-Hash: fd413477f1a9e5ed +# Source-Hash: 4ccd2fc1a471fca5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame depth" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layers" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.frameDepth" -msgstr "Profundidad del marco" +msgid "node.roofSegment.buildUpSection.layers" +msgstr "Capas" -# Source-Hash: 3519d91b7bda18a5 +# Source-Hash: 8f343a87f121347e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame width" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "#15 felt" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.frameWidth" -msgstr "Ancho del marco" +msgid "node.roofSegment.buildUpSection.n15Felt" +msgstr "Fieltro #15" -# Source-Hash: c7e72beff9fe4b37 +# Source-Hash: faa54521399dc5b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Framing" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "#30 felt" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.framing" -msgstr "Entramado" +msgid "node.roofSegment.buildUpSection.n30Felt" +msgstr "Fieltro #30" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.glass" -msgstr "Vidrio" +msgid "node.roofSegment.buildUpSection.none" +msgstr "Ninguna" -# Source-Hash: 9c38875c310547ae +# Source-Hash: 441f7f652ea6a0d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass tint" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preset" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.glassTint" -msgstr "Tinte del vidrio" +msgid "node.roofSegment.buildUpSection.preset" +msgstr "Preajuste" -# Source-Hash: dd330a94b3f7a65a +# Source-Hash: a9cb232546779779 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glazed" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafters" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.glazed" -msgstr "Acristalado" +msgid "node.roofSegment.buildUpSection.rafters" +msgstr "Cabios" -# Source-Hash: e6be52df9197243a +# Source-Hash: 5c0d95afa820e706 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glazing is available for gable, straight shed, and barrel roofs." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roofing" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.glazingIsAvailableForGableStraight" -msgstr "El acristalamiento está disponible para cubiertas a dos aguas, a un agua rectas y abovedadas." +msgid "node.roofSegment.buildUpSection.roofing" +msgstr "Cobertura" -# Source-Hash: a4e7ef2e31d7220b +# Source-Hash: 75a1bff32810894e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid across the roof" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roofing name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.gridAcrossTheRoof" -msgstr "Retícula transversal a la cubierta" +msgid "node.roofSegment.buildUpSection.roofingName" +msgstr "Nombre de la cobertura" -# Source-Hash: 2f28a3b33fccf56b +# Source-Hash: 36a588e44085108c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid along the length" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sheathing" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.gridAlongTheLength" -msgstr "Retícula a lo largo" +msgid "node.roofSegment.buildUpSection.sheathing" +msgstr "Tablero" -# Source-Hash: 1f701893dbf9d72b +# Source-Hash: abdad84e524e56e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid along the slope" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sheathing name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.gridAlongTheSlope" -msgstr "Retícula según la pendiente" +msgid "node.roofSegment.buildUpSection.sheathingName" +msgstr "Nombre del tablero" -# Source-Hash: 20c8dfbadda20e3b +# Source-Hash: a7b5921026935493 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid within each arch bay" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slate" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.gridWithinEachArchBay" -msgstr "Retícula en cada vano en arco" +msgid "node.roofSegment.buildUpSection.slate" +msgstr "Pizarra" -# Source-Hash: 7c339a5fae55681d +# Source-Hash: c156b8bd7920b129 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Infill" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standing-seam metal" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.infill" -msgstr "Relleno" +msgid "node.roofSegment.buildUpSection.standingSeamMetal" +msgstr "Chapa de junta alzada" -# Source-Hash: 1c0b8a5503c5daeb +# Source-Hash: f5defb7d8a17154e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opacity" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Synthetic" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.opacity" -msgstr "Opacidad" +msgid "node.roofSegment.buildUpSection.synthetic" +msgstr "Sintética" -# Source-Hash: 4d412746658f2faf +# Source-Hash: 472f395a8b6319a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pane thickness" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top chord" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.paneThickness" -msgstr "Espesor del paño" +msgid "node.roofSegment.buildUpSection.topChord" +msgstr "Cordón superior" -# Source-Hash: 570136e723cb7d99 +# Source-Hash: 4dd558e7eeec7acf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof system" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trusses" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.roofSystem" -msgstr "Sistema de cubierta" +msgid "node.roofSegment.buildUpSection.trusses" +msgstr "Cerchas" -# Source-Hash: a6a7a36d982b4911 +# Source-Hash: 3909955f8a920be1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roughness" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Underlayment" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.roughness" -msgstr "Rugosidad" +msgid "node.roofSegment.buildUpSection.underlayment" +msgstr "Lámina impermeable" -# Source-Hash: 2fa6fbeda5d45949 +# Source-Hash: 0167cfd2ec25cf5d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spacing is measured on the slope, not its horizontal projection." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Underlayment name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.spacingIsMeasuredOnTheSlope" -msgstr "La separación se mide sobre la pendiente, no en su proyección horizontal." +msgid "node.roofSegment.buildUpSection.underlaymentName" +msgstr "Nombre de la lámina" -# Source-Hash: d998c212030bc7c2 +# Source-Hash: 7095fa6e1c927c5e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wood shake" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.standard" -msgstr "Estándar" +msgid "node.roofSegment.buildUpSection.woodShake" +msgstr "Tejuela de madera" -# Source-Hash: efbe1c4facf561f7 +# Source-Hash: 99afd827dbe5d647 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Subdivides each flat arch bay. Arch bays controls the divisions around the curve." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A single pitched plane of a parent roof." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.roof.glazingPanel.subdividesEachFlatArchBayArch" -msgstr "Subdivide cada vano plano en arco. Vanos en arco controla las divisiones a lo largo de la curva." +msgid "node.roofSegment.description" +msgstr "Un faldón inclinado de una cubierta padre." -# Source-Hash: 1497eac9e4f63016 +# Source-Hash: e72a64b3e00aad98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a panel to override its default infill." -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Segment" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.roof.glazingPanelEditor.chooseAPanelToOverrideIts" -msgstr "Elige un panel para sustituir su relleno predeterminado." +msgid "node.roofSegment.label" +msgstr "Faldón" -# Source-Hash: 3530ac1f4046cd22 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Column" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.column2" -msgstr "Pilar" +msgid "node.roofSegment.panel.actions" +msgstr "Acciones" -# Source-Hash: 9e9715d52410c86f +# Source-Hash: c69865ec5d9d1ac9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Angle" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.custom" -msgstr "Personalizado" +msgid "node.roofSegment.panel.angle" +msgstr "Ángulo" -# Source-Hash: 4ca0e0e73229540c +# Source-Hash: eb8f344a3c137280 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arc" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.default" -msgstr "Predeterminado" +msgid "node.roofSegment.panel.arc" +msgstr "Arco" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 9ef92ad8ae49ed72 +# Source-Hash: 1eb45f83eeaabfad # Review: required -# English: "{columns, plural, one {{columnCount} column} other {{columnCount} columns}} · {rows, plural, one {{rowCount} row} other {{rowCount} rows}}" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto gutters" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.grid" -msgstr "{columns, plural, one {{columnCount} columna} many {{columnCount} columnas} other {{columnCount} columnas}} · {rows, plural, one {{rowCount} fila} many {{rowCount} filas} other {{rowCount} filas}}" +msgid "node.roofSegment.panel.autoGutters" +msgstr "Canalones automáticos" -# Source-Hash: 11624abbcfdd5506 +# Source-Hash: 0986c4933d2b5808 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Individual panels" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto ridge vent" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.individualPanels" -msgstr "Paneles individuales" +msgid "node.roofSegment.panel.autoRidgeVent" +msgstr "Ventilación de cumbrera automática" -# Source-Hash: 3a019ce58d021431 +# Source-Hash: 344fe9d407a233a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel infill" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Barrel" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.panelInfill" -msgstr "Relleno del panel" +msgid "node.roofSegment.panel.barrel" +msgstr "Bóveda" -# Source-Hash: 6eb8025c60d6d3ca +# Source-Hash: 6ca418a2ecab5984 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset to default" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clipped version" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.resetToDefault" -msgstr "Restablecer valores predeterminados" +msgid "node.roofSegment.panel.clippedVersion" +msgstr "Versión recortada" -# Source-Hash: 6fba44f2bfd8af8e +# Source-Hash: 3241ecabee8221a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof face" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Conical" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.roofFace" -msgstr "Faldón" +msgid "node.roofSegment.panel.conical" +msgstr "Cónica" -# Source-Hash: 03a22f6df69c47d3 +# Source-Hash: a37cfbc4db93cfd3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Row" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Conical Shape" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.row2" -msgstr "Fila" +msgid "node.roofSegment.panel.conicalShape" +msgstr "Forma cónica" -# Source-Hash: 6c2cc2d9cd778998 +# Source-Hash: a10f29fcde60eea9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Selected panel infill" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck Thick." +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.selectedPanelInfill" -msgstr "Relleno del panel seleccionado" +msgid "node.roofSegment.panel.deckThick" +msgstr "Esp. tarima" -# Source-Hash: f5f730969df63d1d +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.label" -msgstr "Cubierta" +msgid "node.roofSegment.panel.delete" +msgstr "Eliminar" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.actions" -msgstr "Acciones" +msgid "node.roofSegment.panel.depth" +msgstr "Profundidad" -# Source-Hash: d60471ce3cd45348 +# Source-Hash: 016d8e70618916d4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Chimney" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diameter" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addChimney" -msgstr "Añadir chimenea" +msgid "node.roofSegment.panel.diameter" +msgstr "Diámetro" -# Source-Hash: 1ca6a1cf9cc6e3ed +# Source-Hash: e132bf88b9e4d75e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done editing" +#: packages/nodes/src/roof-segment/panel.tsx +#, fuzzy +msgid "node.roofSegment.panel.doneEditing" +msgstr "Terminar edición" + +# Source-Hash: 00a4416e0a33d856 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Cupola" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drainage" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addCupola" -msgstr "Añadir cúpula" +msgid "node.roofSegment.panel.drainage" +msgstr "Desagüe" -# Source-Hash: 94dea147eeaac52b +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Dormer" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addDormer" -msgstr "Añadir buhardilla" +msgid "node.roofSegment.panel.duplicate" +msgstr "Duplicar" -# Source-Hash: 5679acdd64484726 +# Source-Hash: 6949d667043bee0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Eyebrow Vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addEyebrowVent" -msgstr "Añadir ventilación de ceja" +msgid "node.roofSegment.panel.dutch" +msgstr "Holandesa" -# Source-Hash: 25a141dc0d7c4b44 +# Source-Hash: 4c539865731d5d66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Gutter" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eave cut" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addGutter" -msgstr "Añadir canalón" +msgid "node.roofSegment.panel.eaveCut" +msgstr "Corte del alero" -# Source-Hash: 7230bdc8a2252626 +# Source-Hash: 5c99a67253bfc02a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Skylight" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eave overhang" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addSkylight" -msgstr "Añadir claraboya" +msgid "node.roofSegment.panel.eaveOverhang" +msgstr "Vuelo del alero" -# Source-Hash: 0f220e2602b7ff24 +# Source-Hash: dc90862aafc9d287 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Solar Panel" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit footprint" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addSolarPanel" -msgstr "Añadir panel solar" +msgid "node.roofSegment.panel.editFootprint" +msgstr "Editar huella" -# Source-Hash: 4d83a2e5a4d9e6b4 +# Source-Hash: 9532d5e73585ea62 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End overhang" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addVent" -msgstr "Añadir ventilación" +msgid "node.roofSegment.panel.endOverhang" +msgstr "Vuelo del testero" -# Source-Hash: e9a89a5e4ac8cd61 +# Source-Hash: 74f4143cd02de4a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fascia" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.box" -msgstr "Caja" +msgid "node.roofSegment.panel.fascia" +msgstr "Tabica" -# Source-Hash: 3bf078fe2560daca +# Source-Hash: 45baed9dc8b8047a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "box vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fascia height" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.boxVent" -msgstr "ventilación de caja" +msgid "node.roofSegment.panel.fasciaHeight" +msgstr "Altura de la tabica" -# Source-Hash: 4986740251121471 +# Source-Hash: 9cab4d4c95f63cdd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "chimney" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.chimney" -msgstr "chimenea" +msgid "node.roofSegment.panel.flat" +msgstr "Plana" -# Source-Hash: 9e9715d52410c86f +# Source-Hash: a3c10560fa3c1612 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Footprint" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.custom" -msgstr "Personalizado" +msgid "node.roofSegment.panel.footprint" +msgstr "Huella" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: deaffa095d126dfe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.delete" -msgstr "Eliminar" +msgid "node.roofSegment.panel.gable" +msgstr "Dos aguas" -# Source-Hash: 5169968a4b0c1840 +# Source-Hash: dbd062efc7f4fd7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "dormer" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable overhang" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.dormer" -msgstr "buhardilla" +msgid "node.roofSegment.panel.gableOverhang" +msgstr "Vuelo del hastial" -# Source-Hash: 72e51c6e5e9c6c26 +# Source-Hash: 7f53d9ffca39984a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw Segment" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.drawSegment" -msgstr "Dibujar segmento" +msgid "node.roofSegment.panel.gambrel" +msgstr "Holandés de buhardilla" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 9eda0ea8d447066d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hip" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.duplicate" -msgstr "Duplicar" +msgid "node.roofSegment.panel.hip" +msgstr "Cuatro aguas" -# Source-Hash: 7c4196b9e791c195 +# Source-Hash: 7ae4179d0abd80f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elements" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kink Depth" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.elements" -msgstr "Elementos" +msgid "node.roofSegment.panel.kinkDepth" +msgstr "Profundidad del quiebro" -# Source-Hash: 6b8ba49aa355fe87 +# Source-Hash: e19b2bca70030855 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows walls" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kink Height" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.followsWalls" -msgstr "Sigue los muros" +msgid "node.roofSegment.panel.kinkHeight" +msgstr "Altura del quiebro" -# Source-Hash: 23b434461c990711 +# Source-Hash: 643687bc3adaac76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "gutter" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.gutter" -msgstr "canalón" +msgid "node.roofSegment.panel.length" +msgstr "Longitud" -# Source-Hash: 0608743fc1736d86 +# Source-Hash: 7f7bb0e875af3260 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.level" -msgstr "Planta" +msgid "node.roofSegment.panel.mansard" +msgstr "Mansarda" # Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Move" -#: packages/nodes/src/roof/panel.tsx +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.move" +msgid "node.roofSegment.panel.move" msgstr "Mover" -# Source-Hash: 39661f4827b0f435 +# Source-Hash: 75e3449fc1776d09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move to {level}" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pitch" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.moveToLevel" -msgstr "Mover a {level}" +msgid "node.roofSegment.panel.pitch" +msgstr "Pendiente" -# Source-Hash: c534093ff560a9f0 +# Source-Hash: 6ae4075a23bb4ec4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move to the roof level" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plumb" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.moveToTheRoofLevel" -msgstr "Mover a la planta de cubierta" +msgid "node.roofSegment.panel.plumb" +msgstr "A plomo" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 0939fad1cb1831f0 +# Source-Hash: 16d8ab5937d74bdb # Review: required -# English: "On {storey} with its walls, so it hides that floor's plan in solo and exploded views.{roofs, plural, =0 {} =1 {} other { The floor's {roofCount} roofs move together.}}" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plumb + level" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.onStoreyWalls" -msgstr "En {storey} con sus muros, así que oculta el plano de esa planta en las vistas aislada y explosionada.{roofs, plural, =0 {} =1 {} one {} many { Las {roofCount} cubiertas de la planta se mueven juntas.} other { Las {roofCount} cubiertas de la planta se mueven juntas.}}" +msgid "node.roofSegment.panel.plumbLevel" +msgstr "A plomo + horizontal" # Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Position" -#: packages/nodes/src/roof/panel.tsx +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.position" +msgid "node.roofSegment.panel.position" msgstr "Posición" -# Source-Hash: e6ddc8a624465793 +# Source-Hash: bf91b71a9aa76e94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ridge" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.ridge" -msgstr "Cumbrera" +msgid "node.roofSegment.panel.reset" +msgstr "Restablecer" -# Source-Hash: 83112cbc205e9972 +# Source-Hash: e72a64b3e00aad98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "ridge vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Segment" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.ridgeVent" -msgstr "ventilación de cumbrera" +msgid "node.roofSegment.panel.roofSegment" +msgstr "Faldón" -# Source-Hash: f5f730969df63d1d +# Source-Hash: 19ab9527ae7889f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Type" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.roof" -msgstr "Cubierta" +msgid "node.roofSegment.panel.roofType" +msgstr "Tipo de cubierta" # Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rotation" -#: packages/nodes/src/roof/panel.tsx +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.rotation" +msgid "node.roofSegment.panel.rotation" msgstr "Rotación" -# Source-Hash: 505d8419cf4cc5e1 +# Source-Hash: 85ea1d3c8b749680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segments" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.segments" -msgstr "Segmentos" +msgid "node.roofSegment.panel.shape" +msgstr "Forma" -# Source-Hash: 0c084c517dbc153b +# Source-Hash: c8d0df27faa3feaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{roofType, select, hip {Hip} gable {Gable} shed {Shed} gambrel {Gambrel} dutch {Dutch} mansard {Mansard} flat {Flat} conical {Conical} barrel {Barrel} other {Roof}}" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.segmentType" -msgstr "{roofType, select, hip {A cuatro aguas} gable {A dos aguas} shed {A un agua} gambrel {Holandesa} dutch {Mixta} mansard {Mansarda} flat {Plana} conical {Cónica} barrel {Abovedada} other {Cubierta}}" +msgid "node.roofSegment.panel.shed" +msgstr "Un agua" -# Source-Hash: 0c4c82caccb4775c +# Source-Hash: 4d944a2393bbddb2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "skylight" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingle Thick." +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.skylight" -msgstr "claraboya" +msgid "node.roofSegment.panel.shingleThick" +msgstr "Esp. teja" -# Source-Hash: b9f931508dd6ec70 +# Source-Hash: 93b34a5b546664c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "solar panel" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Span" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.solarPanel" -msgstr "panel solar" +msgid "node.roofSegment.panel.span" +msgstr "Luz" -# Source-Hash: d2428b22f1757a4e +# Source-Hash: 39287346366fc206 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Turbine" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.turbine" -msgstr "Turbina" +msgid "node.roofSegment.panel.square" +msgstr "A escuadra" -# Source-Hash: 86d02a3d3a3a7fa2 +# Source-Hash: e90aceedf4a6b183 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "turbine vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start Angle" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.turbineVent" -msgstr "aireador de turbina" +msgid "node.roofSegment.panel.startAngle" +msgstr "Ángulo inicial" -# Source-Hash: 99afd827dbe5d647 +# Source-Hash: a20c89205a4448d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A single pitched plane of a parent roof." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.description" -msgstr "Un faldón inclinado de una cubierta padre." +msgid "node.roofSegment.panel.structure" +msgstr "Estructura" -# Source-Hash: e72a64b3e00aad98 +# Source-Hash: a2db62c74fe2bcee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Segment" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Rake Length" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.label" -msgstr "Faldón" +msgid "node.roofSegment.panel.topRakeLength" +msgstr "Longitud del alero superior" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 913d9552030ac86a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Rake Thick." #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.actions" -msgstr "Acciones" +msgid "node.roofSegment.panel.topRakeThick" +msgstr "Esp. alero superior" -# Source-Hash: c69865ec5d9d1ac9 +# Source-Hash: 3beb5eb35f0c5c17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trim" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.angle" -msgstr "Ángulo" +msgid "node.roofSegment.panel.trim" +msgstr "Molduras" -# Source-Hash: eb8f344a3c137280 +# Source-Hash: e6c5009c0d31fca1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arc" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist Height" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.arc" -msgstr "Arco" +msgid "node.roofSegment.panel.waistHeight" +msgstr "Altura de cintura" -# Source-Hash: 1eb45f83eeaabfad +# Source-Hash: 4a8caffd24b6ee02 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto gutters" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist Length" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.autoGutters" -msgstr "Canalones automáticos" +msgid "node.roofSegment.panel.waistLength" +msgstr "Longitud de cintura" -# Source-Hash: 0986c4933d2b5808 +# Source-Hash: 71045af5c81a11e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto ridge vent" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist Width" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.autoRidgeVent" -msgstr "Ventilación de cumbrera automática" +msgid "node.roofSegment.panel.waistWidth" +msgstr "Ancho de cintura" -# Source-Hash: 344fe9d407a233a9 +# Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Barrel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.barrel" -msgstr "Bóveda" +msgid "node.roofSegment.panel.wall" +msgstr "Muro" -# Source-Hash: 6ca418a2ecab5984 +# Source-Hash: e0f973edce3e4ca8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clipped version" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall Height" +#: packages/nodes/src/roof-segment/panel.tsx +#, fuzzy +msgid "node.roofSegment.panel.wallHeight" +msgstr "Altura del muro" + +# Source-Hash: d0db6dee5fe2edbd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall Thick." #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.clippedVersion" -msgstr "Versión recortada" +msgid "node.roofSegment.panel.wallThick" +msgstr "Esp. muro" -# Source-Hash: 3241ecabee8221a1 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Conical" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.conical" -msgstr "Cónica" +msgid "node.roofSegment.panel.width" +msgstr "Ancho" -# Source-Hash: a37cfbc4db93cfd3 +# Source-Hash: 6600a850000b98ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Conical Shape" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A captured session with optional mesh, motion, media, and sensor data." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.roofSegment.panel.conicalShape" -msgstr "Forma cónica" +msgid "node.scan.description" +msgstr "Sesión capturada con malla, movimiento, medios y datos de sensores opcionales." -# Source-Hash: a10f29fcde60eea9 +# Source-Hash: 3a0701ebcb9f26cb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Deck Thick." -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Capture" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.roofSegment.panel.deckThick" -msgstr "Esp. tarima" +msgid "node.scan.label" +msgstr "Captura" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 95b5307eefb187c6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segment {number}" +#: packages/nodes/src/door/panel.tsx +#: packages/nodes/src/roof/panel.tsx +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.delete" -msgstr "Eliminar" +msgid "node.segmentNumber" +msgstr "Segmento {number}" -# Source-Hash: 99ac4d03c3061f3a +# Source-Hash: acb8cb92b3674b50 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Separator" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.roofSegment.panel.depth" -msgstr "Profundidad" +msgid "node.separator.label" +msgstr "Separador" -# Source-Hash: 016d8e70618916d4 +# Source-Hash: e34eb5b5bfbfce7c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diameter" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Batt" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.diameter" -msgstr "Diámetro" +msgid "node.shared.buildUpControls.batt" +msgstr "Manta" -# Source-Hash: e132bf88b9e4d75e +# Source-Hash: 430cef5fa9bd2787 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done editing" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Blown" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.doneEditing" -msgstr "Terminar edición" +msgid "node.shared.buildUpControls.blown" +msgstr "Insuflado" -# Source-Hash: 00a4416e0a33d856 +# Source-Hash: 4da800c75b9a6b23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drainage" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drywall" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.drainage" -msgstr "Desagüe" +msgid "node.shared.buildUpControls.drywall" +msgstr "Placa de yeso" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 4e8f119349fa2dd4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drywall thickness" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.duplicate" -msgstr "Duplicar" +msgid "node.shared.buildUpControls.drywallThickness" +msgstr "Espesor de la placa de yeso" -# Source-Hash: 6949d667043bee0b +# Source-Hash: 7d6ed24c02ab0c5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.dutch" -msgstr "Holandesa" +msgid "node.shared.buildUpControls.insulation" +msgstr "Aislamiento" -# Source-Hash: 5c99a67253bfc02a +# Source-Hash: 4251fc1e9051a7db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Eave overhang" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation thickness" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.eaveOverhang" -msgstr "Vuelo del alero" +msgid "node.shared.buildUpControls.insulationThickness" +msgstr "Espesor del aislamiento" -# Source-Hash: dc90862aafc9d287 +# Source-Hash: f567133879529366 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit footprint" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label} thickness" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.editFootprint" -msgstr "Editar huella" +msgid "node.shared.buildUpControls.labelThickness" +msgstr "Espesor de {label}" -# Source-Hash: 9532d5e73585ea62 +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End overhang" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.endOverhang" -msgstr "Vuelo del testero" +msgid "node.shared.buildUpControls.none" +msgstr "Ninguno" -# Source-Hash: 74f4143cd02de4a6 +# Source-Hash: 4f7f8af75bf8e914 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fascia" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "OSB" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.fascia" -msgstr "Tabica" +msgid "node.shared.buildUpControls.osb" +msgstr "OSB" -# Source-Hash: 45baed9dc8b8047a +# Source-Hash: a6fd2cbf5c2154e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fascia height" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plaster" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.fasciaHeight" -msgstr "Altura de la tabica" +msgid "node.shared.buildUpControls.plaster" +msgstr "Enlucido" -# Source-Hash: 9cab4d4c95f63cdd +# Source-Hash: e669c2c08bd80e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plywood" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.flat" -msgstr "Plana" +msgid "node.shared.buildUpControls.plywood" +msgstr "Contrachapado" -# Source-Hash: a3c10560fa3c1612 +# Source-Hash: 3d153fa2037159f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Footprint" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rigid board" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.footprint" -msgstr "Huella" +msgid "node.shared.buildUpControls.rigidBoard" +msgstr "Panel rígido" -# Source-Hash: deaffa095d126dfe +# Source-Hash: e4698e83d02beb6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spacing" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.gable" -msgstr "Dos aguas" +msgid "node.shared.buildUpControls.spacing" +msgstr "Separación" -# Source-Hash: dbd062efc7f4fd7f +# Source-Hash: bb2a1cccfd0bd194 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable overhang" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{spacing} o.c." +#. A framing spacing on centre (centre of one member to the next), e.g. 16" o.c. +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.gableOverhang" -msgstr "Vuelo del hastial" +msgid "node.shared.buildUpControls.spacingOC" +msgstr "{spacing} a ejes" -# Source-Hash: 7f53d9ffca39984a +# Source-Hash: ab62afff8ba3f37f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wood plank" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.gambrel" -msgstr "Holandés de buhardilla" +msgid "node.shared.buildUpControls.woodPlank" +msgstr "Tabla de madera" -# Source-Hash: 9eda0ea8d447066d +# Source-Hash: e7512c891d8da7d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hip" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turn light off" +#: packages/nodes/src/shared/item-interaction-actions.tsx #, fuzzy -msgid "node.roofSegment.panel.hip" -msgstr "Cuatro aguas" +msgid "node.shared.itemInteractionActions.turnLightOff" +msgstr "Apagar la luz" -# Source-Hash: 7ae4179d0abd80f5 +# Source-Hash: d47ec95e14909fe5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kink Depth" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turn light on" +#: packages/nodes/src/shared/item-interaction-actions.tsx #, fuzzy -msgid "node.roofSegment.panel.kinkDepth" -msgstr "Profundidad del quiebro" +msgid "node.shared.itemInteractionActions.turnLightOn" +msgstr "Encender la luz" -# Source-Hash: e19b2bca70030855 +# Source-Hash: 18bf48fbbe121ef0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kink Height" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Casing" +#: packages/nodes/src/shared/opening-casing-section.tsx #, fuzzy -msgid "node.roofSegment.panel.kinkHeight" -msgstr "Altura del quiebro" +msgid "node.shared.openingCasingSection.casing" +msgstr "Tapajuntas" -# Source-Hash: 643687bc3adaac76 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/shared/opening-casing-section.tsx #, fuzzy -msgid "node.roofSegment.panel.length" -msgstr "Longitud" +msgid "node.shared.openingCasingSection.width" +msgstr "Ancho" -# Source-Hash: 7f7bb0e875af3260 +# Source-Hash: ee1c8bc3e27fb550 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Automatic support" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.mansard" -msgstr "Mansarda" +msgid "node.shared.runHangerInspector.automaticSupport" +msgstr "Soporte automático" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 1353e40320c72a99 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger {number} · segment {segment}" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.move" -msgstr "Mover" +msgid "node.shared.runHangerInspector.hangerOnSegment" +msgstr "Colgador {number} · segmento {segment}" -# Source-Hash: 75e3449fc1776d09 +# Source-Hash: 737ced90d0454197 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pitch" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Individual hangers" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.pitch" -msgstr "Pendiente" +msgid "node.shared.runHangerInspector.individualHangers" +msgstr "Colgadores individuales" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: e6b17b09ed91c8c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Missing support" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.position" -msgstr "Posición" +msgid "node.shared.runHangerInspector.missingSupport" +msgstr "Falta soporte" -# Source-Hash: bf91b71a9aa76e94 +# Source-Hash: c895c3c603382ec9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No support within reach. Move the hanger or choose another host." +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.reset" -msgstr "Restablecer" +msgid "node.shared.runHangerInspector.noSupportWithinReachMoveThe" +msgstr "No hay soporte al alcance. Mueve el colgador o elige otro anclaje." -# Source-Hash: e72a64b3e00aad98 +# Source-Hash: 6ce526cb7444be36 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Segment" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger {number} position in metres" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.roofSegment" -msgstr "Faldón" +msgid "node.shared.runHangerInspector.positionLabel" +msgstr "Posición del colgador {number} en metros" -# Source-Hash: 19ab9527ae7889f4 +# Source-Hash: cbd36c4b82a55539 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Type" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position (m)" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.roofType" -msgstr "Tipo de cubierta" +msgid "node.shared.runHangerInspector.positionM" +msgstr "Posición (m)" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: b629c4f8388fd36f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Positions are measured along each path segment. Changing spacing regenerates the numbered slots." +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.rotation" -msgstr "Rotación" +msgid "node.shared.runHangerInspector.positionsAreMeasuredAlongEachPath" +msgstr "Las posiciones se miden a lo largo de cada segmento del trazado. Cambiar la separación regenera las posiciones numeradas." -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: c21cfbdb64e53388 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reveal support" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.shape" -msgstr "Forma" +msgid "node.shared.runHangerInspector.revealSupport" +msgstr "Mostrar soporte" -# Source-Hash: c8d0df27faa3feaa +# Source-Hash: 9d5e4440db18e477 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Skip" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.shed" -msgstr "Un agua" +msgid "node.shared.runHangerInspector.skip" +msgstr "Omitir" -# Source-Hash: 4d944a2393bbddb2 +# Source-Hash: 1b184f78bf989931 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingle Thick." -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger {number} support" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.shingleThick" -msgstr "Esp. teja" +msgid "node.shared.runHangerInspector.supportLabel" +msgstr "Soporte del colgador {number}" -# Source-Hash: 93b34a5b546664c4 +# Source-Hash: b2d703d283baf64a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Span" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "About these checks" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.span" -msgstr "Luz" +msgid "node.shared.systemCheckPanel.aboutTheseChecks" +msgstr "Acerca de estas comprobaciones" -# Source-Hash: e90aceedf4a6b183 +# Source-Hash: 461cc26706956993 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start Angle" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All findings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.startAngle" -msgstr "Ángulo inicial" +msgid "node.shared.systemCheckPanel.allFindings" +msgstr "Todos los hallazgos" -# Source-Hash: a20c89205a4448d2 +# Source-Hash: 7beeb4c4997f5edb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All systems" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.structure" -msgstr "Estructura" +msgid "node.shared.systemCheckPanel.allSystems" +msgstr "Todos los sistemas" -# Source-Hash: a2db62c74fe2bcee +# Source-Hash: d613df280aa13b42 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Rake Length" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connections" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.topRakeLength" -msgstr "Longitud del alero superior" +msgid "node.shared.systemCheckPanel.connections" +msgstr "Conexiones" -# Source-Hash: 913d9552030ac86a +# Source-Hash: 00a4416e0a33d856 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Rake Thick." -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drainage" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.topRakeThick" -msgstr "Esp. alero superior" +msgid "node.shared.systemCheckPanel.drainage" +msgstr "Desagüe" -# Source-Hash: 3beb5eb35f0c5c17 +# Source-Hash: fc4ac19649f0ee8f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trim" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Error" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.trim" -msgstr "Molduras" +msgid "node.shared.systemCheckPanel.error" +msgstr "Error" -# Source-Hash: e6c5009c0d31fca1 +# Source-Hash: b92720ff88a1bcfd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist Height" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Errors" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.waistHeight" -msgstr "Altura de cintura" +msgid "node.shared.systemCheckPanel.errors" +msgstr "Errores" -# Source-Hash: 4a8caffd24b6ee02 +# Source-Hash: d0e23bdbe1b380ff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist Length" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Filter system checks" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.waistLength" -msgstr "Longitud de cintura" +msgid "node.shared.systemCheckPanel.filterSystemChecks" +msgstr "Filtrar comprobaciones" -# Source-Hash: 71045af5c81a11e4 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist Width" -#: packages/nodes/src/roof-segment/panel.tsx +# Source-Hash: 30d8dba84c42040e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hangers" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.waistWidth" -msgstr "Ancho de cintura" +msgid "node.shared.systemCheckPanel.hangers" +msgstr "Colgadores" -# Source-Hash: 2210e5ee50b74dc9 +# Source-Hash: 8cd416ca57d969f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Intersections" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.wall" -msgstr "Muro" +msgid "node.shared.systemCheckPanel.intersections" +msgstr "Intersecciones" -# Source-Hash: e0f973edce3e4ca8 +# Source-Hash: 18d652275a9a525c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Height" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Locate {name} ({id})" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.wallHeight" -msgstr "Altura del muro" +msgid "node.shared.systemCheckPanel.locate" +msgstr "Localizar {name} ({id})" -# Source-Hash: d0db6dee5fe2edbd +# Source-Hash: 88546aa3a5987966 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Thick." -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Missing item" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.wallThick" -msgstr "Esp. muro" +msgid "node.shared.systemCheckPanel.missingItem" +msgstr "Elemento ausente" -# Source-Hash: 3a0ccd6c46877a87 +# Source-Hash: 2452d2922a7ecf4a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No findings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.width" -msgstr "Ancho" +msgid "node.shared.systemCheckPanel.noFindings" +msgstr "Sin hallazgos" -# Source-Hash: 6600a850000b98ad +# Source-Hash: 995442fbfc786768 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A captured session with optional mesh, motion, media, and sensor data." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No findings in this category" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.scan.description" -msgstr "Sesión capturada con malla, movimiento, medios y datos de sensores opcionales." +msgid "node.shared.systemCheckPanel.noFindingsInThisCategory" +msgstr "Sin hallazgos en esta categoría" -# Source-Hash: 3a0701ebcb9f26cb +# Source-Hash: b5c58159b3eef89c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Capture" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open ends" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.scan.label" -msgstr "Captura" +msgid "node.shared.systemCheckPanel.openEnds" +msgstr "Extremos abiertos" -# Source-Hash: 95b5307eefb187c6 +# Source-Hash: 3003dacc858d36ff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segment {number}" -#: packages/nodes/src/door/panel.tsx -#: packages/nodes/src/roof/panel.tsx -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open ends and separate branches may be intentional. Intersection checks use bounding boxes; inspect openings and clearances." +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.segmentNumber" -msgstr "Segmento {number}" +msgid "node.shared.systemCheckPanel.openEndsAndSeparateBranchesMay" +msgstr "Los extremos abiertos y las ramas separadas pueden ser intencionados. Las intersecciones se comprueban con cajas envolventes; revisa huecos y holguras." -# Source-Hash: acb8cb92b3674b50 +# Source-Hash: c40c64562b6a1a91 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Separator" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selected connected system" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.separator.label" -msgstr "Separador" +msgid "node.shared.systemCheckPanel.selectedConnectedSystem" +msgstr "Sistema conectado seleccionado" -# Source-Hash: e7512c891d8da7d8 +# Source-Hash: 68355a98439229e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Turn light off" -#: packages/nodes/src/shared/item-interaction-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selected: {count, plural, one {{number} run} other {{number} runs}} · {length} m" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.itemInteractionActions.turnLightOff" -msgstr "Apagar la luz" +msgid "node.shared.systemCheckPanel.selectedRuns" +msgstr "Seleccionado: {count, plural, one {{number} tramo} many {{number} tramos} other {{number} tramos}} · {length} m" -# Source-Hash: d47ec95e14909fe5 +# Source-Hash: e7a352627f8fcd45 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Turn light on" -#: packages/nodes/src/shared/item-interaction-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Separate branches" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.itemInteractionActions.turnLightOn" -msgstr "Encender la luz" +msgid "node.shared.systemCheckPanel.separateBranches" +msgstr "Ramas separadas" +# Source-Hash: 910a5ee73f2ef8a6 # Review: required -# Source-Hash: ee1c8bc3e27fb550 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Automatic support" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show all findings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.automaticSupport" -msgstr "Soporte automático" +msgid "node.shared.systemCheckPanel.showAllFindings" +msgstr "Mostrar todos los hallazgos" +# Source-Hash: dda8887833d07390 # Review: required -# Source-Hash: 1353e40320c72a99 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger {number} · segment {segment}" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System checks" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.hangerOnSegment" -msgstr "Colgador {number} · segmento {segment}" +msgid "node.shared.systemCheckPanel.systemChecks" +msgstr "Comprobaciones del sistema" +# Source-Hash: 4dad0ed68e63d124 # Review: required -# Source-Hash: 737ced90d0454197 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Individual hangers" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System finding" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.individualHangers" -msgstr "Colgadores individuales" +msgid "node.shared.systemCheckPanel.systemFinding" +msgstr "Hallazgo del sistema" +# Source-Hash: e37307a519466b38 # Review: required -# Source-Hash: e6b17b09ed91c8c2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Missing support" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System findings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.missingSupport" -msgstr "Falta soporte" +msgid "node.shared.systemCheckPanel.systemFindings" +msgstr "Hallazgos del sistema" +# Source-Hash: 5128de8b5a618339 # Review: required -# Source-Hash: c895c3c603382ec9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No support within reach. Move the hanger or choose another host." -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Warning" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.noSupportWithinReachMoveThe" -msgstr "No hay soporte al alcance. Mueve el colgador o elige otro anclaje." +msgid "node.shared.systemCheckPanel.warning" +msgstr "Advertencia" +# Source-Hash: 7e1647f9ce51509e # Review: required -# Source-Hash: 6ce526cb7444be36 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger {number} position in metres" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Warnings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.positionLabel" -msgstr "Posición del colgador {number} en metros" +msgid "node.shared.systemCheckPanel.warnings" +msgstr "Advertencias" +# Source-Hash: 26aff27b7284fc84 # Review: required -# Source-Hash: cbd36c4b82a55539 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position (m)" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A configurable shelving unit. Items host on each row." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.shared.runHangerInspector.positionM" -msgstr "Posición (m)" +msgid "node.shelf.description" +msgstr "Estantería configurable. Los elementos se apoyan en cada fila." +# Source-Hash: d7145f84f8e0e3fe # Review: required -# Source-Hash: b629c4f8388fd36f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Positions are measured along each path segment. Changing spacing regenerates the numbered slots." -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shelf" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.shared.runHangerInspector.positionsAreMeasuredAlongEachPath" -msgstr "Las posiciones se miden a lo largo de cada segmento del trazado. Cambiar la separación regenera las posiciones numeradas." +msgid "node.shelf.label" +msgstr "Estantería" +# Source-Hash: c52492c73312a922 # Review: required -# Source-Hash: c21cfbdb64e53388 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reveal support" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The top-level container holding buildings, zones, and the property boundary." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.shared.runHangerInspector.revealSupport" -msgstr "Mostrar soporte" +msgid "node.site.description" +msgstr "Contenedor de nivel superior con edificios, zonas y el límite de la parcela." +# Source-Hash: 91f90818d42a984e # Review: required -# Source-Hash: 9d5e4440db18e477 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Skip" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Site" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.shared.runHangerInspector.skip" -msgstr "Omitir" +msgid "node.site.label" +msgstr "Parcela" +# Source-Hash: 3b5a53b6d058a02a # Review: required -# Source-Hash: 1b184f78bf989931 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger {number} support" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Address" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.supportLabel" -msgstr "Soporte del colgador {number}" +msgid "node.site.panel.address" +msgstr "Dirección" -# Source-Hash: b2d703d283baf64a +# Source-Hash: ea03c49930137a0f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "About these checks" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "APN" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.aboutTheseChecks" -msgstr "Acerca de estas comprobaciones" +msgid "node.site.panel.apn" +msgstr "N.º de parcela" -# Source-Hash: 461cc26706956993 +# Source-Hash: 8519c9ddf5e6b371 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All findings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto — most north-facing edge" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.allFindings" -msgstr "Todos los hallazgos" +msgid "node.site.panel.autoMostNorthFacingEdge" +msgstr "Auto — borde más orientado al norte" -# Source-Hash: 7beeb4c4997f5edb +# Source-Hash: bc493d7655b3e3ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All systems" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Contour interval (site plan and 3D)" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.allSystems" -msgstr "Todos los sistemas" +msgid "node.site.panel.contourIntervalSitePlanAnd3d" +msgstr "Equidistancia de curvas (plano de emplazamiento y 3D)" -# Source-Hash: d613df280aa13b42 +# Source-Hash: 99208d226da1315f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connections" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "County" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.connections" -msgstr "Conexiones" +msgid "node.site.panel.county" +msgstr "Condado" -# Source-Hash: 00a4416e0a33d856 +# Source-Hash: 0830cf0f95ad429d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drainage" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "e.g. RS-60" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.drainage" -msgstr "Desagüe" +msgid "node.site.panel.eGRs60" +msgstr "p. ej. RS-60" -# Source-Hash: fc4ac19649f0ee8f +# Source-Hash: b3e7e118266b5074 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Error" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "e.g. Tampa LDC §27-156" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.error" -msgstr "Error" +msgid "node.site.panel.eGTampaLdc27156" +msgstr "p. ej. Tampa LDC §27-156" -# Source-Hash: b92720ff88a1bcfd +# Source-Hash: 187e11889d08a2dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Errors" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "every 12 in" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.errors" -msgstr "Errores" +msgid "node.site.panel.every12In" +msgstr "cada 12 in" -# Source-Hash: d0e23bdbe1b380ff +# Source-Hash: 17ee041f655085f8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Filter system checks" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "every 24 in" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.filterSystemChecks" -msgstr "Filtrar comprobaciones" +msgid "node.site.panel.every24In" +msgstr "cada 24 in" -# Source-Hash: 30d8dba84c42040e +# Source-Hash: 40d7f9ddf5efcb7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hangers" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "every 6 in" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.hangers" -msgstr "Colgadores" +msgid "node.site.panel.every6In" +msgstr "cada 6 in" -# Source-Hash: 8cd416ca57d969f5 +# Source-Hash: 442a3ce78ae6b462 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Intersections" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finding…" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.intersections" -msgstr "Intersecciones" +msgid "node.site.panel.finding" +msgstr "Buscando…" -# Source-Hash: 18d652275a9a525c +# Source-Hash: 734c1eac014adc69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Locate {name} ({id})" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Find parcel" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.locate" -msgstr "Localizar {name} ({id})" +msgid "node.site.panel.findParcel" +msgstr "Buscar parcela" -# Source-Hash: 88546aa3a5987966 +# Source-Hash: ccb70faaf91dbcb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Missing item" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front (street) edge" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.missingItem" -msgstr "Elemento ausente" +msgid "node.site.panel.frontStreetEdge" +msgstr "Borde frontal (calle)" -# Source-Hash: 2452d2922a7ecf4a +# Source-Hash: 4232218226616327 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No findings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Looking up the parcel and the streets around it…" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.noFindings" -msgstr "Sin hallazgos" +msgid "node.site.panel.lookingUpTheParcel" +msgstr "Buscando la parcela y las calles de alrededor…" -# Source-Hash: 995442fbfc786768 +# Source-Hash: c39eb5933468a637 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No findings in this category" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lot area" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.noFindingsInThisCategory" -msgstr "Sin hallazgos en esta categoría" +msgid "node.site.panel.lotArea" +msgstr "Superficie de la parcela" -# Source-Hash: b5c58159b3eef89c +# Source-Hash: c8a874b339ff9696 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open ends" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "1200 W Cass St, Tampa, FL" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.openEnds" -msgstr "Extremos abiertos" +msgid "node.site.panel.n1200WCassStTampaFl" +msgstr "1200 W Cass St, Tampa, FL" -# Source-Hash: 3003dacc858d36ff +# Source-Hash: 30a0924a3360be68 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open ends and separate branches may be intentional. Intersection checks use bounding boxes; inspect openings and clearances." -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "none" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.openEndsAndSeparateBranchesMay" -msgstr "Los extremos abiertos y las ramas separadas pueden ser intencionados. Las intersecciones se comprueban con cajas envolventes; revisa huecos y holguras." +msgid "node.site.panel.none" +msgstr "ninguno" -# Source-Hash: c40c64562b6a1a91 +# Source-Hash: dd4e835cb90c5736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Selected connected system" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "North rotation" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.selectedConnectedSystem" -msgstr "Sistema conectado seleccionado" +msgid "node.site.panel.northRotation" +msgstr "Rotación del norte" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 68355a98439229e2 -# Review: required -# English: "Selected: {count, plural, one {{number} run} other {{number} runs}} · {length} m" -#: packages/nodes/src/shared/system-check-panel.tsx +# Source-Hash: a4bfb2891c820e2e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No surveyed lines — contours are drawn from the sculpted ground." +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.selectedRuns" -msgstr "Seleccionado: {count, plural, one {{number} tramo} many {{number} tramos} other {{number} tramos}} · {length} m" +msgid "node.site.panel.noSurveyedLinesContoursAreDrawn" +msgstr "Sin líneas topográficas: las curvas se dibujan a partir del terreno modelado." -# Source-Hash: e7a352627f8fcd45 +# Source-Hash: 1f0d024c0adbf0e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Separate branches" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Orientation" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.separateBranches" -msgstr "Ramas separadas" +msgid "node.site.panel.orientation" +msgstr "Orientación" -# Source-Hash: 910a5ee73f2ef8a6 +# Source-Hash: 9a3961409e34bf66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show all findings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Parcel" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.showAllFindings" -msgstr "Mostrar todos los hallazgos" +msgid "node.site.panel.parcel" +msgstr "Parcela" -# Source-Hash: dda8887833d07390 +# Source-Hash: 3aecc563cb9a2c68 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System checks" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Parcel lookup failed." +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.systemChecks" -msgstr "Comprobaciones del sistema" +msgid "node.site.panel.parcelLookupFailed" +msgstr "La búsqueda de la parcela ha fallado." -# Source-Hash: 4dad0ed68e63d124 +# Source-Hash: 36696c4a8bede421 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System finding" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Project look" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.systemFinding" -msgstr "Hallazgo del sistema" +msgid "node.site.panel.projectLook" +msgstr "Aspecto del proyecto" -# Source-Hash: e37307a519466b38 +# Source-Hash: 5b50fc78ccdaf7aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System findings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Save current look" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.systemFindings" -msgstr "Hallazgos del sistema" +msgid "node.site.panel.saveCurrentLook" +msgstr "Guardar el aspecto actual" -# Source-Hash: 5128de8b5a618339 +# Source-Hash: f06b316f421963d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Warning" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Save the current lighting and display as this project's default. Personal display changes stay in this browser." +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.warning" -msgstr "Advertencia" +msgid "node.site.panel.saveTheCurrentLightingAndDisplay" +msgstr "Guardar la iluminación y la visualización actuales como predeterminadas del proyecto. Los cambios personales de visualización se quedan en este navegador." -# Source-Hash: 7e1647f9ce51509e +# Source-Hash: e87df48b61eda8ce # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Warnings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Setbacks" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.warnings" -msgstr "Advertencias" +msgid "node.site.panel.setbacks" +msgstr "Retranqueos" -# Source-Hash: 26aff27b7284fc84 +# Source-Hash: 9ede31abea7ad545 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A configurable shelving unit. Items host on each row." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show ground" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shelf.description" -msgstr "Estantería configurable. Los elementos se apoyan en cada fila." +msgid "node.site.panel.showGround" +msgstr "Mostrar terreno" -# Source-Hash: d7145f84f8e0e3fe +# Source-Hash: 1e16a47e5e10c83e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shelf" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show the contour lines in 3D" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shelf.label" -msgstr "Estantería" +msgid "node.site.panel.showTheContourLinesIn3d" +msgstr "Mostrar las curvas de nivel en 3D" -# Source-Hash: c52492c73312a922 +# Source-Hash: 464241679edcbdb4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The top-level container holding buildings, zones, and the property boundary." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "side" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.description" -msgstr "Contenedor de nivel superior con edificios, zonas y el límite de la parcela." +msgid "node.site.panel.side" +msgstr "lateral" # Source-Hash: 91f90818d42a984e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Site" -#: packages/nodes/src/i18n/definition-messages.ts +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.label" +msgid "node.site.panel.site" msgstr "Parcela" -# Source-Hash: 3b5a53b6d058a02a +# Source-Hash: 6165ee130f0082e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Address" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Source" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.address" -msgstr "Dirección" +msgid "node.site.panel.source" +msgstr "Fuente" -# Source-Hash: ea03c49930137a0f +# Source-Hash: 5f3110d075c6a1a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "APN" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Source / citation" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.apn" -msgstr "N.º de parcela" +msgid "node.site.panel.sourceCitation" +msgstr "Fuente / cita" -# Source-Hash: 8519c9ddf5e6b371 +# Source-Hash: 041cfc610fef830b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto — most north-facing edge" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Street address" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.autoMostNorthFacingEdge" -msgstr "Auto — borde más orientado al norte" +msgid "node.site.panel.streetAddress" +msgstr "Dirección postal" -# Source-Hash: bc493d7655b3e3ad +# Source-Hash: bdca51c5e6437075 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Contour interval (site plan and 3D)" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "survey" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.contourIntervalSitePlanAnd3d" -msgstr "Equidistancia de curvas (plano de emplazamiento y 3D)" +msgid "node.site.panel.survey" +msgstr "levantamiento" -# Source-Hash: 99208d226da1315f +# Source-Hash: 2177f21713b01a24 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "County" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {{lineCount} surveyed line} other {{lineCount} surveyed lines}} at {interval} ft ({datum}) — {source}" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.county" -msgstr "Condado" +msgid "node.site.panel.surveyedContours" +msgstr "{count, plural, one {{lineCount} línea topográfica} many {{lineCount} líneas topográficas} other {{lineCount} líneas topográficas}} cada {interval} ft ({datum}) — {source}" -# Source-Hash: 0830cf0f95ad429d +# Source-Hash: d457508edd5bb8cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "e.g. RS-60" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terrain" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.eGRs60" -msgstr "p. ej. RS-60" +msgid "node.site.panel.terrain" +msgstr "Terreno" -# Source-Hash: b3e7e118266b5074 +# Source-Hash: 4c8601a0b7aeed3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "e.g. Tampa LDC §27-156" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type an address first." #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.eGTampaLdc27156" -msgstr "p. ej. Tampa LDC §27-156" +msgid "node.site.panel.typeAnAddressFirst" +msgstr "Escribe primero una dirección." -# Source-Hash: 187e11889d08a2dc +# Source-Hash: dfe4cd35b3e0d5f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "every 12 in" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use project look" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.every12In" -msgstr "cada 12 in" +msgid "node.site.panel.useProjectLook" +msgstr "Usar el aspecto del proyecto" -# Source-Hash: 17ee041f655085f8 +# Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "every 24 in" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone" +#: packages/nodes/src/site/panel.tsx +#, fuzzy +msgid "node.site.panel.zone" +msgstr "Zona" + +# Source-Hash: e360f89d3c0ec456 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front" +#: packages/nodes/src/site/panel.tsx +#, fuzzy +msgid "node.site.setback.front" +msgstr "Frente" + +# Source-Hash: ab1354f1aa520a54 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left (override)" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.every24In" -msgstr "cada 24 in" +msgid "node.site.setback.leftOverride" +msgstr "Izquierda (sustitución)" -# Source-Hash: 40d7f9ddf5efcb7f +# Source-Hash: 1a7e8e8f8e9232d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "every 6 in" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rear" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.every6In" -msgstr "cada 6 in" +msgid "node.site.setback.rear" +msgstr "Fondo" -# Source-Hash: 442a3ce78ae6b462 +# Source-Hash: 8370146b38c30102 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finding…" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right (override)" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.finding" -msgstr "Buscando…" +msgid "node.site.setback.rightOverride" +msgstr "Derecha (sustitución)" -# Source-Hash: 734c1eac014adc69 +# Source-Hash: feefe9c7cb273e79 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Find parcel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Side" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.findParcel" -msgstr "Buscar parcela" +msgid "node.site.setback.side" +msgstr "Lateral" -# Source-Hash: ccb70faaf91dbcb1 +# Source-Hash: 67d903d7fe0c69c1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front (street) edge" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framed glass opening on a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.site.panel.frontStreetEdge" -msgstr "Borde frontal (calle)" +msgid "node.skylight.description" +msgstr "Abertura acristalada con marco en un faldón." -# Source-Hash: 4232218226616327 +# Source-Hash: 358826fbdeaf72b9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Looking up the parcel and the streets around it…" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Skylight" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.site.panel.lookingUpTheParcel" -msgstr "Buscando la parcela y las calles de alrededor…" +msgid "node.skylight.label" +msgstr "Claraboya" -# Source-Hash: c39eb5933468a637 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lot area" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.lotArea" -msgstr "Superficie de la parcela" +msgid "node.skylight.panel.actions" +msgstr "Acciones" -# Source-Hash: c8a874b339ff9696 +# Source-Hash: f1113261ad2797de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "1200 W Cass St, Tampa, FL" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Along X" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.n1200WCassStTampaFl" -msgstr "1200 W Cass St, Tampa, FL" +msgid "node.skylight.panel.alongX" +msgstr "Según X" -# Source-Hash: 30a0924a3360be68 +# Source-Hash: 5b84b1c644493370 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "none" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Along Z" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.none" -msgstr "ninguno" +msgid "node.skylight.panel.alongZ" +msgstr "Según Z" -# Source-Hash: dd4e835cb90c5736 +# Source-Hash: b3a163b453896bef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "North rotation" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.northRotation" -msgstr "Rotación del norte" +msgid "node.skylight.panel.bottom" +msgstr "Inferior" -# Source-Hash: a4bfb2891c820e2e +# Source-Hash: b8ff053666ee326b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No surveyed lines — contours are drawn from the sculpted ground." -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curb" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.noSurveyedLinesContoursAreDrawn" -msgstr "Sin líneas topográficas: las curvas se dibujan a partir del terreno modelado." +msgid "node.skylight.panel.curb" +msgstr "Bordillo" -# Source-Hash: 1f0d024c0adbf0e8 +# Source-Hash: 14144df9e1364eea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Orientation" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cutout Offset" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.orientation" -msgstr "Orientación" +msgid "node.skylight.panel.cutoutOffset" +msgstr "Desfase del recorte" -# Source-Hash: 9a3961409e34bf66 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Parcel" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.parcel" -msgstr "Parcela" +msgid "node.skylight.panel.delete" +msgstr "Eliminar" -# Source-Hash: 3aecc563cb9a2c68 +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Parcel lookup failed." -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.parcelLookupFailed" -msgstr "La búsqueda de la parcela ha fallado." +msgid "node.skylight.panel.depth" +msgstr "Profundidad" -# Source-Hash: 36696c4a8bede421 +# Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Project look" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.projectLook" -msgstr "Aspecto del proyecto" +msgid "node.skylight.panel.dimensions" +msgstr "Dimensiones" -# Source-Hash: 5b50fc78ccdaf7aa +# Source-Hash: ce3a6c03765dbbd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Save current look" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.saveCurrentLook" -msgstr "Guardar el aspecto actual" +msgid "node.skylight.panel.frame" +msgstr "Marco" -# Source-Hash: f06b316f421963d7 +# Source-Hash: 911ea36eb835f3a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Save the current lighting and display as this project's default. Personal display changes stay in this browser." -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass Thickness" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.saveTheCurrentLightingAndDisplay" -msgstr "Guardar la iluminación y la visualización actuales como predeterminadas del proyecto. Los cambios personales de visualización se quedan en este navegador." +msgid "node.skylight.panel.glassThickness" +msgstr "Grosor del vidrio" -# Source-Hash: e87df48b61eda8ce +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Setbacks" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.setbacks" -msgstr "Retranqueos" +msgid "node.skylight.panel.height" +msgstr "Altura" -# Source-Hash: 9ede31abea7ad545 +# Source-Hash: d56303913961984f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show ground" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern Height" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.showGround" -msgstr "Mostrar terreno" +msgid "node.skylight.panel.lanternHeight" +msgstr "Altura del lucernario" -# Source-Hash: 1e16a47e5e10c83e +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show the contour lines in 3D" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.showTheContourLinesIn3d" -msgstr "Mostrar las curvas de nivel en 3D" +msgid "node.skylight.panel.left" +msgstr "Izquierda" -# Source-Hash: 464241679edcbdb4 +# Source-Hash: f3e9604e3b85510f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "side" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Motor" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.side" -msgstr "lateral" +msgid "node.skylight.panel.motor" +msgstr "Motor" -# Source-Hash: 91f90818d42a984e +# Source-Hash: a025444e0f500725 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Site" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Motor Housing" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.site" -msgstr "Parcela" +msgid "node.skylight.panel.motorHousing" +msgstr "Carcasa del motor" -# Source-Hash: 6165ee130f0082e8 +# Source-Hash: b2cbc4e2e5545a6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Source" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.source" -msgstr "Fuente" +msgid "node.skylight.panel.no" +msgstr "No" -# Source-Hash: 5f3110d075c6a1a7 +# Source-Hash: a8e0b9fe5cfb4e3e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Source / citation" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No Motor" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.sourceCitation" -msgstr "Fuente / cita" +msgid "node.skylight.panel.noMotor" +msgstr "Sin motor" -# Source-Hash: 041cfc610fef830b +# Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Street address" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.streetAddress" -msgstr "Dirección postal" +msgid "node.skylight.panel.open" +msgstr "Abrir" -# Source-Hash: bdca51c5e6437075 +# Source-Hash: 9bfc55f879926fe6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "survey" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening Angle" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.survey" -msgstr "levantamiento" +msgid "node.skylight.panel.openingAngle" +msgstr "Ángulo de apertura" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 2177f21713b01a24 +# Source-Hash: 9da0cbfad144d737 # Review: required -# English: "{count, plural, one {{lineCount} surveyed line} other {{lineCount} surveyed lines}} at {interval} ft ({datum}) — {source}" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.surveyedContours" -msgstr "{count, plural, one {{lineCount} línea topográfica} many {{lineCount} líneas topográficas} other {{lineCount} líneas topográficas}} cada {interval} ft ({datum}) — {source}" +msgid "node.skylight.panel.position" +msgstr "Posición" -# Source-Hash: d457508edd5bb8cf +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terrain" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.terrain" -msgstr "Terreno" +msgid "node.skylight.panel.right" +msgstr "Derecha" -# Source-Hash: 4c8601a0b7aeed3a +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type an address first." -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.typeAnAddressFirst" -msgstr "Escribe primero una dirección." +msgid "node.skylight.panel.rotation" +msgstr "Rotación" -# Source-Hash: dfe4cd35b3e0d5f5 +# Source-Hash: 358826fbdeaf72b9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use project look" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Skylight" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.useProjectLook" -msgstr "Usar el aspecto del proyecto" +msgid "node.skylight.panel.skylight" +msgstr "Claraboya" -# Source-Hash: a107b4d76d6972e3 +# Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.zone" -msgstr "Zona" +msgid "node.skylight.panel.thickness" +msgstr "Espesor" -# Source-Hash: e360f89d3c0ec456 +# Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.front" -msgstr "Frente" +msgid "node.skylight.panel.top" +msgstr "Superior" -# Source-Hash: ab1354f1aa520a54 +# Source-Hash: 75991d106eb93dae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left (override)" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Scale" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.leftOverride" -msgstr "Izquierda (sustitución)" +msgid "node.skylight.panel.topScale" +msgstr "Escala superior" -# Source-Hash: 1a7e8e8f8e9232d7 +# Source-Hash: 3272a61417949895 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rear" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Track Width" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.rear" -msgstr "Fondo" +msgid "node.skylight.panel.trackWidth" +msgstr "Ancho del riel" -# Source-Hash: 8370146b38c30102 +# Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right (override)" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.rightOverride" -msgstr "Derecha (sustitución)" +msgid "node.skylight.panel.type" +msgstr "Tipo" -# Source-Hash: feefe9c7cb273e79 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Side" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.side" -msgstr "Lateral" +msgid "node.skylight.panel.width" +msgstr "Ancho" -# Source-Hash: 67d903d7fe0c69c1 +# Source-Hash: 184fda5c980b9d9c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Framed glass opening on a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Yes" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.skylight.description" -msgstr "Abertura acristalada con marco en un faldón." +msgid "node.skylight.panel.yes" +msgstr "Sí" -# Source-Hash: 358826fbdeaf72b9 +# Source-Hash: 445aacf307de133d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Skylight" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat roof skylight" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.skylight.label" -msgstr "Claraboya" +msgid "node.skylight.type.flat" +msgstr "Claraboya para cubierta plana" +# Source-Hash: 446176b7c5d8b284 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof lantern" #: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.skylight.panel.actions" -msgstr "Acciones" +msgid "node.skylight.type.lantern" +msgstr "Linterna de cubierta" +# Source-Hash: a6559387f108518f # Review: required -# Source-Hash: f1113261ad2797de -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Along X" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening skylight" #: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.skylight.panel.alongX" -msgstr "Según X" +msgid "node.skylight.type.opening" +msgstr "Claraboya practicable" +# Source-Hash: 379436bb5a74867a # Review: required -# Source-Hash: 5b84b1c644493370 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Along Z" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sliding skylight" #: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.skylight.panel.alongZ" -msgstr "Según Z" +msgid "node.skylight.type.sliding" +msgstr "Claraboya corredera" +# Source-Hash: d26ac61f593fe1bf # Review: required -# Source-Hash: b3a163b453896bef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walk-on rooflight" #: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.skylight.panel.bottom" -msgstr "Inferior" +msgid "node.skylight.type.walkOn" +msgstr "Claraboya transitable" +# Source-Hash: ad8f8036d34f6cea # Review: required -# Source-Hash: b8ff053666ee326b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curb" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A polygon-bounded floor surface that hosts items on top." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.skylight.panel.curb" -msgstr "Bordillo" +msgid "node.slab.description" +msgstr "Superficie de suelo delimitada por un polígono que aloja elementos encima." +# Source-Hash: 8775bc8dc9593964 # Review: required -# Source-Hash: 14144df9e1364eea -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cutout Offset" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.skylight.panel.cutoutOffset" -msgstr "Desfase del recorte" +msgid "node.slab.label" +msgstr "Forjado" +# Source-Hash: 659e6b799ad7c27d # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Hole" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.delete" -msgstr "Eliminar" +msgid "node.slab.panel.addHole" +msgstr "Añadir hueco" +# Source-Hash: 8332ab41e22958f1 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Area" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.depth" -msgstr "Profundidad" +msgid "node.slab.panel.area" +msgstr "Área" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.dimensions" -msgstr "Dimensiones" +msgid "node.slab.panel.auto" +msgstr "Auto" +# Source-Hash: fadada809e27477c # Review: required -# Source-Hash: ce3a6c03765dbbd8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.frame" -msgstr "Marco" +msgid "node.slab.panel.base" +msgstr "Base" +# Source-Hash: 12195951bba19804 # Review: required -# Source-Hash: 911ea36eb835f3a6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass Thickness" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut hatch" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.glassThickness" -msgstr "Grosor del vidrio" +msgid "node.slab.panel.cutHatch" +msgstr "Cortar trampilla" +# Source-Hash: 4e4f1a24e4a9d61e # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut opening" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.height" -msgstr "Altura" +msgid "node.slab.panel.cutOpening" +msgstr "Abrir hueco" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: d56303913961984f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern Height" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.lanternHeight" -msgstr "Altura del lucernario" +msgid "node.slab.panel.depth" +msgstr "Profundidad" +# Source-Hash: 16552c2580bbe8b8 # Review: required -# Source-Hash: f365c6b6dd9ebab9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.left" -msgstr "Izquierda" +msgid "node.slab.panel.done" +msgstr "Hecho" +# Source-Hash: 8a3bc5111b9e97f4 # Review: required -# Source-Hash: f3e9604e3b85510f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Motor" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevation" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.motor" -msgstr "Motor" +msgid "node.slab.panel.elevation" +msgstr "Cota" +# Source-Hash: 201b720b76d79762 # Review: required -# Source-Hash: a025444e0f500725 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Motor Housing" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Extends the perimeter down to terrain. The flat surface, base, and thickness stay unchanged." +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.motorHousing" -msgstr "Carcasa del motor" +msgid "node.slab.panel.extendsThePerimeterDownToTerrain" +msgstr "Extiende el perímetro hasta el terreno. La superficie plana, la base y el espesor no cambian." +# Source-Hash: 387ce45ca2eb045f # Review: required -# Source-Hash: b2cbc4e2e5545a6c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fixed" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.no" -msgstr "No" +msgid "node.slab.panel.fixed" +msgstr "Fijo" +# Source-Hash: d7148fa065bc709b # Review: required -# Source-Hash: a8e0b9fe5cfb4e3e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No Motor" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.noMotor" -msgstr "Sin motor" +msgid "node.slab.panel.floor" +msgstr "Planta" +# Source-Hash: 89b2cfd72a0a7e23 # Review: required -# Source-Hash: 3e52f04f92e08070 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows terrain" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.open" -msgstr "Abrir" +msgid "node.slab.panel.followsTerrain" +msgstr "Sigue el terreno" +# Source-Hash: 48c832c1fc389290 # Review: required -# Source-Hash: 9bfc55f879926fe6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening Angle" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.openingAngle" -msgstr "Ángulo de apertura" +msgid "node.slab.panel.foundation" +msgstr "Cimentación" +# Source-Hash: 34504c6ca6445e76 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Holes" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.position" -msgstr "Posición" +msgid "node.slab.panel.holes" +msgstr "Huecos" +# Source-Hash: 6e68b62d2aa611a4 # Review: required -# Source-Hash: b34d5ee0f218221d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Info" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.right" -msgstr "Derecha" +msgid "node.slab.panel.info" +msgstr "Info" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.rotation" -msgstr "Rotación" +msgid "node.slab.panel.move" +msgstr "Mover" +# Source-Hash: 1d2dafb0d8f26ed5 # Review: required -# Source-Hash: 358826fbdeaf72b9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Skylight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No holes" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.skylight" -msgstr "Claraboya" +msgid "node.slab.panel.noHoles" +msgstr "Sin huecos" +# Source-Hash: c6a29e75bf215488 # Review: required -# Source-Hash: fdbb503f0941bd56 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rim" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.thickness" -msgstr "Espesor" +msgid "node.slab.panel.rim" +msgstr "Borde" +# Source-Hash: 8775bc8dc9593964 # Review: required -# Source-Hash: 27644f0497fd9849 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.top" -msgstr "Superior" +msgid "node.slab.panel.slab" +msgstr "Forjado" +# Source-Hash: fb23c960abf5de23 # Review: required -# Source-Hash: 75991d106eb93dae -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Scale" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard (2\")" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.topScale" -msgstr "Escala superior" +msgid "node.slab.panel.standard2" +msgstr "Estándar (2\")" +# Source-Hash: 5f865b052c9b40eb # Review: required -# Source-Hash: 3272a61417949895 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Track Width" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard (5cm)" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.trackWidth" -msgstr "Ancho del riel" +msgid "node.slab.panel.standard5cm" +msgstr "Estándar (5 cm)" +# Source-Hash: cff0e2e72cfab157 # Review: required -# Source-Hash: c44f7ab8bbd24858 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sunken (15cm)" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.type" -msgstr "Tipo" +msgid "node.slab.panel.sunken15cm" +msgstr "Hundido (15 cm)" +# Source-Hash: 8abc2aec4be98fe9 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sunken (6\")" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.width" -msgstr "Ancho" +msgid "node.slab.panel.sunken6" +msgstr "Hundido (6\")" +# Source-Hash: 78a454b7ac7a3cd9 # Review: required -# Source-Hash: 184fda5c980b9d9c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Yes" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.yes" -msgstr "Sí" +msgid "node.slab.panel.surface" +msgstr "Superficie" +# Source-Hash: 516636d85be919f0 # Review: required -# Source-Hash: 445aacf307de133d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat roof skylight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thick (15cm)" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.type.flat" -msgstr "Claraboya para cubierta plana" +msgid "node.slab.panel.thick15cm" +msgstr "Grueso (15 cm)" +# Source-Hash: c84078f3560da233 # Review: required -# Source-Hash: 446176b7c5d8b284 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof lantern" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thick (6\")" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.type.lantern" -msgstr "Linterna de cubierta" +msgid "node.slab.panel.thick6" +msgstr "Grueso (6\")" +# Source-Hash: fdbb503f0941bd56 # Review: required -# Source-Hash: a6559387f108518f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening skylight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.type.opening" -msgstr "Claraboya practicable" +msgid "node.slab.panel.thickness" +msgstr "Espesor" +# Source-Hash: 61c191f6df40285b # Review: required -# Source-Hash: 379436bb5a74867a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sliding skylight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thin (1\")" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.type.sliding" -msgstr "Claraboya corredera" +msgid "node.slab.panel.thin1" +msgstr "Fino (1\")" +# Source-Hash: d345b1f707506fe7 # Review: required -# Source-Hash: d26ac61f593fe1bf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walk-on rooflight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thin (2cm)" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.type.walkOn" -msgstr "Claraboya transitable" +msgid "node.slab.panel.thin2cm" +msgstr "Fino (2 cm)" -# Source-Hash: ad8f8036d34f6cea +# Source-Hash: 065ffaaf64ab479d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A polygon-bounded floor surface that hosts items on top." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid of photovoltaic panels mounted on a roof segment." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.slab.description" -msgstr "Superficie de suelo delimitada por un polígono que aloja elementos encima." +msgid "node.solarPanel.description" +msgstr "Conjunto de paneles fotovoltaicos montados en un faldón." -# Source-Hash: 8775bc8dc9593964 +# Source-Hash: 4d18446ff8eaa680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solar Panel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.slab.label" -msgstr "Forjado" +msgid "node.solarPanel.label" +msgstr "Panel solar" -# Source-Hash: 659e6b799ad7c27d +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Hole" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.addHole" -msgstr "Añadir hueco" +msgid "node.solarPanel.panel.actions" +msgstr "Acciones" -# Source-Hash: 8332ab41e22958f1 +# Source-Hash: 2184867946897298 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Area" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Array" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.area" -msgstr "Área" +msgid "node.solarPanel.panel.array" +msgstr "Matriz" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: 6eaa0e2a78d44d59 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto-fit to roof" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.auto" -msgstr "Auto" +msgid "node.solarPanel.panel.autoFitToRoof" +msgstr "Ajustar a la cubierta" -# Source-Hash: fadada809e27477c +# Source-Hash: 30edd1c180aac9b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Columns" +#: packages/nodes/src/solar-panel/panel.tsx +#, fuzzy +msgid "node.solarPanel.panel.columns" +msgstr "Columnas" + +# Source-Hash: d1c6dd6335337cc1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom — dimensions don't match any preset" +#: packages/nodes/src/solar-panel/panel.tsx +#, fuzzy +msgid "node.solarPanel.panel.customDimensionsDonTMatchAny" +msgstr "Personalizado: las dimensiones no coinciden con ningún ajuste predefinido" + +# Source-Hash: b26de372b4b0eaac +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.base" -msgstr "Base" +msgid "node.solarPanel.panel.delete" +msgstr "Eliminar" -# Source-Hash: 12195951bba19804 +# Source-Hash: fe9356b1d0e0396b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut hatch" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip orientation" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.cutHatch" -msgstr "Cortar trampilla" +msgid "node.solarPanel.panel.flipOrientation" +msgstr "Invertir orientación" -# Source-Hash: 4e4f1a24e4a9d61e +# Source-Hash: eaaa20f3b603140f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut opening" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flush" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.cutOpening" -msgstr "Abrir hueco" +msgid "node.solarPanel.panel.flush" +msgstr "Enrasado" -# Source-Hash: 99ac4d03c3061f3a +# Source-Hash: fd413477f1a9e5ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame depth" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.depth" -msgstr "Profundidad" +msgid "node.solarPanel.panel.frameDepth" +msgstr "Profundidad del marco" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: 6aa2318fa815e5f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame thickness" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.done" -msgstr "Hecho" +msgid "node.solarPanel.panel.frameThickness" +msgstr "Espesor del marco" -# Source-Hash: 8a3bc5111b9e97f4 +# Source-Hash: c5657f721eae3dff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevation" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap X" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.elevation" -msgstr "Cota" +msgid "node.solarPanel.panel.gapX" +msgstr "Separación X" -# Source-Hash: 201b720b76d79762 +# Source-Hash: e6e3b393aa7c0d98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Extends the perimeter down to terrain. The flat surface, base, and thickness stay unchanged." -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap Y" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.extendsThePerimeterDownToTerrain" -msgstr "Extiende el perímetro hasta el terreno. La superficie plana, la base y el espesor no cambian." +msgid "node.solarPanel.panel.gapY" +msgstr "Separación Y" -# Source-Hash: 387ce45ca2eb045f +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fixed" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.fixed" -msgstr "Fijo" +msgid "node.solarPanel.panel.height" +msgstr "Altura" -# Source-Hash: d7148fa065bc709b +# Source-Hash: 81d365ccef73068c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.floor" -msgstr "Planta" +msgid "node.solarPanel.panel.mounting" +msgstr "Montaje" -# Source-Hash: 89b2cfd72a0a7e23 +# Source-Hash: 482469f5a0873f73 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows terrain" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.followsTerrain" -msgstr "Sigue el terreno" +msgid "node.solarPanel.panel.panel" +msgstr "Panel" -# Source-Hash: 48c832c1fc389290 +# Source-Hash: 441f7f652ea6a0d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preset" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.foundation" -msgstr "Cimentación" +msgid "node.solarPanel.panel.preset" +msgstr "Preajuste" -# Source-Hash: 34504c6ca6445e76 +# Source-Hash: c913b494c3901a17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Holes" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rows" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.holes" -msgstr "Huecos" +msgid "node.solarPanel.panel.rows" +msgstr "Filas" -# Source-Hash: 6e68b62d2aa611a4 +# Source-Hash: a4dba2b2675dbba0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Info" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Setbacks too large to fit a panel." +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.info" -msgstr "Info" +msgid "node.solarPanel.panel.setbacksTooLarge" +msgstr "Retranqueos demasiado grandes para colocar un panel." -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 4d18446ff8eaa680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solar Panel" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.move" -msgstr "Mover" +msgid "node.solarPanel.panel.solarPanel" +msgstr "Panel solar" -# Source-Hash: 1d2dafb0d8f26ed5 +# Source-Hash: 0af6194a8b8d8be6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No holes" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standoff" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.noHoles" -msgstr "Sin huecos" +msgid "node.solarPanel.panel.standoff" +msgstr "Separador" -# Source-Hash: c6a29e75bf215488 +# Source-Hash: 58cb60c14826f1d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rim" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilt angle" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.rim" -msgstr "Borde" +msgid "node.solarPanel.panel.tiltAngle" +msgstr "Ángulo de inclinación" -# Source-Hash: 8775bc8dc9593964 +# Source-Hash: 787005b26aec58a3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilted" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.slab" -msgstr "Forjado" +msgid "node.solarPanel.panel.tilted" +msgstr "Inclinado" -# Source-Hash: fb23c960abf5de23 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard (2\")" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.standard2" -msgstr "Estándar (2\")" +msgid "node.solarPanel.panel.width" +msgstr "Ancho" -# Source-Hash: 5f865b052c9b40eb +# Source-Hash: cd53f16290b67f7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard (5cm)" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Compact" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.standard5cm" -msgstr "Estándar (5 cm)" +msgid "node.solarPanel.preset.compact" +msgstr "Compacto" -# Source-Hash: cff0e2e72cfab157 +# Source-Hash: 317ebe2aa996af70 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sunken (15cm)" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frameless" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.sunken15cm" -msgstr "Hundido (15 cm)" +msgid "node.solarPanel.preset.frameless" +msgstr "Sin marco" -# Source-Hash: 8abc2aec4be98fe9 +# Source-Hash: 46660ad432e19312 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sunken (6\")" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Residential" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.sunken6" -msgstr "Hundido (6\")" +msgid "node.solarPanel.preset.residential" +msgstr "Residencial" -# Source-Hash: 78a454b7ac7a3cd9 +# Source-Hash: b33386b8fe3725fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Residential Large" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.surface" -msgstr "Superficie" +msgid "node.solarPanel.preset.residentialLarge" +msgstr "Residencial grande" -# Source-Hash: 516636d85be919f0 +# Source-Hash: 638f17c80f424dd3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thick (15cm)" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Player or camera origin within a level. One per level." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.slab.panel.thick15cm" -msgstr "Grueso (15 cm)" +msgid "node.spawn.description" +msgstr "Origen del jugador o la cámara en una planta. Uno por planta." -# Source-Hash: c84078f3560da233 +# Source-Hash: 3e2f6b4274f592c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thick (6\")" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spawn Point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.slab.panel.thick6" -msgstr "Grueso (6\")" +msgid "node.spawn.label" +msgstr "Punto de aparición" -# Source-Hash: fdbb503f0941bd56 +# Source-Hash: faaa4f6b40001667 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Body" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.slab.panel.thickness" -msgstr "Espesor" +msgid "node.stair.constructionControls.body" +msgstr "Cuerpo" -# Source-Hash: 61c191f6df40285b +# Source-Hash: 29b9fdb127a54435 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thin (1\")" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center stringer" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.slab.panel.thin1" -msgstr "Fino (1\")" +msgid "node.stair.constructionControls.centerStringer" +msgstr "Zanca central" -# Source-Hash: d345b1f707506fe7 +# Source-Hash: b2b2383577835a61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thin (2cm)" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Closed risers" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.slab.panel.thin2cm" -msgstr "Fino (2 cm)" +msgid "node.stair.constructionControls.closedRisers" +msgstr "Contrahuellas cerradas" -# Source-Hash: 065ffaaf64ab479d +# Source-Hash: 49a25acbaf33ee3d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid of photovoltaic panels mounted on a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "From structure" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.description" -msgstr "Conjunto de paneles fotovoltaicos montados en un faldón." +msgid "node.stair.constructionControls.fromStructure" +msgstr "Según la estructura" -# Source-Hash: 4d18446ff8eaa680 +# Source-Hash: 6f6b188bff3c0223 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solar Panel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inherit" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.label" -msgstr "Panel solar" +msgid "node.stair.constructionControls.inherit" +msgstr "Heredar" +# Source-Hash: ce25dc4a23f3ae10 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Nosing" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.actions" -msgstr "Acciones" +msgid "node.stair.constructionControls.nosing" +msgstr "Mamperlán" +# Source-Hash: 3e52f04f92e08070 # Review: required -# Source-Hash: 2184867946897298 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Array" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.array" -msgstr "Matriz" +msgid "node.stair.constructionControls.open" +msgstr "Abrir" +# Source-Hash: 7717e0464ad1e7df # Review: required -# Source-Hash: 6eaa0e2a78d44d59 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto-fit to roof" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Original" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.autoFitToRoof" -msgstr "Ajustar a la cubierta" +msgid "node.stair.constructionControls.original" +msgstr "Original" +# Source-Hash: 8a6f6c6b0cca7460 # Review: required -# Source-Hash: 30edd1c180aac9b4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Columns" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Riser thickness" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.columns" -msgstr "Columnas" +msgid "node.stair.constructionControls.riserThickness" +msgstr "Espesor de la contrahuella" +# Source-Hash: 2fe058966023b542 # Review: required -# Source-Hash: d1c6dd6335337cc1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom — dimensions don't match any preset" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Side stringers" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.customDimensionsDonTMatchAny" -msgstr "Personalizado: las dimensiones no coinciden con ningún ajuste predefinido" +msgid "node.stair.constructionControls.sideStringers" +msgstr "Zancas laterales" +# Source-Hash: ef3e765e692faf4c # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.delete" -msgstr "Eliminar" +msgid "node.stair.constructionControls.solid" +msgstr "Sólido" +# Source-Hash: 4c1489839e306865 # Review: required -# Source-Hash: fe9356b1d0e0396b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip orientation" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringer depth" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.flipOrientation" -msgstr "Invertir orientación" +msgid "node.stair.constructionControls.stringerDepth" +msgstr "Canto de la zanca" +# Source-Hash: 17e1a09c422d3660 # Review: required -# Source-Hash: eaaa20f3b603140f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flush" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringer width" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.flush" -msgstr "Enrasado" +msgid "node.stair.constructionControls.stringerWidth" +msgstr "Ancho de la zanca" +# Source-Hash: 146f8e61ff310dc5 # Review: required -# Source-Hash: fd413477f1a9e5ed -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame depth" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tread finish" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.frameDepth" -msgstr "Profundidad del marco" +msgid "node.stair.constructionControls.treadFinish" +msgstr "Acabado de huella" +# Source-Hash: 9089f91f3fbbf4cd # Review: required -# Source-Hash: 6aa2318fa815e5f2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame thickness" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tread thickness" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.frameThickness" -msgstr "Espesor del marco" +msgid "node.stair.constructionControls.treadThickness" +msgstr "Espesor de la huella" +# Source-Hash: 44dda7136b93c8ee # Review: required -# Source-Hash: c5657f721eae3dff -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap X" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.gapX" -msgstr "Separación X" +msgid "node.stair.constructionControls.waist" +msgstr "Losa" +# Source-Hash: dfd6d2ff7a94f22e # Review: required -# Source-Hash: e6e3b393aa7c0d98 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap Y" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist thickness" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.gapY" -msgstr "Separación Y" +msgid "node.stair.constructionControls.waistThickness" +msgstr "Espesor de la losa" +# Source-Hash: 8535b75637105412 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A stair composed of one or more flights with configurable treads, risers, railings." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.solarPanel.panel.height" -msgstr "Altura" +msgid "node.stair.description" +msgstr "Escalera de uno o varios tramos con huellas, contrahuellas y barandillas configurables." +# Source-Hash: c24b098693e1006d # Review: required -# Source-Hash: 81d365ccef73068c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The flight chain does not reach the declared destination." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.mounting" -msgstr "Montaje" +msgid "node.stair.diagnostic.arrivalMismatch" +msgstr "La cadena de tramos no llega al destino declarado." +# Source-Hash: 124ad1cd6bb00013 # Review: required -# Source-Hash: 482469f5a0873f73 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Two risers plus going is outside the 0.60–0.65 m design range." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.panel" -msgstr "Panel" +msgid "node.stair.diagnostic.comfortTarget" +msgstr "Dos contrahuellas más una huella quedan fuera del rango de diseño de 0,60–0,65 m." +# Source-Hash: 7452fcd8370bef34 # Review: required -# Source-Hash: 441f7f652ea6a0d8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preset" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Going is below the design target." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.preset" -msgstr "Preajuste" +msgid "node.stair.diagnostic.goingTarget" +msgstr "La huella es inferior al objetivo de diseño." +# Source-Hash: 449683eb727091d5 # Review: required -# Source-Hash: c913b494c3901a17 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rows" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overhead surfaces leave less than the target headroom." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.rows" -msgstr "Filas" +msgid "node.stair.diagnostic.headroomTarget" +msgstr "Las superficies superiores dejan menos altura libre que el objetivo." +# Source-Hash: 9e9357408f6a0d08 # Review: required -# Source-Hash: a4dba2b2675dbba0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Setbacks too large to fit a panel." -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Detailed headroom could not be evaluated: check riser counts and the surface query budget." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.setbacksTooLarge" -msgstr "Retranqueos demasiado grandes para colocar un panel." +msgid "node.stair.diagnostic.headroomUnresolved" +msgstr "No se ha podido evaluar la altura libre detallada: revisa el número de contrahuellas y el presupuesto de consultas de superficie." +# Source-Hash: 40fd019d72ff3835 # Review: required -# Source-Hash: 4d18446ff8eaa680 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solar Panel" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight dimensions and integer riser count must be positive." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.solarPanel" -msgstr "Panel solar" +msgid "node.stair.diagnostic.invalidFlight" +msgstr "Las dimensiones del tramo y el número entero de contrahuellas deben ser positivos." +# Source-Hash: 3d4b6f859bd8de50 # Review: required -# Source-Hash: 0af6194a8b8d8be6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standoff" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The destination must be above the stair base." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.standoff" -msgstr "Separador" +msgid "node.stair.diagnostic.invalidRise" +msgstr "El destino debe estar por encima de la base de la escalera." +# Source-Hash: 5f196b22e2c8296a # Review: required -# Source-Hash: 58cb60c14826f1d0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilt angle" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing depth exceeds a full circle at the walking line; the visible landing is limited to one circle." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.tiltAngle" -msgstr "Ángulo de inclinación" +msgid "node.stair.diagnostic.landingOverlap" +msgstr "La profundidad del descansillo supera un círculo completo en la línea de huella; el descansillo visible se limita a un círculo." +# Source-Hash: 0122ec92b951a114 # Review: required -# Source-Hash: 787005b26aec58a3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilted" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The narrow end of a winder tread is below 0.10 m; check the intended stair use." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.tilted" -msgstr "Inclinado" +msgid "node.stair.diagnostic.narrowWinderEnd" +msgstr "El extremo estrecho de una huella compensada es inferior a 0,10 m; revisa el uso previsto de la escalera." +# Source-Hash: a664dc7f3b014af8 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight riser heights differ. Use uniform-riser repair only if this is a proposed design." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.width" -msgstr "Ancho" +msgid "node.stair.diagnostic.nonuniformRisers" +msgstr "Las contrahuellas del tramo difieren. Usa la reparación de contrahuellas uniformes solo si es un diseño propuesto." +# Source-Hash: cd140b519d37b01e # Review: required -# Source-Hash: cd53f16290b67f7f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Compact" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A landing has a stored rise; inspect its transition before repair." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.preset.compact" -msgstr "Compacto" +msgid "node.stair.diagnostic.raisedLanding" +msgstr "Un descansillo tiene una altura guardada; revisa su transición antes de reparar." +# Source-Hash: a94cfa7b2a21cf14 # Review: required -# Source-Hash: 317ebe2aa996af70 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frameless" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Riser height exceeds the design target." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.preset.frameless" -msgstr "Sin marco" +msgid "node.stair.diagnostic.riserTarget" +msgstr "La contrahuella supera el objetivo de diseño." +# Source-Hash: 53d7084bc41c1ad6 # Review: required -# Source-Hash: 46660ad432e19312 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Residential" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.solarPanel.preset.residential" -msgstr "Residencial" +msgid "node.stair.label" +msgstr "Escalera" +# Source-Hash: 4ee35f740730ae87 # Review: required -# Source-Hash: b33386b8fe3725fa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Residential Large" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.preset.residentialLarge" -msgstr "Residencial grande" +msgid "node.stair.layout.straight" +msgstr "Recto" -# Source-Hash: 638f17c80f424dd3 +# Source-Hash: 1cda16cb49e6fb93 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Player or camera origin within a level. One per level." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{layout} turn" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.spawn.description" -msgstr "Origen del jugador o la cámara en una planta. Uno por planta." +msgid "node.stair.layout.turn" +msgstr "Giro {layout}" -# Source-Hash: 3e2f6b4274f592c0 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spawn Point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.spawn.label" -msgstr "Punto de aparición" +msgid "node.stair.panel.actions" +msgstr "Acciones" -# Source-Hash: faaa4f6b40001667 +# Source-Hash: 15eaf25f306541f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Body" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add flight" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.body" -msgstr "Cuerpo" +msgid "node.stair.panel.addFlight" +msgstr "Añadir tramo" -# Source-Hash: 29b9fdb127a54435 +# Source-Hash: 1fa37c346bffb8e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center stringer" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add landing" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.centerStringer" -msgstr "Zanca central" +msgid "node.stair.panel.addLanding" +msgstr "Añadir descansillo" -# Source-Hash: b2b2383577835a61 +# Source-Hash: 9ccbd6c1785f1e73 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Closed risers" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Apply {label} layout" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.closedRisers" -msgstr "Contrahuellas cerradas" +msgid "node.stair.panel.applyLabelLayout" +msgstr "Aplicar la distribución {label}" -# Source-Hash: 6f6b188bff3c0223 +# Source-Hash: 7eb42ea0fc442b8d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inherit" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto Cutout" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.inherit" -msgstr "Heredar" +msgid "node.stair.panel.autoCutout" +msgstr "Recorte automático" -# Source-Hash: ce25dc4a23f3ae10 +# Source-Hash: 3eda29328f91485d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Nosing" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Balusters" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.nosing" -msgstr "Mamperlán" +msgid "node.stair.panel.balusters" +msgstr "Balaustres" -# Source-Hash: 3e52f04f92e08070 +# Source-Hash: 19ae2360207ecf5a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Boards" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.open" -msgstr "Abrir" +msgid "node.stair.panel.boards" +msgstr "Tablas" -# Source-Hash: 7717e0464ad1e7df +# Source-Hash: 69578b7dd7723fa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Original" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Both" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.original" -msgstr "Original" +msgid "node.stair.panel.both" +msgstr "Ambos" -# Source-Hash: 8a6f6c6b0cca7460 +# Source-Hash: 5e2429ced8144ab4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Riser thickness" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cable" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.riserThickness" -msgstr "Espesor de la contrahuella" +msgid "node.stair.panel.cable" +msgstr "Cable" -# Source-Hash: 2fe058966023b542 +# Source-Hash: 11d6eec5d485488d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Side stringers" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center Column" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.sideStringers" -msgstr "Zancas laterales" +msgid "node.stair.panel.centerColumn" +msgstr "Columna central" -# Source-Hash: ef3e765e692faf4c +# Source-Hash: 5fbbf4ad24befa7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clockwise" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.solid" -msgstr "Sólido" +msgid "node.stair.panel.clockwise" +msgstr "Horario" -# Source-Hash: 4c1489839e306865 +# Source-Hash: 31028ca51b49018b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stringer depth" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connected to {surface}. Move the stair to connect to another edge." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.stringerDepth" -msgstr "Canto de la zanca" +msgid "node.stair.panel.connectedTo" +msgstr "Conectada a {surface}. Mueve la escalera para conectarla a otro borde." -# Source-Hash: 17e1a09c422d3660 +# Source-Hash: 33133921e270509f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stringer width" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connected to a surface. Move the stair to connect to another edge." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.stringerWidth" -msgstr "Ancho de la zanca" +msgid "node.stair.panel.connectedToSurface" +msgstr "Conectada a una superficie. Mueve la escalera para conectarla a otro borde." -# Source-Hash: 146f8e61ff310dc5 +# Source-Hash: ce1429556f57d7ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tread finish" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Construction" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.treadFinish" -msgstr "Acabado de huella" +msgid "node.stair.panel.construction" +msgstr "Construcción" -# Source-Hash: 9089f91f3fbbf4cd +# Source-Hash: 5e3e3ab7d91c2c4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tread thickness" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Counterclockwise" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.treadThickness" -msgstr "Espesor de la huella" +msgid "node.stair.panel.counterclockwise" +msgstr "Antihorario" -# Source-Hash: 44dda7136b93c8ee +# Source-Hash: a028e08962c388e0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curved" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.waist" -msgstr "Losa" +msgid "node.stair.panel.curved" +msgstr "Curvo" -# Source-Hash: dfd6d2ff7a94f22e +# Source-Hash: 0bd4232a56d25366 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist thickness" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom rise" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.waistThickness" -msgstr "Espesor de la losa" +msgid "node.stair.panel.customRise" +msgstr "Contrahuella personalizada" -# Source-Hash: 8535b75637105412 +# Source-Hash: f3aa561772702108 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A stair composed of one or more flights with configurable treads, risers, railings." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.description" -msgstr "Escalera de uno o varios tramos con huellas, contrahuellas y barandillas configurables." +msgid "node.stair.panel.deck" +msgstr "Tarima" -# Source-Hash: c24b098693e1006d +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The flight chain does not reach the declared destination." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.arrivalMismatch" -msgstr "La cadena de tramos no llega al destino declarado." +msgid "node.stair.panel.delete" +msgstr "Eliminar" -# Source-Hash: 124ad1cd6bb00013 +# Source-Hash: 1c34e5cc37add163 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Two risers plus going is outside the 0.60–0.65 m design range." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Design targets" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.comfortTarget" -msgstr "Dos contrahuellas más una huella quedan fuera del rango de diseño de 0,60–0,65 m." +msgid "node.stair.panel.designTargets" +msgstr "Objetivos de diseño" -# Source-Hash: 7452fcd8370bef34 +# Source-Hash: 748877ae309c313c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Going is below the design target." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Destination" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.goingTarget" -msgstr "La huella es inferior al objetivo de diseño." +msgid "node.stair.panel.destination" +msgstr "Destino" -# Source-Hash: 449683eb727091d5 +# Source-Hash: 1fa48e82752d1505 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overhead surfaces leave less than the target headroom." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag near a deck, patio, concrete slab, or landing edge to fit the stair." #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.headroomTarget" -msgstr "Las superficies superiores dejan menos altura libre que el objetivo." +msgid "node.stair.panel.dragNearADeckPatioConcrete" +msgstr "Arrastra cerca de una tarima, patio, losa o borde de descansillo para ajustar la escalera." -# Source-Hash: 9e9357408f6a0d08 +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Detailed headroom could not be evaluated: check riser counts and the surface query budget." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/stair/panel.tsx +#, fuzzy +msgid "node.stair.panel.duplicate" +msgstr "Duplicar" + +# Source-Hash: 776903eb3756eea9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equal angle" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.headroomUnresolved" -msgstr "No se ha podido evaluar la altura libre detallada: revisa el número de contrahuellas y el presupuesto de consultas de superficie." +msgid "node.stair.panel.equalAngle" +msgstr "Ángulo igual" -# Source-Hash: 40fd019d72ff3835 +# Source-Hash: 8956a359d7cec0a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flight dimensions and integer riser count must be positive." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equal going" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.invalidFlight" -msgstr "Las dimensiones del tramo y el número entero de contrahuellas deben ser positivos." +msgid "node.stair.panel.equalGoing" +msgstr "Huella igual" -# Source-Hash: 3d4b6f859bd8de50 +# Source-Hash: 6ff728d5058c7e31 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The destination must be above the stair base." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit risers and going" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.invalidRise" -msgstr "El destino debe estar por encima de la base de la escalera." +msgid "node.stair.panel.fitRisersAndGoing" +msgstr "Ajustar contrahuellas y huellas" -# Source-Hash: 5f196b22e2c8296a +# Source-Hash: d60a4c7995bd2184 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing depth exceeds a full circle at the walking line; the visible landing is limited to one circle." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit To Floor" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.landingOverlap" -msgstr "La profundidad del descansillo supera un círculo completo en la línea de huella; el descansillo visible se limita a un círculo." +msgid "node.stair.panel.fitToFloor" +msgstr "Ajustar al suelo" -# Source-Hash: 0122ec92b951a114 +# Source-Hash: 0638614580661eb0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The narrow end of a winder tread is below 0.10 m; check the intended stair use." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit uniform risers" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.narrowWinderEnd" -msgstr "El extremo estrecho de una huella compensada es inferior a 0,10 m; revisa el uso previsto de la escalera." +msgid "node.stair.panel.fitUniformRisers" +msgstr "Ajustar contrahuellas uniformes" -# Source-Hash: a664dc7f3b014af8 +# Source-Hash: 4d365dbc1fb92b90 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flight riser heights differ. Use uniform-riser repair only if this is a proposed design." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight {number}: {count, plural, one {{riserCount} riser} other {{riserCount} risers}} · R {riser} · T {going} · {slope}" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.nonuniformRisers" -msgstr "Las contrahuellas del tramo difieren. Usa la reparación de contrahuellas uniformes solo si es un diseño propuesto." +msgid "node.stair.panel.flightMeasurements" +msgstr "Tramo {number}: {count, plural, one {{riserCount} contrahuella} many {{riserCount} contrahuellas} other {{riserCount} contrahuellas}} · CH {riser} · H {going} · {slope}" -# Source-Hash: cd140b519d37b01e +# Source-Hash: 6e946bd1acd94637 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A landing has a stored rise; inspect its transition before repair." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floors, ceilings and stairs only." #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.raisedLanding" -msgstr "Un descansillo tiene una altura guardada; revisa su transición antes de reparar." +msgid "node.stair.panel.floorsCeilingsAndStairsOnly" +msgstr "Solo suelos, techos y escaleras." -# Source-Hash: a94cfa7b2a21cf14 +# Source-Hash: fa10ea42944107a8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Riser height exceeds the design target." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows deck" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.riserTarget" -msgstr "La contrahuella supera el objetivo de diseño." +msgid "node.stair.panel.followsDeck" +msgstr "Sigue la tarima" -# Source-Hash: 53d7084bc41c1ad6 +# Source-Hash: a5c2353769b603d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows level" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.label" -msgstr "Escalera" +msgid "node.stair.panel.followsLevel" +msgstr "Sigue la planta" -# Source-Hash: 4ee35f740730ae87 +# Source-Hash: b7fc627a965bc016 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "From Level" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.layout.straight" -msgstr "Recto" +msgid "node.stair.panel.fromLevel" +msgstr "Desde la planta" -# Source-Hash: 1cda16cb49e6fb93 +# Source-Hash: 523b9912e283b644 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{layout} turn" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Geometry" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.layout.turn" -msgstr "Giro {layout}" +msgid "node.stair.panel.geometry" +msgstr "Geometría" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.actions" -msgstr "Acciones" +msgid "node.stair.panel.glass" +msgstr "Vidrio" -# Source-Hash: 15eaf25f306541f9 +# Source-Hash: 55adba80c39500f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add flight" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Headroom:" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.addFlight" -msgstr "Añadir tramo" +msgid "node.stair.panel.headroom" +msgstr "Altura libre:" -# Source-Hash: 1fa37c346bffb8e4 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add landing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.addLanding" -msgstr "Añadir descansillo" +msgid "node.stair.panel.height" +msgstr "Altura" -# Source-Hash: 9ccbd6c1785f1e73 +# Source-Hash: 9bcdccd29e64c4d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Apply {label} layout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inner gap" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.applyLabelLayout" -msgstr "Aplicar la distribución {label}" +msgid "node.stair.panel.innerGap" +msgstr "Separación interior" -# Source-Hash: 7eb42ea0fc442b8d +# Source-Hash: 8b54356df7ae40bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto Cutout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inner Radius" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.autoCutout" -msgstr "Recorte automático" +msgid "node.stair.panel.innerRadius" +msgstr "Radio interior" -# Source-Hash: 3eda29328f91485d +# Source-Hash: 88d5b9ecb242c650 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Balusters" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Integrated" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.balusters" -msgstr "Balaustres" +msgid "node.stair.panel.integrated" +msgstr "Integrado" -# Source-Hash: 19ae2360207ecf5a +# Source-Hash: de9566487b17a73b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Boards" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.boards" -msgstr "Tablas" +msgid "node.stair.panel.landing" +msgstr "Descansillo" -# Source-Hash: 69578b7dd7723fa1 +# Source-Hash: 54800340a0eeab23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Both" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layout" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.both" -msgstr "Ambos" +msgid "node.stair.panel.layout" +msgstr "Distribución" -# Source-Hash: 5e2429ced8144ab4 +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cable" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.cable" -msgstr "Cable" +msgid "node.stair.panel.left" +msgstr "Izquierda" -# Source-Hash: 11d6eec5d485488d +# Source-Hash: 7d4f8532c0d115e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center Column" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left turn" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.centerColumn" -msgstr "Columna central" +msgid "node.stair.panel.leftTurn" +msgstr "Giro a la izquierda" -# Source-Hash: 5fbbf4ad24befa7f +# Source-Hash: c6aa74075f37313a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clockwise" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Measurements" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.clockwise" -msgstr "Horario" +msgid "node.stair.panel.measurements" +msgstr "Medidas" -# Source-Hash: 31028ca51b49018b +# Source-Hash: 8e464a8f52254f27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connected to {surface}. Move the stair to connect to another edge." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Metal" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.connectedTo" -msgstr "Conectada a {surface}. Mueve la escalera para conectarla a otro borde." +msgid "node.stair.panel.metal" +msgstr "Metal" -# Source-Hash: 33133921e270509f -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connected to a surface. Move the stair to connect to another edge." +# Source-Hash: bd02c614454fbd2b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.connectedToSurface" -msgstr "Conectada a una superficie. Mueve la escalera para conectarla a otro borde." +msgid "node.stair.panel.move" +msgstr "Mover" -# Source-Hash: ce1429556f57d7ee +# Source-Hash: a4f1cc34aae4db27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Construction" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Moving this stair keeps its current rise, steps, and run." #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.construction" -msgstr "Construcción" +msgid "node.stair.panel.movingThisStairKeepsItsCurrent" +msgstr "Mover esta escalera mantiene su altura, peldaños y desarrollo actuales." -# Source-Hash: 5e3e3ab7d91c2c4f +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Counterclockwise" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.counterclockwise" -msgstr "Antihorario" +msgid "node.stair.panel.none" +msgstr "Ninguno" -# Source-Hash: a028e08962c388e0 +# Source-Hash: 47c858b3022b3ae5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curved" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No overhead surface" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.curved" -msgstr "Curvo" +msgid "node.stair.panel.noOverheadSurface" +msgstr "Sin superficie superior" -# Source-Hash: 0bd4232a56d25366 +# Source-Hash: 17f1933d93cf655c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom rise" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not evaluated" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.customRise" -msgstr "Contrahuella personalizada" +msgid "node.stair.panel.notEvaluated" +msgstr "No evaluado" -# Source-Hash: f3aa561772702108 +# Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Deck" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.deck" -msgstr "Tarima" +msgid "node.stair.panel.opening" +msgstr "Abertura" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 599220556fc4bbfb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening Offset" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.delete" -msgstr "Eliminar" +msgid "node.stair.panel.openingOffset" +msgstr "Desfase del hueco" -# Source-Hash: 1c34e5cc37add163 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Design targets" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.designTargets" -msgstr "Objetivos de diseño" +msgid "node.stair.panel.position" +msgstr "Posición" -# Source-Hash: 748877ae309c313c +# Source-Hash: f522323372a7a59e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Destination" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post & rail" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.destination" -msgstr "Destino" +msgid "node.stair.panel.postRail" +msgstr "Poste y travesaño" -# Source-Hash: 1fa48e82752d1505 +# Source-Hash: 240ed9c77627b9a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag near a deck, patio, concrete slab, or landing edge to fit the stair." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.dragNearADeckPatioConcrete" -msgstr "Arrastra cerca de una tarima, patio, losa o borde de descansillo para ajustar la escalera." +msgid "node.stair.panel.railing" +msgstr "Barandilla" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.duplicate" -msgstr "Duplicar" +msgid "node.stair.panel.right" +msgstr "Derecha" -# Source-Hash: 776903eb3756eea9 +# Source-Hash: ae876c3e9a5913eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equal angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right turn" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.equalAngle" -msgstr "Ángulo igual" +msgid "node.stair.panel.rightTurn" +msgstr "Giro a la derecha" -# Source-Hash: 8956a359d7cec0a6 +# Source-Hash: fe8c5b735495eb00 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equal going" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rise" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.equalGoing" -msgstr "Huella igual" +msgid "node.stair.panel.rise" +msgstr "Altura" -# Source-Hash: 6ff728d5058c7e31 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fit risers and going" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.fitRisersAndGoing" -msgstr "Ajustar contrahuellas y huellas" +msgid "node.stair.panel.rotation" +msgstr "Rotación" -# Source-Hash: d60a4c7995bd2184 +# Source-Hash: 505d8419cf4cc5e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fit To Floor" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segments" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.fitToFloor" -msgstr "Ajustar al suelo" +msgid "node.stair.panel.segments" +msgstr "Segmentos" -# Source-Hash: 0638614580661eb0 +# Source-Hash: 0b9a0bef102b75bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fit uniform risers" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{type, select, landing {Landing} other {Stair}}" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.fitUniformRisers" -msgstr "Ajustar contrahuellas uniformes" +msgid "node.stair.panel.segmentType" +msgstr "{type, select, landing {Descansillo} other {Tramo}}" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 4d365dbc1fb92b90 +# Source-Hash: 87b926bbf34a78ed # Review: required -# English: "Flight {number}: {count, plural, one {{riserCount} riser} other {{riserCount} risers}} · R {riser} · T {going} · {slope}" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sizing" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.flightMeasurements" -msgstr "Tramo {number}: {count, plural, one {{riserCount} contrahuella} many {{riserCount} contrahuellas} other {{riserCount} contrahuellas}} · CH {riser} · H {going} · {slope}" +msgid "node.stair.panel.sizing" +msgstr "Dimensionado" -# Source-Hash: 6e946bd1acd94637 +# Source-Hash: 8a0f4562198c266f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floors, ceilings and stairs only." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snap to nearby surfaces" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.floorsCeilingsAndStairsOnly" -msgstr "Solo suelos, techos y escaleras." +msgid "node.stair.panel.snapToNearbySurfaces" +msgstr "Ajustar a superficies cercanas" -# Source-Hash: fa10ea42944107a8 +# Source-Hash: f9a4a870cb3d3c41 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows deck" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spiral" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.followsDeck" -msgstr "Sigue la tarima" +msgid "node.stair.panel.spiral" +msgstr "Helicoidal" -# Source-Hash: a5c2353769b603d5 +# Source-Hash: f8d4f66145e1eba0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows level" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Staircase" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.followsLevel" -msgstr "Sigue la planta" +msgid "node.stair.panel.staircase" +msgstr "Escalera" -# Source-Hash: b7fc627a965bc016 +# Source-Hash: be8122fbf16dec33 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "From Level" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Steps" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.fromLevel" -msgstr "Desde la planta" +msgid "node.stair.panel.steps" +msgstr "Peldaños" -# Source-Hash: 523b9912e283b644 +# Source-Hash: 8846dc96332c5181 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Geometry" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Step Supports" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.geometry" -msgstr "Geometría" +msgid "node.stair.panel.stepSupports" +msgstr "Soportes de peldaño" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: 4ee35f740730ae87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.glass" -msgstr "Vidrio" +msgid "node.stair.panel.straight" +msgstr "Recto" -# Source-Hash: 55adba80c39500f9 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Headroom:" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.headroom" -msgstr "Altura libre:" +msgid "node.stair.panel.style" +msgstr "Estilo" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: cde3878287069df2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface connection" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.height" -msgstr "Altura" +msgid "node.stair.panel.surfaceConnection" +msgstr "Conexión a la superficie" -# Source-Hash: 9bcdccd29e64c4d8 +# Source-Hash: 4e0f8b363503efff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inner gap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sweep" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.innerGap" -msgstr "Separación interior" +msgid "node.stair.panel.sweep" +msgstr "Barrido" -# Source-Hash: 8b54356df7ae40bf +# Source-Hash: 4c294d88d712855a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inner Radius" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target going" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.innerRadius" -msgstr "Radio interior" +msgid "node.stair.panel.targetGoing" +msgstr "Huella objetivo" -# Source-Hash: 88d5b9ecb242c650 +# Source-Hash: 74cfba22cf2e6eb8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Integrated" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target headroom" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.integrated" -msgstr "Integrado" +msgid "node.stair.panel.targetHeadroom" +msgstr "Altura libre objetivo" -# Source-Hash: de9566487b17a73b +# Source-Hash: 9d05958a265a6726 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target max riser" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.landing" -msgstr "Descansillo" +msgid "node.stair.panel.targetMaxRiser" +msgstr "Contrahuella máxima objetivo" -# Source-Hash: 54800340a0eeab23 +# Source-Hash: d10322b16178ce37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Layout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target minimum going" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.layout" -msgstr "Distribución" +msgid "node.stair.panel.targetMinimumGoing" +msgstr "Huella mínima objetivo" -# Source-Hash: f365c6b6dd9ebab9 +# Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.left" -msgstr "Izquierda" +msgid "node.stair.panel.thickness" +msgstr "Espesor" -# Source-Hash: 7d4f8532c0d115e9 +# Source-Hash: b3214a20e45a7aed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left turn" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "To" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.leftTurn" -msgstr "Giro a la izquierda" +msgid "node.stair.panel.to" +msgstr "Hasta" -# Source-Hash: c6aa74075f37313a +# Source-Hash: 846fc58043454194 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Measurements" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Landing" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.measurements" -msgstr "Medidas" +msgid "node.stair.panel.topLanding" +msgstr "Descansillo superior" -# Source-Hash: 8e464a8f52254f27 +# Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Metal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.metal" -msgstr "Metal" +msgid "node.stair.panel.type" +msgstr "Tipo" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: b4c2f503b19443c6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unavailable" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.move" -msgstr "Mover" +msgid "node.stair.panel.unavailable" +msgstr "No disponible" -# Source-Hash: a4f1cc34aae4db27 +# Source-Hash: 546fa6dd4e62e82d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Moving this stair keeps its current rise, steps, and run." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walking line offset" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.movingThisStairKeepsItsCurrent" -msgstr "Mover esta escalera mantiene su altura, peldaños y desarrollo actuales." +msgid "node.stair.panel.walkingLineOffset" +msgstr "Desfase de la línea de huella" -# Source-Hash: f2953d2931e36d0c +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.none" -msgstr "Ninguno" +msgid "node.stair.panel.width" +msgstr "Ancho" -# Source-Hash: 47c858b3022b3ae5 +# Source-Hash: 7b65cc10483fb191 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No overhead surface" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Winder" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.noOverheadSurface" -msgstr "Sin superficie superior" +msgid "node.stair.panel.winder" +msgstr "Compensada" -# Source-Hash: 17f1933d93cf655c +# Source-Hash: 69578b7dd7723fa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Not evaluated" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Both" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.notEvaluated" -msgstr "No evaluado" +msgid "node.stair.railingControls.both" +msgstr "Ambos" -# Source-Hash: e04298381837252f +# Source-Hash: fe633d20f198d7e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom sloped extension" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.opening" -msgstr "Abertura" +msgid "node.stair.railingControls.bottomExtension" +msgstr "Prolongación inclinada inferior" -# Source-Hash: 599220556fc4bbfb +# Source-Hash: 384842ae1e1c6825 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening Offset" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuous" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.openingOffset" -msgstr "Desfase del hueco" +msgid "node.stair.railingControls.continuous" +msgstr "Continuo" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: d7148fa065bc709b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.position" -msgstr "Posición" +msgid "node.stair.railingControls.floor" +msgstr "Planta" -# Source-Hash: f522323372a7a59e +# Source-Hash: 644d2d9e9c3dd31f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post & rail" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handrail diameter" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.postRail" -msgstr "Poste y travesaño" +msgid "node.stair.railingControls.handrailDiameter" +msgstr "Diámetro del pasamanos" -# Source-Hash: 240ed9c77627b9a1 +# Source-Hash: 5f3f2be1e572a066 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handrail height" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.railing" -msgstr "Barandilla" +msgid "node.stair.railingControls.handrailHeight" +msgstr "Altura del pasamanos" -# Source-Hash: b34d5ee0f218221d +# Source-Hash: cb3239847f068a1b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handrail inset" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.right" -msgstr "Derecha" +msgid "node.stair.railingControls.handrailInset" +msgstr "Retranqueo del pasamanos" + +# Source-Hash: f365c6b6dd9ebab9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/stair/railing-controls.tsx +#, fuzzy +msgid "node.stair.railingControls.left" +msgstr "Izquierda" -# Source-Hash: ae876c3e9a5913eb +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right turn" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.rightTurn" -msgstr "Giro a la derecha" +msgid "node.stair.railingControls.none" +msgstr "Ninguno" -# Source-Hash: fe8c5b735495eb00 +# Source-Hash: e6ac8d7c9639c351 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rise" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No return" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.rise" -msgstr "Altura" +msgid "node.stair.railingControls.noReturn" +msgstr "Sin retorno" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: 5688b2003002d03a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Original layout" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.rotation" -msgstr "Rotación" +msgid "node.stair.railingControls.originalLayout" +msgstr "Distribución original" -# Source-Hash: 505d8419cf4cc5e1 +# Source-Hash: d0d904fbd052d7b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segments" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post-facing" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.segments" -msgstr "Segmentos" +msgid "node.stair.railingControls.postFacing" +msgstr "Hacia el poste" -# Source-Hash: 0b9a0bef102b75bc +# Source-Hash: fc4d8c6f156b0430 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{type, select, landing {Landing} other {Stair}}" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return length" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.segmentType" -msgstr "{type, select, landing {Descansillo} other {Tramo}}" +msgid "node.stair.railingControls.returnLength" +msgstr "Longitud del retorno" -# Source-Hash: 87b926bbf34a78ed +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sizing" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.sizing" -msgstr "Dimensionado" +msgid "node.stair.railingControls.right" +msgstr "Derecha" -# Source-Hash: 8a0f4562198c266f +# Source-Hash: e1f8354a95b5060a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snap to nearby surfaces" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Separate handrail" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.snapToNearbySurfaces" -msgstr "Ajustar a superficies cercanas" +msgid "node.stair.railingControls.separateHandrail" +msgstr "Pasamanos independiente" -# Source-Hash: f9a4a870cb3d3c41 +# Source-Hash: 005f0197ec3bc95a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spiral" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set the length to reach the wall or post." +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.spiral" -msgstr "Helicoidal" +msgid "node.stair.railingControls.setTheLengthToReachThe" +msgstr "Ajusta la longitud para llegar al muro o al poste." -# Source-Hash: f8d4f66145e1eba0 +# Source-Hash: bef713f3ec96f758 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Staircase" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top horizontal extension" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.staircase" -msgstr "Escalera" +msgid "node.stair.railingControls.topExtension" +msgstr "Prolongación horizontal superior" -# Source-Hash: be8122fbf16dec33 +# Source-Hash: bdad79929de6b142 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Steps" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall-facing" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.steps" -msgstr "Peldaños" +msgid "node.stair.railingControls.wallFacing" +msgstr "Hacia el muro" -# Source-Hash: 8846dc96332c5181 +# Source-Hash: 1709ce71eba750ff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Step Supports" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A solid poured flight on a footing; risers closed, no stringers." +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.stepSupports" -msgstr "Soportes de peldaño" +msgid "node.stair.structureControls.aSolidPouredFlightOnA" +msgstr "Un tramo macizo hormigonado sobre una zapata; contrahuellas cerradas, sin zancas." -# Source-Hash: 4ee35f740730ae87 +# Source-Hash: 56be143b76f65392 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto ({autoCount})" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.straight" -msgstr "Recto" +msgid "node.stair.structureControls.autoAutocount" +msgstr "Auto ({autoCount})" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: d7820aaac08e4fcb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto (closed)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.style" -msgstr "Estilo" +msgid "node.stair.structureControls.autoClosed" +msgstr "Auto (cerradas)" -# Source-Hash: cde3878287069df2 +# Source-Hash: c7cbd493df719e71 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface connection" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto (open)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.surfaceConnection" -msgstr "Conexión a la superficie" +msgid "node.stair.structureControls.autoOpen" +msgstr "Auto (abiertas)" -# Source-Hash: 4e0f8b363503efff +# Source-Hash: be21258d52930d5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sweep" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto (pressure-treated)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.sweep" -msgstr "Barrido" +msgid "node.stair.structureControls.autoPressureTreated" +msgstr "Auto (tratada a presión)" -# Source-Hash: 4c294d88d712855a +# Source-Hash: 1828540d95a5b5c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target going" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto ({treads})" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.targetGoing" -msgstr "Huella objetivo" +msgid "node.stair.structureControls.autoTreads" +msgstr "Auto ({treads})" -# Source-Hash: 74cfba22cf2e6eb8 +# Source-Hash: 43c1949fa53685b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target headroom" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto (untreated)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.targetHeadroom" -msgstr "Altura libre objetivo" +msgid "node.stair.structureControls.autoUntreated" +msgstr "Auto (sin tratar)" -# Source-Hash: 9d05958a265a6726 +# Source-Hash: d0a3ca3ce29ae833 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target max riser" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Closed (1x8 boards)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.targetMaxRiser" -msgstr "Contrahuella máxima objetivo" +msgid "node.stair.structureControls.closed1x8Boards" +msgstr "Cerradas (tablas 1x8)" -# Source-Hash: d10322b16178ce37 +# Source-Hash: 824471a3691b51db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target minimum going" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Concrete" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.targetMinimumGoing" -msgstr "Huella mínima objetivo" +msgid "node.stair.structureControls.concrete" +msgstr "Hormigón" -# Source-Hash: fdbb503f0941bd56 +# Source-Hash: dcb2dd54c3301068 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# steel channel} other {# steel channels}}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.thickness" -msgstr "Espesor" +msgid "node.stair.structureControls.countSteelChannels" +msgstr "{count, plural, one {# perfil en U de acero} many {# perfiles en U de acero} other {# perfiles en U de acero}}" -# Source-Hash: b3214a20e45a7aed +# Source-Hash: fbf12088b828a103 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "To" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# steel channel at {spacing} o.c.} other {# steel channels at {spacing} o.c.}}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.to" -msgstr "Hasta" +msgid "node.stair.structureControls.countSteelChannelsAtSpacing" +msgstr "{count, plural, one {# perfil en U de acero a {spacing} entre ejes} many {# perfiles en U de acero a {spacing} entre ejes} other {# perfiles en U de acero a {spacing} entre ejes}}" -# Source-Hash: 846fc58043454194 +# Source-Hash: 6f0f06f0531c7e96 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Landing" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# stringer} other {# stringers}}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.topLanding" -msgstr "Descansillo superior" +msgid "node.stair.structureControls.countStringers" +msgstr "{count, plural, one {# zanca} many {# zancas} other {# zancas}}" -# Source-Hash: c44f7ab8bbd24858 +# Source-Hash: cfdb3f3fc95ea940 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# stringer at {spacing} o.c.} other {# stringers at {spacing} o.c.}}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.type" -msgstr "Tipo" +msgid "node.stair.structureControls.countStringersAtSpacing" +msgstr "{count, plural, one {# zanca a {spacing} entre ejes} many {# zancas a {spacing} entre ejes} other {# zancas a {spacing} entre ejes}}" -# Source-Hash: b4c2f503b19443c6 +# Source-Hash: fa4b97d3aa600bcd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unavailable" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.unavailable" -msgstr "No disponible" +msgid "node.stair.structureControls.cut" +msgstr "Dentada" -# Source-Hash: 546fa6dd4e62e82d +# Source-Hash: ba4f3c1346b3e7af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walking line offset" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight {number}: {layout}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.walkingLineOffset" -msgstr "Desfase de la línea de huella" +msgid "node.stair.structureControls.flightLayout" +msgstr "Tramo {number}: {layout}" + +# Source-Hash: 4cbb34fdf4c1e107 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Housed sides" +#: packages/nodes/src/stair/structure-controls.tsx +#, fuzzy +msgid "node.stair.structureControls.housedSides" +msgstr "Laterales cajeados" -# Source-Hash: 3a0ccd6c46877a87 +# Source-Hash: e3ddff241f642295 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{inches} in o.c." +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.width" -msgstr "Ancho" +msgid "node.stair.structureControls.inchesInOC" +msgstr "{inches} in a ejes" -# Source-Hash: 7b65cc10483fb191 +# Source-Hash: 542ca0bee99a1533 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Winder" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{layout} (auto)" +#. The stringer count was chosen automatically, not set by hand. +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.winder" -msgstr "Compensada" +msgid "node.stair.structureControls.layoutAuto" +msgstr "{layout} (auto)" -# Source-Hash: 69578b7dd7723fa1 +# Source-Hash: 73dcfae611575500 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Both" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lumber" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.both" -msgstr "Ambos" +msgid "node.stair.structureControls.lumber" +msgstr "Madera" -# Source-Hash: fe633d20f198d7e4 +# Source-Hash: d10743fce478d9f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom sloped extension" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Max spacing" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.bottomExtension" -msgstr "Prolongación inclinada inferior" +msgid "node.stair.structureControls.maxSpacing" +msgstr "Separación máx." -# Source-Hash: 384842ae1e1c6825 +# Source-Hash: ce25dc4a23f3ae10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuous" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Nosing" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.continuous" -msgstr "Continuo" +msgid "node.stair.structureControls.nosing" +msgstr "Mamperlán" -# Source-Hash: d7148fa065bc709b +# Source-Hash: ba534b07476bc06d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "One {stock}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.floor" -msgstr "Planta" +msgid "node.stair.structureControls.oneStock" +msgstr "Una tabla {stock}" -# Source-Hash: 644d2d9e9c3dd31f +# Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handrail diameter" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.handrailDiameter" -msgstr "Diámetro del pasamanos" +msgid "node.stair.structureControls.open" +msgstr "Abiertas" -# Source-Hash: 5f3f2be1e572a066 +# Source-Hash: 20f023962f848e14 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handrail height" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Original body" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.handrailHeight" -msgstr "Altura del pasamanos" +msgid "node.stair.structureControls.originalBody" +msgstr "Cuerpo original" -# Source-Hash: cb3239847f068a1b +# Source-Hash: ac658d76a942652f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handrail inset" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plywood + finish" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.handrailInset" -msgstr "Retranqueo del pasamanos" +msgid "node.stair.structureControls.plywoodFinish" +msgstr "Contrachapado + acabado" -# Source-Hash: f365c6b6dd9ebab9 +# Source-Hash: 86fda85cdc89fd27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pressure-treated" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.left" -msgstr "Izquierda" +msgid "node.stair.structureControls.pressureTreated" +msgstr "Tratada a presión" -# Source-Hash: f2953d2931e36d0c +# Source-Hash: d903bba423ddb755 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Risers" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.none" -msgstr "Ninguno" +msgid "node.stair.structureControls.risers" +msgstr "Contrahuellas" -# Source-Hash: e6ac8d7c9639c351 +# Source-Hash: ff0400a550f24adf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No return" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Steel stringers" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.noReturn" -msgstr "Sin retorno" +msgid "node.stair.structureControls.steelStringers" +msgstr "Zancas de acero" -# Source-Hash: 5688b2003002d03a +# Source-Hash: 50d4cac7f3002cd2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Original layout" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringer count" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.originalLayout" -msgstr "Distribución original" +msgid "node.stair.structureControls.stringerCount" +msgstr "Número de zancas" -# Source-Hash: d0d904fbd052d7b2 +# Source-Hash: 71733e5b479af2a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post-facing" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringers" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.postFacing" -msgstr "Hacia el poste" +msgid "node.stair.structureControls.stringers" +msgstr "Zancas" -# Source-Hash: fc4d8c6f156b0430 +# Source-Hash: 191196b94d1c86f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return length" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringer type" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.returnLength" -msgstr "Longitud del retorno" +msgid "node.stair.structureControls.stringerType" +msgstr "Tipo de zanca" -# Source-Hash: b34d5ee0f218221d +# Source-Hash: a20c89205a4448d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.right" -msgstr "Derecha" +msgid "node.stair.structureControls.structure" +msgstr "Estructura" -# Source-Hash: e1f8354a95b5060a +# Source-Hash: 869e3785611a0858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Separate handrail" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Treads" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.separateHandrail" -msgstr "Pasamanos independiente" +msgid "node.stair.structureControls.treads" +msgstr "Huellas" -# Source-Hash: 005f0197ec3bc95a +# Source-Hash: e1e6555b827b4620 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set the length to reach the wall or post." -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Two {stock}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.setTheLengthToReachThe" -msgstr "Ajusta la longitud para llegar al muro o al poste." +msgid "node.stair.structureControls.twoStock" +msgstr "Dos tablas {stock}" -# Source-Hash: bef713f3ec96f758 +# Source-Hash: 5c362de43a2cbac1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top horizontal extension" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Untreated" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.topExtension" -msgstr "Prolongación horizontal superior" +msgid "node.stair.structureControls.untreated" +msgstr "Sin tratar" -# Source-Hash: bdad79929de6b142 +# Source-Hash: 401bae5ffee978fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall-facing" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wood stringers" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.wallFacing" -msgstr "Hacia el muro" +msgid "node.stair.structureControls.woodStringers" +msgstr "Zancas de madera" # Source-Hash: ce0b6361eb77e93c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A single flight of a parent stair." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -29750,8 +32483,8 @@ msgstr "Un tramo de una escalera padre." # Source-Hash: 2159ec5769e1c59a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stair Segment" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -29760,8 +32493,8 @@ msgstr "Tramo de escalera" # Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29770,8 +32503,8 @@ msgstr "Acciones" # Source-Hash: 551b04c03b07595e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Attachment" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29780,8 +32513,8 @@ msgstr "Conexión" # Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29790,8 +32523,8 @@ msgstr "Eliminar" # Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dimensions" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29800,8 +32533,8 @@ msgstr "Dimensiones" # Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duplicate" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29810,8 +32543,8 @@ msgstr "Duplicar" # Source-Hash: ad063fb27f370c28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Editing switches the stair to Custom rise" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29820,8 +32553,8 @@ msgstr "Editar cambia la escalera a contrahuella personalizada" # Source-Hash: 776903eb3756eea9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Equal angle" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29830,8 +32563,8 @@ msgstr "Ángulo igual" # Source-Hash: 8956a359d7cec0a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Equal going" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29840,8 +32573,8 @@ msgstr "Huella igual" # Source-Hash: 66f1018b50c2e426 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fill to floor" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29850,8 +32583,8 @@ msgstr "Rellenar hasta el suelo" # Source-Hash: deff4254bb163b2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flight" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29860,8 +32593,8 @@ msgstr "Tramo" # Source-Hash: d6da828cd0c5e8cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flight shape" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29870,8 +32603,8 @@ msgstr "Forma del tramo" # Source-Hash: e360f89d3c0ec456 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Front" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29880,8 +32613,8 @@ msgstr "Frente" # Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Height" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29890,8 +32623,8 @@ msgstr "Altura" # Source-Hash: 9bcdccd29e64c4d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Inner gap" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29900,8 +32633,8 @@ msgstr "Separación interior" # Source-Hash: de9566487b17a73b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Landing" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29910,8 +32643,8 @@ msgstr "Descansillo" # Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Left" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29920,8 +32653,8 @@ msgstr "Izquierda" # Source-Hash: 7d4f8532c0d115e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Left turn" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29930,8 +32663,8 @@ msgstr "Giro a la izquierda" # Source-Hash: 643687bc3adaac76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Length" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29940,8 +32673,8 @@ msgstr "Longitud" # Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Move" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29950,8 +32683,8 @@ msgstr "Mover" # Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Position" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29960,8 +32693,8 @@ msgstr "Posición" # Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Right" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29970,8 +32703,8 @@ msgstr "Derecha" # Source-Hash: ae876c3e9a5913eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Right turn" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29980,8 +32713,8 @@ msgstr "Giro a la derecha" # Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rotation" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29990,8 +32723,8 @@ msgstr "Rotación" # Source-Hash: 2159ec5769e1c59a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stair Segment" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30000,8 +32733,8 @@ msgstr "Tramo de escalera" # Source-Hash: be8122fbf16dec33 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Steps" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30010,8 +32743,8 @@ msgstr "Peldaños" # Source-Hash: 4ee35f740730ae87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Straight" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30020,8 +32753,8 @@ msgstr "Recto" # Source-Hash: a20c89205a4448d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Structure" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30030,8 +32763,8 @@ msgstr "Estructura" # Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Thickness" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30040,8 +32773,8 @@ msgstr "Espesor" # Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Type" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30050,8 +32783,8 @@ msgstr "Tipo" # Source-Hash: 546fa6dd4e62e82d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Walking line offset" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30060,8 +32793,8 @@ msgstr "Desfase de la línea de huella" # Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Width" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30070,8 +32803,8 @@ msgstr "Ancho" # Source-Hash: 7b65cc10483fb191 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Winder" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30080,8 +32813,8 @@ msgstr "Compensada" # Source-Hash: 5434a3189441c913 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Persistent construction grid axis with identification bubbles." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30090,8 +32823,8 @@ msgstr "Eje de replanteo persistente con burbujas de identificación." # Source-Hash: 0cfe636f7fdd9fd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Structural Grid" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30100,8 +32833,8 @@ msgstr "Retícula estructural" # Source-Hash: 36b714210f25c284 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wind-driven spinning whirlybird exhaust vent for a roof slope." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30110,198 +32843,198 @@ msgstr "Extractor eólico giratorio para un faldón." # Source-Hash: 4a855abb962f5e7a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Turbine Vent" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy msgid "node.turbineVent.label" msgstr "Extractor eólico" -# Review: required # Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.actions" msgstr "Acciones" -# Review: required # Source-Hash: c65f02bcdc3231d6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Cylinder" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.cylinder" msgstr "Cilindro" -# Review: required # Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.delete" msgstr "Eliminar" -# Review: required # Source-Hash: 016d8e70618916d4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Diameter" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.diameter" msgstr "Diámetro" -# Review: required # Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dimensions" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.dimensions" msgstr "Dimensiones" -# Review: required # Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duplicate" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.duplicate" msgstr "Duplicar" -# Review: required # Source-Hash: 2d4223f80dc3945c -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Globe" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.globe" msgstr "Globo" -# Review: required # Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Height" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.height" msgstr "Altura" -# Review: required # Source-Hash: c0ff16d77ebc9593 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Motion" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.motion" msgstr "Movimiento" -# Review: required # Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Move" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.move" msgstr "Mover" -# Review: required # Source-Hash: 6faf9532dcbfe4bc -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Neck Height" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.neckHeight" msgstr "Altura del cuello" -# Review: required # Source-Hash: 1550d72740e66f77 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Pause" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.pause" msgstr "Pausa" -# Review: required # Source-Hash: c7b10382e01914ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Play" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.play" msgstr "Reproducir" -# Review: required # Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Position" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.position" msgstr "Posición" -# Review: required # Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rotation" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.rotation" msgstr "Rotación" -# Review: required # Source-Hash: bf553d40ce68834d -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Spin Speed" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.spinSpeed" msgstr "Velocidad de giro" -# Review: required # Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Style" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.style" msgstr "Estilo" -# Review: required # Source-Hash: 4a855abb962f5e7a -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Turbine Vent" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.turbineVent" msgstr "Extractor eólico" -# Review: required # Source-Hash: 80cef0dce71e121f -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Vanes" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy @@ -30310,8 +33043,8 @@ msgstr "Álabes" # Source-Hash: e3d2aaaf5c72bc3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A named group of zones forming one apartment, hotel room or commercial lot." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30320,8 +33053,8 @@ msgstr "Grupo con nombre de zonas que forma un piso, una habitación de hotel o # Source-Hash: 40e5a51d0d205fcf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Apartment" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30330,8 +33063,8 @@ msgstr "Apartamento" # Source-Hash: ad041d9634dd55ea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Commercial" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30340,8 +33073,8 @@ msgstr "Comercial" # Source-Hash: 862f30cb2d49f812 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Common" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30350,8 +33083,8 @@ msgstr "Común" # Source-Hash: cd7e1bc42d47a105 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hotel room" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30360,8 +33093,8 @@ msgstr "Habitación de hotel" # Source-Hash: 062cc0f1afef0c52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unit" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30370,8 +33103,8 @@ msgstr "Unidad" # Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Room" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30380,8 +33113,8 @@ msgstr "Estancia" # Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30390,8 +33123,8 @@ msgstr "Zona" # Source-Hash: e25d5b5630b9d8df # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Members sit on levels that are not adjacent." #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30400,8 +33133,8 @@ msgstr "Los miembros están en plantas no contiguas." # Source-Hash: 5ebeb440e0e64d01 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No zones assigned yet." #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30410,8 +33143,8 @@ msgstr "Aún no hay zonas asignadas." # Source-Hash: 07731fa851c75d8c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Remove {name} from unit" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30420,8 +33153,8 @@ msgstr "Quitar {name} de la unidad" # Source-Hash: 389839734c8350b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Remove zone from unit" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30430,8 +33163,8 @@ msgstr "Quitar la zona de la unidad" # Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30440,8 +33173,8 @@ msgstr "Acciones" # Source-Hash: fe18958cedd627d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Color" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30450,8 +33183,8 @@ msgstr "Color" # Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30460,8 +33193,8 @@ msgstr "Eliminar" # Source-Hash: b80dc93401f953a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Focus" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30470,8 +33203,8 @@ msgstr "Enfocar" # Source-Hash: 1218205b3bb34f1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gross area" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30480,8 +33213,8 @@ msgstr "Superficie bruta" # Source-Hash: aa9d6710f4cac041 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kind" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30490,8 +33223,8 @@ msgstr "Tipo" # Source-Hash: cc3d601d59e2e26c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Levels" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30500,8 +33233,8 @@ msgstr "Plantas" # Source-Hash: 6bbc51529519435c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Members" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30510,8 +33243,8 @@ msgstr "Miembros" # Source-Hash: 6cc5df35f0338e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Name" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30520,8 +33253,8 @@ msgstr "Nombre" # Source-Hash: 54b25f70c7b63446 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No rooms yet. Pick this unit from a room's panel, or draw zones while it is focused." #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30530,8 +33263,8 @@ msgstr "Aún no hay estancias. Elige esta unidad desde el panel de una estancia # Source-Hash: 85d640066187108d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Report" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30540,8 +33273,8 @@ msgstr "Informe" # Source-Hash: 062cc0f1afef0c52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unit" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30550,8 +33283,8 @@ msgstr "Unidad" # Source-Hash: d53242481ff46157 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Merge walls" #: packages/nodes/src/wall/actions.tsx #, fuzzy @@ -30560,28 +33293,38 @@ msgstr "Unir muros" # Source-Hash: d7ead4708d50965f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Split wall" #: packages/nodes/src/wall/actions.tsx #, fuzzy msgid "node.wall.actions.splitWall" msgstr "Dividir muro" +# Source-Hash: 2f8c3189a0b3972b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "These walls cannot be merged." +#: packages/nodes/src/wall/actions.tsx +#, fuzzy +msgid "node.wall.actions.theseWallsCannotBeMerged" +msgstr "Estos muros no se pueden unir." + # Source-Hash: 96a6f084d095ea36 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column {column}, row {row}: {type, select, glass {glass} solid {solid} other {empty}}" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy msgid "node.wall.curtain.cell" msgstr "Columna {column}, fila {row}: {type, select, glass {vidrio} solid {opaco} other {vacío}}" -# AI-Provider: cursor-agent -# AI-Model: claude-opus # Source-Hash: 904e9b269b68c670 # Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {{number} column} other {{number} columns}} · {spacing} grid spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30590,18 +33333,18 @@ msgstr "{count, plural, one {{number} columna} many {{number} columnas} other {{ # Source-Hash: 8b2b2f11fca9f077 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No panels" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy msgid "node.wall.curtain.noPanels" msgstr "Sin paneles" -# AI-Provider: cursor-agent -# AI-Model: claude-opus # Source-Hash: 9f5d9775377b666e # Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {{number} row} other {{number} rows}} · {spacing} grid spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30610,8 +33353,8 @@ msgstr "{count, plural, one {{number} fila} many {{number} filas} other {{number # Source-Hash: 90638d5a19a4f0a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Apply tint" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30620,8 +33363,8 @@ msgstr "Aplicar tinte" # Source-Hash: a7d624ec0f879829 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Border / opening frame" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30630,8 +33373,8 @@ msgstr "Borde / marco del hueco" # Source-Hash: b3a163b453896bef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bottom" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30640,8 +33383,8 @@ msgstr "Inferior" # Source-Hash: 5503fb89c40cefeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bottom row" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30650,8 +33393,8 @@ msgstr "Fila inferior" # Source-Hash: 1928d9e7a16360d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Cancel tint" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30660,8 +33403,8 @@ msgstr "Cancelar tinte" # Source-Hash: 5211341ed18f33f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Center" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30670,8 +33413,8 @@ msgstr "Centro" # Source-Hash: 9f4c033fa80119db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Choose a cell or enter its column and row. Use arrow keys to move between cells. Columns run from the wall start; rows count upward." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30680,8 +33423,8 @@ msgstr "Elige una celda o introduce su columna y fila. Usa las flechas para move # Source-Hash: bbeadcebc59c923f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Clear hidden overrides" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30690,8 +33433,8 @@ msgstr "Borrar sustituciones ocultas" # Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30700,8 +33443,8 @@ msgstr "Pilar" # Source-Hash: 711a6426e336877a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column layout" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30710,8 +33453,8 @@ msgstr "Distribución de columnas" # Source-Hash: 59b2ab5fdf54c2e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column {column}, row {row}" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30720,8 +33463,8 @@ msgstr "Columna {column}, fila {row}" # Source-Hash: ce1429556f57d7ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Construction" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30730,8 +33473,8 @@ msgstr "Construcción" # Source-Hash: 59d2bec8b9ae1025 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Continuous mullions and transoms assembled along the wall." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30740,8 +33483,8 @@ msgstr "Montantes y travesaños continuos montados a lo largo del muro." # Source-Hash: bbc5e5f3f3b99232 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Curtain wall panel selection" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30750,8 +33493,8 @@ msgstr "Selección de paneles del muro cortina" # Source-Hash: 9fd79cf417eab9ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Custom infill" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30760,8 +33503,8 @@ msgstr "Relleno personalizado" # Source-Hash: 097ed751fa47e5fd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Default panel" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30770,8 +33513,8 @@ msgstr "Panel predeterminado" # Source-Hash: 0a0c98ae42f519ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Edit individual panels" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30780,8 +33523,8 @@ msgstr "Editar paneles individuales" # Source-Hash: 8690f82f64806e4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Effective thickness: {thickness}, limited by frame depth." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30790,8 +33533,8 @@ msgstr "Espesor efectivo: {thickness}, limitado por la profundidad del marco." # Source-Hash: 65b1cbba3b92c5b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Empty" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30800,8 +33543,8 @@ msgstr "Vacío" # Source-Hash: c6e7792839d09c69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Enable panel editing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30810,8 +33553,8 @@ msgstr "Activar edición de paneles" # Source-Hash: 135874d189176d13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "End" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30820,8 +33563,8 @@ msgstr "Final" # Source-Hash: 4fb65101d0b1a222 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fixed spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30830,8 +33573,8 @@ msgstr "Separación fija" # Source-Hash: 1c851bde836b3b57 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Following wall defaults" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30840,8 +33583,8 @@ msgstr "Siguiendo los valores del muro" # Source-Hash: 49be990b89741501 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Frame dimensions" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30850,8 +33593,8 @@ msgstr "Dimensiones del marco" # Source-Hash: c7e72beff9fe4b37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Framing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30860,8 +33603,8 @@ msgstr "Entramado" # Source-Hash: 221f418784836f11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fully capped" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30870,8 +33613,8 @@ msgstr "Totalmente rematado" # Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glass" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30880,8 +33623,8 @@ msgstr "Vidrio" # Source-Hash: a17c63662aa4404d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glass appearance" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30890,8 +33633,8 @@ msgstr "Apariencia del vidrio" # Source-Hash: f59c4938a2116a2e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glass appearance is controlled by the paint tool." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30900,8 +33643,8 @@ msgstr "La apariencia del vidrio se controla con la herramienta de pintura." # Source-Hash: 9c38875c310547ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glass tint" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30910,8 +33653,8 @@ msgstr "Tinte del vidrio" # Source-Hash: 7660a6aa7e7cd365 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glazing gap" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30920,8 +33663,8 @@ msgstr "Holgura del acristalamiento" # Source-Hash: 6e739c8a698efaab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Grid limited to 32 panels per axis. Spacing expands to fit this wall." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30930,8 +33673,8 @@ msgstr "Retícula limitada a 32 paneles por eje. La separación se amplía para # Source-Hash: 1c63255b675bbcd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{length, plural, one {{number} custom panel is outside this grid. It returns if the grid expands.} other {{number} custom panels are outside this grid. They return if the grid expands.}}" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30940,8 +33683,8 @@ msgstr "{length, plural, one {{number} panel personalizado está fuera de esta c # Source-Hash: 84af317e818c10cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Horizontal caps" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30950,8 +33693,8 @@ msgstr "Tapajuntas horizontales" # Source-Hash: 7a71f6b25c5dc718 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Horizontal frame width" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30960,8 +33703,8 @@ msgstr "Ancho del marco horizontal" # Source-Hash: 54800340a0eeab23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Layout" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30970,8 +33713,8 @@ msgstr "Distribución" # Source-Hash: fc37833ef19c8feb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Low roughness is smooth; high roughness gives a matte surface in rendered shading." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30980,8 +33723,8 @@ msgstr "Una rugosidad baja es lisa; una alta da una superficie mate en el sombre # Source-Hash: 321ca5101ab61db7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Maximum spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30990,8 +33733,8 @@ msgstr "Separación máxima" # Source-Hash: 1452f51ec5dfc6ba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Module joint width" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31000,8 +33743,8 @@ msgstr "Ancho de junta entre módulos" # Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "None" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31010,8 +33753,8 @@ msgstr "Ninguno" # Source-Hash: 1c0b8a5503c5daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opacity" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31020,8 +33763,8 @@ msgstr "Opacidad" # Source-Hash: 0f9ba67daa6b4625 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opaque band" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31030,8 +33773,8 @@ msgstr "Banda opaca" # Source-Hash: fdf533d6592eff60 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opaque bands replace a full row with solid panels. Apply their finish with the paint tool." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31040,8 +33783,8 @@ msgstr "Las bandas opacas sustituyen una fila entera por paneles opacos. Aplica # Source-Hash: b91302bf741c9fd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Panel count" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31050,8 +33793,8 @@ msgstr "Número de paneles" # Source-Hash: 3a019ce58d021431 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Panel infill" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31060,8 +33803,8 @@ msgstr "Relleno del panel" # Source-Hash: 6ce059aee1386f72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Panels" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31070,8 +33813,8 @@ msgstr "Paneles" # Source-Hash: d24fe036670f54a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Panel thickness" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31080,8 +33823,8 @@ msgstr "Espesor del panel" # Source-Hash: a780f13a732bab88 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reset this panel" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31090,8 +33833,8 @@ msgstr "Restablecer este panel" # Source-Hash: 03a22f6df69c47d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Row" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31100,8 +33843,8 @@ msgstr "Fila" # Source-Hash: 0e18ec19d0e4ea93 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Row layout" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31110,8 +33853,8 @@ msgstr "Distribución de filas" # Source-Hash: dfb58bbd8932811d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Separate framed modules with joints between units." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31120,8 +33863,8 @@ msgstr "Módulos enmarcados separados con juntas entre unidades." # Source-Hash: ef3e765e692faf4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Solid" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31130,8 +33873,8 @@ msgstr "Sólido" # Source-Hash: e4698e83d02beb6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31140,8 +33883,8 @@ msgstr "Separación" # Source-Hash: 0a26a1e61c825660 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Start" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31150,8 +33893,8 @@ msgstr "Inicio" # Source-Hash: d3d738ccbc7103ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stick-built" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31160,8 +33903,8 @@ msgstr "Construido in situ" # Source-Hash: fbdb9260ee302d3d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Structural glazing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31170,8 +33913,8 @@ msgstr "Acristalamiento estructural" # Source-Hash: 393d5c5ec4e7014c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Surface roughness" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31180,8 +33923,8 @@ msgstr "Rugosidad de superficie" # Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31190,8 +33933,8 @@ msgstr "Superior" # Source-Hash: 51aa1c35a1761178 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top row" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31200,8 +33943,8 @@ msgstr "Fila superior" # Source-Hash: 1181faa315f26c83 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Uncapped members sit behind the glazing." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31210,8 +33953,8 @@ msgstr "Los perfiles sin tapa quedan detrás del acristalamiento." # Source-Hash: e68eeb4033268842 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unitized" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31220,8 +33963,8 @@ msgstr "Unitizado" # Source-Hash: 355b469b8a9c42f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Use glass settings instead" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31230,8 +33973,8 @@ msgstr "Usar en su lugar los ajustes del vidrio" # Source-Hash: 9d75fad413e547e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Use the Door or Window tool to add an opening through the wall." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31240,8 +33983,8 @@ msgstr "Usa la herramienta Puerta o Ventana para añadir un hueco en el muro." # Source-Hash: c1fa8c24203a5dde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Vertical caps" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31250,8 +33993,8 @@ msgstr "Tapajuntas verticales" # Source-Hash: 0560516882b93f0d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Vertical frame width" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31260,8 +34003,8 @@ msgstr "Ancho del marco vertical" # Source-Hash: 4b903041c38cdd72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall system" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31270,8 +34013,8 @@ msgstr "Sistema de muro" # Source-Hash: 6c753f6234766116 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A straight or curved wall segment. Hosts doors, windows, lean-to extensions, and wall-mounted items." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -31280,8 +34023,8 @@ msgstr "Tramo de muro recto o curvo. Aloja puertas, ventanas, anexos a un agua y # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -31290,8 +34033,8 @@ msgstr "Muro" # Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31300,8 +34043,8 @@ msgstr "Acciones" # Source-Hash: 67d2ec01cdce2bdc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Assembly" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31310,8 +34053,8 @@ msgstr "Composición" # Source-Hash: 05b65242d8c48791 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Auto" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31320,8 +34063,8 @@ msgstr "Auto" # Source-Hash: 69578b7dd7723fa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Both" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31330,8 +34073,8 @@ msgstr "Ambos" # Source-Hash: b3a163b453896bef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bottom" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31340,8 +34083,8 @@ msgstr "Inferior" # Source-Hash: 75d323d0159b0df8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Brick veneer" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31350,8 +34093,8 @@ msgstr "Chapado de ladrillo" # Source-Hash: 32d0bfee628c42a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Chair rail" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31360,8 +34103,8 @@ msgstr "Moldura de silla" # Source-Hash: a85f39db8f92f8e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "CMU" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31370,8 +34113,8 @@ msgstr "Bloque de hormigón" # Source-Hash: f76e125a47ed0612 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Colonial" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31380,8 +34123,8 @@ msgstr "Colonial" # Source-Hash: a4962c0f39d629ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Cove" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31390,8 +34133,8 @@ msgstr "Media caña" # Source-Hash: e5d425095ade6f06 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Craft" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31400,8 +34143,8 @@ msgstr "Artesanal" # Source-Hash: fa8a6b7f2f4eee63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Crown molding" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31410,8 +34153,8 @@ msgstr "Moldura de techo" # Source-Hash: 9736e0a78294e68d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Curtain wall" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31420,8 +34163,8 @@ msgstr "Muro cortina" # Source-Hash: f08fbb462e9afc0e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Curve" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31430,8 +34173,8 @@ msgstr "Curva" # Source-Hash: 9e9715d52410c86f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Custom" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31440,8 +34183,8 @@ msgstr "Personalizado" # Source-Hash: b2a1b3bc9676fe05 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Custom height" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31450,8 +34193,8 @@ msgstr "Altura personalizada" # Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Depth" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31460,8 +34203,8 @@ msgstr "Profundidad" # Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dimensions" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31470,8 +34213,8 @@ msgstr "Dimensiones" # Source-Hash: 4da800c75b9a6b23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Drywall" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31480,8 +34223,8 @@ msgstr "Placa de yeso" # Source-Hash: d6ba089e1ca40cdf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Extends downward to meet the terrain. Height and top stay unchanged." #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31490,8 +34233,8 @@ msgstr "Se extiende hacia abajo hasta el terreno. La altura y la parte superior # Source-Hash: 0ead5e5711b98bf6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Exterior" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31500,8 +34243,8 @@ msgstr "Exterior" # Source-Hash: fd89c31f16639f50 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fiber cement" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31510,8 +34253,8 @@ msgstr "Fibrocemento" # Source-Hash: a6be391d580de5cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fill to terrain" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31520,8 +34263,8 @@ msgstr "Rellenar hasta el terreno" # Source-Hash: 9cab4d4c95f63cdd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flat" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31530,8 +34273,8 @@ msgstr "Plana" # Source-Hash: a5c2353769b603d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follows level" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31540,18 +34283,28 @@ msgstr "Sigue la planta" # Source-Hash: fd413477f1a9e5ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Frame depth" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.frameDepth" msgstr "Profundidad del marco" +# Source-Hash: cb22c8e4b0d92234 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framer's default" +#: packages/nodes/src/wall/panel.tsx +#, fuzzy +msgid "node.wall.panel.framersDefault" +msgstr "Predeterminado del entramado" + # Source-Hash: c7e72beff9fe4b37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Framing" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31560,8 +34313,8 @@ msgstr "Entramado" # Source-Hash: eda78e8a76f068d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gypsum" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31570,8 +34323,8 @@ msgstr "Yeso" # Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Height" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31580,8 +34333,8 @@ msgstr "Altura" # Source-Hash: 2d89c1638aa8dd7e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide code" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31590,8 +34343,8 @@ msgstr "Ocultar código" # Source-Hash: 0c6dcbbbda6b4dbb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "ICF" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31600,8 +34353,8 @@ msgstr "Encofrado aislante" # Source-Hash: ff005196861cef68 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Interior" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31610,8 +34363,8 @@ msgstr "Interior" # Source-Hash: 9a4325140858cfec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Lap siding" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31620,8 +34373,8 @@ msgstr "Revestimiento solapado" # Source-Hash: 297b21e90e8c25f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Layered" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31630,8 +34383,8 @@ msgstr "Por capas" # Source-Hash: bf279d0f8f1e3b78 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Layer thicknesses follow the 2021 IRC assembly data. Drafting aid, not engineering — verify with the authority having jurisdiction." #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31640,8 +34393,8 @@ msgstr "Los espesores de capa siguen los datos de composición del IRC 2021. Ayu # Source-Hash: 643687bc3adaac76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Length" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31650,8 +34403,8 @@ msgstr "Longitud" # Source-Hash: 9e84d6d7b9885c4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Loading…" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31660,8 +34413,8 @@ msgstr "Cargando…" # Source-Hash: f6cbdaa17e989b91 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Modern" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31670,8 +34423,8 @@ msgstr "Moderno" # Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "None" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31680,8 +34433,8 @@ msgstr "Ninguno" # Source-Hash: c7300ca33851fba7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "None (single layer)" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31690,8 +34443,8 @@ msgstr "Ninguno (capa única)" # Source-Hash: 0f0e13abf9b2bb67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Offset" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31700,8 +34453,8 @@ msgstr "Desfase" # Source-Hash: 04b3006bd4e6e207 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Ogee" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31710,8 +34463,8 @@ msgstr "Gola" # Source-Hash: 4f7f8af75bf8e914 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "OSB" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31720,8 +34473,8 @@ msgstr "OSB" # Source-Hash: 1243161deca7d470 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Partition: the interior finish is applied to both faces." #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31730,8 +34483,8 @@ msgstr "Tabique: el acabado interior se aplica a ambas caras." # Source-Hash: 3ee270463954f502 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Picture" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31740,8 +34493,8 @@ msgstr "Marco" # Source-Hash: a6fd2cbf5c2154e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Plaster" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31750,8 +34503,8 @@ msgstr "Enlucido" # Source-Hash: e669c2c08bd80e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Plywood" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31760,18 +34513,28 @@ msgstr "Contrachapado" # Source-Hash: 441f7f652ea6a0d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Preset" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.preset" msgstr "Preajuste" +# Source-Hash: 240ed9c77627b9a1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" +#: packages/nodes/src/wall/panel.tsx +#, fuzzy +msgid "node.wall.panel.railing" +msgstr "Barandilla" + # Source-Hash: 62bf2677b9ec30fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31780,8 +34543,8 @@ msgstr "Referencia" # Source-Hash: 9469a102f04ea196 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Remove" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31790,8 +34553,8 @@ msgstr "Quitar" # Source-Hash: ad0457800a1f0eb4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Round" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31800,8 +34563,8 @@ msgstr "Redondo" # Source-Hash: e9a0a3688faba18b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scripted finish" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31810,8 +34573,8 @@ msgstr "Acabado por script" # Source-Hash: 36a588e44085108c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Sheathing" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31820,8 +34583,8 @@ msgstr "Tablero" # Source-Hash: 6ae9aa7061d8c617 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shoe" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31830,8 +34593,8 @@ msgstr "Cuarto bocel" # Source-Hash: 136762ac1bc96e6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Side A" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31840,8 +34603,8 @@ msgstr "Cara A" # Source-Hash: 8b9cb16850549c35 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Side B" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31850,8 +34613,8 @@ msgstr "Cara B" # Source-Hash: e6a27f6f8cd489b9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Side {face}" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31860,8 +34623,8 @@ msgstr "Cara {face}" # Source-Hash: d9d55c5883a53789 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Skirting" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31870,8 +34633,8 @@ msgstr "Rodapié" # Source-Hash: d998c212030bc7c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Standard" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31880,8 +34643,8 @@ msgstr "Estándar" # Source-Hash: da3e3dd077163ba0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Steel studs" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31890,8 +34653,8 @@ msgstr "Montantes de acero" # Source-Hash: ed3989f23a2d185e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Step" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31900,8 +34663,8 @@ msgstr "Escalonado" # Source-Hash: 9450fcb4a14674af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stone veneer" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31910,18 +34673,28 @@ msgstr "Chapado de piedra" # Source-Hash: 687cf7bc64b0224e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stucco" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.stucco" msgstr "Estuco" +# Source-Hash: 4fce02ee3f69bf99 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Studs" +#: packages/nodes/src/wall/panel.tsx +#, fuzzy +msgid "node.wall.panel.studs" +msgstr "Montantes" + # Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Thickness" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31930,18 +34703,28 @@ msgstr "Espesor" # Source-Hash: 00cb7b58f3a10140 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{thickness} · from assembly" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.thicknessFromAssembly" msgstr "{thickness} · según la composición" +# Source-Hash: 9eef4c34dfbc970b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This project" +#: packages/nodes/src/wall/panel.tsx +#, fuzzy +msgid "node.wall.panel.thisProject" +msgstr "Este proyecto" + # Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31950,8 +34733,8 @@ msgstr "Superior" # Source-Hash: 3ee03b0e9ae1be4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Total thickness" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31960,8 +34743,8 @@ msgstr "Espesor total" # Source-Hash: ea7e8bbd87ce4152 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unverified: {presetNote}" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31970,8 +34753,8 @@ msgstr "Sin verificar: {presetNote}" # Source-Hash: 21242af83a2a6d17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "View code" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31980,8 +34763,8 @@ msgstr "Ver código" # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31990,8 +34773,8 @@ msgstr "Muro" # Source-Hash: eab795728c4a3f5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall type" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32000,8 +34783,8 @@ msgstr "Tipo de muro" # Source-Hash: e97a456d667465f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Which face is outside is undetermined (no room detected on either side) — the exterior layers are drawn on side B." #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32010,18 +34793,108 @@ msgstr "No se sabe qué cara es la exterior (no se detecta ninguna estancia a ni # Source-Hash: 31e404a4a4870faf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wood studs" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.woodStuds" msgstr "Montantes de madera" +# Source-Hash: ece946252401f4ab +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A guard's openings must not pass a 4 in sphere (IRC R312.1.3)." +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.aGuardSOpeningsMustNot" +msgstr "Las aberturas de una barandilla no deben dejar pasar una esfera de 4 in (IRC R312.1.3)." + +# Source-Hash: 646ef0fbcbc58edf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.height" +msgstr "Altura" + +# Source-Hash: 7c339a5fae55681d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Infill" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.infill" +msgstr "Relleno" + +# Source-Hash: d814a47c4eccee3f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "2x6 cap" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.n2x6Cap" +msgstr "Remate 2x6" + +# Source-Hash: 137b45940b723a6e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "36 in" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.n36In" +msgstr "36 in" + +# Source-Hash: ebf854ac4dd4daaf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "42 in" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.n42In" +msgstr "42 in" + +# Source-Hash: ede386e1d510ebfb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Posts" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.posts" +msgstr "Postes" + +# Source-Hash: 240ed9c77627b9a1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.railing" +msgstr "Barandilla" + +# Source-Hash: 1a79a485d91f3f28 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.style" +msgstr "Estilo" + # Source-Hash: 5211341ed18f33f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Center" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32030,8 +34903,8 @@ msgstr "Centro" # Source-Hash: 09576259041494f3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Inside face" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32040,8 +34913,8 @@ msgstr "Cara interior" # Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Left" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32050,8 +34923,8 @@ msgstr "Izquierda" # Source-Hash: 697001376b872e74 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Outside face" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32060,8 +34933,8 @@ msgstr "Cara exterior" # Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Right" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32070,8 +34943,8 @@ msgstr "Derecha" # Source-Hash: eac63d14f275db3d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{trim, select, skirting {Hide skirting} crown {Hide crown molding} other {Hide chair rail}}" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32080,18 +34953,28 @@ msgstr "{trim, select, skirting {Ocultar rodapié} crown {Ocultar moldura de tec # Source-Hash: 8db070a4247db221 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{trim, select, skirting {Show skirting} crown {Show crown molding} other {Show chair rail}}" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.trim.show" msgstr "{trim, select, skirting {Mostrar rodapié} crown {Mostrar moldura de techo} other {Mostrar moldura de silla}}" +# Source-Hash: b1757d76048706b7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap hinge side" +#: packages/nodes/src/window/actions.tsx +#, fuzzy +msgid "node.window.actions.swapHingeSide" +msgstr "Cambiar el lado de las bisagras" + # Source-Hash: ea6a51e66eb0c0dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A window cut into a wall. Animated open/close for opening windows." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -32100,8 +34983,8 @@ msgstr "Ventana abierta en un muro, con apertura animada en las practicables." # Source-Hash: aa3c35ed33e181e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -32110,8 +34993,8 @@ msgstr "Ventana" # Source-Hash: 011e4de244050a78 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Raise" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32120,8 +35003,8 @@ msgstr "Elevar" # Source-Hash: 19ca2434d4f7eb87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slats" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32130,8 +35013,8 @@ msgstr "Lamas" # Source-Hash: c00de0e2c9b0ddcb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slide" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32140,8 +35023,8 @@ msgstr "Deslizar" # Source-Hash: e48604b5f7b2a5f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Swing" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32150,8 +35033,8 @@ msgstr "Abatir" # Source-Hash: 1615637fe68e188a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Tilt" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32160,8 +35043,8 @@ msgstr "Inclinar" # Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32170,8 +35053,8 @@ msgstr "Acciones" # Source-Hash: 663175a9c461a96d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "All" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32180,8 +35063,8 @@ msgstr "Todo" # Source-Hash: 710261f5ffb32617 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Arch" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32190,8 +35073,8 @@ msgstr "Arco" # Source-Hash: 3715cd54e4775087 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Arch Height" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32201,7 +35084,7 @@ msgstr "Altura del arco" # Source-Hash: 05b65242d8c48791 # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 +# AI-Model: claude-opus-5-5 # English: "Auto" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32211,7 +35094,7 @@ msgstr "Auto" # Source-Hash: 8a04486ba122ea7d # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 +# AI-Model: claude-opus-5-5 # English: "Auto follows the wall" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32220,8 +35103,8 @@ msgstr "Auto sigue el muro" # Source-Hash: 30edd1c180aac9b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Columns" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32230,8 +35113,8 @@ msgstr "Columnas" # Source-Hash: 2f417371c399ad67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Col Widths" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32240,8 +35123,8 @@ msgstr "Anchos de columna" # Source-Hash: 2ee121dca87bb64a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Corner" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32250,8 +35133,8 @@ msgstr "Esquina" # Source-Hash: 04e3425c5ea29359 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Corner post" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32260,8 +35143,8 @@ msgstr "Poste de esquina" # Source-Hash: 7a90a42b578f2435 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Corner Radius" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32270,8 +35153,8 @@ msgstr "Radio de esquina" # Source-Hash: 67d10b97eff316c1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Custom: the panes match no style." #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32280,8 +35163,8 @@ msgstr "Personalizado: los paños no coinciden con ningún estilo." # Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32290,8 +35173,8 @@ msgstr "Eliminar" # Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Depth" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32300,8 +35183,8 @@ msgstr "Profundidad" # Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dimensions" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32310,8 +35193,8 @@ msgstr "Dimensiones" # Source-Hash: c53c3307e2a2a32a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Divider" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32320,8 +35203,8 @@ msgstr "Divisor" # Source-Hash: 72c65752a1d1bbb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Down" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32330,8 +35213,8 @@ msgstr "Abajo" # Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duplicate" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32340,8 +35223,8 @@ msgstr "Duplicar" # Source-Hash: 8497c4373d5d18ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Enable Sill" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32350,8 +35233,8 @@ msgstr "Activar alféizar" # Source-Hash: 61f9413d3bbabde7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flip Side" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32360,8 +35243,8 @@ msgstr "Invertir lado" # Source-Hash: ce3a6c03765dbbd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Frame" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32371,7 +35254,7 @@ msgstr "Marco" # Source-Hash: 0cce8ae784f78478 # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 +# AI-Model: claude-opus-5-5 # English: "Depth (auto)" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32380,8 +35263,8 @@ msgstr "Profundidad (auto)" # Source-Hash: 092033938ca2debb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "French" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32390,8 +35273,8 @@ msgstr "Francesa" # Source-Hash: a6362b937fffe999 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fused glass" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32400,8 +35283,8 @@ msgstr "Vidrio fundido" # Source-Hash: 7e4a0a38f694be6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Grid" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32410,8 +35293,8 @@ msgstr "Cuadrícula" # Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Height" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32420,8 +35303,8 @@ msgstr "Altura" # Source-Hash: 42824e50de26bc14 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Individual" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32430,8 +35313,8 @@ msgstr "Individual" # Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Left" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32440,8 +35323,8 @@ msgstr "Izquierda" # Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Move" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32450,8 +35333,8 @@ msgstr "Mover" # Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opening" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32460,8 +35343,8 @@ msgstr "Abertura" # Source-Hash: ecb81bd3eefa6a47 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opening Shape" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32470,8 +35353,8 @@ msgstr "Forma del hueco" # Source-Hash: cf40395b71bedcca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Other side" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32480,8 +35363,8 @@ msgstr "Otro lado" # Source-Hash: 28fe6e9deddde6e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "pos" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32490,8 +35373,8 @@ msgstr "pos" # Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Position" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32500,8 +35383,8 @@ msgstr "Posición" # Source-Hash: 3b6f225112035fde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rect" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32510,8 +35393,8 @@ msgstr "Rect." # Source-Hash: 59236bd016c6b904 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reveal Radius" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32520,8 +35403,8 @@ msgstr "Radio del derrame" # Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Right" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32530,8 +35413,8 @@ msgstr "Derecha" # Source-Hash: fc826da6c99303e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rounded" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32540,8 +35423,8 @@ msgstr "Redondeado" # Source-Hash: fb811056b862b6d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Row Heights" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32550,8 +35433,8 @@ msgstr "Alturas de fila" # Source-Hash: c913b494c3901a17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rows" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32560,8 +35443,8 @@ msgstr "Filas" # Source-Hash: 62ded63b01564969 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Sill" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32570,8 +35453,8 @@ msgstr "Alféizar" # Source-Hash: 62ab2eb3c775da95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Single" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32580,8 +35463,8 @@ msgstr "Simple" # Source-Hash: a8096eb4beaadeef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Size is limited to the wall, including clearance for the opening frame." #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32590,8 +35473,8 @@ msgstr "El tamaño está limitado al muro, incluida la holgura del marco del hue # Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Style" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32600,8 +35483,8 @@ msgstr "Estilo" # Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Thickness" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32610,8 +35493,8 @@ msgstr "Espesor" # Source-Hash: 79ff1ae7250c1711 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "This side" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32620,8 +35503,8 @@ msgstr "Este lado" # Source-Hash: 7e2505dd1d5e3513 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top Shape" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32630,8 +35513,8 @@ msgstr "Forma superior" # Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Type" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32640,8 +35523,8 @@ msgstr "Tipo" # Source-Hash: c29767f86bd9df1e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unwrap" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32650,8 +35533,8 @@ msgstr "Separar" # Source-Hash: 1d732503a54a532f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Up" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32660,8 +35543,8 @@ msgstr "Arriba" # Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Width" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32670,8 +35553,8 @@ msgstr "Ancho" # Source-Hash: aa3c35ed33e181e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32680,8 +35563,8 @@ msgstr "Ventana" # Source-Hash: f59cd625e6082651 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window Type" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32690,8 +35573,8 @@ msgstr "Tipo de ventana" # Source-Hash: 7bf8c4e2b90b3021 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wraps the corner with {partner}" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32700,8 +35583,8 @@ msgstr "Rodea la esquina con {partner}" # Source-Hash: 8f1f8eff5fbe90e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wraps the corner with its partner" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32710,8 +35593,8 @@ msgstr "Rodea la esquina con su pareja" # Source-Hash: cccf75b8c8dc5ad6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wrap the corner" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32720,8 +35603,8 @@ msgstr "Rodear la esquina" # Source-Hash: 9d63109edd8b22c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Casement" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32730,8 +35613,8 @@ msgstr "Abatible" # Source-Hash: e06fc5a432b74a5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Double-hung" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32740,8 +35623,8 @@ msgstr "Guillotina doble" # Source-Hash: 7e4a0a38f694be6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Grid" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32750,8 +35633,8 @@ msgstr "Cuadrícula" # Source-Hash: fbb293fe8aee84b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Horizontal bands" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32760,8 +35643,8 @@ msgstr "Bandas horizontales" # Source-Hash: 3ee270463954f502 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Picture" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32770,8 +35653,8 @@ msgstr "Marco" # Source-Hash: 62ab2eb3c775da95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Single" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32780,8 +35663,8 @@ msgstr "Simple" # Source-Hash: 18cbc73c5e1590aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Sliding" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32790,8 +35673,8 @@ msgstr "Corredera" # Source-Hash: 0c88aea2bd130193 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Tall grid" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32800,8 +35683,8 @@ msgstr "Retícula alta" # Source-Hash: 9628d0cc155e29a3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Transom" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32810,8 +35693,8 @@ msgstr "Montante" # Source-Hash: 305f3aba543b1962 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Triple-hung" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32820,8 +35703,8 @@ msgstr "Guillotina triple" # Source-Hash: 8af77effb76bc6e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wide grid" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32830,8 +35713,8 @@ msgstr "Retícula ancha" # Source-Hash: 50393830365aaf2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Awning" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32840,8 +35723,8 @@ msgstr "Proyectante" # Source-Hash: 8447ee52258e16e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bay" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32850,8 +35733,8 @@ msgstr "Mirador" # Source-Hash: e828c89bd0ba1ea4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bow" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32860,8 +35743,8 @@ msgstr "Ventana en arco" # Source-Hash: 9d63109edd8b22c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Casement" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32870,8 +35753,8 @@ msgstr "Ventana abatible" # Source-Hash: b0b737fc5cb1d32a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Double Hung" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32880,8 +35763,8 @@ msgstr "Guillotina doble" # Source-Hash: 387ce45ca2eb045f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fixed" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32890,8 +35773,8 @@ msgstr "Fijo" # Source-Hash: 04a40f27911c3192 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hopper" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32900,8 +35783,8 @@ msgstr "Abatible inferior" # Source-Hash: 5746be19ba2a53be # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Louvered" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32910,8 +35793,8 @@ msgstr "De lamas" # Source-Hash: de6ffb1cf676f270 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Single Hung" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32920,8 +35803,8 @@ msgstr "Guillotina simple" # Source-Hash: 18cbc73c5e1590aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Sliding" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32930,8 +35813,8 @@ msgstr "Corredera" # Source-Hash: 4a4d97a4101793b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A polygonal site zone (lawn, water, paving) with a TSL gradient material." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -32940,8 +35823,8 @@ msgstr "Zona poligonal del terreno (césped, agua, pavimento) con un material de # Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -32950,8 +35833,8 @@ msgstr "Zona" # Source-Hash: e9a6d2e71b97e757 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Enclosed room" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -32960,8 +35843,8 @@ msgstr "Estancia cerrada" # Source-Hash: 3660922f0a8f1d3c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Floor surface" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -32970,8 +35853,8 @@ msgstr "Superficie del suelo" # Source-Hash: 88c8703c4ff21ee1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Footprint only" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -32980,8 +35863,8 @@ msgstr "Solo huella" # Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "None" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -32990,8 +35873,8 @@ msgstr "Ninguno" # Source-Hash: a9756a3da570c3dd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Not proven" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33000,8 +35883,8 @@ msgstr "No demostrado" # Source-Hash: ff97d005a536cf58 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Room quantities" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33010,8 +35893,8 @@ msgstr "Mediciones de la estancia" # Source-Hash: f520e6a06fbeb803 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top view with zone edge dimensions" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33020,8 +35903,8 @@ msgstr "Vista superior con las cotas de los bordes de la zona" # Source-Hash: 062cc0f1afef0c52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unit" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33030,8 +35913,8 @@ msgstr "Unidad" # Source-Hash: 429bd43d726de417 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Volume" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33040,8 +35923,8 @@ msgstr "Volumen" # Source-Hash: a7941c60a3b6998a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall surface" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33050,8 +35933,8 @@ msgstr "Superficie de muro" # Source-Hash: b8b0dbdff53a83ca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone boundary unavailable" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33060,8 +35943,8 @@ msgstr "Límite de zona no disponible" # Source-Hash: 6bfb4c6f4d7b0ff2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone quantities" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy diff --git a/packages/editor/src/i18n/locales/es/messages.ts b/packages/editor/src/i18n/locales/es/messages.ts index 24fa7da3af..2a7f25575b 100644 --- a/packages/editor/src/i18n/locales/es/messages.ts +++ b/packages/editor/src/i18n/locales/es/messages.ts @@ -1 +1 @@ -/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"core.level.basement\":[\"Sótano\"],\"core.level.basementNumber\":[\"Sótano \",[\"number\"]],\"core.level.floorNumber\":[\"Planta \",[\"number\"]],\"core.level.groundFloor\":[\"Planta baja\"],\"editor.buildPanel.advanced\":[\"Avanzado\"],\"editor.buildPanel.rooms.hint\":[\"muros · suelo · techo\"],\"editor.buildPanel.rooms.idle\":[\"Elige una forma para empezar. Cada estancia incluye sus muros, suelo y techo.\"],\"editor.buildPanel.rooms.polygon.caption\":[[\"lead\"],\" y vuelve a pulsar la primera para cerrar. Para estancias en L o con ángulos.\"],\"editor.buildPanel.rooms.polygon.label\":[\"Polígono\"],\"editor.buildPanel.rooms.polygon.lead\":[\"Haz clic en cada esquina\"],\"editor.buildPanel.rooms.polygon.title\":[\"Estancia poligonal\"],\"editor.buildPanel.rooms.rectangle.caption\":[[\"lead\"],\" en la cuadrícula. Los muros, el suelo y el techo se crean a la vez.\"],\"editor.buildPanel.rooms.rectangle.label\":[\"Rectángulo\"],\"editor.buildPanel.rooms.rectangle.lead\":[\"Haz clic en dos esquinas\"],\"editor.buildPanel.rooms.rectangle.title\":[\"Estancia rectangular\"],\"editor.buildPanel.rooms.title\":[\"Estancias\"],\"editor.buildPanel.rooms.walls.caption\":[[\"lead\"],\" Cierra el contorno para crear una estancia o déjalo abierto para tabiques.\"],\"editor.buildPanel.rooms.walls.label\":[\"Muros\"],\"editor.buildPanel.rooms.walls.lead\":[\"Dibuja un muro cada vez.\"],\"editor.buildPanel.rooms.walls.title\":[\"Muros\"],\"viewer.camera.orbitLeft\":[\"Orbitar a la izquierda\"],\"viewer.camera.orbitRight\":[\"Orbitar a la derecha\"],\"viewer.camera.topView\":[\"Vista superior\"],\"viewer.common.off\":[\"Desactivado\"],\"viewer.common.on\":[\"Activado\"],\"viewer.display.camera\":[\"Cámara\"],\"viewer.display.colored\":[\"A color\"],\"viewer.display.colors\":[\"Colores\"],\"viewer.display.edges.off\":[\"Desactivadas\"],\"viewer.display.edges.offDetail\":[\"Sin líneas de arista\"],\"viewer.display.edges.soft\":[\"Suaves\"],\"viewer.display.edges.softDetail\":[\"Contorno tenue de los pliegues principales\"],\"viewer.display.edges.strong\":[\"Marcadas\"],\"viewer.display.edges.strongDetail\":[\"Líneas de arista nítidas y opacas\"],\"viewer.display.edges.title\":[\"Aristas\"],\"viewer.display.monochrome\":[\"Monocromo\"],\"viewer.display.orthographic\":[\"Ortográfica\"],\"viewer.display.perspective\":[\"Perspectiva\"],\"viewer.display.render.rendered\":[\"Realista\"],\"viewer.display.render.renderedDetail\":[\"Oclusión ambiental completa\"],\"viewer.display.render.solid\":[\"Sólido\"],\"viewer.display.render.solidDetail\":[\"Plano y rápido, sin oclusión ambiental\"],\"viewer.display.render.title\":[\"Renderizado\"],\"viewer.display.shadows\":[\"Sombras\"],\"viewer.display.title\":[\"Ajustes de visualización\"],\"viewer.floorplan.alignNorth\":[\"Orientar la vista al norte\"],\"viewer.floorplan.empty\":[\"No hay planos de planta disponibles para esta escena.\"],\"viewer.floorplan.fit\":[\"Ajustar plano\"],\"viewer.floorplan.floor\":[\"Planta\"],\"viewer.floorplan.floorPlan\":[\"Plano de planta\"],\"viewer.floorplan.viewLabel\":[\"Vista 2D de \",[\"floor\"]],\"viewer.floorplan.zoomIn\":[\"Acercar\"],\"viewer.floorplan.zoomOut\":[\"Alejar\"],\"viewer.header.back\":[\"Volver\"],\"viewer.header.levels\":[\"Plantas\"],\"viewer.header.rooms\":[\"Estancias\"],\"viewer.header.selection\":[\"Selección\"],\"viewer.header.units\":[\"Unidades\"],\"viewer.header.untitled\":[\"Sin título\"],\"viewer.header.zones\":[\"Zonas\"],\"viewer.levels.exploded\":[\"Separadas\"],\"viewer.levels.label\":[\"Plantas: \",[\"mode\"]],\"viewer.levels.manual\":[\"Manual\"],\"viewer.levels.solo\":[\"Aislada\"],\"viewer.levels.stacked\":[\"Apiladas\"],\"viewer.stage.layout\":[\"Disposición de vistas\"],\"viewer.stage.split\":[\"Dividida\"],\"viewer.theme.blueprint\":[\"Plano técnico\"],\"viewer.theme.mediterranean\":[\"Mediterráneo\"],\"viewer.theme.night\":[\"Noche\"],\"viewer.theme.overcast\":[\"Nublado\"],\"viewer.theme.paper\":[\"Papel\"],\"viewer.theme.studio\":[\"Estudio\"],\"viewer.theme.sunset\":[\"Atardecer\"],\"viewer.theme.title\":[\"Ambiente\"],\"viewer.theme.twilight\":[\"Crepúsculo\"],\"viewer.theme.verdant\":[\"Verde\"],\"viewer.visibility.guides\":[\"Guías\"],\"viewer.visibility.scans\":[\"Escaneos 3D\"],\"viewer.visibility.title\":[\"Visibilidad\"],\"viewer.walkthrough.label\":[\"Recorrido: \",[\"state\"]],\"viewer.walls.cutaway\":[\"Vista seccionada\"],\"viewer.walls.fullHeight\":[\"Altura completa\"],\"viewer.walls.label\":[\"Muros: \",[\"mode\"]],\"viewer.walls.low\":[\"Bajos\"]}")as Messages; \ No newline at end of file +/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"core.level.basement\":[\"Sótano\"],\"core.level.basementNumber\":[\"Sótano \",[\"number\"]],\"core.level.floorNumber\":[\"Planta \",[\"number\"]],\"core.level.groundFloor\":[\"Planta baja\"],\"editor.buildPanel.advanced\":[\"Avanzado\"],\"editor.buildPanel.rooms.hint\":[\"muros · suelo · techo\"],\"editor.buildPanel.rooms.idle\":[\"Elige una forma para empezar. Cada estancia incluye sus muros, suelo y techo.\"],\"editor.buildPanel.rooms.polygon.caption\":[[\"lead\"],\" y vuelve a pulsar la primera para cerrar. Para estancias en L o con ángulos.\"],\"editor.buildPanel.rooms.polygon.label\":[\"Polígono\"],\"editor.buildPanel.rooms.polygon.lead\":[\"Haz clic en cada esquina\"],\"editor.buildPanel.rooms.polygon.title\":[\"Estancia poligonal\"],\"editor.buildPanel.rooms.rectangle.caption\":[[\"lead\"],\" en la cuadrícula. Los muros, el suelo y el techo se crean a la vez.\"],\"editor.buildPanel.rooms.rectangle.label\":[\"Rectángulo\"],\"editor.buildPanel.rooms.rectangle.lead\":[\"Haz clic en dos esquinas\"],\"editor.buildPanel.rooms.rectangle.title\":[\"Estancia rectangular\"],\"editor.buildPanel.rooms.title\":[\"Estancias\"],\"editor.buildPanel.rooms.walls.label\":[\"Muros\"],\"editor.buildPanel.rooms.walls.title\":[\"Muros\"],\"viewer.camera.orbitLeft\":[\"Orbitar a la izquierda\"],\"viewer.camera.orbitRight\":[\"Orbitar a la derecha\"],\"viewer.camera.topView\":[\"Vista superior\"],\"viewer.common.off\":[\"Desactivado\"],\"viewer.common.on\":[\"Activado\"],\"viewer.display.camera\":[\"Cámara\"],\"viewer.display.colored\":[\"A color\"],\"viewer.display.colors\":[\"Colores\"],\"viewer.display.edges.off\":[\"Desactivadas\"],\"viewer.display.edges.offDetail\":[\"Sin líneas de arista\"],\"viewer.display.edges.soft\":[\"Suaves\"],\"viewer.display.edges.softDetail\":[\"Contorno tenue de los pliegues principales\"],\"viewer.display.edges.strong\":[\"Marcadas\"],\"viewer.display.edges.strongDetail\":[\"Líneas de arista nítidas y opacas\"],\"viewer.display.edges.title\":[\"Aristas\"],\"viewer.display.monochrome\":[\"Monocromo\"],\"viewer.display.orthographic\":[\"Ortográfica\"],\"viewer.display.perspective\":[\"Perspectiva\"],\"viewer.display.render.rendered\":[\"Realista\"],\"viewer.display.render.renderedDetail\":[\"Oclusión ambiental completa\"],\"viewer.display.render.solid\":[\"Sólido\"],\"viewer.display.render.solidDetail\":[\"Plano y rápido, sin oclusión ambiental\"],\"viewer.display.render.title\":[\"Renderizado\"],\"viewer.display.shadows\":[\"Sombras\"],\"viewer.display.title\":[\"Ajustes de visualización\"],\"viewer.floorplan.alignNorth\":[\"Orientar la vista al norte\"],\"viewer.floorplan.empty\":[\"No hay planos de planta disponibles para esta escena.\"],\"viewer.floorplan.fit\":[\"Ajustar plano\"],\"viewer.floorplan.floor\":[\"Planta\"],\"viewer.floorplan.floorPlan\":[\"Plano de planta\"],\"viewer.floorplan.viewLabel\":[\"Vista 2D de \",[\"floor\"]],\"viewer.floorplan.zoomIn\":[\"Acercar\"],\"viewer.floorplan.zoomOut\":[\"Alejar\"],\"viewer.header.back\":[\"Volver\"],\"viewer.header.levels\":[\"Plantas\"],\"viewer.header.rooms\":[\"Estancias\"],\"viewer.header.selection\":[\"Selección\"],\"viewer.header.units\":[\"Unidades\"],\"viewer.header.untitled\":[\"Sin título\"],\"viewer.header.zones\":[\"Zonas\"],\"viewer.levels.exploded\":[\"Separadas\"],\"viewer.levels.label\":[\"Plantas: \",[\"mode\"]],\"viewer.levels.manual\":[\"Manual\"],\"viewer.levels.solo\":[\"Aislada\"],\"viewer.levels.stacked\":[\"Apiladas\"],\"viewer.stage.layout\":[\"Disposición de vistas\"],\"viewer.stage.split\":[\"Dividida\"],\"viewer.theme.blueprint\":[\"Plano técnico\"],\"viewer.theme.mediterranean\":[\"Mediterráneo\"],\"viewer.theme.night\":[\"Noche\"],\"viewer.theme.overcast\":[\"Nublado\"],\"viewer.theme.paper\":[\"Papel\"],\"viewer.theme.studio\":[\"Estudio\"],\"viewer.theme.sunset\":[\"Atardecer\"],\"viewer.theme.title\":[\"Ambiente\"],\"viewer.theme.twilight\":[\"Crepúsculo\"],\"viewer.theme.verdant\":[\"Verde\"],\"viewer.visibility.guides\":[\"Guías\"],\"viewer.visibility.scans\":[\"Escaneos 3D\"],\"viewer.visibility.title\":[\"Visibilidad\"],\"viewer.walkthrough.label\":[\"Recorrido: \",[\"state\"]],\"viewer.walls.cutaway\":[\"Vista seccionada\"],\"viewer.walls.fullHeight\":[\"Altura completa\"],\"viewer.walls.label\":[\"Muros: \",[\"mode\"]],\"viewer.walls.low\":[\"Bajos\"]}")as Messages; \ No newline at end of file diff --git a/packages/editor/src/i18n/locales/fr/messages.po b/packages/editor/src/i18n/locales/fr/messages.po index b261e6fc85..f525dead6e 100644 --- a/packages/editor/src/i18n/locales/fr/messages.po +++ b/packages/editor/src/i18n/locales/fr/messages.po @@ -15,8 +15,8 @@ msgstr "" # Source-Hash: 8ffb1c5066e53a8d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Pascal home" #: apps/editor/components/app-home-link.tsx #, fuzzy @@ -25,8 +25,8 @@ msgstr "Accueil Pascal" # Source-Hash: 534540df302975a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Gate" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -35,8 +35,8 @@ msgstr "Ajouter un portail" # Source-Hash: 8b9110c4e72f2db2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Open Passage" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -45,8 +45,8 @@ msgstr "Ajouter un passage" # Source-Hash: 9a4d56454dc89966 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add to rooms" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -55,8 +55,8 @@ msgstr "Ajouter aux pièces" # Source-Hash: a17210912addc85f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "← All build tools" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -65,8 +65,8 @@ msgstr "← Tous les outils de construction" # Source-Hash: 6b63404967e1d5b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Choose Gate or Open Passage, then click its position on any fence. Find placed gates and openings under their fence in the scene graph." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -75,8 +75,8 @@ msgstr "Choisissez Portail ou Passage, puis cliquez sur sa position sur une clô # Source-Hash: 8fd051e1e1a6c1a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Click a lineset to lay the line beside it." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -85,8 +85,8 @@ msgstr "Cliquez sur une liaison frigorifique pour poser la ligne à côté." # Source-Hash: 7308869944020839 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Double gate" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -95,8 +95,8 @@ msgstr "Portail double" # Source-Hash: 281d63a4b3e2de4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Features & extensions" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -105,8 +105,8 @@ msgstr "Éléments et extensions" # Source-Hash: b18788f1d889c1d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fence features" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -115,8 +115,8 @@ msgstr "Éléments de clôture" # Source-Hash: 62803100bd6e7cc2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follow lineset" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -125,8 +125,8 @@ msgstr "Suivre la liaison frigorifique" # Source-Hash: 4a479aa23542d766 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gate" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -135,8 +135,8 @@ msgstr "Portail" # Source-Hash: 54098b5ee574737a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gate style" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -145,8 +145,8 @@ msgstr "Style de portail" # Source-Hash: 8fec7e969045a8e7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Horizontal boards" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -155,8 +155,8 @@ msgstr "Lames horizontales" # Source-Hash: 09197c4fea516277 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hover a fence to preview. Click to place. Esc cancels. Leave room between openings." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -165,8 +165,8 @@ msgstr "Survolez une clôture pour prévisualiser. Cliquez pour placer. Échap p # Source-Hash: c390ba248e629b9e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Leaves" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -175,8 +175,8 @@ msgstr "Vantaux" # Source-Hash: c34c9b36492c6e21 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Liquid Line" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -185,8 +185,8 @@ msgstr "Ligne liquide" # Source-Hash: c15c1af69ec5c1eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Match fence style" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -195,8 +195,8 @@ msgstr "Assortir au style de clôture" # Source-Hash: 95057eef5cd69340 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "MEP" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -205,8 +205,8 @@ msgstr "CVC-P" # Source-Hash: 50accd740fa2e736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Off" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -215,8 +215,8 @@ msgstr "Désactivé" # Source-Hash: 9cc01faad79c28da # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "On" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -225,8 +225,8 @@ msgstr "Activé" # Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opening" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -235,8 +235,8 @@ msgstr "Ouverture" # Source-Hash: 9514d3c022e68808 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opening width (m)" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -245,8 +245,8 @@ msgstr "Largeur de l’ouverture (m)" # Source-Hash: 6b108fb1d0eb8f9d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Open rails" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -255,8 +255,8 @@ msgstr "Lisses ajourées" # Source-Hash: a5a7af5e5fff1c81 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Outdoor" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -265,8 +265,8 @@ msgstr "Extérieur" # Source-Hash: 9295ddc2805b21e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Picket" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -275,8 +275,8 @@ msgstr "Piquets" # Source-Hash: 3a08ede9e51d5395 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Roof type" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -285,8 +285,8 @@ msgstr "Type de toit" # Source-Hash: 0f9daa442776a317 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rooms already create their floor and ceiling. Use these for platforms and one-off structure." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -295,8 +295,8 @@ msgstr "Les pièces créent déjà leur sol et leur plafond. Utilisez ces outils # Source-Hash: fc79fd0c7730de76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Search build tools and kitchen items" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -305,8 +305,8 @@ msgstr "Rechercher des outils de construction et des éléments de cuisine" # Source-Hash: dc1901f276edca6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Search tools, fridge, sink…" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -315,8 +315,8 @@ msgstr "Rechercher des outils, frigo, évier…" # Source-Hash: 9558db89023d4f05 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Select a curved wall to match its radius and arc." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -325,8 +325,8 @@ msgstr "Sélectionnez un mur courbe pour reprendre son rayon et son arc." # Source-Hash: d327097d9ac1099f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Single gate" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -335,8 +335,8 @@ msgstr "Portail simple" # Source-Hash: 99acd5128c51c8a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slab, ceiling, column…" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -345,8 +345,8 @@ msgstr "Dalle, plafond, poteau…" # Source-Hash: af6f8885fe0fa4e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Solid privacy" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -355,8 +355,8 @@ msgstr "Occultant plein" # Source-Hash: e2b1a3bb9630b33b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Trace a line alongside an existing lineset (F)." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -365,8 +365,8 @@ msgstr "Tracer une ligne le long d’une liaison existante (F)." # Source-Hash: eba3df14a2de0812 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Vertical slats" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -375,8 +375,8 @@ msgstr "Lames verticales" # Source-Hash: 2ee62be78ba76f53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "All projects" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -385,8 +385,8 @@ msgstr "Tous les projets" # Source-Hash: 20226b68d5467072 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Preview" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -395,8 +395,8 @@ msgstr "Aperçu" # Source-Hash: 9f2cbc9214c8f7b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Project name" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -405,8 +405,8 @@ msgstr "Nom du projet" # Source-Hash: 150e143a84240eee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rename project" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -415,8 +415,8 @@ msgstr "Renommer le projet" # Source-Hash: 331e1584943b09b9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Share" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -425,8 +425,8 @@ msgstr "Partager" # Source-Hash: 4b2f676fb4c9ec63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add {label}" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -435,8 +435,8 @@ msgstr "Ajouter {label}" # Source-Hash: 53f98cc505aacbb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add to kitchen" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -445,8 +445,8 @@ msgstr "Ajouter à la cuisine" # Source-Hash: 923a2e81dcc77852 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Choose an item, then click to place it. Appliances include their cabinetry." #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -455,8 +455,8 @@ msgstr "Choisissez un élément, puis cliquez pour le placer. L’électroménag # Source-Hash: 44156a2c888e8a4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Find in this project · {length}" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -465,8 +465,8 @@ msgstr "Rechercher dans ce projet · {length}" # Source-Hash: aeda65db67edac21 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Find {name}" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -475,8 +475,8 @@ msgstr "Trouver {name}" # Source-Hash: c1d847411ba09cd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen · Add" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -485,8 +485,8 @@ msgstr "Cuisine · Ajouter" # Source-Hash: bb3f4f8d3407c409 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen · In this project" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -495,8 +495,8 @@ msgstr "Cuisine · Dans ce projet" # Source-Hash: 25ffad31086309f1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen cabinet" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -505,8 +505,8 @@ msgstr "Meuble de cuisine" # Source-Hash: a5af7817a7e8947d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No matching kitchen items placed yet." #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -515,8 +515,8 @@ msgstr "Aucun élément de cuisine correspondant placé pour l’instant." # Source-Hash: 640155f99c25773b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Select and show in scene" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -525,8 +525,8 @@ msgstr "Sélectionner et afficher dans la scène" # Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Ceiling" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -535,8 +535,8 @@ msgstr "Plafond" # Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -545,8 +545,8 @@ msgstr "Poteau" # Source-Hash: 787e10f5db16904e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Door" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -555,8 +555,8 @@ msgstr "Porte" # Source-Hash: e971d82044e2f48e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duct" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -565,8 +565,8 @@ msgstr "Gaine" # Source-Hash: 457155657704f7cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "DWV Pipe" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -575,8 +575,8 @@ msgstr "Tuyau d’évacuation" # Source-Hash: ab5cbab7be160a1c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Elevator" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -585,8 +585,8 @@ msgstr "Ascenseur" # Source-Hash: 02042fde61b5aa11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fence" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -595,8 +595,8 @@ msgstr "Clôture" # Source-Hash: 3bf1c1a8dbb93743 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "HVAC Unit" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -605,8 +605,8 @@ msgstr "Unité CVC" # Source-Hash: 1176d2568d093bf1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -615,8 +615,8 @@ msgstr "Cuisine" # Source-Hash: 362b03eba9d8234c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Lineset" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -625,8 +625,8 @@ msgstr "Liaison frigorifique" # Source-Hash: c34c9b36492c6e21 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Liquid Line" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -635,18 +635,28 @@ msgstr "Ligne liquide" # Source-Hash: 95057eef5cd69340 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "MEP" #: apps/editor/lib/build-palette.ts #, fuzzy msgid "app.lib.buildPalette.mep" msgstr "CVC-P" +# Source-Hash: 5cc981e79d737694 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post" +#: apps/editor/lib/build-palette.ts +#, fuzzy +msgid "app.lib.buildPalette.post" +msgstr "Poteau bois" + # Source-Hash: 161e5386b939e1bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Register" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -655,8 +665,8 @@ msgstr "Bouche" # Source-Hash: f5f730969df63d1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Roof" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -665,8 +675,8 @@ msgstr "Toit" # Source-Hash: d7145f84f8e0e3fe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shelf" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -675,8 +685,8 @@ msgstr "Étagère" # Source-Hash: 8775bc8dc9593964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slab" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -685,8 +695,8 @@ msgstr "Dalle" # Source-Hash: 95e8af5d2b3ca73d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Spawn point" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -695,8 +705,8 @@ msgstr "Point d’apparition" # Source-Hash: f05bc67c57e4d530 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stairs" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -705,8 +715,8 @@ msgstr "Escalier" # Source-Hash: 96281876ce53ba08 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Terrace" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -715,8 +725,8 @@ msgstr "Terrasse" # Source-Hash: d457508edd5bb8cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Terrain" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -725,8 +735,8 @@ msgstr "Terrain" # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -735,8 +745,8 @@ msgstr "Mur" # Source-Hash: aa3c35ed33e181e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -745,8 +755,8 @@ msgstr "Fenêtre" # Source-Hash: d40c50013043284f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Fitting" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -755,8 +765,8 @@ msgstr "Ajouter un raccord" # Source-Hash: 534540df302975a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Gate" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -765,8 +775,8 @@ msgstr "Ajouter un portail" # Source-Hash: 8b9110c4e72f2db2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Open Passage" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -775,8 +785,8 @@ msgstr "Ajouter un passage" # Source-Hash: 7136b5836de6e69f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Trap" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -785,8 +795,8 @@ msgstr "Ajouter un siphon" # Source-Hash: 8f4b2028ad75465d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Build" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -795,8 +805,8 @@ msgstr "Construire" # Source-Hash: a23831beeb35ad3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Create from" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -805,8 +815,8 @@ msgstr "Créer à partir de" # Source-Hash: 8146c309bd8326f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Draw the roof footprint with two corner clicks." #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -815,8 +825,8 @@ msgstr "Tracez l’emprise du toit en cliquant deux angles." # Source-Hash: e971d82044e2f48e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duct" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -825,8 +835,8 @@ msgstr "Gaine" # Source-Hash: 457155657704f7cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "DWV Pipe" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -835,8 +845,8 @@ msgstr "Tuyau d’évacuation" # Source-Hash: 281d63a4b3e2de4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Features & extensions" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -845,8 +855,8 @@ msgstr "Éléments et extensions" # Source-Hash: 02042fde61b5aa11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fence" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -855,8 +865,8 @@ msgstr "Clôture" # Source-Hash: 62803100bd6e7cc2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follow lineset" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -865,8 +875,8 @@ msgstr "Suivre la liaison frigorifique" # Source-Hash: c80972ec078ac551 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gates & openings" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -875,8 +885,8 @@ msgstr "Portails et ouvertures" # Source-Hash: 3720347aa16ee777 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hover a room to preview its boundary, then click to place." #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -885,8 +895,8 @@ msgstr "Survolez une pièce pour prévisualiser son contour, puis cliquez pour p # Source-Hash: 1176d2568d093bf1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -895,8 +905,8 @@ msgstr "Cuisine" # Source-Hash: 95057eef5cd69340 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "MEP" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -905,8 +915,8 @@ msgstr "CVC-P" # Source-Hash: 2e6d8cda361c648d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Modular Cabinet" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -915,8 +925,8 @@ msgstr "Meuble modulaire" # Source-Hash: 50accd740fa2e736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Off" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -925,8 +935,8 @@ msgstr "Désactivé" # Source-Hash: 9cc01faad79c28da # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "On" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -935,8 +945,8 @@ msgstr "Activé" # Source-Hash: 3fafdc69e7756f19 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Painting" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -945,8 +955,8 @@ msgstr "Peinture" # Source-Hash: f5f730969df63d1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Roof" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -955,8 +965,8 @@ msgstr "Toit" # Source-Hash: 3a08ede9e51d5395 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Roof type" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -965,8 +975,8 @@ msgstr "Type de toit" # Source-Hash: 0c35bee851cc57a2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {# tool} other {# tools}}" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -975,8 +985,8 @@ msgstr "{count, plural, one {# outil} many {# outils} other {# outils}}" # Source-Hash: 3241ecabee8221a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Conical" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -985,8 +995,8 @@ msgstr "Conique" # Source-Hash: b5c56dd8c68de309 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Draw" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -995,8 +1005,8 @@ msgstr "Dessiner" # Source-Hash: 6949d667043bee0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dutch" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1005,8 +1015,8 @@ msgstr "Demi-croupe" # Source-Hash: 9cab4d4c95f63cdd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flat" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1015,8 +1025,8 @@ msgstr "Plat" # Source-Hash: deaffa095d126dfe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gable" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1025,8 +1035,8 @@ msgstr "Deux pans" # Source-Hash: 7f53d9ffca39984a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gambrel" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1035,8 +1045,8 @@ msgstr "Brisé" # Source-Hash: 9eda0ea8d447066d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hip" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1045,8 +1055,8 @@ msgstr "Croupe" # Source-Hash: 7f7bb0e875af3260 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Mansard" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1055,8 +1065,8 @@ msgstr "Mansarde" # Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Room" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1065,8 +1075,8 @@ msgstr "Pièce" # Source-Hash: c8d0df27faa3feaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shed" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1075,8 +1085,8 @@ msgstr "Appentis" # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1085,8 +1095,8 @@ msgstr "Mur" # Source-Hash: 8d17e7556ce142da # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Another session saved first — refresh?" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1095,8 +1105,8 @@ msgstr "Une autre session a enregistré en premier — actualiser ?" # Source-Hash: 8f4b2028ad75465d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Build" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1105,8 +1115,8 @@ msgstr "Construire" # Source-Hash: a2bd204e93e90598 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dismiss" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1115,8 +1125,8 @@ msgstr "Fermer" # Source-Hash: daebc0755d239c99 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Items" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1125,8 +1135,8 @@ msgstr "Objets" # Source-Hash: cf2e870fce0f2f51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Paint" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1135,8 +1145,8 @@ msgstr "Peindre" # Source-Hash: 854555777b69a4b1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reload" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1145,8 +1155,8 @@ msgstr "Recharger" # Source-Hash: 8dc78e215a97d9fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scene" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1155,8 +1165,8 @@ msgstr "Scène" # Source-Hash: 83909f82446ee9c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Settings" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1165,8 +1175,8 @@ msgstr "Paramètres" # Source-Hash: ee255fa26d076dcc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Your changes haven't been saved. Reload to pick up the latest version." #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1175,8 +1185,8 @@ msgstr "Vos modifications n’ont pas été enregistrées. Rechargez pour récup # Source-Hash: 703e1b4b9b715d3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Anyone with the link can view this project. They cannot edit it." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1185,8 +1195,8 @@ msgstr "Toute personne disposant du lien peut voir ce projet, sans pouvoir le mo # Source-Hash: 07e04484867c17d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Copied" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1195,8 +1205,8 @@ msgstr "Copié" # Source-Hash: 4f60d1e142affa9c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Copy" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1205,8 +1215,8 @@ msgstr "Copier" # Source-Hash: 8ff50e1a9962a4db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Could not read the sharing state." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1215,8 +1225,8 @@ msgstr "Impossible de lire l’état du partage." # Source-Hash: 791e281338a51483 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Could not turn off the public link." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1225,8 +1235,8 @@ msgstr "Impossible de désactiver le lien public." # Source-Hash: 2c5ddecfd652ba63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Could not turn on the public link." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1235,8 +1245,8 @@ msgstr "Impossible d’activer le lien public." # Source-Hash: 15e49d4da8765318 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Embed code" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1245,8 +1255,8 @@ msgstr "Code d’intégration" # Source-Hash: d4523c2d303f99b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Embed link" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1255,8 +1265,8 @@ msgstr "Lien d’intégration" # Source-Hash: 252f2cbf5e1609a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide controls" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1265,8 +1275,8 @@ msgstr "Masquer les commandes" # Source-Hash: ba77c0610a63bb2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Link" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1275,8 +1285,8 @@ msgstr "Lien" # Source-Hash: a2560430aaec31d9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Only the 3D view, no header or toolbar." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1285,8 +1295,8 @@ msgstr "Uniquement la vue 3D, sans en-tête ni barre d’outils." # Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Open" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1295,8 +1305,8 @@ msgstr "Ouvrir" # Source-Hash: b34faaa5378056c6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Public link" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1305,38 +1315,78 @@ msgstr "Lien public" # Source-Hash: 7525e8007fcab09b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Share project" #: apps/editor/components/share-panel.tsx #, fuzzy msgid "app.sharePanel.shareProject" msgstr "Partager le projet" +# Source-Hash: c90de8776040735c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Above" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.above" +msgstr "Dessus" + # Source-Hash: 3d3f438d5a49eba7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Automatic dimensions" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.automaticDimensions" msgstr "Cotes automatiques" +# Source-Hash: 1794e014a604344c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Below" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.below" +msgstr "Dessous" + +# Source-Hash: 69578b7dd7723fa1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Both" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.both" +msgstr "Les deux" + # Source-Hash: 14622745dbf93f4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Camera" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.camera" msgstr "Caméra" +# Source-Hash: a03ae72f209e32db +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceilings" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.ceilings" +msgstr "Plafonds" + # Source-Hash: e6bce525c47ba3ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Clean plan; dimensions appear with selection" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1345,8 +1395,8 @@ msgstr "Plan épuré ; les cotes apparaissent à la sélection" # Source-Hash: 61ce356577cfb04a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Collapse sidebar" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1355,8 +1405,8 @@ msgstr "Réduire la barre latérale" # Source-Hash: 2416a48df28d6205 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Crisp, opaque edge lines" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1365,8 +1415,8 @@ msgstr "Arêtes nettes et opaques" # Source-Hash: 4da8b3678ed77b45 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Cutaway" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1375,18 +1425,28 @@ msgstr "Coupe" # Source-Hash: 4ca0e0e73229540c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Default" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.default" msgstr "Par défaut" +# Source-Hash: 12df69f42beb0643 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.dimensions" +msgstr "Dimensions" + # Source-Hash: a313661ef9dd0a65 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Display" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1395,8 +1455,8 @@ msgstr "Affichage" # Source-Hash: d0db46f206a88e2e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Display settings" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1405,8 +1465,8 @@ msgstr "Paramètres d’affichage" # Source-Hash: 0286962ab8e9cfcd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Door/window marks" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1415,18 +1475,28 @@ msgstr "Repères de portes et fenêtres" # Source-Hash: 027bbc8b7287c06a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Edges" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.edges" msgstr "Arêtes" +# Source-Hash: 9bacee5dbd658209 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Editing" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.editing" +msgstr "Édition" + # Source-Hash: d86126c5d16c6238 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Enter VR" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1435,8 +1505,8 @@ msgstr "Entrer en VR" # Source-Hash: eb99fb0b382e58cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Exit VR" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1445,8 +1515,8 @@ msgstr "Quitter la VR" # Source-Hash: aeac665749d3101d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Expand sidebar" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1455,8 +1525,8 @@ msgstr "Développer la barre latérale" # Source-Hash: 08c178ee733ff009 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Expert" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1465,28 +1535,18 @@ msgstr "Expert" # Source-Hash: be12f8788f1f0a05 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Exploded" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.exploded" msgstr "Éclatée" -# Source-Hash: c6f865a366ef5755 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Face of stud" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.faceOfStud" -msgstr "Nu de l’ossature" - # Source-Hash: 0c583f1d4201293b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Faint outline of major creases" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1495,28 +1555,18 @@ msgstr "Contour léger des arêtes principales" # Source-Hash: 08ecd5878b08139d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Feet & inches" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.feetInches" msgstr "Pieds et pouces" -# Source-Hash: 43b8017fa821c46c -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finished faces" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.finishedFaces" -msgstr "Faces finies" - # Source-Hash: 8827df1cdeb02ed9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flat and fast — no ambient occlusion" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1525,8 +1575,8 @@ msgstr "Plat et rapide — sans occlusion ambiante" # Source-Hash: 060a718cdcff61b3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Floor plan annotations" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1535,8 +1585,8 @@ msgstr "Annotations du plan d’étage" # Source-Hash: 483171f79dc32ae5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Floor plan mode" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1545,8 +1595,8 @@ msgstr "Mode plan d’étage" # Source-Hash: 8bb9e54fc786ca77 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Full ambient occlusion" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1555,8 +1605,8 @@ msgstr "Occlusion ambiante complète" # Source-Hash: 91fd3544d9ce16bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Full documentation and annotation controls" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1565,38 +1615,70 @@ msgstr "Documentation et annotations complètes" # Source-Hash: 131bac2467f4fdf6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Full height" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.fullHeight" msgstr "Pleine hauteur" -# Source-Hash: c9838bc98cb35125 +# Source-Hash: 91c2dd3678e981b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Full wall thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ghosted for reference" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy -msgid "app.viewerToolbar.fullWallThickness" -msgstr "Épaisseur totale du mur" +msgid "app.viewerToolbar.ghostedForReference" +msgstr "En transparence, pour repère" # Source-Hash: 7e4a0a38f694be6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Grid" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.grid" msgstr "Grille" +# Source-Hash: 81ef3a25ccb6eaf7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "ID" +#. Short for inside dimension: measured between the inside faces of walls. +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.id" +msgstr "Int." + +# Source-Hash: 09f615a2c6a14a76 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "ID + OD" +#. Inside and outside dimensions together. +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.idOd" +msgstr "Int. + Ext." + +# Source-Hash: 8a7ff5011275abbd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inside" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.inside" +msgstr "Intérieur" + # Source-Hash: 4bf4a6861d7d633e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Levels: {mode}" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1605,8 +1687,8 @@ msgstr "Niveaux : {mode}" # Source-Hash: 803532407fb5962b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Low" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1615,8 +1697,8 @@ msgstr "Bas" # Source-Hash: 32f9a404c0bdce10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Magnetic snap" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1625,8 +1707,8 @@ msgstr "Aimantation" # Source-Hash: 387082cd5f118bed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Manual" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1635,8 +1717,8 @@ msgstr "Manuel" # Source-Hash: 2fb69122dd996c0a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Manual dimensions" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1645,18 +1727,28 @@ msgstr "Cotes manuelles" # Source-Hash: c6aa74075f37313a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Measurements" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.measurements" msgstr "Mesures" +# Source-Hash: b2cac1ec253d4394 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Measure walls" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.measureWalls" +msgstr "Mesurer les murs" + # Source-Hash: 0a39470be3b84536 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Meters" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1665,38 +1757,59 @@ msgstr "Mètres" # Source-Hash: 83cce6c521e71d01 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Millimeters" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.millimeters" msgstr "Millimètres" -# Source-Hash: b784527bb90b9c5e +# Source-Hash: 340a0a4e7703227b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "3D measurements" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "2D only" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.n2dOnly" +msgstr "2D seulement" + +# Source-Hash: ed5416e4329bd789 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "3D only" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy -msgid "app.viewerToolbar.n3dMeasurements" -msgstr "Mesures 3D" +msgid "app.viewerToolbar.n3dOnly" +msgstr "3D seulement" # Source-Hash: 4ff58913a4492199 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No edge lines" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.noEdgeLines" msgstr "Aucune arête" +# Source-Hash: fdaa3b3faa1844fd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "OD" +#. Short for outside dimension: measured between the outside faces of walls. +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.od" +msgstr "Ext." + # Source-Hash: 50accd740fa2e736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Off" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1705,8 +1818,8 @@ msgstr "Désactivé" # Source-Hash: 9cc01faad79c28da # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "On" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1715,28 +1828,68 @@ msgstr "Activé" # Source-Hash: ed59dd8ce7797a66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Orthographic" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.orthographic" msgstr "Orthographique" +# Source-Hash: 370413dd021d6ea7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Other levels" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.otherLevels" +msgstr "Autres niveaux" + +# Source-Hash: dc4fe6cb415ed882 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outside" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.outside" +msgstr "Extérieur" + +# Source-Hash: 4b5cbc83a3533c2a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overall size, outside face to outside face" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.overallSizeOutsideFaceToOutsideFace" +msgstr "Dimensions hors tout, d’une face extérieure à l’autre" + # Source-Hash: 316e25993ff72b88 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Perspective" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.perspective" msgstr "Perspective" +# Source-Hash: 007a63bd7c1e2b55 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plan" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.plan" +msgstr "Plan" + # Source-Hash: 20226b68d5467072 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Preview" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1745,8 +1898,8 @@ msgstr "Aperçu" # Source-Hash: 34c20b72a42ca618 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Preview mode" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1755,8 +1908,8 @@ msgstr "Mode aperçu" # Source-Hash: 5e58af99d6d4fa6a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Render" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1765,8 +1918,8 @@ msgstr "Rendu" # Source-Hash: f363702a10aedaeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rendered" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1775,18 +1928,48 @@ msgstr "Rendu" # Source-Hash: 4959d5538efc595c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Room labels" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.roomLabels" msgstr "Étiquettes des pièces" +# Source-Hash: 257efab00820fb67 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room sizes, inside face to inside face" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.roomSizesInsideFaceToInsideFace" +msgstr "Dimensions des pièces, d’une face intérieure à l’autre" + +# Source-Hash: 1ed28930a451001d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room sizes inside, overall size outside" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.roomSizesInsideOverallSizeOutside" +msgstr "Dimensions des pièces à l’intérieur, hors tout à l’extérieur" + +# Source-Hash: 8dc78e215a97d9fc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scene" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.scene" +msgstr "Scène" + # Source-Hash: 82720864e5034398 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scene theme" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1795,28 +1978,38 @@ msgstr "Thème de la scène" # Source-Hash: 4c6bcb30b40047fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shadows" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.shadows" msgstr "Ombres" -# Source-Hash: 59dc62417b44931d +# Source-Hash: e04ae95c14479764 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single wall axis" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shared by 2D and 3D" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.sharedBy2dAnd3d" +msgstr "Commun à la 2D et à la 3D" + +# Source-Hash: 827e0c6ac9936b69 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy -msgid "app.viewerToolbar.singleWallAxis" -msgstr "Axe unique du mur" +msgid "app.viewerToolbar.show" +msgstr "Afficher" # Source-Hash: d266d83ec490df4e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Soft" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1825,8 +2018,8 @@ msgstr "Douces" # Source-Hash: ef3e765e692faf4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Solid" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1835,8 +2028,8 @@ msgstr "Plein" # Source-Hash: e9f59b513f2f45ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Solo" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1845,8 +2038,8 @@ msgstr "Isolé" # Source-Hash: 481b7608ce12139b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stack" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1855,8 +2048,8 @@ msgstr "Empilé" # Source-Hash: 61ad94ca68b0458e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stair annotations" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1865,28 +2058,18 @@ msgstr "Annotations d’escalier" # Source-Hash: f82927a01d4c5e45 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Strong" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.strong" msgstr "Marquées" -# Source-Hash: e1be031e67d95382 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structural core face" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.structuralCoreFace" -msgstr "Nu du noyau structurel" - # Source-Hash: efc50964d7b0ec47 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Structural grids & column centers" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1895,18 +2078,28 @@ msgstr "Trames structurelles et axes des poteaux" # Source-Hash: 5ce4f6b80cd30f86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Translucent" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.translucent" msgstr "Translucide" +# Source-Hash: 07511ce5a194e1ed +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turn on Dimensions to show them" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.turnOnDimensionsToShowThem" +msgstr "Activez les dimensions pour les afficher" + # Source-Hash: b404dded35241274 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Units" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1915,38 +2108,18 @@ msgstr "Unités" # Source-Hash: faf51e28b748e0d9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Walkthrough" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.walkthrough" msgstr "Visite" -# Source-Hash: 62281975e51da7e3 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall centerline" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.wallCenterline" -msgstr "Axe du mur" - -# Source-Hash: ff145d7003118ec6 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall dimensions" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.wallDimensions" -msgstr "Cotes des murs" - # Source-Hash: 13969d1d6e310aa4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Walls: {label}" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1983,8 +2156,8 @@ msgstr "Rez-de-chaussée" # Source-Hash: fdd8b3366021a1cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Orbit Left" #: packages/editor/src/components/ui/action-menu/camera-actions.tsx #, fuzzy @@ -1993,8 +2166,8 @@ msgstr "Orbiter à gauche" # Source-Hash: 4a56359f284a3b17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Orbit Right" #: packages/editor/src/components/ui/action-menu/camera-actions.tsx #, fuzzy @@ -2003,8 +2176,8 @@ msgstr "Orbiter à droite" # Source-Hash: f5c12d738240f889 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top View" #: packages/editor/src/components/ui/action-menu/camera-actions.tsx #, fuzzy @@ -2013,8 +2186,8 @@ msgstr "Vue de dessus" # Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/editor/src/components/ui/action-menu/control-modes.tsx #, fuzzy @@ -2023,8 +2196,8 @@ msgstr "Supprimer" # Source-Hash: a4395168488bb476 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Select" #: packages/editor/src/components/ui/action-menu/control-modes.tsx #, fuzzy @@ -2033,8 +2206,8 @@ msgstr "Sélectionner" # Source-Hash: d9a257653600d5a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Resume following" #: packages/editor/src/components/ui/action-menu/follow-pascal-pill.tsx #, fuzzy @@ -2043,8 +2216,8 @@ msgstr "Reprendre le suivi" # Source-Hash: 4f073f8051cca3ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follow Pascal: Off" #: packages/editor/src/components/ui/action-menu/follow-pascal-toggle.tsx #, fuzzy @@ -2053,8 +2226,8 @@ msgstr "Suivre Pascal : désactivé" # Source-Hash: 328ea04bb8cd12f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follow Pascal: On" #: packages/editor/src/components/ui/action-menu/follow-pascal-toggle.tsx #, fuzzy @@ -2063,8 +2236,8 @@ msgstr "Suivre Pascal : activé" # Source-Hash: 7f4dcb90defe1ac2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Appliance" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2073,8 +2246,8 @@ msgstr "Électroménager" # Source-Hash: 0655333424a8b6fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bathroom" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2083,8 +2256,8 @@ msgstr "Salle de bain" # Source-Hash: ed68e72f5353712b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Furniture" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2093,8 +2266,8 @@ msgstr "Mobilier" # Source-Hash: 1176d2568d093bf1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2103,8 +2276,8 @@ msgstr "Cuisine" # Source-Hash: a5a7af5e5fff1c81 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Outdoor" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2113,8 +2286,8 @@ msgstr "Extérieur" # Source-Hash: c69865ec5d9d1ac9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Angle" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2123,8 +2296,8 @@ msgstr "Angle" # Source-Hash: 622f566fe1e3d8e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Angular dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2133,8 +2306,8 @@ msgstr "Cote angulaire" # Source-Hash: 7e3b0d541355305e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Arc length" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2143,8 +2316,8 @@ msgstr "Longueur d’arc" # Source-Hash: 8332ab41e22958f1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Area" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2153,8 +2326,8 @@ msgstr "Surface" # Source-Hash: 88c7750ed51d47a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Center mark" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2163,8 +2336,8 @@ msgstr "Repère de centre" # Source-Hash: 634912dabb092872 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Chord dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2173,8 +2346,8 @@ msgstr "Cote de corde" # Source-Hash: 3cb090120253f68f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Continuous dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2183,8 +2356,8 @@ msgstr "Cote continue" # Source-Hash: fb91b1d43b8362d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Coordinate dimensions" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2193,8 +2366,8 @@ msgstr "Cotes en coordonnées" # Source-Hash: 530cb7ea461e8298 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Diameter dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2203,8 +2376,8 @@ msgstr "Cote de diamètre" # Source-Hash: fe7ddb094aa8ff4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Distance" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2213,8 +2386,8 @@ msgstr "Distance" # Source-Hash: fee6203bb9046929 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Floor plan" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2223,8 +2396,8 @@ msgstr "Plan d’étage" # Source-Hash: a73539fc472e2e12 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Linear dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2233,8 +2406,8 @@ msgstr "Cote linéaire" # Source-Hash: 6bba239f244c3d28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Measurement options" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2243,8 +2416,8 @@ msgstr "Options de mesure" # Source-Hash: 2cf5ca9b834ce8d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Measurement type" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2253,8 +2426,8 @@ msgstr "Type de mesure" # Source-Hash: 0431574a0e6d69d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Measure: {selectedLabel}" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2263,8 +2436,8 @@ msgstr "Mesure : {selectedLabel}" # Source-Hash: ac87e14dabd5a256 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Perimeter" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2273,8 +2446,8 @@ msgstr "Périmètre" # Source-Hash: 6c9acc0589bdd4d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Radius dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2283,8 +2456,8 @@ msgstr "Cote de rayon" # Source-Hash: 01b0015e4e176124 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Smart" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2293,8 +2466,8 @@ msgstr "Intelligente" # Source-Hash: 429bd43d726de417 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Volume" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2303,8 +2476,8 @@ msgstr "Volume" # Source-Hash: 64f3eb5e1936906d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Point and ask" #: packages/editor/src/components/ui/action-menu/point-ask-button.tsx #, fuzzy @@ -2313,8 +2486,8 @@ msgstr "Pointer et demander" # Source-Hash: d86d31e83f6f0888 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Point and ask (C)" #: packages/editor/src/components/ui/action-menu/point-ask-button.tsx #, fuzzy @@ -2323,18 +2496,28 @@ msgstr "Pointer et demander (C)" # Source-Hash: 65622d2ef53c1f3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Point and ask works in the 3D view" #: packages/editor/src/components/ui/action-menu/point-ask-button.tsx #, fuzzy msgid "editor.actionMenu.pointAskButton.pointAndAskWorksInThe" msgstr "Pointer et demander fonctionne dans la vue 3D" +# Source-Hash: e14858b33b6e2623 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam" +#: packages/editor/src/components/ui/action-menu/structure-tools.tsx +#, fuzzy +msgid "editor.actionMenu.structureTools.beam" +msgstr "Poutre" + # Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Ceiling" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2343,8 +2526,8 @@ msgstr "Plafond" # Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2353,8 +2536,8 @@ msgstr "Poteau" # Source-Hash: 787e10f5db16904e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Door" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2363,8 +2546,8 @@ msgstr "Porte" # Source-Hash: e971d82044e2f48e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duct" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2373,8 +2556,8 @@ msgstr "Gaine" # Source-Hash: 6d0c3833d87535e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duct Fitting" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2383,8 +2566,8 @@ msgstr "Raccord de gaine" # Source-Hash: 457155657704f7cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "DWV Pipe" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2393,8 +2576,8 @@ msgstr "Tuyau d’évacuation" # Source-Hash: ab5cbab7be160a1c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Elevator" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2403,8 +2586,8 @@ msgstr "Ascenseur" # Source-Hash: 02042fde61b5aa11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fence" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2413,8 +2596,8 @@ msgstr "Clôture" # Source-Hash: 7f4d93d5f2083844 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gable Roof" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2423,8 +2606,8 @@ msgstr "Toit à deux pans" # Source-Hash: 3bf1c1a8dbb93743 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "HVAC Unit" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2433,8 +2616,8 @@ msgstr "Unité CVC" # Source-Hash: 362b03eba9d8234c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Lineset" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2443,8 +2626,8 @@ msgstr "Liaison frigorifique" # Source-Hash: c34c9b36492c6e21 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Liquid Line" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2453,8 +2636,8 @@ msgstr "Ligne liquide" # Source-Hash: c040baa6ed4c7aa5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Pipe Fitting" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2463,8 +2646,8 @@ msgstr "Raccord de tuyau" # Source-Hash: 161e5386b939e1bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Register" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2473,8 +2656,8 @@ msgstr "Bouche" # Source-Hash: d7145f84f8e0e3fe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shelf" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2483,8 +2666,8 @@ msgstr "Étagère" # Source-Hash: 8775bc8dc9593964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slab" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2493,8 +2676,8 @@ msgstr "Dalle" # Source-Hash: 3e2f6b4274f592c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Spawn Point" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2503,8 +2686,8 @@ msgstr "Point d’apparition" # Source-Hash: f05bc67c57e4d530 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stairs" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2513,8 +2696,8 @@ msgstr "Escalier" # Source-Hash: b778a315e82065a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Trap" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2523,8 +2706,8 @@ msgstr "Siphon" # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2533,8 +2716,8 @@ msgstr "Mur" # Source-Hash: aa3c35ed33e181e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2543,18 +2726,28 @@ msgstr "Fenêtre" # Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy msgid "editor.actionMenu.structureTools.zone" msgstr "Zone" +# Source-Hash: a309ae5ee641f072 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dashed outlines of the neighbouring levels’ walls, to line walls up and check a roof against the walls under it." +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.dashedOutlinesOfTheNeighbouringLevels" +msgstr "Contours en pointillés des murs des niveaux voisins, pour aligner les murs et vérifier un toit par rapport aux murs situés dessous." + # Source-Hash: cdf3f12939ba108c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete guide image" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2563,8 +2756,8 @@ msgstr "Supprimer l’image guide" # Source-Hash: 6add06abbafa8289 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete scan" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2573,8 +2766,8 @@ msgstr "Supprimer le relevé 3D" # Source-Hash: 6f5e541cb5fb502f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {# guide image on this level} other {# guide images on this level}}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2583,8 +2776,8 @@ msgstr "{count, plural, one {# image guide sur ce niveau} many {# images guides # Source-Hash: 8a832a2f33757bf8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guide image {number}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2593,8 +2786,8 @@ msgstr "Image guide {number}" # Source-Hash: 7f3aaccfe8d1af1f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guide images" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2603,8 +2796,8 @@ msgstr "Images guides" # Source-Hash: 9b1de02505434d74 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guide image settings" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2613,8 +2806,8 @@ msgstr "Réglages des images guides" # Source-Hash: 892d5dd34372028b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guides" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2623,8 +2816,8 @@ msgstr "Guides" # Source-Hash: ccfb05c78d47d6f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guides: Hidden" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2633,8 +2826,8 @@ msgstr "Guides : masqués" # Source-Hash: 6d7ca85c4f389991 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guides: Visible" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2643,8 +2836,8 @@ msgstr "Guides : visibles" # Source-Hash: 5f6264ac469f57c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide guide images" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2653,8 +2846,8 @@ msgstr "Masquer les images guides" # Source-Hash: cae234c23229c80b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide reference floor" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2663,8 +2856,8 @@ msgstr "Masquer le niveau de référence" # Source-Hash: 469a8416de876e0e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide scans" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2673,18 +2866,38 @@ msgstr "Masquer les relevés 3D" # Source-Hash: 873620c284a5651f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count} below" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy msgid "editor.actionMenu.viewToggles.levelsBelow" msgstr "{count} en dessous" +# Source-Hash: 6661c6766fdd1a7f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No level above" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.noLevelAbove" +msgstr "Aucun niveau au-dessus" + +# Source-Hash: e34d9ec372c823ef +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No level below" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.noLevelBelow" +msgstr "Aucun niveau en dessous" + # Source-Hash: 22a59ae72d8c9504 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No lower floor available." #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2693,8 +2906,8 @@ msgstr "Aucun niveau inférieur disponible." # Source-Hash: 1c0b8a5503c5daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opacity" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2703,8 +2916,8 @@ msgstr "Opacité" # Source-Hash: 8bbd9bc90ac70a4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference floor" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2713,8 +2926,8 @@ msgstr "Niveau de référence" # Source-Hash: 45493691a23c7690 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference floor: {selectedLevelName}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2723,8 +2936,8 @@ msgstr "Niveau de référence : {selectedLevelName}" # Source-Hash: 7178c7b5a4581367 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference floor settings" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2733,8 +2946,8 @@ msgstr "Réglages du niveau de référence" # Source-Hash: a52848021f822f5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "References" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2743,8 +2956,8 @@ msgstr "Références" # Source-Hash: e59c9eec7dbd6ba1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Upload GLB meshes as scan references or blueprint images as guide references." #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2753,8 +2966,8 @@ msgstr "Importez des maillages GLB comme relevés 3D de référence ou des plans # Source-Hash: 3e73d06c3e96efba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference settings" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2763,8 +2976,8 @@ msgstr "Réglages des références" # Source-Hash: aa0df2c2f00672e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "References: Hidden" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2773,8 +2986,8 @@ msgstr "Références : masquées" # Source-Hash: 9976708fc92bfa91 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "References: Visible" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2783,8 +2996,8 @@ msgstr "Références : visibles" # Source-Hash: 320a5f1ec012900b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Riser diagram" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2793,8 +3006,8 @@ msgstr "Schéma des colonnes" # Source-Hash: 357b3d3eaf878a9f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {# scan on this level} other {# scans on this level}}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2803,8 +3016,8 @@ msgstr "{count, plural, one {# relevé 3D sur ce niveau} many {# relevés 3D sur # Source-Hash: f09f12547484c888 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scan {number}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2813,8 +3026,8 @@ msgstr "Relevé 3D {number}" # Source-Hash: 3260bfa69cca50e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scans" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2823,8 +3036,8 @@ msgstr "Relevés 3D" # Source-Hash: c9c52015095997e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scan settings" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2833,8 +3046,8 @@ msgstr "Réglages des relevés 3D" # Source-Hash: 60abc9f1a8aec65c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scans: Hidden" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2843,8 +3056,8 @@ msgstr "Relevés 3D : masqués" # Source-Hash: 2d2ff119a7dd7911 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scans: Visible" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2853,8 +3066,8 @@ msgstr "Relevés 3D : visibles" # Source-Hash: 8211234b205fd9a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Show guide images" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2863,8 +3076,8 @@ msgstr "Afficher les images guides" # Source-Hash: 7786cae6acb04cfa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Show reference floor" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2873,29 +3086,91 @@ msgstr "Afficher le niveau de référence" # Source-Hash: 6066f0b6cff8a910 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Show scans" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy msgid "editor.actionMenu.viewToggles.showScans" msgstr "Afficher les relevés 3D" +# Source-Hash: c100768fc929ccf4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show walls below and above" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.showWallsBelowAndAbove" +msgstr "Afficher les murs du dessous et du dessus" + # Source-Hash: def6dff836767bda # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Upload scan or guide image" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy msgid "editor.actionMenu.viewToggles.uploadScanOrGuideImage" msgstr "Importer un relevé 3D ou une image guide" -# Source-Hash: 6aee0962fc18c0f1 +# Source-Hash: e9ac75feeb58a5be # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back to home" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls above" +#: apps/editor/components/viewer-toolbar.tsx +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsAbove" +msgstr "Murs du dessus" + +# Source-Hash: 790a0b5c6dbf0e9b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below" +#: apps/editor/components/viewer-toolbar.tsx +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsBelow" +msgstr "Murs du dessous" + +# Source-Hash: e74e28937511bce9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below and above" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsBelowAndAbove" +msgstr "Murs du dessous et du dessus" + +# Source-Hash: 7c7bd2a996dfd5ce +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below and above settings" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsBelowAndAboveSettings" +msgstr "Réglages des murs du dessous et du dessus" + +# Source-Hash: 43bc80f62aeab442 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below and above: shown" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsBelowAndAboveShown" +msgstr "Murs du dessous et du dessus : affichés" + +# Source-Hash: 6aee0962fc18c0f1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back to home" #: packages/editor/src/components/editor/index.tsx #, fuzzy msgid "editor.backToHome" @@ -2985,12 +3260,45 @@ msgstr "Pièce rectangulaire" msgid "editor.buildPanel.rooms.title" msgstr "Pièces" -# Source-Hash: 8a21a03c4acf396b -# Review: human -# English: "{lead} Close a loop and it becomes a room; leave it open for partitions." +# Source-Hash: 9755d557ce490458 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divides a room or closes off a porch without building a wall; rooms close on it. Change any wall later from its controls." +#: packages/editor/src/components/ui/build-panel/build-panel.tsx +#, fuzzy +msgid "editor.buildPanel.rooms.wallKinds.invisibleHelp" +msgstr "Sépare une pièce ou ferme un porche sans construire de mur ; les pièces se ferment dessus. Modifiez n’importe quel mur ensuite depuis ses commandes." + +# Source-Hash: abe7e7de0d337058 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall kind" +#: packages/editor/src/components/ui/build-panel/build-panel.tsx +#, fuzzy +msgid "editor.buildPanel.rooms.wallKinds.label" +msgstr "Type de mur" + +# Source-Hash: b4d012ac50ef1e82 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A guard for stairs, balconies and mezzanines; rooms close on it. Change any wall later from its controls." +#: packages/editor/src/components/ui/build-panel/build-panel.tsx +#, fuzzy +msgid "editor.buildPanel.rooms.wallKinds.railingHelp" +msgstr "Un garde-corps pour escaliers, balcons et mezzanines ; les pièces se ferment dessus. Modifiez n’importe quel mur ensuite depuis ses commandes." + +# Source-Hash: 5e6d896656f4e056 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "One wall per two clicks. Its sides become exterior or interior from the rooms it bounds. Change any wall later from its controls." #: packages/editor/src/components/ui/build-panel/build-panel.tsx -msgid "editor.buildPanel.rooms.walls.caption" -msgstr "{lead} Fermez la boucle pour créer une pièce, ou laissez-la ouverte pour une cloison." +#, fuzzy +msgid "editor.buildPanel.rooms.wallKinds.standardHelp" +msgstr "Un mur tous les deux clics. Ses faces deviennent extérieures ou intérieures selon les pièces qu’il borde. Modifiez n’importe quel mur ensuite depuis ses commandes." # Source-Hash: aac9a732d2159ccc # Review: human @@ -2999,13 +3307,6 @@ msgstr "{lead} Fermez la boucle pour créer une pièce, ou laissez-la ouverte po msgid "editor.buildPanel.rooms.walls.label" msgstr "Murs" -# Source-Hash: 9843edd68426fa2d -# Review: human -# English: "Draw one wall at a time." -#: packages/editor/src/components/ui/build-panel/build-panel.tsx -msgid "editor.buildPanel.rooms.walls.lead" -msgstr "Tracez un mur à la fois." - # Source-Hash: aac9a732d2159ccc # Review: human # English: "Walls" @@ -3013,26735 +3314,29167 @@ msgstr "Tracez un mur à la fois." msgid "editor.buildPanel.rooms.walls.title" msgstr "Murs" -# Source-Hash: 1f3650da23603008 +# Source-Hash: 1dba2aacc55e0bb7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Camera controls hint" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete from this project" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.cameraControlsHint" -msgstr "Aide sur les commandes de caméra" +msgid "editor.buildPanel.wallTypeControls.deleteFromThisProject" +msgstr "Supprimer de ce projet" -# Source-Hash: 101b6a54c377049a +# Source-Hash: 58a1b780e877ddc3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pan" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate as a new type…" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.cameraHint.pan" -msgstr "Panoramique" +msgid "editor.buildPanel.wallTypeControls.duplicateAsANewType" +msgstr "Dupliquer comme nouveau type…" -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: 43e7aad9a5f75b6a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit layers…" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.cameraHint.rotate" -msgstr "Pivoter" +msgid "editor.buildPanel.wallTypeControls.editLayers" +msgstr "Modifier les couches…" -# Source-Hash: 663cecc316eb91b8 +# Source-Hash: 8f1ea5a4c16ba810 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zoom" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit or duplicate this wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.cameraHint.zoom" -msgstr "Zoom" +msgid "editor.buildPanel.wallTypeControls.editOrDuplicateThisWallType" +msgstr "Modifier ou dupliquer ce type de mur" -# Source-Hash: 34b7ca7ff46c44a9 +# Source-Hash: 273fcb71b4f9272f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{label}: {finish}" -#: packages/editor/src/components/ui/controls/finish-swatch.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New wall type…" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.controls.finishSwatch.ariaLabel" -msgstr "{label} : {finish}" +msgid "editor.buildPanel.wallTypeControls.newWallType" +msgstr "Nouveau type de mur…" -# Source-Hash: 4ca0e0e73229540c +# Source-Hash: 079e4005e0093122 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default" -#: packages/editor/src/components/ui/controls/finish-swatch.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Presets stay as cited. Duplicate one to change its layers." +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.controls.finishSwatch.default" -msgstr "Par défaut" +msgid "editor.buildPanel.wallTypeControls.presetsStayAsCitedDuplicateOne" +msgstr "Les préréglages restent conformes à leur source. Dupliquez-en un pour modifier ses couches." -# Source-Hash: a2bd204e93e90598 +# Source-Hash: b071c943d8da1500 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dismiss" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.dismiss" -msgstr "Fermer" +msgid "editor.buildPanel.wallTypeEditorDialog.add" +msgstr "Ajouter" -# Source-Hash: 9222f970dce6cc60 +# Source-Hash: fcc69acc0fd92288 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dismiss camera controls hint" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Air space" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.dismissCameraControlsHint" -msgstr "Fermer l’aide sur les commandes de caméra" +msgid "editor.buildPanel.wallTypeEditorDialog.airSpace" +msgstr "Lame d’air" -# Source-Hash: aeac665749d3101d +# Source-Hash: 46fb2832f979d656 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Expand sidebar" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A wall type holds at most {limit, plural, one {# layer} other {# layers}}." +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.expandSidebar" -msgstr "Développer la barre latérale" +msgid "editor.buildPanel.wallTypeEditorDialog.aWallTypeHoldsAtMost" +msgstr "Un type de mur compte au plus {limit, plural, one {# couche} many {# couches} other {# couches}}." -# Source-Hash: dd86efcab72fc5c7 +# Source-Hash: 75d323d0159b0df8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Axis" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brick veneer" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.axis" -msgstr "Axe" +msgid "editor.buildPanel.wallTypeEditorDialog.brickVeneer" +msgstr "Parement brique" -# Source-Hash: 5232a826549f915e +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "⌥ axis" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.axis2" -msgstr "⌥ axe" +msgid "editor.buildPanel.wallTypeEditorDialog.cancel" +msgstr "Annuler" -# Source-Hash: 7001600001844c92 +# Source-Hash: 4da800c75b9a6b23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "⚠ no equipment" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drywall" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.noEquipment" -msgstr "⚠ aucun équipement" +msgid "editor.buildPanel.wallTypeEditorDialog.drywall" +msgstr "Plaque de plâtre" -# Source-Hash: eae0194029f96edb +# Source-Hash: 1f2e15ce909adf0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {# register} other {# registers}}" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.registerCount" -msgstr "{count, plural, one {# bouche} many {# bouches} other {# bouches}}" +msgid "editor.buildPanel.wallTypeEditorDialog.duplicateWallType" +msgstr "Dupliquer le type de mur" -# Source-Hash: 8fb180251a321cef +# Source-Hash: 832628bc67f36778 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.rTRotate" -msgstr "R/T pivoter" +msgid "editor.buildPanel.wallTypeEditorDialog.editWallType" +msgstr "Modifier le type de mur" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 6fb660d4eabe8d6a +# Source-Hash: 7d3d13d418b64f1b # Review: required -# English: "{count, plural, one {{number} run} other {{number} runs}}" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Every wall type has one framing core" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.runCount" -msgstr "{count, plural, one {{number} tronçon} many {{number} tronçons} other {{number} tronçons}}" +msgid "editor.buildPanel.wallTypeEditorDialog.everyWallTypeHasOneFraming" +msgstr "Chaque type de mur a un noyau d’ossature" -# Source-Hash: 88e6c2e1c344b2fc +# Source-Hash: fd89c31f16639f50 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fiber cement" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.system" -msgstr "Système" +msgid "editor.buildPanel.wallTypeEditorDialog.fiberCement" +msgstr "Fibrociment" -# Source-Hash: f0e76aea883d4e48 +# Source-Hash: b3907da0ad234f10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add a floor under the roof" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.addAFloorUnderTheRoof" -msgstr "Ajouter un niveau sous le toit" +msgid "editor.buildPanel.wallTypeEditorDialog.finish" +msgstr "Finition" -# Source-Hash: a982ff9b075af829 +# Source-Hash: 23306d290f066b1e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add level above" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framing core" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.addLevelAbove" -msgstr "Ajouter un niveau au-dessus" +msgid "editor.buildPanel.wallTypeEditorDialog.framingCore" +msgstr "Noyau d’ossature" -# Source-Hash: 0db7d221df08fa6b +# Source-Hash: b50fa488c2bfb502 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add level below" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{fullReason} Remove one to add another." +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.addLevelBelow" -msgstr "Ajouter un niveau en dessous" +msgid "editor.buildPanel.wallTypeEditorDialog.fullreasonRemoveOneToAddAnother" +msgstr "{fullReason} Retirez-en une pour en ajouter une autre." -# Source-Hash: c0774c185060fc13 +# Source-Hash: e3e25fbbf14e97fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gypsum sheathing" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.cancel" -msgstr "Annuler" +msgid "editor.buildPanel.wallTypeEditorDialog.gypsumSheathing" +msgstr "Plaque de plâtre extérieure" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 8a7ff5011275abbd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inside" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.delete" -msgstr "Supprimer" +msgid "editor.buildPanel.wallTypeEditorDialog.inside" +msgstr "Intérieur" -# Source-Hash: 8e29375893d63408 +# Source-Hash: 7d6ed24c02ab0c5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete level" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.deleteLevel" -msgstr "Supprimer le niveau" +msgid "editor.buildPanel.wallTypeEditorDialog.insulation" +msgstr "Isolant" -# Source-Hash: c3bc69ec52022250 +# Source-Hash: 9a4325140858cfec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Are you sure you want to delete {levelName}? All walls, floors, and objects on this level will be permanently removed." -#: packages/editor/src/components/ui/floating-level-selector.tsx -#, fuzzy -msgid "editor.floatingLevelSelector.deleteLevelConfirm" -msgstr "Voulez-vous vraiment supprimer {levelName} ? Tous les murs, planchers et objets de ce niveau seront définitivement supprimés." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lap siding" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +#, fuzzy +msgid "editor.buildPanel.wallTypeEditorDialog.lapSiding" +msgstr "Bardage à clin" -# Source-Hash: 5b2826ddac95cd0c +# Source-Hash: d7ee1cefa20d0e32 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag to reorder" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layer" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.dragToReorder" -msgstr "Faire glisser pour réorganiser" +msgid "editor.buildPanel.wallTypeEditorDialog.layer" +msgstr "Couche" -# Source-Hash: 933177338f5a03ed +# Source-Hash: bd00fff893ace820 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate level" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layer role" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.duplicateLevel" -msgstr "Dupliquer le niveau" +msgid "editor.buildPanel.wallTypeEditorDialog.layerRole" +msgstr "Rôle de la couche" -# Source-Hash: 9614c6825a7c67bf +# Source-Hash: e5536deeaabfacec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate with options..." -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lining" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.duplicateWithOptions" -msgstr "Dupliquer avec options..." +msgid "editor.buildPanel.wallTypeEditorDialog.lining" +msgstr "Doublage" -# Source-Hash: 5ec91bb339806413 +# Source-Hash: 964b86ae1474ff98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Exit unit focus" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Material" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.exitUnitFocus" -msgstr "Quitter le focus sur le logement" +msgid "editor.buildPanel.wallTypeEditorDialog.material" +msgstr "Matériau" -# Source-Hash: a88c3f8bed58b4fa +# Source-Hash: 75d79fb9a2e8fcf6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Focused unit has zones here" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mineral wool board" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.focusedUnitHasZonesHere" -msgstr "Le logement ciblé a des zones ici" +msgid "editor.buildPanel.wallTypeEditorDialog.mineralWoolBoard" +msgstr "Panneau de laine minérale" -# Source-Hash: 655055a310fb5d13 +# Source-Hash: 78acc1bad880ce0f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The ground floor stands {distance} over grade. Seat the ground floor 8 in over grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move in" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.groundFloorOverGrade" -msgstr "Le rez-de-chaussée est {distance} au-dessus du sol. Placer le rez-de-chaussée à 8 in au-dessus du sol" +msgid "editor.buildPanel.wallTypeEditorDialog.moveIn" +msgstr "Déplacer vers l’intérieur" -# Source-Hash: 77548faae4869eec +# Source-Hash: 2de6ee30b4e608bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The ground floor stands {distance} under grade. Seat the ground floor 8 in over grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move out" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.groundFloorUnderGrade" -msgstr "Le rez-de-chaussée est {distance} sous le sol. Placer le rez-de-chaussée à 8 in au-dessus du sol" +msgid "editor.buildPanel.wallTypeEditorDialog.moveOut" +msgstr "Déplacer vers l’extérieur" -# Source-Hash: e3763ae2dc62c03f +# Source-Hash: 6cc5df35f0338e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground line: the levels under it are below grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Name" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.groundLineTheLevelsUnderIt" -msgstr "Ligne de sol : les niveaux en dessous sont enterrés" +msgid "editor.buildPanel.wallTypeEditorDialog.name" +msgstr "Nom" -# Source-Hash: e12035eb47cc61cc +# Source-Hash: 4b3edeb00b32607e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground · {offset}" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.groundOffset" -msgstr "Sol · {offset}" +msgid "editor.buildPanel.wallTypeEditorDialog.newWallType" +msgstr "Nouveau type de mur" -# Source-Hash: 5661c11383217661 +# Source-Hash: 4f7f8af75bf8e914 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Insert level here" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "OSB" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.insertLevelHere" -msgstr "Insérer un niveau ici" +msgid "editor.buildPanel.wallTypeEditorDialog.osb" +msgstr "OSB" -# Source-Hash: 0215b36d5a08597a +# Source-Hash: dc4fe6cb415ed882 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level height" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outside" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.levelHeight" -msgstr "Hauteur du niveau" +msgid "editor.buildPanel.wallTypeEditorDialog.outside" +msgstr "Extérieur" -# Source-Hash: 91af436e81bb0875 +# Source-Hash: a6fd2cbf5c2154e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paste copied selection" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plaster" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.pasteCopiedSelection" -msgstr "Coller la sélection copiée" +msgid "editor.buildPanel.wallTypeEditorDialog.plaster" +msgstr "Enduit plâtre" -# Source-Hash: 68bc52f53240cbec +# Source-Hash: e669c2c08bd80e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reorder {levelName}" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plywood" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.reorderLevelname" -msgstr "Réorganiser {levelName}" +msgid "editor.buildPanel.wallTypeEditorDialog.plywood" +msgstr "Contreplaqué" -# Source-Hash: 625d53de72ebc2ef +# Source-Hash: ca36e9fd7fba1fce # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Seat the building so this floor stands at grade; the floors under it are below grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove layer" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.seatTheBuildingSoThisFloor" -msgstr "Placer le bâtiment pour que cet étage soit au niveau du sol ; les étages inférieurs sont enterrés" +msgid "editor.buildPanel.wallTypeEditorDialog.removeLayer" +msgstr "Retirer la couche" -# Source-Hash: 7ac9c00895c30d76 +# Source-Hash: 7d8f351c35f89b94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set as ground floor" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rigid foam" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.setAsGroundFloor" -msgstr "Définir comme rez-de-chaussée" +msgid "editor.buildPanel.wallTypeEditorDialog.rigidFoam" +msgstr "Mousse rigide" -# Source-Hash: d6b381247066a7aa +# Source-Hash: e8bc984965d5753d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The ground level cannot be deleted" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Save wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.theGroundLevelCannotBeDeleted" -msgstr "Le niveau du rez-de-chaussée ne peut pas être supprimé" +msgid "editor.buildPanel.wallTypeEditorDialog.saveWallType" +msgstr "Enregistrer le type de mur" -# Source-Hash: b1122051dce0d7a1 +# Source-Hash: 36a588e44085108c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "This floor stands at grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sheathing" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.thisFloorStandsAtGrade" -msgstr "Cet étage est au niveau du sol" +msgid "editor.buildPanel.wallTypeEditorDialog.sheathing" +msgstr "Contreventement" -# Source-Hash: 062cc0f1afef0c52 +# Source-Hash: 9450fcb4a14674af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unit" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stone veneer" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.unit" -msgstr "Lot" +msgid "editor.buildPanel.wallTypeEditorDialog.stoneVeneer" +msgstr "Parement pierre" -# Source-Hash: 5871b7c20478f4a1 +# Source-Hash: 687cf7bc64b0224e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor area" -#: packages/editor/src/i18n/floor-footprint-name.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stucco" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floorFootprint.area" -msgstr "Surface de plancher" +msgid "editor.buildPanel.wallTypeEditorDialog.stucco" +msgstr "Enduit" -# Source-Hash: 8b2e1435272aa86a +# Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{room} floor" -#: packages/editor/src/i18n/floor-footprint-name.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floorFootprint.room" -msgstr "Plancher {room}" +msgid "editor.buildPanel.wallTypeEditorDialog.thickness" +msgstr "Épaisseur" -# Source-Hash: 4731183fec06cbdf +# Source-Hash: 72e31eecaeb87447 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shared floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx -#: packages/editor/src/i18n/floor-footprint-name.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Total {thickness}" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floorFootprint.shared" -msgstr "Plancher partagé" +msgid "editor.buildPanel.wallTypeEditorDialog.totalThickness" +msgstr "Total {thickness}" -# Source-Hash: c0774c185060fc13 +# Source-Hash: eab795728c4a3f5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/helpers/building-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.helpers.buildingHelper.cancel" -msgstr "Annuler" +msgid "editor.buildPanel.wallTypeEditorDialog.wallType" +msgstr "Type de mur" -# Source-Hash: 4c6ca3441c74da9e +# Source-Hash: 3744d42a0e4ee161 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place building" -#: packages/editor/src/components/ui/helpers/building-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plain wall" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.helpers.buildingHelper.placeBuilding" -msgstr "Placer le bâtiment" +msgid "editor.buildPanel.wallTypes.plainWall" +msgstr "Mur simple" -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: 1f3650da23603008 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" -#: packages/editor/src/components/ui/helpers/building-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera controls hint" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.buildingHelper.rotate" -msgstr "Pivoter" +msgid "editor.cameraControlsHint" +msgstr "Aide sur les commandes de caméra" -# Source-Hash: 832470d3aeee82fd +# Source-Hash: 101b6a54c377049a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel placement" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pan" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.cancelPlacement" -msgstr "Annuler le placement" +msgid "editor.cameraHint.pan" +msgstr "Panoramique" -# Source-Hash: e374fcaee33c3e2c +# Source-Hash: 306d409f8a1cf480 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuation — click or press C to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.continuationClickOrPressCTo" -msgstr "Enchaînement — cliquez ou appuyez sur C pour changer" +msgid "editor.cameraHint.rotate" +msgstr "Pivoter" -# Source-Hash: b108c7dc2ec2b9de +# Source-Hash: 663cecc316eb91b8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuation: {label}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zoom" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.continuationLabel" -msgstr "Enchaînement : {label}" +msgid "editor.cameraHint.zoom" +msgstr "Zoom" -# Source-Hash: 729d87891cb7dbb1 +# Source-Hash: 34b7ca7ff46c44a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag to draw fence" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label}: {finish}" +#: packages/editor/src/components/ui/controls/finish-swatch.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.dragToDrawFence" -msgstr "Faites glisser pour tracer la clôture" +msgid "editor.controls.finishSwatch.ariaLabel" +msgstr "{label} : {finish}" -# Source-Hash: b52e874718af1916 +# Source-Hash: 4ca0e0e73229540c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Erase: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default" +#: packages/editor/src/components/ui/controls/finish-swatch.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.eraseScope" -msgstr "Effacer : {scope}" +msgid "editor.controls.finishSwatch.default" +msgstr "Par défaut" -# Source-Hash: 61f7494abc319e66 +# Source-Hash: a2bd204e93e90598 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Erase scope — click or press Shift to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dismiss" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.eraseScopeClickOrPressShift" -msgstr "Portée de l’effacement — cliquez ou appuyez sur Maj pour changer" +msgid "editor.dismiss" +msgstr "Fermer" -# Source-Hash: 59993c163d68cc53 +# Source-Hash: 9222f970dce6cc60 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Erase scope: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dismiss camera controls hint" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.eraseScopeLabel" -msgstr "Portée de l’effacement : {scope}" +msgid "editor.dismissCameraControlsHint" +msgstr "Fermer l’aide sur les commandes de caméra" -# Source-Hash: a4bdcbc6cab772bf +# Source-Hash: aeac665749d3101d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fence type — click or press T to switch between straight, curved and freehand" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Expand sidebar" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.fenceTypeClickOrPressT" -msgstr "Type de clôture — cliquez ou appuyez sur T pour passer de droite à courbe ou libre" +msgid "editor.expandSidebar" +msgstr "Développer la barre latérale" -# Source-Hash: 2a9ed258727078ac +# Source-Hash: dd86efcab72fc5c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fewer shortcuts" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Axis" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.fewerShortcuts" -msgstr "Moins de raccourcis" +msgid "editor.floatingActionMenu.axis" +msgstr "Axe" -# Source-Hash: 698fa6e78af4d4b7 +# Source-Hash: 5232a826549f915e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish curve (or double-click)" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "⌥ axis" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.finishCurveOrDoubleClick" -msgstr "Terminer la courbe (ou double-clic)" +msgid "editor.floatingActionMenu.axis2" +msgstr "⌥ axe" -# Source-Hash: 09f6d79edf5cfd16 +# Source-Hash: 7001600001844c92 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid: {length}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "⚠ no equipment" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.gridLength" -msgstr "Grille : {length}" +msgid "editor.floatingActionMenu.noEquipment" +msgstr "⚠ aucun équipement" -# Source-Hash: c493b562040c4328 +# Source-Hash: eae0194029f96edb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid step — click or tap Ctrl to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# register} other {# registers}}" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.gridStepClickOrTapCtrl" -msgstr "Pas de grille — cliquez ou appuyez sur Ctrl pour changer" +msgid "editor.floatingActionMenu.registerCount" +msgstr "{count, plural, one {# bouche} many {# bouches} other {# bouches}}" -# Source-Hash: d36a8c93d81b3a36 +# Source-Hash: 8fb180251a321cef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid step: {length}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.gridStepLength" -msgstr "Pas de grille : {length}" +msgid "editor.floatingActionMenu.rTRotate" +msgstr "R/T pivoter" -# Source-Hash: abea993ede7daa7e +# Source-Hash: 6fb660d4eabe8d6a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a painted surface to erase" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {{number} run} other {{number} runs}}" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.hoverAPaintedSurfaceToErase" -msgstr "Survolez une surface peinte pour l’effacer" +msgid "editor.floatingActionMenu.runCount" +msgstr "{count, plural, one {{number} tronçon} many {{number} tronçons} other {{number} tronçons}}" -# Source-Hash: fc1ed0ddc0cfcef5 +# Source-Hash: 88e6c2e1c344b2fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a surface to paint" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.hoverASurfaceToPaint" -msgstr "Survolez une surface pour la peindre" +msgid "editor.floatingActionMenu.system" +msgstr "Système" -# Source-Hash: 63dec5de4a337015 +# Source-Hash: f0e76aea883d4e48 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a surface to pick its material" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add a floor under the roof" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.hoverASurfaceToPickIts" -msgstr "Survolez une surface pour prélever son matériau" +msgid "editor.floatingLevelSelector.addAFloorUnderTheRoof" +msgstr "Ajouter un niveau sous le toit" -# Source-Hash: 7ad6dc1b1f03f970 +# Source-Hash: a982ff9b075af829 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "More shortcuts" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add level above" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.moreShortcuts" -msgstr "Plus de raccourcis" +msgid "editor.floatingLevelSelector.addLevelAbove" +msgstr "Ajouter un niveau au-dessus" -# Source-Hash: 476b8f5f9ee542e6 +# Source-Hash: 0db7d221df08fa6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add level below" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.paintScope" -msgstr "Peindre : {scope}" +msgid "editor.floatingLevelSelector.addLevelBelow" +msgstr "Ajouter un niveau en dessous" -# Source-Hash: 9c09ce4c34122277 +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint scope — click or press Shift to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.paintScopeClickOrPressShift" -msgstr "Portée de la peinture — cliquez ou appuyez sur Maj pour changer" +msgid "editor.floatingLevelSelector.cancel" +msgstr "Annuler" -# Source-Hash: 7890aa81687f6654 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint scope: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.paintScopeLabel" -msgstr "Portée de la peinture : {scope}" +msgid "editor.floatingLevelSelector.delete" +msgstr "Supprimer" -# Source-Hash: a75b3abc0784b12b +# Source-Hash: 8e29375893d63408 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete level" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.pickScope" -msgstr "Prélever : {scope}" +msgid "editor.floatingLevelSelector.deleteLevel" +msgstr "Supprimer le niveau" -# Source-Hash: 69c1044e6ea87ccf +# Source-Hash: c3bc69ec52022250 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place gate on a fence" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Are you sure you want to delete {levelName}? All walls, floors, and objects on this level will be permanently removed." +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.placeGateOnAFence" -msgstr "Placer le portail sur une clôture" - -# Source-Hash: 3754255b8affc7a0 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place passage on a fence" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx -#, fuzzy -msgid "editor.helpers.contextualHelperPanel.placePassageOnAFence" -msgstr "Placer le passage sur une clôture" +msgid "editor.floatingLevelSelector.deleteLevelConfirm" +msgstr "Voulez-vous vraiment supprimer {levelName} ? Tous les murs, planchers et objets de ce niveau seront définitivement supprimés." -# Source-Hash: a8328c8964e947fa +# Source-Hash: 5b2826ddac95cd0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select a material to paint" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag to reorder" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.selectAMaterialToPaint" -msgstr "Choisissez un matériau à peindre" +msgid "editor.floatingLevelSelector.dragToReorder" +msgstr "Faire glisser pour réorganiser" -# Source-Hash: 6f95d7116aea5738 +# Source-Hash: 933177338f5a03ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping: Angles" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate level" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingAngles" -msgstr "Aimantation : angles" +msgid "editor.floatingLevelSelector.duplicateLevel" +msgstr "Dupliquer le niveau" -# Source-Hash: 2d6d8d85d2ebed47 +# Source-Hash: 9614c6825a7c67bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping: Grid" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate with options..." +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingGrid" -msgstr "Aimantation : grille" +msgid "editor.floatingLevelSelector.duplicateWithOptions" +msgstr "Dupliquer avec options..." -# Source-Hash: 9096c5f9d8ce0f7c +# Source-Hash: 5ec91bb339806413 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping: Lines" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Exit unit focus" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingLines" -msgstr "Aimantation : lignes" +msgid "editor.floatingLevelSelector.exitUnitFocus" +msgstr "Quitter le focus sur le logement" -# Source-Hash: b663afbf0835cf32 +# Source-Hash: a88c3f8bed58b4fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping mode — click or press Shift to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Focused unit has zones here" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingModeClickOrPressShift" -msgstr "Mode d’aimantation — cliquez ou appuyez sur Maj pour changer" +msgid "editor.floatingLevelSelector.focusedUnitHasZonesHere" +msgstr "Le logement ciblé a des zones ici" -# Source-Hash: d00e984fc88f71aa +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The ground floor stands {distance} over grade. Seat the ground floor 8 in over grade" +# Source-Hash: 6a00e82fda812178 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping: Off" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingOff" -msgstr "Aimantation : désactivée" +msgid "editor.floatingLevelSelector.groundFloorOverGrade" +msgstr "Le rez-de-chaussée se trouve à {distance} au-dessus du sol. {action}" -# Source-Hash: 6be9d0d312200761 +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The ground floor stands {distance} under grade. Seat the ground floor 8 in over grade" +# Source-Hash: 61f400e77494df9b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight continuation is unavailable for curved or freehand fences" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.straightContinuationIsUnavailableForCurved" -msgstr "L’enchaînement droit n’est pas disponible pour les clôtures courbes ou libres" +msgid "editor.floatingLevelSelector.groundFloorUnderGrade" +msgstr "Le rez-de-chaussée se trouve à {distance} sous le sol. {action}" -# Source-Hash: 0d56b1f0a0493302 +# Source-Hash: e3763ae2dc62c03f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight: Continuous" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground line: the levels under it are below grade" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.straightContinuous" -msgstr "Droite : continue" +msgid "editor.floatingLevelSelector.groundLineTheLevelsUnderIt" +msgstr "Ligne de sol : les niveaux en dessous sont enterrés" -# Source-Hash: c034e85d3e7fd27e +# Source-Hash: e12035eb47cc61cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight fence continuation — click or press C to toggle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground · {offset}" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.straightFenceContinuationClickOrPress" -msgstr "Enchaînement de clôture droite — cliquez ou appuyez sur C pour basculer" +msgid "editor.floatingLevelSelector.groundOffset" +msgstr "Sol · {offset}" -# Source-Hash: e3f679cdb4a3d603 +# Source-Hash: 5661c11383217661 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight: Single" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insert level here" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.straightSingle" -msgstr "Droite : simple" +msgid "editor.floatingLevelSelector.insertLevelHere" +msgstr "Insérer un niveau ici" -# Source-Hash: 9a56d90d461b4bca +# Source-Hash: 0215b36d5a08597a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add point" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level height" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.addPoint" -msgstr "Ajouter un point" +msgid "editor.floatingLevelSelector.levelHeight" +msgstr "Hauteur du niveau" -# Source-Hash: c3dc3918c823a5e6 +# Source-Hash: 91af436e81bb0875 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add point · click the first to close" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paste copied selection" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.addPointClickTheFirstTo" -msgstr "Ajouter un point · cliquez sur le premier pour fermer" +msgid "editor.floatingLevelSelector.pasteCopiedSelection" +msgstr "Coller la sélection copiée" -# Source-Hash: d8cf72d482d56cd7 +# Source-Hash: 68bc52f53240cbec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Brush size" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reorder {levelName}" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.brushSize" -msgstr "Taille du pinceau" +msgid "editor.floatingLevelSelector.reorderLevelname" +msgstr "Réorganiser {levelName}" -# Source-Hash: c0774c185060fc13 +# Source-Hash: 625d53de72ebc2ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Seat the building so this floor stands at grade; the floors under it are below grade" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.cancel" -msgstr "Annuler" +msgid "editor.floatingLevelSelector.seatTheBuildingSoThisFloor" +msgstr "Placer le bâtiment pour que cet étage soit au niveau du sol ; les étages inférieurs sont enterrés" -# Source-Hash: 104fdab7934ec66c +# Source-Hash: 7ac9c00895c30d76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel picking" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set as ground floor" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.cancelPicking" -msgstr "Annuler la sélection" +msgid "editor.floatingLevelSelector.setAsGroundFloor" +msgstr "Définir comme rez-de-chaussée" -# Source-Hash: c318cf0ce70b8977 +# Source-Hash: d6b381247066a7aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel stroke" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The ground level cannot be deleted" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.cancelStroke" -msgstr "Annuler le tracé" +msgid "editor.floatingLevelSelector.theGroundLevelCannotBeDeleted" +msgstr "Le niveau du rez-de-chaussée ne peut pas être supprimé" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: b1122051dce0d7a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This floor stands at grade" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.done" -msgstr "Terminé" +msgid "editor.floatingLevelSelector.thisFloorStandsAtGrade" +msgstr "Cet étage est au niveau du sol" -# Source-Hash: e297db9ca0ce6d31 +# Source-Hash: 062cc0f1afef0c52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw the mezzanine" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unit" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.drawTheMezzanine" -msgstr "Dessiner la mezzanine" +msgid "editor.floatingLevelSelector.unit" +msgstr "Lot" -# Source-Hash: c8be604718a7a9fd +# Source-Hash: 5871b7c20478f4a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw the opening" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor area" +#: packages/editor/src/i18n/floor-footprint-name.ts #, fuzzy -msgid "editor.helpers.helperManager.drawTheOpening" -msgstr "Dessiner l’ouverture" +msgid "editor.floorFootprint.area" +msgstr "Surface de plancher" -# Source-Hash: 231386ae6d534163 +# Source-Hash: 8b2e1435272aa86a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw the terrace" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{room} floor" +#: packages/editor/src/i18n/floor-footprint-name.ts #, fuzzy -msgid "editor.helpers.helperManager.drawTheTerrace" -msgstr "Dessiner la terrasse" +msgid "editor.floorFootprint.room" +msgstr "Plancher {room}" -# Source-Hash: e092e803eb60af69 +# Source-Hash: 4731183fec06cbdf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Exit smart measure" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shared floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +#: packages/editor/src/i18n/floor-footprint-name.ts #, fuzzy -msgid "editor.helpers.helperManager.exitSmartMeasure" -msgstr "Quitter la mesure intelligente" +msgid "editor.floorFootprint.shared" +msgstr "Plancher partagé" -# Source-Hash: b3907da0ad234f10 +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/helpers/building-helper.tsx #, fuzzy -msgid "editor.helpers.helperManager.finish" -msgstr "Terminer" +msgid "editor.helpers.buildingHelper.cancel" +msgstr "Annuler" -# Source-Hash: f74bd937ae2e3a40 +# Source-Hash: 4c6ca3441c74da9e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish at the edge" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place building" +#: packages/editor/src/components/ui/helpers/building-helper.tsx #, fuzzy -msgid "editor.helpers.helperManager.finishAtTheEdge" -msgstr "Terminer au bord" +msgid "editor.helpers.buildingHelper.placeBuilding" +msgstr "Placer le bâtiment" -# Source-Hash: 21029cf1c45697cc +# Source-Hash: 306d409f8a1cf480 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Free move" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/editor/src/components/ui/helpers/building-helper.tsx #, fuzzy -msgid "editor.helpers.helperManager.freeMove" -msgstr "Déplacement libre" +msgid "editor.helpers.buildingHelper.rotate" +msgstr "Pivoter" -# Source-Hash: 3247d8689bed6ff6 +# Source-Hash: 832470d3aeee82fd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Free move · slide doors and windows" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel placement" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.freeMoveSlideDoorsAndWindows" -msgstr "Déplacement libre · faire glisser portes et fenêtres" +msgid "editor.helpers.contextualHelperPanel.cancelPlacement" +msgstr "Annuler le placement" -# Source-Hash: b5ad765b43e75a5c +# Source-Hash: e374fcaee33c3e2c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hold to pick a material" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuation — click or press C to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.holdToPickAMaterial" -msgstr "Maintenez pour prélever un matériau" +msgid "editor.helpers.contextualHelperPanel.continuationClickOrPressCTo" +msgstr "Enchaînement — cliquez ou appuyez sur C pour changer" -# Source-Hash: 46b53c5449c98964 +# Source-Hash: b108c7dc2ec2b9de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inspect surface dimensions" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuation: {label}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.inspectSurfaceDimensions" -msgstr "Inspecter les dimensions de la surface" +msgid "editor.helpers.contextualHelperPanel.continuationLabel" +msgstr "Enchaînement : {label}" -# Source-Hash: 63f1f7006ae14177 +# Source-Hash: 729d87891cb7dbb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint with this material" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag to draw fence" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.paintWithThisMaterial" -msgstr "Peindre avec ce matériau" +msgid "editor.helpers.contextualHelperPanel.dragToDrawFence" +msgstr "Faites glisser pour tracer la clôture" -# Source-Hash: 188f55cc5afbe34f +# Source-Hash: b52e874718af1916 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick target height" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Erase: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.pickTargetHeight" -msgstr "Choisir la hauteur cible" +msgid "editor.helpers.contextualHelperPanel.eraseScope" +msgstr "Effacer : {scope}" -# Source-Hash: 2880fc9752eababa +# Source-Hash: 61f7494abc319e66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pin measurement lens" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Erase scope — click or press Shift to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.pinMeasurementLens" -msgstr "Épingler la loupe de mesure" +msgid "editor.helpers.contextualHelperPanel.eraseScopeClickOrPressShift" +msgstr "Portée de l’effacement — cliquez ou appuyez sur Maj pour changer" -# Source-Hash: 722741535b346e09 +# Source-Hash: 59993c163d68cc53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Erase scope: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.place" -msgstr "Placer" +msgid "editor.helpers.contextualHelperPanel.eraseScopeLabel" +msgstr "Portée de l’effacement : {scope}" -# Source-Hash: 82010a7fd6350c93 +# Source-Hash: a4bdcbc6cab772bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place inside the room" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fence type — click or press T to switch between straight, curved and freehand" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.placeInsideTheRoom" -msgstr "Placer dans la pièce" +msgid "editor.helpers.contextualHelperPanel.fenceTypeClickOrPressT" +msgstr "Type de clôture — cliquez ou appuyez sur T pour passer de droite à courbe ou libre" -# Source-Hash: 8b97f4503edb27b9 +# Source-Hash: 2a9ed258727078ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Press anywhere, drag to the opposite corner" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fewer shortcuts" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.pressAnywhereDragToTheOpposite" -msgstr "Appuyez n’importe où, faites glisser jusqu’à l’angle opposé" +msgid "editor.helpers.contextualHelperPanel.fewerShortcuts" +msgstr "Moins de raccourcis" -# Source-Hash: 786f0b1c81b2a6c0 +# Source-Hash: 698fa6e78af4d4b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raise or lower" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish curve (or double-click)" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.raiseOrLower" -msgstr "Monter ou descendre" +msgid "editor.helpers.contextualHelperPanel.finishCurveOrDoubleClick" +msgstr "Terminer la courbe (ou double-clic)" -# Source-Hash: b033f46ae3a0cbb7 +# Source-Hash: 09f6d79edf5cfd16 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove a painted part, or reset a surface" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid: {length}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.removeAPaintedPartOrReset" -msgstr "Retirer une partie peinte ou réinitialiser une surface" +msgid "editor.helpers.contextualHelperPanel.gridLength" +msgstr "Grille : {length}" -# Source-Hash: 0dc6d121791696f7 +# Source-Hash: c493b562040c4328 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove last point" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid step — click or tap Ctrl to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.removeLastPoint" -msgstr "Retirer le dernier point" +msgid "editor.helpers.contextualHelperPanel.gridStepClickOrTapCtrl" +msgstr "Pas de grille — cliquez ou appuyez sur Ctrl pour changer" -# Source-Hash: f85bdac0a1d16603 +# Source-Hash: d36a8c93d81b3a36 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Resize" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid step: {length}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.resize" -msgstr "Redimensionner" +msgid "editor.helpers.contextualHelperPanel.gridStepLength" +msgstr "Pas de grille : {length}" -# Source-Hash: 8a665ecaeffa9308 +# Source-Hash: abea993ede7daa7e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ±45°" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a painted surface to erase" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.rotate45" -msgstr "Pivoter de ±45°" +msgid "editor.helpers.contextualHelperPanel.hoverAPaintedSurfaceToErase" +msgstr "Survolez une surface peinte pour l’effacer" -# Source-Hash: 6099ee99f8c38700 +# Source-Hash: fc1ed0ddc0cfcef5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate the selection ±45°" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a surface to paint" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.rotateTheSelection45" -msgstr "Pivoter la sélection de ±45°" +msgid "editor.helpers.contextualHelperPanel.hoverASurfaceToPaint" +msgstr "Survolez une surface pour la peindre" -# Source-Hash: c93ae898b4d59f6f +# Source-Hash: 63dec5de4a337015 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set one corner, then the opposite" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a surface to pick its material" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.setOneCornerThenTheOpposite" -msgstr "Placez un angle, puis l’angle opposé" +msgid "editor.helpers.contextualHelperPanel.hoverASurfaceToPickIts" +msgstr "Survolez une surface pour prélever son matériau" -# Source-Hash: c0774c185060fc13 +# Source-Hash: 7ad6dc1b1f03f970 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/helpers/item-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "More shortcuts" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.itemHelper.cancel" -msgstr "Annuler" +msgid "editor.helpers.contextualHelperPanel.moreShortcuts" +msgstr "Plus de raccourcis" -# Source-Hash: ed7f3d8417a3e074 +# Source-Hash: 476b8f5f9ee542e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Force place" -#: packages/editor/src/components/ui/helpers/item-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.itemHelper.forcePlace" -msgstr "Forcer le placement" +msgid "editor.helpers.contextualHelperPanel.paintScope" +msgstr "Peindre : {scope}" -# Source-Hash: 722741535b346e09 +# Source-Hash: 9c09ce4c34122277 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place" -#: packages/editor/src/components/ui/helpers/item-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint scope — click or press Shift to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.itemHelper.place" -msgstr "Placer" +msgid "editor.helpers.contextualHelperPanel.paintScopeClickOrPressShift" +msgstr "Portée de la peinture — cliquez ou appuyez sur Maj pour changer" -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: 7890aa81687f6654 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" -#: packages/editor/src/components/ui/helpers/item-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint scope: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.itemHelper.rotate" -msgstr "Pivoter" +msgid "editor.helpers.contextualHelperPanel.paintScopeLabel" +msgstr "Portée de la peinture : {scope}" -# Source-Hash: e9dfc2a178bca5f7 +# Source-Hash: a75b3abc0784b12b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guided constraints bypassed" -#: packages/editor/src/components/ui/helpers/registered-tool-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.registeredToolHelper.guidedConstraintsBypassed" -msgstr "Contraintes guidées ignorées" +msgid "editor.helpers.contextualHelperPanel.pickScope" +msgstr "Prélever : {scope}" -# Source-Hash: c69865ec5d9d1ac9 +# Source-Hash: 69c1044e6ea87ccf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Angle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place gate on a fence" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.angle.g10zaw" -msgstr "Angle" +msgid "editor.helpers.contextualHelperPanel.placeGateOnAFence" +msgstr "Placer le portail sur une clôture" -# Source-Hash: 9c562983f6fed685 +# Source-Hash: 3754255b8affc7a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arm length m" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place passage on a fence" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.armLengthM.1jclqgw" -msgstr "Longueur du bras m" +msgid "editor.helpers.contextualHelperPanel.placePassageOnAFence" +msgstr "Placer le passage sur une clôture" -# Source-Hash: 38461bc364321749 +# Source-Hash: a8328c8964e947fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Attachment side" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select a material to paint" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.attachmentSide.6n9s5v" -msgstr "Côté de raccordement" +msgid "editor.helpers.contextualHelperPanel.selectAMaterialToPaint" +msgstr "Choisissez un matériau à peindre" -# Source-Hash: 441124187e7da2fc +# Source-Hash: 6f95d7116aea5738 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping: Angles" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.autoHangers.10554ka" -msgstr "Suspentes auto" +msgid "editor.helpers.contextualHelperPanel.snappingAngles" +msgstr "Aimantation : angles" -# Source-Hash: e20033e4b0045f1c +# Source-Hash: 2d6d8d85d2ebed47 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto miter corners" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping: Grid" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.autoMiterCorners.zxr5lt" -msgstr "Angles en onglet auto" +msgid "editor.helpers.contextualHelperPanel.snappingGrid" +msgstr "Aimantation : grille" -# Source-Hash: 92f3a8b63963daeb +# Source-Hash: 9096c5f9d8ce0f7c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto span" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping: Lines" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.autoSpan.1gas9r6" -msgstr "Portée auto" +msgid "editor.helpers.contextualHelperPanel.snappingLines" +msgstr "Aimantation : lignes" -# Source-Hash: 8b2dfb9b9137fda0 +# Source-Hash: b663afbf0835cf32 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back ratio" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping mode — click or press Shift to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.backRatio.1ughd99" -msgstr "Ratio arrière" +msgid "editor.helpers.contextualHelperPanel.snappingModeClickOrPressShift" +msgstr "Mode d’aimantation — cliquez ou appuyez sur Maj pour changer" -# Source-Hash: 75dfae8d9f03fa0e +# Source-Hash: d00e984fc88f71aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping: Off" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.baseHeight.1hs4zdf" -msgstr "Hauteur de base" +msgid "editor.helpers.contextualHelperPanel.snappingOff" +msgstr "Aimantation : désactivée" -# Source-Hash: 1cc2da12e8463e85 +# Source-Hash: 6be9d0d312200761 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base style" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight continuation is unavailable for curved or freehand fences" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.baseStyle.24vty5" -msgstr "Style de base" +msgid "editor.helpers.contextualHelperPanel.straightContinuationIsUnavailableForCurved" +msgstr "L’enchaînement droit n’est pas disponible pour les clôtures courbes ou libres" -# Source-Hash: f9d95c6df06b6223 +# Source-Hash: 0d56b1f0a0493302 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Beam height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight: Continuous" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.beamHeight.1kq0oh1" -msgstr "Hauteur de poutre" +msgid "editor.helpers.contextualHelperPanel.straightContinuous" +msgstr "Droite : continue" -# Source-Hash: a133f8d23b1274dc +# Source-Hash: c034e85d3e7fd27e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Beam width" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight fence continuation — click or press C to toggle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.beamWidth.1q1mzbe" -msgstr "Largeur de poutre" +msgid "editor.helpers.contextualHelperPanel.straightFenceContinuationClickOrPress" +msgstr "Enchaînement de clôture droite — cliquez ou appuyez sur C pour basculer" -# Source-Hash: b98c0d0189526335 +# Source-Hash: e3f679cdb4a3d603 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Body shape" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight: Single" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.bodyShape.arvkuw" -msgstr "Forme du corps" +msgid "editor.helpers.contextualHelperPanel.straightSingle" +msgstr "Droite : simple" -# Source-Hash: 2251ecab18467631 +# Source-Hash: 9a56d90d461b4bca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bracket style" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add point" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.bracketStyle.1vvoptm" -msgstr "Style de console" +msgid "editor.helpers.helperManager.addPoint" +msgstr "Ajouter un point" -# Source-Hash: 5e9d4a4fcea481ca +# Source-Hash: c3dc3918c823a5e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Branch angle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add point · click the first to close" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.branchAngle.v56zme" -msgstr "Angle de piquage" +msgid "editor.helpers.helperManager.addPointClickTheFirstTo" +msgstr "Ajouter un point · cliquez sur le premier pour fermer" -# Source-Hash: dec709f1f9c714ee +# Source-Hash: d8cf72d482d56cd7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cab height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brush size" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cabHeight.1yn34mk" -msgstr "Hauteur de cabine" +msgid "editor.helpers.helperManager.brushSize" +msgstr "Taille du pinceau" -# Source-Hash: 87863f8366e1c88a +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Canopy form" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.canopyForm.1czzggp" -msgstr "Forme de l’auvent" +msgid "editor.helpers.helperManager.cancel" +msgstr "Annuler" -# Source-Hash: d52b53241789ee63 +# Source-Hash: 104fdab7934ec66c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel picking" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cap.s0thej" -msgstr "Chapeau" +msgid "editor.helpers.helperManager.cancelPicking" +msgstr "Annuler la sélection" -# Source-Hash: 2f2e49598ec8188e +# Source-Hash: c318cf0ce70b8977 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap overhang" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel stroke" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.capOverhang.kxxz9j" -msgstr "Débord du chapeau" +msgid "editor.helpers.helperManager.cancelStroke" +msgstr "Annuler le tracé" -# Source-Hash: 8523c086e95b83e2 +# Source-Hash: 16552c2580bbe8b8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap shape" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.capShape.17mbxhu" -msgstr "Forme du chapeau" +msgid "editor.helpers.helperManager.done" +msgstr "Terminé" -# Source-Hash: acd98600a518dd95 +# Source-Hash: e297db9ca0ce6d31 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap thickness" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw the mezzanine" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.capThickness.u835q9" -msgstr "Épaisseur du chapeau" +msgid "editor.helpers.helperManager.drawTheMezzanine" +msgstr "Dessiner la mezzanine" -# Source-Hash: 7af3b69b4b5aeb19 +# Source-Hash: c8be604718a7a9fd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Carcass height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw the opening" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.carcassHeight.1aks0zy" -msgstr "Hauteur du caisson" +msgid "editor.helpers.helperManager.drawTheOpening" +msgstr "Dessiner l’ouverture" -# Source-Hash: 827709caa79db37f +# Source-Hash: 231386ae6d534163 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cleanout style" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw the terrace" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cleanoutStyle.127zz6z" -msgstr "Style de regard" +msgid "editor.helpers.helperManager.drawTheTerrace" +msgstr "Dessiner la terrasse" -# Source-Hash: a549dc98e2a1bd07 +# Source-Hash: e092e803eb60af69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar diameter" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Exit smart measure" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.collarDiameter.1d5k28r" -msgstr "Diamètre du collier" +msgid "editor.helpers.helperManager.exitSmartMeasure" +msgstr "Quitter la mesure intelligente" -# Source-Hash: aa0232fc6f3eeadc +# Source-Hash: b3907da0ad234f10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.collarHeight.1dqwsrf" -msgstr "Hauteur du collier" +msgid "editor.helpers.helperManager.finish" +msgstr "Terminer" -# Source-Hash: cbd8079c3f540a4c +# Source-Hash: f74bd937ae2e3a40 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar shape" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish at the edge" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.collarShape.1gacv11" -msgstr "Forme du collier" +msgid "editor.helpers.helperManager.finishAtTheEdge" +msgstr "Terminer au bord" -# Source-Hash: 557cde7f95616454 +# Source-Hash: 21029cf1c45697cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar width" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free move" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.collarWidth.qvc9ik" -msgstr "Largeur du collier" +msgid "editor.helpers.helperManager.freeMove" +msgstr "Déplacement libre" -# Source-Hash: 30edd1c180aac9b4 +# Source-Hash: 3247d8689bed6ff6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Columns" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free move · slide doors and windows" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.columns.1sy73ks" -msgstr "Colonnes" +msgid "editor.helpers.helperManager.freeMoveSlideDoorsAndWindows" +msgstr "Déplacement libre · faire glisser portes et fenêtres" -# Source-Hash: cd5b2f70924b7c2d +# Source-Hash: b5ad765b43e75a5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Conical full circle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hold to pick a material" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.conicalFullCircle.1pgkpz5" -msgstr "Conique cercle complet" +msgid "editor.helpers.helperManager.holdToPickAMaterial" +msgstr "Maintenez pour prélever un matériau" -# Source-Hash: dc90f3abb935e7e2 +# Source-Hash: 46b53c5449c98964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connection mode" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inspect surface dimensions" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.connectionMode.1nty478" -msgstr "Mode de raccordement" +msgid "editor.helpers.helperManager.inspectSurfaceDimensions" +msgstr "Inspecter les dimensions de la surface" -# Source-Hash: 1a9a49d7135d4f15 +# Source-Hash: 63f1f7006ae14177 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connection offset" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint with this material" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.connectionOffset.2m70s8" -msgstr "Décalage de raccordement" +msgid "editor.helpers.helperManager.paintWithThisMaterial" +msgstr "Peindre avec ce matériau" -# Source-Hash: 69be301fcb8030e2 +# Source-Hash: 188f55cc5afbe34f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner bevel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick target height" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cornerBevel.16iniho" -msgstr "Chanfrein d’angle" +msgid "editor.helpers.helperManager.pickTargetHeight" +msgstr "Choisir la hauteur cible" -# Source-Hash: b997a96a9dc7e450 +# Source-Hash: 2880fc9752eababa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Covering type" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pin measurement lens" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.coveringType.95yd3k" -msgstr "Type de revêtement" +msgid "editor.helpers.helperManager.pinMeasurementLens" +msgstr "Épingler la loupe de mesure" -# Source-Hash: 03b33160d8baa966 +# Source-Hash: 722741535b346e09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cricketHeight.pok31n" -msgstr "Hauteur de la costière" +msgid "editor.helpers.helperManager.place" +msgstr "Placer" -# Source-Hash: 21552eee05ccb5d6 +# Source-Hash: 82010a7fd6350c93 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket length" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place inside the room" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cricketLength.i2aht8" -msgstr "Longueur de la costière" +msgid "editor.helpers.helperManager.placeInsideTheRoom" +msgstr "Placer dans la pièce" -# Source-Hash: c13b707bfdeac855 +# Source-Hash: 8b97f4503edb27b9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket side" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Press anywhere, drag to the opposite corner" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cricketSide.1xnwil7" -msgstr "Côté de la costière" +msgid "editor.helpers.helperManager.pressAnywhereDragToTheOpposite" +msgstr "Appuyez n’importe où, faites glisser jusqu’à l’angle opposé" -# Source-Hash: 4ee7089fa1b3e63b +# Source-Hash: 786f0b1c81b2a6c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket style" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raise or lower" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cricketStyle.10j0lat" -msgstr "Style de costière" +msgid "editor.helpers.helperManager.raiseOrLower" +msgstr "Monter ou descendre" -# Source-Hash: b8ff053666ee326b +# Source-Hash: b033f46ae3a0cbb7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curb" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove a painted part, or reset a surface" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.curb.5xi2ol" -msgstr "Costière" +msgid "editor.helpers.helperManager.removeAPaintedPartOrReset" +msgstr "Retirer une partie peinte ou réinitialiser une surface" -# Source-Hash: 8da648df210dbc0d +# Source-Hash: 0dc6d121791696f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curb height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove last point" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.curbHeight.1yn97sg" -msgstr "Hauteur de costière" +msgid "editor.helpers.helperManager.removeLastPoint" +msgstr "Retirer le dernier point" -# Source-Hash: 0c01b9848f5d9673 +# Source-Hash: f85bdac0a1d16603 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curve offset" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Resize" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.curveOffset.l4xhvr" -msgstr "Flèche de courbure" +msgid "editor.helpers.helperManager.resize" +msgstr "Redimensionner" -# Source-Hash: 69179f4caa384585 +# Source-Hash: 8a665ecaeffa9308 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Damper angle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ±45°" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.damperAngle.h5fxn7" -msgstr "Angle du registre" +msgid "editor.helpers.helperManager.rotate45" +msgstr "Pivoter de ±45°" -# Source-Hash: 15cff91231e806a4 +# Source-Hash: 6099ee99f8c38700 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Deck thickness" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate the selection ±45°" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.deckThickness.4jmqze" -msgstr "Épaisseur de la terrasse" +msgid "editor.helpers.helperManager.rotateTheSelection45" +msgstr "Pivoter la sélection de ±45°" -# Source-Hash: eff1e7dc0901b9d0 +# Source-Hash: c93ae898b4d59f6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default level id" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set one corner, then the opposite" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.defaultLevelId.xmrjzp" -msgstr "ID de niveau par défaut" +msgid "editor.helpers.helperManager.setOneCornerThenTheOpposite" +msgstr "Placez un angle, puis l’angle opposé" -# Source-Hash: 99ac4d03c3061f3a +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/helpers/item-helper.tsx #, fuzzy -msgid "editor.inspector.field.depth.1lu11u2" -msgstr "Profondeur" +msgid "editor.helpers.itemHelper.cancel" +msgstr "Annuler" -# Source-Hash: 016d8e70618916d4 +# Source-Hash: ed7f3d8417a3e074 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diameter" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Force place" +#: packages/editor/src/components/ui/helpers/item-helper.tsx #, fuzzy -msgid "editor.inspector.field.diameter.s3robe" -msgstr "Diamètre" +msgid "editor.helpers.itemHelper.forcePlace" +msgstr "Forcer le placement" -# Source-Hash: dab4100e83e4e6b3 +# Source-Hash: 722741535b346e09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diameter2" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place" +#: packages/editor/src/components/ui/helpers/item-helper.tsx #, fuzzy -msgid "editor.inspector.field.diameter2.pm6cl4" -msgstr "Diamètre 2" +msgid "editor.helpers.itemHelper.place" +msgstr "Placer" -# Source-Hash: 5747145349432396 +# Source-Hash: 306d409f8a1cf480 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door duration ms" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/editor/src/components/ui/helpers/item-helper.tsx #, fuzzy -msgid "editor.inspector.field.doorDurationMs.13nx909" -msgstr "Durée de porte ms" +msgid "editor.helpers.itemHelper.rotate" +msgstr "Pivoter" -# Source-Hash: 6f4aca26196c221f +# Source-Hash: e9dfc2a178bca5f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guided constraints bypassed" +#: packages/editor/src/components/ui/helpers/registered-tool-helper.tsx #, fuzzy -msgid "editor.inspector.field.doorHeight.92r9k4" -msgstr "Hauteur de porte" +msgid "editor.helpers.registeredToolHelper.guidedConstraintsBypassed" +msgstr "Contraintes guidées ignorées" -# Source-Hash: 990ae81752236e3a +# Source-Hash: c69865ec5d9d1ac9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door panel style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.doorPanelStyle.2qog4q" -msgstr "Style de panneau de porte" +msgid "editor.inspector.field.angle.g10zaw" +msgstr "Angle" -# Source-Hash: c94e002123bb1199 +# Source-Hash: 9c562983f6fed685 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arm length m" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.doorStyle.gerpos" -msgstr "Style de porte" +msgid "editor.inspector.field.armLengthM.1jclqgw" +msgstr "Longueur du bras m" -# Source-Hash: 91aeb04b0b7b605e +# Source-Hash: 38461bc364321749 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Attachment side" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.doorWidth.sy732l" -msgstr "Largeur de porte" +msgid "editor.inspector.field.attachmentSide.6n9s5v" +msgstr "Côté de raccordement" -# Source-Hash: baad1238f70f79ea +# Source-Hash: 441124187e7da2fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspout enabled" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.downspoutEnabled.1gn00nv" -msgstr "Descente activée" +msgid "editor.inspector.field.autoHangers.10554ka" +msgstr "Suspentes auto" -# Source-Hash: e288531858c4c44d +# Source-Hash: e20033e4b0045f1c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspout position" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto miter corners" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.downspoutPosition.fxcsop" -msgstr "Position de la descente" +msgid "editor.inspector.field.autoMiterCorners.zxr5lt" +msgstr "Angles en onglet auto" -# Source-Hash: 861d28317325cf61 +# Source-Hash: 92f3a8b63963daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct material" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto span" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.ductMaterial.i8eonq" -msgstr "Matériau de gaine" +msgid "editor.inspector.field.autoSpan.1gas9r6" +msgstr "Portée auto" -# Source-Hash: ad8ab4ae38c3299c +# Source-Hash: 8b2dfb9b9137fda0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch gablet rake" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchGabletRake.6paydp" -msgstr "Rive du pignon à demi-croupe" - -# Source-Hash: 913d25cf2c5ff179 +msgid "editor.inspector.field.backRatio.1ughd99" +msgstr "Ratio arrière" + +# Source-Hash: 75dfae8d9f03fa0e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch hip height ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchHipHeightRatio.1etnwgg" -msgstr "Ratio de hauteur de demi-croupe" +msgid "editor.inspector.field.baseHeight.1hs4zdf" +msgstr "Hauteur de base" -# Source-Hash: f4a80233d49f2b20 +# Source-Hash: 1cc2da12e8463e85 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch hip width ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchHipWidthRatio.1dopfvb" -msgstr "Ratio de largeur de demi-croupe" +msgid "editor.inspector.field.baseStyle.24vty5" +msgstr "Style de base" -# Source-Hash: 92021b0e37f9a25a +# Source-Hash: f9d95c6df06b6223 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch top rake thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchTopRakeThickness.1w9khxt" -msgstr "Épaisseur de rive haute" +msgid "editor.inspector.field.beamHeight.1kq0oh1" +msgstr "Hauteur de poutre" -# Source-Hash: d0a2ec13d71ce659 +# Source-Hash: a133f8d23b1274dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch waist length ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchWaistLengthRatio.agtoxw" -msgstr "Ratio de longueur de taille" +msgid "editor.inspector.field.beamWidth.1q1mzbe" +msgstr "Largeur de poutre" -# Source-Hash: 993396ccca2cd1d5 +# Source-Hash: b98c0d0189526335 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dwell ms" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Body shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dwellMs.1lkk0o5" -msgstr "Arrêt ms" +msgid "editor.inspector.field.bodyShape.arvkuw" +msgstr "Forme du corps" -# Source-Hash: 9cf550eb019bca1b +# Source-Hash: 2251ecab18467631 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edge inset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bracket style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.edgeInset.1obeimx" -msgstr "Retrait de bord" +msgid "editor.inspector.field.bracketStyle.1vvoptm" +msgstr "Style de console" -# Source-Hash: 8a3bc5111b9e97f4 +# Source-Hash: 5e9d4a4fcea481ca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Branch angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.elevation.4jbp44" -msgstr "Altitude" +msgid "editor.inspector.field.branchAngle.v56zme" +msgstr "Angle de piquage" -# Source-Hash: 1fc91958e30dbeaf +# Source-Hash: dec709f1f9c714ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End cap left" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cab height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.endCapLeft.19jel4v" -msgstr "Embout gauche" +msgid "editor.inspector.field.cabHeight.1yn34mk" +msgstr "Hauteur de cabine" -# Source-Hash: 4c9ae62e0ed70635 +# Source-Hash: 87863f8366e1c88a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End cap right" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Canopy form" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.endCapRight.lhse9c" -msgstr "Embout droit" +msgid "editor.inspector.field.canopyForm.1czzggp" +msgstr "Forme de l’auvent" -# Source-Hash: a9cba06250228a55 +# Source-Hash: d52b53241789ee63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End caps" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.endCaps.4fsb5b" -msgstr "Embouts" +msgid "editor.inspector.field.cap.s0thej" +msgstr "Chapeau" -# Source-Hash: ebad74353b5a7610 +# Source-Hash: 2f2e49598ec8188e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End post" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.endPost.1guwsk0" -msgstr "Poteau d’extrémité" +msgid "editor.inspector.field.capOverhang.kxxz9j" +msgstr "Débord du chapeau" -# Source-Hash: ecbe36df4238439e +# Source-Hash: 8523c086e95b83e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equipment type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.equipmentType.1mc2ywt" -msgstr "Type d’équipement" +msgid "editor.inspector.field.capShape.17mbxhu" +msgstr "Forme du chapeau" -# Source-Hash: 66f1018b50c2e426 +# Source-Hash: acd98600a518dd95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fill to floor" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.fillToFloor.1oppnkf" -msgstr "Remplir jusqu’au sol" +msgid "editor.inspector.field.capThickness.u835q9" +msgstr "Épaisseur du chapeau" -# Source-Hash: 1cfe33235b30b1d8 +# Source-Hash: 7af3b69b4b5aeb19 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finial" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Carcass height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.finial.1ertf4s" -msgstr "Épi de faîtage" +msgid "editor.inspector.field.carcassHeight.1aks0zy" +msgstr "Hauteur du caisson" -# Source-Hash: 28cd69e506709f16 +# Source-Hash: 827709caa79db37f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fitting type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cleanout style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.fittingType.18mz17s" -msgstr "Type de raccord" +msgid "editor.inspector.field.cleanoutStyle.127zz6z" +msgstr "Style de regard" -# Source-Hash: 3c1aec5e6fb180cf +# Source-Hash: a549dc98e2a1bd07 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flashing height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flashingHeight.3e8nn6" -msgstr "Hauteur du solin" +msgid "editor.inspector.field.collarDiameter.1d5k28r" +msgstr "Diamètre du collier" -# Source-Hash: 327ba762101db94d +# Source-Hash: aa0232fc6f3eeadc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flashing projection" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flashingProjection.hhf0fk" -msgstr "Saillie du solin" +msgid "editor.inspector.field.collarHeight.1dqwsrf" +msgstr "Hauteur du collier" -# Source-Hash: 9473e2ab53370b40 +# Source-Hash: cbd8079c3f540a4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueCount.j3t2ci" -msgstr "Nombre de conduits" +msgid "editor.inspector.field.collarShape.1gacv11" +msgstr "Forme du collier" -# Source-Hash: fd0b65425ed3df8b +# Source-Hash: 557cde7f95616454 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueDiameter.cjhubg" -msgstr "Diamètre du conduit" +msgid "editor.inspector.field.collarWidth.qvc9ik" +msgstr "Largeur du collier" -# Source-Hash: 07ebe5e3780c624b +# Source-Hash: 30edd1c180aac9b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Columns" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueHeight.1dhc4y4" -msgstr "Hauteur du conduit" +msgid "editor.inspector.field.columns.1sy73ks" +msgstr "Colonnes" -# Source-Hash: ff8319792830d591 +# Source-Hash: cd5b2f70924b7c2d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Conical full circle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueShape.1ealiy4" -msgstr "Forme du conduit" +msgid "editor.inspector.field.conicalFullCircle.1pgkpz5" +msgstr "Conique cercle complet" -# Source-Hash: 5acf77854a0030ec +# Source-Hash: dc90f3abb935e7e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connection mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueSpacing.exhzco" -msgstr "Espacement des conduits" +msgid "editor.inspector.field.connectionMode.1nty478" +msgstr "Mode de raccordement" -# Source-Hash: 0a64209c0edacaa1 +# Source-Hash: 1a9a49d7135d4f15 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Footing style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connection offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.footingStyle.e3btg6" -msgstr "Style de semelle" +msgid "editor.inspector.field.connectionOffset.2m70s8" +msgstr "Décalage de raccordement" -# Source-Hash: fd413477f1a9e5ed +# Source-Hash: 69be301fcb8030e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner bevel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.frameDepth.1934a5n" -msgstr "Profondeur du cadre" +msgid "editor.inspector.field.cornerBevel.16iniho" +msgstr "Chanfrein d’angle" -# Source-Hash: 6aa2318fa815e5f2 +# Source-Hash: b997a96a9dc7e450 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Covering type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.frameThickness.1agxzd8" -msgstr "Épaisseur du cadre" +msgid "editor.inspector.field.coveringType.95yd3k" +msgstr "Type de revêtement" -# Source-Hash: 9a3495a1e3181b56 +# Source-Hash: 03b33160d8baa966 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Framing strategy" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.framingStrategy.3jx9qe" -msgstr "Stratégie d’ossature" +msgid "editor.inspector.field.cricketHeight.pok31n" +msgstr "Hauteur de la costière" -# Source-Hash: 49f329aab535fd3a +# Source-Hash: 21552eee05ccb5d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "From level id" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket length" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.fromLevelId.15ieejs" -msgstr "ID du niveau de départ" +msgid "editor.inspector.field.cricketLength.i2aht8" +msgstr "Longueur de la costière" -# Source-Hash: dbd062efc7f4fd7f +# Source-Hash: c13b707bfdeac855 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket side" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gableOverhang.2z0obw" -msgstr "Débord de rive" +msgid "editor.inspector.field.cricketSide.1xnwil7" +msgstr "Côté de la costière" -# Source-Hash: 517caa8af48afb22 +# Source-Hash: 4ee7089fa1b3e63b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel lower height ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gambrelLowerHeightRatio.wqq7lg" -msgstr "Ratio de hauteur du brisis" +msgid "editor.inspector.field.cricketStyle.10j0lat" +msgstr "Style de costière" -# Source-Hash: 03ecb8f3b625d49d +# Source-Hash: b8ff053666ee326b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel lower width ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curb" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gambrelLowerWidthRatio.uvyb1v" -msgstr "Ratio de largeur du brisis" +msgid "editor.inspector.field.curb.5xi2ol" +msgstr "Costière" -# Source-Hash: f3ca5555e8c54375 +# Source-Hash: 8da648df210dbc0d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap x" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curb height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gapX.wjxa7" -msgstr "Écart x" +msgid "editor.inspector.field.curbHeight.1yn97sg" +msgstr "Hauteur de costière" -# Source-Hash: 2736f7c5dfc7d917 +# Source-Hash: 0c01b9848f5d9673 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap y" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curve offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gapY.mkbl8" -msgstr "Écart y" +msgid "editor.inspector.field.curveOffset.l4xhvr" +msgstr "Flèche de courbure" -# Source-Hash: 5d03ca50d712339b +# Source-Hash: 69179f4caa384585 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Damper angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.glassThickness.s97b0x" -msgstr "Épaisseur du vitrage" +msgid "editor.inspector.field.damperAngle.h5fxn7" +msgstr "Angle du registre" -# Source-Hash: 4fc3e60be28f60d5 +# Source-Hash: 15cff91231e806a4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground clearance" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.groundClearance.4os7f0" -msgstr "Garde au sol" +msgid "editor.inspector.field.deckThickness.4jmqze" +msgstr "Épaisseur de la terrasse" -# Source-Hash: 6a22a09b67309545 +# Source-Hash: eff1e7dc0901b9d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guard infill" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default level id" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.guardInfill.16heiig" -msgstr "Remplissage du garde-corps" +msgid "editor.inspector.field.defaultLevelId.xmrjzp" +msgstr "ID de niveau par défaut" -# Source-Hash: 98dfdac04af3c762 +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gutter enabled" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gutterEnabled.1oxiltf" -msgstr "Gouttière activée" +msgid "editor.inspector.field.depth.1lu11u2" +msgstr "Profondeur" -# Source-Hash: 4bdc3cdf0fe0ac3c +# Source-Hash: 016d8e70618916d4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gutter profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gutterProfile.1ngzqi3" -msgstr "Profil de gouttière" +msgid "editor.inspector.field.diameter.s3robe" +msgstr "Diamètre" -# Source-Hash: 76555670cba9bb13 +# Source-Hash: dab4100e83e4e6b3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gutter size" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diameter2" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gutterSize.jgavtz" -msgstr "Taille de gouttière" +msgid "editor.inspector.field.diameter2.pm6cl4" +msgstr "Diamètre 2" -# Source-Hash: c14d3aa4a98efa98 +# Source-Hash: 5747145349432396 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger max reach" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door duration ms" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.hangerMaxReach.1869epv" -msgstr "Portée max. du support" +msgid "editor.inspector.field.doorDurationMs.13nx909" +msgstr "Durée de porte ms" -# Source-Hash: dfbc357fb556559b +# Source-Hash: 6f4aca26196c221f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.hangerSpacing.i2b5d7" -msgstr "Espacement des supports" +msgid "editor.inspector.field.doorHeight.92r9k4" +msgstr "Hauteur de porte" -# Source-Hash: 3ce5e50c572644ed +# Source-Hash: 990ae81752236e3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door panel style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.hangerStyle.l7v7gb" -msgstr "Style de support" +msgid "editor.inspector.field.doorPanelStyle.2qog4q" +msgstr "Style de panneau de porte" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: c94e002123bb1199 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.height.7puwki" -msgstr "Hauteur" +msgid "editor.inspector.field.doorStyle.gerpos" +msgstr "Style de porte" -# Source-Hash: d0b836103c795726 +# Source-Hash: 91aeb04b0b7b605e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height2" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.height2.7b3jlc" -msgstr "Hauteur 2" +msgid "editor.inspector.field.doorWidth.sy732l" +msgstr "Largeur de porte" -# Source-Hash: 681fd794e601ace5 +# Source-Hash: baad1238f70f79ea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height above ridge" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspout enabled" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.heightAboveRidge.1k99brk" -msgstr "Hauteur au-dessus du faîtage" +msgid "editor.inspector.field.downspoutEnabled.1gn00nv" +msgstr "Descente activée" -# Source-Hash: b4905e5ec62a170f +# Source-Hash: e288531858c4c44d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High edge height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspout position" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.highEdgeHeight.1s7v90t" -msgstr "Hauteur du bord haut" +msgid "editor.inspector.field.downspoutPosition.fxcsop" +msgstr "Position de la descente" -# Source-Hash: c136d5cd7f3ce04a +# Source-Hash: 861d28317325cf61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct material" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.highOverhang.67w55d" -msgstr "Débord haut" +msgid "editor.inspector.field.ductMaterial.i8eonq" +msgstr "Matériau de gaine" -# Source-Hash: 8b4cd537cc650dac +# Source-Hash: ad8ab4ae38c3299c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High side mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch gablet rake" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.highSideMode.1rc1r5j" -msgstr "Mode du côté haut" +msgid "editor.inspector.field.dutchGabletRake.6paydp" +msgstr "Rive du pignon à demi-croupe" -# Source-Hash: c38e4e73ed9779f4 +# Source-Hash: 913d25cf2c5ff179 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hood overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch hip height ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.hoodOverhang.1q1hcin" -msgstr "Débord du capot" +msgid "editor.inspector.field.dutchHipHeightRatio.1etnwgg" +msgstr "Ratio de hauteur de demi-croupe" -# Source-Hash: 9884ee52a0e84c0d +# Source-Hash: f4a80233d49f2b20 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Infill placement" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch hip width ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.infillPlacement.11dxzpo" -msgstr "Position du remplissage" +msgid "editor.inspector.field.dutchHipWidthRatio.1dopfvb" +msgstr "Ratio de largeur de demi-croupe" -# Source-Hash: 37fde9f9290ddc59 +# Source-Hash: 92021b0e37f9a25a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inlet shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch top rake thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.inletShape.ypayh2" -msgstr "Forme d’entrée" +msgid "editor.inspector.field.dutchTopRakeThickness.1w9khxt" +msgstr "Épaisseur de rive haute" -# Source-Hash: d840917007332b94 +# Source-Hash: d0a2ec13d71ce659 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inner radius" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch waist length ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.innerRadius.1fkmg0j" -msgstr "Rayon intérieur" +msgid "editor.inspector.field.dutchWaistLengthRatio.agtoxw" +msgstr "Ratio de longueur de taille" -# Source-Hash: c8ce389856a90ae2 +# Source-Hash: 993396ccca2cd1d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Insulated" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dwell ms" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.insulated.iwziey" -msgstr "Isolé" +msgid "editor.inspector.field.dwellMs.1lkk0o5" +msgstr "Arrêt ms" -# Source-Hash: 043a7a10b6c91f4f +# Source-Hash: 9cf550eb019bca1b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Insulation r" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edge inset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.insulationR.663ufx" -msgstr "Isolation R" +msgid "editor.inspector.field.edgeInset.1obeimx" +msgstr "Retrait de bord" -# Source-Hash: fe661655ba41b709 +# Source-Hash: 8a3bc5111b9e97f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lanternHeight.oz7zpm" -msgstr "Hauteur du lanterneau" +msgid "editor.inspector.field.elevation.4jbp44" +msgstr "Altitude" -# Source-Hash: ab22022e7d5597af +# Source-Hash: 1fc91958e30dbeaf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern top scale" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End cap left" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lanternTopScale.hkmpp2" -msgstr "Échelle du haut du lanterneau" +msgid "editor.inspector.field.endCapLeft.19jel4v" +msgstr "Embout gauche" -# Source-Hash: 17f854a76ebc033a +# Source-Hash: 4c9ae62e0ed70635 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ledger depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End cap right" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.ledgerDepth.7av8k9" -msgstr "Profondeur de la lisse" +msgid "editor.inspector.field.endCapRight.lhse9c" +msgstr "Embout droit" -# Source-Hash: 547d3a8a9e3e24f5 +# Source-Hash: a9cba06250228a55 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ledger height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End caps" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.ledgerHeight.zo2oif" -msgstr "Hauteur de la lisse" +msgid "editor.inspector.field.endCaps.4fsb5b" +msgstr "Embouts" -# Source-Hash: 88603f884243c81e +# Source-Hash: ebad74353b5a7610 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ledger vertical offset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End post" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.ledgerVerticalOffset.1athbgt" -msgstr "Décalage vertical de la lisse" +msgid "editor.inspector.field.endPost.1guwsk0" +msgstr "Poteau d’extrémité" -# Source-Hash: 6519f495202b830d +# Source-Hash: ecbe36df4238439e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left end condition" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equipment type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.leftEndCondition.1syqlaw" -msgstr "Condition d’extrémité gauche" +msgid "editor.inspector.field.equipmentType.1mc2ywt" +msgstr "Type d’équipement" -# Source-Hash: d041b8217c356977 +# Source-Hash: 66f1018b50c2e426 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fill to floor" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.leftOverhang.1ydl9ma" -msgstr "Débord gauche" +msgid "editor.inspector.field.fillToFloor.1oppnkf" +msgstr "Remplir jusqu’au sol" -# Source-Hash: 643687bc3adaac76 +# Source-Hash: 1cfe33235b30b1d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finial" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.length.1kpdcfp" -msgstr "Longueur" +msgid "editor.inspector.field.finial.1ertf4s" +msgstr "Épi de faîtage" -# Source-Hash: d6deaf0ceb9f43af +# Source-Hash: 28cd69e506709f16 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Liquid diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fitting type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.liquidDiameter.w3pk7c" -msgstr "Diamètre liquide" +msgid "editor.inspector.field.fittingType.18mz17s" +msgstr "Type de raccord" -# Source-Hash: 45aca762426392fa +# Source-Hash: 3c1aec5e6fb180cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Louver count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flashing height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.louverCount.lhw2gr" -msgstr "Nombre de lames" +msgid "editor.inspector.field.flashingHeight.3e8nn6" +msgstr "Hauteur du solin" -# Source-Hash: c645a86c55eb0075 +# Source-Hash: 327ba762101db94d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low beam inset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flashing projection" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lowBeamInset.1g7yw5l" -msgstr "Retrait de la poutre basse" +msgid "editor.inspector.field.flashingProjection.hhf0fk" +msgstr "Saillie du solin" -# Source-Hash: 7e7b896682c78c5b +# Source-Hash: 9473e2ab53370b40 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low edge height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lowEdgeHeight.47mae1" -msgstr "Hauteur du bord bas" +msgid "editor.inspector.field.flueCount.j3t2ci" +msgstr "Nombre de conduits" -# Source-Hash: 9deb775fc64854b2 +# Source-Hash: fd0b65425ed3df8b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lowOverhang.t4nz1h" -msgstr "Débord bas" +msgid "editor.inspector.field.flueDiameter.cjhubg" +msgstr "Diamètre du conduit" -# Source-Hash: 9aa621d270fe64b1 +# Source-Hash: 07ebe5e3780c624b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard steep height ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.mansardSteepHeightRatio.1hbb8rq" -msgstr "Ratio de hauteur du brisis mansardé" +msgid "editor.inspector.field.flueHeight.1dhc4y4" +msgstr "Hauteur du conduit" -# Source-Hash: 7cb03b27c632949b +# Source-Hash: ff8319792830d591 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard steep width ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.mansardSteepWidthRatio.6xk6vd" -msgstr "Ratio de largeur du brisis mansardé" +msgid "editor.inspector.field.flueShape.1ealiy4" +msgstr "Forme du conduit" -# Source-Hash: 95772435857a7424 +# Source-Hash: 5acf77854a0030ec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match host roof material" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.matchHostRoofMaterial.s56zwj" -msgstr "Reprendre le matériau du toit porteur" +msgid "editor.inspector.field.flueSpacing.exhzco" +msgstr "Espacement des conduits" -# Source-Hash: dc22618e31654bde +# Source-Hash: 0a64209c0edacaa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match host roof structure" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Footing style" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.matchHostRoofStructure.bojht3" -msgstr "Reprendre la structure du toit porteur" +msgid "editor.inspector.field.footingStyle.e3btg6" +msgstr "Style de semelle" -# Source-Hash: 06b36a09a84fa8b1 +# Source-Hash: fd413477f1a9e5ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mount" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame depth" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.mount.h80tay" -msgstr "Fixation" +msgid "editor.inspector.field.frameDepth.1934a5n" +msgstr "Profondeur du cadre" -# Source-Hash: a288700f96d2b362 +# Source-Hash: 6aa2318fa815e5f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.mountingType.1xvin1e" -msgstr "Type de montage" +msgid "editor.inspector.field.frameThickness.1agxzd8" +msgstr "Épaisseur du cadre" -# Source-Hash: 3087bc9b219af9ef +# Source-Hash: 9a3495a1e3181b56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Neck height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framing strategy" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.neckHeight.19ym8n1" -msgstr "Hauteur du col" +msgid "editor.inspector.field.framingStrategy.3jx9qe" +msgstr "Stratégie d’ossature" -# Source-Hash: 1c0b8a5503c5daeb +# Source-Hash: 49f329aab535fd3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opacity" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "From level id" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.opacity.1pmpfd2" -msgstr "Opacité" +msgid "editor.inspector.field.fromLevelId.15ieejs" +msgstr "ID du niveau de départ" -# Source-Hash: 51b7ab6a0a78d90a +# Source-Hash: dbd062efc7f4fd7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.openingAngle.brhi7c" -msgstr "Angle d’ouverture" +msgid "editor.inspector.field.gableOverhang.2z0obw" +msgstr "Débord de rive" -# Source-Hash: 1d714b576a057902 +# Source-Hash: 517caa8af48afb22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening offset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel lower height ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.openingOffset.wpoqt6" -msgstr "Décalage de l’ouverture" +msgid "editor.inspector.field.gambrelLowerHeightRatio.wqq7lg" +msgstr "Ratio de hauteur du brisis" -# Source-Hash: 55e5629865efd03d +# Source-Hash: 03ecb8f3b625d49d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening side" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel lower width ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.openingSide.18l2iwe" -msgstr "Côté d’ouverture" +msgid "editor.inspector.field.gambrelLowerWidthRatio.uvyb1v" +msgstr "Ratio de largeur du brisis" -# Source-Hash: 9824d357692ecb8a +# Source-Hash: f3ca5555e8c54375 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Operation state" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap x" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.operationState.1lwrz07" -msgstr "État d’ouverture" +msgid "editor.inspector.field.gapX.wjxa7" +msgstr "Écart x" -# Source-Hash: 4f1cbc14dcfb8f3b +# Source-Hash: 2736f7c5dfc7d917 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Outlet shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap y" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.outletShape.lgpqhx" -msgstr "Forme de sortie" +msgid "editor.inspector.field.gapY.mkbl8" +msgstr "Écart y" -# Source-Hash: 88540def2ce16ac5 +# Source-Hash: 5d03ca50d712339b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.overhang.b5ljpv" -msgstr "Débord" +msgid "editor.inspector.field.glassThickness.s97b0x" +msgstr "Épaisseur du vitrage" -# Source-Hash: 50d7e5e370667f63 +# Source-Hash: 4fc3e60be28f60d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground clearance" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.panelHeight.1kf31vk" -msgstr "Hauteur du panneau" +msgid "editor.inspector.field.groundClearance.4os7f0" +msgstr "Garde au sol" -# Source-Hash: 068d9e0adabc4578 +# Source-Hash: 6a22a09b67309545 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guard infill" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.panelWidth.946581" -msgstr "Largeur du panneau" +msgid "editor.inspector.field.guardInfill.16heiig" +msgstr "Remplissage du garde-corps" -# Source-Hash: aca94a3adc0b0f01 +# Source-Hash: 98dfdac04af3c762 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern alignment" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gutter enabled" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.patternAlignment.jd1ht0" -msgstr "Alignement du motif" +msgid "editor.inspector.field.gutterEnabled.1oxiltf" +msgstr "Gouttière activée" -# Source-Hash: 9e9f9408ec2c8f0b +# Source-Hash: 4bdc3cdf0fe0ac3c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gutter profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.patternCount.1r37pve" -msgstr "Nombre de motifs" +msgid "editor.inspector.field.gutterProfile.1ngzqi3" +msgstr "Profil de gouttière" -# Source-Hash: 4712c449e9a42d3b +# Source-Hash: 76555670cba9bb13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern distribution" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gutter size" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.patternDistribution.fmam51" -msgstr "Répartition du motif" +msgid "editor.inspector.field.gutterSize.jgavtz" +msgstr "Taille de gouttière" -# Source-Hash: 63f833f219b9a592 +# Source-Hash: c14d3aa4a98efa98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern remainder" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger max reach" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.patternRemainder.i47p5y" -msgstr "Reste du motif" +msgid "editor.inspector.field.hangerMaxReach.1869epv" +msgstr "Portée max. du support" -# Source-Hash: e0b8f766411329ff +# Source-Hash: dfbc357fb556559b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketProfile.1xgzuyc" -msgstr "Profil des lattes" +msgid "editor.inspector.field.hangerSpacing.i2b5d7" +msgstr "Espacement des supports" -# Source-Hash: dfac7d68ea16e8a8 +# Source-Hash: 3ce5e50c572644ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket rail count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketRailCount.atgt6w" -msgstr "Nombre de lisses" +msgid "editor.inspector.field.hangerStyle.l7v7gb" +msgstr "Style de support" -# Source-Hash: cd2652254a81d288 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketSpacing.p8d98w" -msgstr "Espacement des lattes" +msgid "editor.inspector.field.height.7puwki" +msgstr "Hauteur" -# Source-Hash: 462f6cb03b23d773 +# Source-Hash: d0b836103c795726 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket top" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height2" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketTop.1tskplu" -msgstr "Haut des lattes" +msgid "editor.inspector.field.height2.7b3jlc" +msgstr "Hauteur 2" -# Source-Hash: 0a4dbbe1cf592326 +# Source-Hash: 681fd794e601ace5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket top clearance" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height above ridge" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketTopClearance.16eq1k0" -msgstr "Dégagement en haut des lattes" +msgid "editor.inspector.field.heightAboveRidge.1k99brk" +msgstr "Hauteur au-dessus du faîtage" -# Source-Hash: c99ccea380ca41bf +# Source-Hash: b4905e5ec62a170f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket variation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High edge height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketVariation.f7vl1c" -msgstr "Variation des lattes" +msgid "editor.inspector.field.highEdgeHeight.1s7v90t" +msgstr "Hauteur du bord haut" -# Source-Hash: 798382373625fecd +# Source-Hash: c136d5cd7f3ce04a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketWidth.3fr3rh" -msgstr "Largeur des lattes" +msgid "editor.inspector.field.highOverhang.67w55d" +msgstr "Débord haut" -# Source-Hash: 48ce215c3be034c7 +# Source-Hash: 8b4cd537cc650dac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pipe material" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High side mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.pipeMaterial.1ggc2wy" -msgstr "Matériau du tuyau" +msgid "editor.inspector.field.highSideMode.1rc1r5j" +msgstr "Mode du côté haut" -# Source-Hash: 75e3449fc1776d09 +# Source-Hash: c38e4e73ed9779f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pitch" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hood overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.pitch.xe6ekx" -msgstr "Pente" +msgid "editor.inspector.field.hoodOverhang.1q1hcin" +msgstr "Débord du capot" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: 9884ee52a0e84c0d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Infill placement" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.position.1quewx6" -msgstr "Position" +msgid "editor.inspector.field.infillPlacement.11dxzpo" +msgstr "Position du remplissage" -# Source-Hash: d090baf9f08c2280 +# Source-Hash: 37fde9f9290ddc59 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post bracing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inlet shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postBracing.crq8nn" -msgstr "Contreventement des poteaux" +msgid "editor.inspector.field.inletShape.ypayh2" +msgstr "Forme d’entrée" -# Source-Hash: 6467b580eed1d333 +# Source-Hash: d840917007332b94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post cap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inner radius" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postCap.1xcvxrv" -msgstr "Chapeau de poteau" +msgid "editor.inspector.field.innerRadius.1fkmg0j" +msgstr "Rayon intérieur" -# Source-Hash: e1d91cdd16cc6593 +# Source-Hash: c8ce389856a90ae2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulated" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postCount.22r56c" -msgstr "Nombre de poteaux" +msgid "editor.inspector.field.insulated.iwziey" +msgstr "Isolé" -# Source-Hash: d6d8b8653cb43624 +# Source-Hash: 043a7a10b6c91f4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation r" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postDepth.1ko6j1m" -msgstr "Profondeur du poteau" +msgid "editor.inspector.field.insulationR.663ufx" +msgstr "Isolation R" -# Source-Hash: dd071e84e259ee48 +# Source-Hash: fe661655ba41b709 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post inset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postInset.le36li" -msgstr "Retrait du poteau" +msgid "editor.inspector.field.lanternHeight.oz7zpm" +msgstr "Hauteur du lanterneau" -# Source-Hash: 88c5d586822e58f0 +# Source-Hash: ab22022e7d5597af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post layout mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern top scale" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postLayoutMode.16jre62" -msgstr "Mode de répartition des poteaux" +msgid "editor.inspector.field.lanternTopScale.hkmpp2" +msgstr "Échelle du haut du lanterneau" -# Source-Hash: faa36308c1ecb2a9 +# Source-Hash: 17f854a76ebc033a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post size" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ledger depth" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postSize.1jodxek" -msgstr "Taille du poteau" +msgid "editor.inspector.field.ledgerDepth.7av8k9" +msgstr "Profondeur de la lisse" -# Source-Hash: c8e8490c957e01f3 +# Source-Hash: 547d3a8a9e3e24f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ledger height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postSpacing.voppfi" -msgstr "Espacement des poteaux" +msgid "editor.inspector.field.ledgerHeight.zo2oif" +msgstr "Hauteur de la lisse" -# Source-Hash: b98cbe8478508d41 +# Source-Hash: 88603f884243c81e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post through" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ledger vertical offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postThrough.1abgu4a" -msgstr "Poteau traversant" +msgid "editor.inspector.field.ledgerVerticalOffset.1athbgt" +msgstr "Décalage vertical de la lisse" -# Source-Hash: d1492df1fbb22c29 +# Source-Hash: 6519f495202b830d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left end condition" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postWidth.rk26fz" -msgstr "Largeur du poteau" +msgid "editor.inspector.field.leftEndCondition.1syqlaw" +msgstr "Condition d’extrémité gauche" -# Source-Hash: 96ad4bd0f7baa40e +# Source-Hash: d041b8217c356977 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.profile.1kwlci6" -msgstr "Profil" +msgid "editor.inspector.field.leftOverhang.1ydl9ma" +msgstr "Débord gauche" -# Source-Hash: d01cd36d3939abab +# Source-Hash: 643687bc3adaac76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Projection" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.projection.jhtig0" -msgstr "Saillie" +msgid "editor.inspector.field.length.1kpdcfp" +msgstr "Longueur" -# Source-Hash: 800a7a9159519b46 +# Source-Hash: d6deaf0ceb9f43af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Purlin height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Liquid diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.purlinHeight.eo9cjm" -msgstr "Hauteur de panne" +msgid "editor.inspector.field.liquidDiameter.w3pk7c" +msgstr "Diamètre liquide" -# Source-Hash: da4d0d12715d6c33 +# Source-Hash: 45aca762426392fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Purlin spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Louver count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.purlinSpacing.4gbzb2" -msgstr "Espacement des pannes" +msgid "editor.inspector.field.louverCount.lhw2gr" +msgstr "Nombre de lames" -# Source-Hash: b4774bcbdf599812 +# Source-Hash: c645a86c55eb0075 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Purlin width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low beam inset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.purlinWidth.r6tu3j" -msgstr "Largeur de panne" +msgid "editor.inspector.field.lowBeamInset.1g7yw5l" +msgstr "Retrait de la poutre basse" -# Source-Hash: 2a4dd54f8a8c15ef +# Source-Hash: 7e7b896682c78c5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafter end inset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low edge height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rafterEndInset.14c0wy5" -msgstr "Retrait d’about de chevron" +msgid "editor.inspector.field.lowEdgeHeight.47mae1" +msgstr "Hauteur du bord bas" -# Source-Hash: 5a80a11b97c0e043 +# Source-Hash: 9deb775fc64854b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafter height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rafterHeight.1e1n99w" -msgstr "Hauteur de chevron" +msgid "editor.inspector.field.lowOverhang.t4nz1h" +msgstr "Débord bas" -# Source-Hash: b6348d554660af5b +# Source-Hash: 9aa621d270fe64b1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafter spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard steep height ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rafterSpacing.19subc0" -msgstr "Espacement des chevrons" +msgid "editor.inspector.field.mansardSteepHeightRatio.1hbb8rq" +msgstr "Ratio de hauteur du brisis mansardé" -# Source-Hash: 112c447946c3beaa +# Source-Hash: 7cb03b27c632949b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafter width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard steep width ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rafterWidth.eksj4t" -msgstr "Largeur de chevron" +msgid "editor.inspector.field.mansardSteepWidthRatio.6xk6vd" +msgstr "Ratio de largeur du brisis mansardé" -# Source-Hash: 7020d720876a2106 +# Source-Hash: 95772435857a7424 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match host roof material" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.railingHeight.6wf4bm" -msgstr "Hauteur du garde-corps" - -# Source-Hash: 3e89ce193885b5b4 +msgid "editor.inspector.field.matchHostRoofMaterial.s56zwj" +msgstr "Reprendre le matériau du toit porteur" + +# Source-Hash: dc22618e31654bde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match host roof structure" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.railingMode.ov7xpu" -msgstr "Mode du garde-corps" +msgid "editor.inspector.field.matchHostRoofStructure.bojht3" +msgstr "Reprendre la structure du toit porteur" -# Source-Hash: 174342bb31a86afc +# Source-Hash: 06b36a09a84fa8b1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mount" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.railingStyle.1nyd2u" -msgstr "Style de garde-corps" +msgid "editor.inspector.field.mount.h80tay" +msgstr "Fixation" -# Source-Hash: a44eedc895b95474 +# Source-Hash: a288700f96d2b362 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Resize lock" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.resizeLock.b2hbr0" -msgstr "Verrouiller les proportions" +msgid "editor.inspector.field.mountingType.1xvin1e" +msgstr "Type de montage" -# Source-Hash: edd319917231def8 +# Source-Hash: 3087bc9b219af9ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Neck height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.returnDiameter.166ozhe" -msgstr "Diamètre de reprise" +msgid "editor.inspector.field.neckHeight.19ym8n1" +msgstr "Hauteur du col" -# Source-Hash: dafa151b183daa77 +# Source-Hash: 1c0b8a5503c5daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opacity" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.returnHeight.b9sq6y" -msgstr "Hauteur de reprise" +msgid "editor.inspector.field.opacity.1pmpfd2" +msgstr "Opacité" -# Source-Hash: cd55fd029ad2803b +# Source-Hash: 51b7ab6a0a78d90a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.returnShape.1e3a27i" -msgstr "Forme de reprise" +msgid "editor.inspector.field.openingAngle.brhi7c" +msgstr "Angle d’ouverture" -# Source-Hash: 6a7c411667124177 +# Source-Hash: 1d714b576a057902 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.returnWidth.z9r3h3" -msgstr "Largeur de reprise" +msgid "editor.inspector.field.openingOffset.wpoqt6" +msgstr "Décalage de l’ouverture" -# Source-Hash: 460bd11bfc2e5697 +# Source-Hash: 55e5629865efd03d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right end condition" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening side" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rightEndCondition.tjlw3l" -msgstr "Condition d’extrémité droite" +msgid "editor.inspector.field.openingSide.18l2iwe" +msgstr "Côté d’ouverture" -# Source-Hash: 1ed35f8d27ae5583 +# Source-Hash: 9824d357692ecb8a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Operation state" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rightOverhang.yqbeft" -msgstr "Débord droit" +msgid "editor.inspector.field.operationState.1lwrz07" +msgstr "État d’ouverture" -# Source-Hash: 39c02aa2d97a62ba +# Source-Hash: 4f1cbc14dcfb8f3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outlet shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.roofHeight.1uhy6qy" -msgstr "Hauteur du toit" +msgid "editor.inspector.field.outletShape.lgpqhx" +msgstr "Forme de sortie" -# Source-Hash: d62f8833d77ca8a1 +# Source-Hash: 88540def2ce16ac5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.roofStyle.pawqfy" -msgstr "Style de toit" +msgid "editor.inspector.field.overhang.b5ljpv" +msgstr "Débord" -# Source-Hash: 0ddd561a4126b826 +# Source-Hash: 50d7e5e370667f63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.roofThickness.1xlr3rx" -msgstr "Épaisseur du toit" +msgid "editor.inspector.field.panelHeight.1kf31vk" +msgstr "Hauteur du panneau" -# Source-Hash: 3a08ede9e51d5395 +# Source-Hash: 068d9e0adabc4578 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.roofType.1m9kv5h" -msgstr "Type de toit" +msgid "editor.inspector.field.panelWidth.946581" +msgstr "Largeur du panneau" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: aca94a3adc0b0f01 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern alignment" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rotation.ly2rj" -msgstr "Rotation" +msgid "editor.inspector.field.patternAlignment.jd1ht0" +msgstr "Alignement du motif" -# Source-Hash: c913b494c3901a17 +# Source-Hash: 9e9f9408ec2c8f0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rows" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rows.1ba1neg" -msgstr "Rangées" +msgid "editor.inspector.field.patternCount.1r37pve" +msgstr "Nombre de motifs" -# Source-Hash: 8210f376c0d29acc +# Source-Hash: 4712c449e9a42d3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scale" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern distribution" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.scale.b6rpxt" -msgstr "Échelle" +msgid "editor.inspector.field.patternDistribution.fmam51" +msgstr "Répartition du motif" -# Source-Hash: adb6face4bac5245 +# Source-Hash: 63f833f219b9a592 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Seam detail" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern remainder" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.seamDetail.197za48" -msgstr "Détail de joint" +msgid "editor.inspector.field.patternRemainder.i47p5y" +msgstr "Reste du motif" -# Source-Hash: 4b2aed9d56cc4dee +# Source-Hash: e0b8f766411329ff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segment type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.segmentType.l667sy" -msgstr "Type de segment" +msgid "editor.inspector.field.picketProfile.1xgzuyc" +msgstr "Profil des lattes" -# Source-Hash: a7794a81141b4de4 +# Source-Hash: dfac7d68ea16e8a8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket rail count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shaftStyle.1i5ampa" -msgstr "Style de gaine" +msgid "editor.inspector.field.picketRailCount.atgt6w" +msgstr "Nombre de lisses" -# Source-Hash: 8eb6438543b18cdb +# Source-Hash: cd2652254a81d288 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft wall thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shaftWallThickness.bduslr" -msgstr "Épaisseur des parois de gaine" +msgid "editor.inspector.field.picketSpacing.p8d98w" +msgstr "Espacement des lattes" -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: 462f6cb03b23d773 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket top" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shape.iq9t52" -msgstr "Forme" +msgid "editor.inspector.field.picketTop.1tskplu" +msgstr "Haut des lattes" -# Source-Hash: 44a8ab89c854cad1 +# Source-Hash: 0a4dbbe1cf592326 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape2" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket top clearance" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shape2.fi0nx8" -msgstr "Forme 2" +msgid "editor.inspector.field.picketTopClearance.16eq1k0" +msgstr "Dégagement en haut des lattes" -# Source-Hash: fcee9712879570ae +# Source-Hash: c99ccea380ca41bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed high side" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket variation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shedHighSide.bzzddg" -msgstr "Côté haut du monopente" +msgid "editor.inspector.field.picketVariation.f7vl1c" +msgstr "Variation des lattes" -# Source-Hash: f5a931cd6e97e5e2 +# Source-Hash: 798382373625fecd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingle thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shingleThickness.1hn5wxr" -msgstr "Épaisseur des bardeaux" +msgid "editor.inspector.field.picketWidth.3fr3rh" +msgstr "Largeur des lattes" -# Source-Hash: b14990b3e4222dd3 +# Source-Hash: 48ce215c3be034c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder extent" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pipe material" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shoulderExtent.11j8uiv" -msgstr "Étendue de l’épaulement" +msgid "editor.inspector.field.pipeMaterial.1ggc2wy" +msgstr "Matériau du tuyau" -# Source-Hash: 505de343ec5010e6 +# Source-Hash: 75e3449fc1776d09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pitch" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shoulderHeight.xyqn6g" -msgstr "Hauteur de l’épaulement" +msgid "editor.inspector.field.pitch.xe6ekx" +msgstr "Pente" -# Source-Hash: 58d48c01b7ec1a40 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shoulderStyle.1hkcv2w" -msgstr "Style d’épaulement" +msgid "editor.inspector.field.position.1quewx6" +msgstr "Position" -# Source-Hash: af84db1026bf2e6c +# Source-Hash: d090baf9f08c2280 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show center column" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post bracing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.showCenterColumn.1uggg45" -msgstr "Afficher la colonne centrale" +msgid "editor.inspector.field.postBracing.crq8nn" +msgstr "Contreventement des poteaux" -# Source-Hash: 80214dc086ebc1b1 +# Source-Hash: 6467b580eed1d333 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show infill" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post cap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.showInfill.33rv7u" -msgstr "Afficher le remplissage" +msgid "editor.inspector.field.postCap.1xcvxrv" +msgstr "Chapeau de poteau" -# Source-Hash: f02d6cdfb4c6ad08 +# Source-Hash: e1d91cdd16cc6593 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show step supports" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.showStepSupports.1kg8h8m" -msgstr "Afficher les supports de marche" +msgid "editor.inspector.field.postCount.22r56c" +msgstr "Nombre de poteaux" -# Source-Hash: 5d1147c774718b76 +# Source-Hash: d6d8b8653cb43624 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Side flashing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post depth" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.sideFlashing.cv744o" -msgstr "Solin latéral" +msgid "editor.inspector.field.postDepth.1ko6j1m" +msgstr "Profondeur du poteau" -# Source-Hash: 60bb3338e0ad558c +# Source-Hash: dd071e84e259ee48 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Size" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post inset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.size.1a4x3zw" -msgstr "Taille" +msgid "editor.inspector.field.postInset.le36li" +msgstr "Retrait du poteau" -# Source-Hash: fbdbc6c97c75b030 +# Source-Hash: 88c5d586822e58f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Skylight type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post layout mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.skylightType.1a5vj3i" -msgstr "Type de puits de lumière" +msgid "editor.inspector.field.postLayoutMode.16jre62" +msgstr "Mode de répartition des poteaux" -# Source-Hash: c9a6561cb3c3da82 +# Source-Hash: faa36308c1ecb2a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab opening mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post size" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.slabOpeningMode.g4f730" -msgstr "Mode de trémie de dalle" +msgid "editor.inspector.field.postSize.1jodxek" +msgstr "Taille du poteau" -# Source-Hash: ef0efc845ccdba78 +# Source-Hash: c8e8490c957e01f3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slat gap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.slatGap.slmk93" -msgstr "Écart entre lames" +msgid "editor.inspector.field.postSpacing.voppfi" +msgstr "Espacement des poteaux" -# Source-Hash: 4daab7a2ce2ecef3 +# Source-Hash: b98cbe8478508d41 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slide direction" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post through" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.slideDirection.1527q13" -msgstr "Sens de coulissement" +msgid "editor.inspector.field.postThrough.1abgu4a" +msgstr "Poteau traversant" -# Source-Hash: 93b34a5b546664c4 +# Source-Hash: d1492df1fbb22c29 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Span" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.span.1bmmuw1" -msgstr "Portée" +msgid "editor.inspector.field.postWidth.rk26fz" +msgstr "Largeur du poteau" -# Source-Hash: 3b006be0b1f0493f +# Source-Hash: 96ad4bd0f7baa40e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Speed" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.speed.2w2xwg" -msgstr "Vitesse" +msgid "editor.inspector.field.profile.1kwlci6" +msgstr "Profil" -# Source-Hash: c8cfb8336a240cb1 +# Source-Hash: d01cd36d3939abab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spin speed" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Projection" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.spinSpeed.1ozx746" -msgstr "Vitesse de rotation" +msgid "editor.inspector.field.projection.jhtig0" +msgstr "Saillie" -# Source-Hash: c9f54c3b258961c7 +# Source-Hash: 800a7a9159519b46 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Purlin height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.stairType.1u05e02" -msgstr "Type d’escalier" +msgid "editor.inspector.field.purlinHeight.eo9cjm" +msgstr "Hauteur de panne" -# Source-Hash: 0af6194a8b8d8be6 +# Source-Hash: da4d0d12715d6c33 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standoff" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Purlin spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.standoff.4wv2g0" -msgstr "Entretoise" +msgid "editor.inspector.field.purlinSpacing.4gbzb2" +msgstr "Espacement des pannes" -# Source-Hash: 0464d4efa1e80c62 +# Source-Hash: b4774bcbdf599812 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standoff height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Purlin width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.standoffHeight.1qdnff" -msgstr "Hauteur d’entretoise" +msgid "editor.inspector.field.purlinWidth.r6tu3j" +msgstr "Largeur de panne" -# Source-Hash: 85da28b0b26b8c2a +# Source-Hash: 2a4dd54f8a8c15ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start post" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafter end inset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.startPost.1ood9kv" -msgstr "Poteau de départ" +msgid "editor.inspector.field.rafterEndInset.14c0wy5" +msgstr "Retrait d’about de chevron" -# Source-Hash: d5dc1ba8cca3193d +# Source-Hash: 5a80a11b97c0e043 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Step count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafter height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.stepCount.nzorrw" -msgstr "Nombre de marches" +msgid "editor.inspector.field.rafterHeight.1e1n99w" +msgstr "Hauteur de chevron" -# Source-Hash: cadbb9cadd6a5e6f +# Source-Hash: b6348d554660af5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Strap spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafter spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.strapSpacing.1cyt3dc" -msgstr "Espacement des feuillards" +msgid "editor.inspector.field.rafterSpacing.19subc0" +msgstr "Espacement des chevrons" -# Source-Hash: c017cd56b3ae5865 +# Source-Hash: 112c447946c3beaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Strap style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafter width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.strapStyle.fh1oy4" -msgstr "Style de feuillard" +msgid "editor.inspector.field.rafterWidth.eksj4t" +msgstr "Largeur de chevron" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: 7020d720876a2106 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.style.nf3vcm" -msgstr "Style" +msgid "editor.inspector.field.railingHeight.6wf4bm" +msgstr "Hauteur du garde-corps" -# Source-Hash: 7b3f016989c631a7 +# Source-Hash: 3e89ce193885b5b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Suction diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.suctionDiameter.nutxtj" -msgstr "Diamètre d’aspiration" +msgid "editor.inspector.field.railingMode.ov7xpu" +msgstr "Mode du garde-corps" -# Source-Hash: 3f1e0fd30e5b1f39 +# Source-Hash: 174342bb31a86afc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supplyDiameter.h5ldh5" -msgstr "Diamètre de soufflage" +msgid "editor.inspector.field.railingStyle.1nyd2u" +msgstr "Style de garde-corps" -# Source-Hash: 05c9b608538e181d +# Source-Hash: a44eedc895b95474 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Resize lock" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supplyHeight.zy6ru1" -msgstr "Hauteur de soufflage" +msgid "editor.inspector.field.resizeLock.b2hbr0" +msgstr "Verrouiller les proportions" -# Source-Hash: 3c9400722baa474d +# Source-Hash: edd319917231def8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supplyShape.k39wnb" -msgstr "Forme de soufflage" +msgid "editor.inspector.field.returnDiameter.166ozhe" +msgstr "Diamètre de reprise" -# Source-Hash: af7619025438f995 +# Source-Hash: dafa151b183daa77 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supplyWidth.g66axi" -msgstr "Largeur de soufflage" +msgid "editor.inspector.field.returnHeight.b9sq6y" +msgstr "Hauteur de reprise" -# Source-Hash: 617e198cf3f214d3 +# Source-Hash: cd55fd029ad2803b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Support offset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supportOffset.1w4cocr" -msgstr "Décalage du support" +msgid "editor.inspector.field.returnShape.1e3a27i" +msgstr "Forme de reprise" -# Source-Hash: 2686abc093f3dfb1 +# Source-Hash: 6a7c411667124177 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sweep angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.sweepAngle.ucmmlw" -msgstr "Angle de balayage" +msgid "editor.inspector.field.returnWidth.z9r3h3" +msgstr "Largeur de reprise" -# Source-Hash: 88e6c2e1c344b2fc +# Source-Hash: 460bd11bfc2e5697 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right end condition" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.system.13qbhrw" -msgstr "Système" +msgid "editor.inspector.field.rightEndCondition.tjlw3l" +msgstr "Condition d’extrémité droite" -# Source-Hash: ccb3afc48bd9a284 +# Source-Hash: 1ed35f8d27ae5583 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terminal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.terminal.1501knl" -msgstr "Terminal" +msgid "editor.inspector.field.rightOverhang.yqbeft" +msgstr "Débord droit" -# Source-Hash: de1777c521046f7d +# Source-Hash: 39c02aa2d97a62ba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terminal type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.terminalType.1ne8lgb" -msgstr "Type de terminal" +msgid "editor.inspector.field.roofHeight.1uhy6qy" +msgstr "Hauteur du toit" -# Source-Hash: fdbb503f0941bd56 +# Source-Hash: d62f8833d77ca8a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.thickness.1l8hu45" -msgstr "Épaisseur" +msgid "editor.inspector.field.roofStyle.pawqfy" +msgstr "Style de toit" -# Source-Hash: 58cb60c14826f1d0 +# Source-Hash: 0ddd561a4126b826 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilt angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.tiltAngle.1312yw1" -msgstr "Angle d’inclinaison" +msgid "editor.inspector.field.roofThickness.1xlr3rx" +msgstr "Épaisseur du toit" -# Source-Hash: 7057972ff4c78dc7 +# Source-Hash: 3a08ede9e51d5395 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "To level id" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.toLevelId.8i5qx7" -msgstr "ID du niveau d’arrivée" +msgid "editor.inspector.field.roofType.1m9kv5h" +msgstr "Type de toit" -# Source-Hash: fa8fc3d5c612e774 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top landing depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.topLandingDepth.ki7gk2" -msgstr "Profondeur du palier d’arrivée" +msgid "editor.inspector.field.rotation.ly2rj" +msgstr "Rotation" -# Source-Hash: 6e4a0b98089ec2cd +# Source-Hash: c913b494c3901a17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top landing mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rows" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.topLandingMode.zk0h7e" -msgstr "Mode du palier d’arrivée" +msgid "editor.inspector.field.rows.1ba1neg" +msgstr "Rangées" -# Source-Hash: c182bb3c8a701085 +# Source-Hash: 8210f376c0d29acc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top rail height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scale" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.topRailHeight.fscisv" -msgstr "Hauteur de la lisse haute" +msgid "editor.inspector.field.scale.b6rpxt" +msgstr "Échelle" -# Source-Hash: 8c5502f1d8087b7b +# Source-Hash: adb6face4bac5245 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transition mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Seam detail" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.transitionMode.f3evgt" -msgstr "Mode de transition" +msgid "editor.inspector.field.seamDetail.197za48" +msgstr "Détail de joint" -# Source-Hash: 96eb5997f0aa2dde +# Source-Hash: 4b2aed9d56cc4dee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transition width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segment type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.transitionWidth.rtgz3m" -msgstr "Largeur de transition" +msgid "editor.inspector.field.segmentType.l667sy" +msgstr "Type de segment" -# Source-Hash: 812d27902509339f +# Source-Hash: a7794a81141b4de4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vane count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.vaneCount.55vtye" -msgstr "Nombre d’ailettes" +msgid "editor.inspector.field.shaftStyle.1i5ampa" +msgstr "Style de gaine" -# Source-Hash: 1e7dcd717c8ac239 +# Source-Hash: 8eb6438543b18cdb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft wall thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.wallHeight.18vmh5c" -msgstr "Hauteur du mur" +msgid "editor.inspector.field.shaftWallThickness.bduslr" +msgstr "Épaisseur des parois de gaine" -# Source-Hash: f14bdaed6101896a +# Source-Hash: 85ea1d3c8b749680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall shell" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.wallShell.vqsyhv" -msgstr "Enveloppe murale" +msgid "editor.inspector.field.shape.iq9t52" +msgstr "Forme" -# Source-Hash: 801268585c9a679b +# Source-Hash: 44a8ab89c854cad1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall skirt height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape2" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.wallSkirtHeight.1uea2ad" -msgstr "Hauteur du soubassement" +msgid "editor.inspector.field.shape2.fi0nx8" +msgstr "Forme 2" -# Source-Hash: 6b377d0ba1565477 +# Source-Hash: fcee9712879570ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall thickness" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed high side" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.wallThickness.17wn4iv" -msgstr "Épaisseur du mur" +msgid "editor.inspector.field.shedHighSide.bzzddg" +msgstr "Côté haut du monopente" -# Source-Hash: 3a0ccd6c46877a87 +# Source-Hash: f5a931cd6e97e5e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingle thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.width.gfxz9b" -msgstr "Largeur" +msgid "editor.inspector.field.shingleThickness.1hn5wxr" +msgstr "Épaisseur des bardeaux" -# Source-Hash: de05070474f589b4 +# Source-Hash: b14990b3e4222dd3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width2" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder extent" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.width2.1nqawvr" -msgstr "Largeur 2" +msgid "editor.inspector.field.shoulderExtent.11j8uiv" +msgstr "Étendue de l’épaulement" -# Source-Hash: 6199b641888a83fa +# Source-Hash: 505de343ec5010e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "With back" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.withBack.1ay8nus" -msgstr "Avec fond" +msgid "editor.inspector.field.shoulderHeight.xyqn6g" +msgstr "Hauteur de l’épaulement" -# Source-Hash: 699934d8b9571b64 +# Source-Hash: 58d48c01b7ec1a40 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "With bottom" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.withBottom.1x1z1vo" -msgstr "Avec fond inférieur" +msgid "editor.inspector.field.shoulderStyle.1hkcv2w" +msgstr "Style d’épaulement" -# Source-Hash: 03987b9aadaab50f +# Source-Hash: af84db1026bf2e6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "With sides" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show center column" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.withSides.uq066x" -msgstr "Avec côtés" +msgid "editor.inspector.field.showCenterColumn.1uggg45" +msgstr "Afficher la colonne centrale" -# Source-Hash: f571cb2d06ae01ae +# Source-Hash: 80214dc086ebc1b1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Advanced" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show infill" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.advanced.qwfkor" -msgstr "Avancé" +msgid "editor.inspector.field.showInfill.33rv7u" +msgstr "Afficher le remplissage" -# Source-Hash: a886619d15bae47e +# Source-Hash: f02d6cdfb4c6ad08 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Air" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show step supports" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.air.15jotdj" -msgstr "Air" +msgid "editor.inspector.field.showStepSupports.1kg8h8m" +msgstr "Afficher les supports de marche" -# Source-Hash: b69fc1f8128958fc +# Source-Hash: 5d1147c774718b76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Appearance" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Side flashing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.appearance.dli9wf" -msgstr "Apparence" +msgid "editor.inspector.field.sideFlashing.cv744o" +msgstr "Solin latéral" -# Source-Hash: faaa4f6b40001667 +# Source-Hash: 60bb3338e0ad558c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Body" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Size" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.body.ign4wl" -msgstr "Corps" +msgid "editor.inspector.field.size.1a4x3zw" +msgstr "Taille" -# Source-Hash: fdf7108a011bd94b +# Source-Hash: fbdbc6c97c75b030 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cab" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Skylight type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.cab.o4z1ox" -msgstr "Cabine" +msgid "editor.inspector.field.skylightType.1a5vj3i" +msgstr "Type de puits de lumière" -# Source-Hash: 5737c4567e0f6863 +# Source-Hash: c9a6561cb3c3da82 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab opening mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.cabinet.rzvymr" -msgstr "Meuble" +msgid "editor.inspector.field.slabOpeningMode.g4f730" +msgstr "Mode de trémie de dalle" -# Source-Hash: d52b53241789ee63 +# Source-Hash: ef0efc845ccdba78 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slat gap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.cap.s0thej" -msgstr "Chapeau" +msgid "editor.inspector.field.slatGap.slmk93" +msgstr "Écart entre lames" -# Source-Hash: 93a545688c917e69 +# Source-Hash: 4daab7a2ce2ecef3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slide direction" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.collar.1am2iqo" -msgstr "Collier" +msgid "editor.inspector.field.slideDirection.1527q13" +msgstr "Sens de coulissement" -# Source-Hash: 7a9c55b1c5a6e61d +# Source-Hash: 93b34a5b546664c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connection" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Span" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.connection.2r1h4p" -msgstr "Raccordement" +msgid "editor.inspector.field.span.1bmmuw1" +msgstr "Portée" -# Source-Hash: d613df280aa13b42 +# Source-Hash: 3b006be0b1f0493f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connections" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Speed" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.connections.ai4w8u" -msgstr "Raccordements" +msgid "editor.inspector.field.speed.2w2xwg" +msgstr "Vitesse" -# Source-Hash: ce1429556f57d7ee +# Source-Hash: c8cfb8336a240cb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Construction" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spin speed" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.construction.j6p9kc" -msgstr "Construction" +msgid "editor.inspector.field.spinSpeed.1ozx746" +msgstr "Vitesse de rotation" -# Source-Hash: f8ba7d73d3006d57 +# Source-Hash: c9f54c3b258961c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.cricket.6iwg8g" -msgstr "Costière" +msgid "editor.inspector.field.stairType.1u05e02" +msgstr "Type d’escalier" -# Source-Hash: b8ff053666ee326b +# Source-Hash: 0af6194a8b8d8be6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curb" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standoff" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.curb.5xi2ol" -msgstr "Costière" +msgid "editor.inspector.field.standoff.4wv2g0" +msgstr "Entretoise" -# Source-Hash: 3b9c59e996dcc9c5 +# Source-Hash: 0464d4efa1e80c62 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curve points" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standoff height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.curvePoints.ztdcnn" -msgstr "Points de courbe" +msgid "editor.inspector.field.standoffHeight.1qdnff" +msgstr "Hauteur d’entretoise" -# Source-Hash: 12df69f42beb0643 +# Source-Hash: 85da28b0b26b8c2a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start post" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.dimensions.pewa8g" -msgstr "Dimensions" +msgid "editor.inspector.field.startPost.1ood9kv" +msgstr "Poteau de départ" -# Source-Hash: 20f60b98de67849b +# Source-Hash: d5dc1ba8cca3193d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Doors" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Step count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.doors.18w2kpa" -msgstr "Portes" +msgid "editor.inspector.field.stepCount.nzorrw" +msgstr "Nombre de marches" -# Source-Hash: 6b6f8068bbc4c902 +# Source-Hash: cadbb9cadd6a5e6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dormer" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Strap spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.dormer.1fjs5tq" -msgstr "Lucarne" +msgid "editor.inspector.field.strapSpacing.1cyt3dc" +msgstr "Espacement des feuillards" -# Source-Hash: cda262793b4cc754 +# Source-Hash: c017cd56b3ae5865 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dormer roof" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Strap style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.dormerRoof.u9uy2g" -msgstr "Toit de lucarne" +msgid "editor.inspector.field.strapStyle.fh1oy4" +msgstr "Style de feuillard" -# Source-Hash: 00a4416e0a33d856 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drainage" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.drainage.7easy0" -msgstr "Évacuation" +msgid "editor.inspector.field.style.nf3vcm" +msgstr "Style" -# Source-Hash: 8a3bc5111b9e97f4 +# Source-Hash: 7b3f016989c631a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Suction diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.elevation.4jbp44" -msgstr "Altitude" +msgid "editor.inspector.field.suctionDiameter.nutxtj" +msgstr "Diamètre d’aspiration" -# Source-Hash: a9cba06250228a55 +# Source-Hash: 3f1e0fd30e5b1f39 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End caps" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.endCaps.4fsb5b" -msgstr "Embouts" +msgid "editor.inspector.field.supplyDiameter.h5ldh5" +msgstr "Diamètre de soufflage" -# Source-Hash: 228f2206862e41cf +# Source-Hash: 05c9b608538e181d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equipment" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.equipment.1xtq0ev" -msgstr "Équipement" +msgid "editor.inspector.field.supplyHeight.zy6ru1" +msgstr "Hauteur de soufflage" -# Source-Hash: a19276baa3688cbf +# Source-Hash: 3c9400722baa474d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Face" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.face.1531fr0" -msgstr "Face" +msgid "editor.inspector.field.supplyShape.k39wnb" +msgstr "Forme de soufflage" -# Source-Hash: fb34ee7c59cb84ac +# Source-Hash: af7619025438f995 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fitting" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.fitting.171z1r4" -msgstr "Raccord" +msgid "editor.inspector.field.supplyWidth.g66axi" +msgstr "Largeur de soufflage" -# Source-Hash: f817c09ef0bb6d69 +# Source-Hash: 617e198cf3f214d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flues" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Support offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.flues.nq6pye" -msgstr "Conduits" +msgid "editor.inspector.field.supportOffset.1w4cocr" +msgstr "Décalage du support" -# Source-Hash: a3c10560fa3c1612 +# Source-Hash: 2686abc093f3dfb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Footprint" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sweep angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.footprint.g8q2pg" -msgstr "Emprise" +msgid "editor.inspector.field.sweepAngle.ucmmlw" +msgstr "Angle de balayage" -# Source-Hash: ce3a6c03765dbbd8 +# Source-Hash: 88e6c2e1c344b2fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.frame.q7q9fq" -msgstr "Cadre" +msgid "editor.inspector.field.system.13qbhrw" +msgstr "Système" -# Source-Hash: 523b9912e283b644 +# Source-Hash: ccb3afc48bd9a284 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Geometry" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terminal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.geometry.a21os1" -msgstr "Géométrie" +msgid "editor.inspector.field.terminal.1501knl" +msgstr "Terminal" -# Source-Hash: 7e4a0a38f694be6b +# Source-Hash: de1777c521046f7d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terminal type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.grid.d8gwxd" -msgstr "Grille" +msgid "editor.inspector.field.terminalType.1ne8lgb" +msgstr "Type de terminal" -# Source-Hash: 30d8dba84c42040e +# Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hangers" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.hangers.agnfzn" -msgstr "Supports" +msgid "editor.inspector.field.thickness.1l8hu45" +msgstr "Épaisseur" -# Source-Hash: 8c1bc3a078056ff7 +# Source-Hash: 58cb60c14826f1d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hardware" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilt angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.hardware.1nygwm1" -msgstr "Quincaillerie" +msgid "editor.inspector.field.tiltAngle.1312yw1" +msgstr "Angle d’inclinaison" -# Source-Hash: 2a47557eb4a5f766 +# Source-Hash: 7057972ff4c78dc7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hung wall" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "To level id" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.hungWall.1ftr1gz" -msgstr "Mur suspendu" +msgid "editor.inspector.field.toLevelId.8i5qx7" +msgstr "ID du niveau d’arrivée" -# Source-Hash: 7d6ed24c02ab0c5c +# Source-Hash: fa8fc3d5c612e774 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Insulation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top landing depth" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.insulation.1kyo5e7" -msgstr "Isolation" +msgid "editor.inspector.field.topLandingDepth.ki7gk2" +msgstr "Profondeur du palier d’arrivée" -# Source-Hash: d4c6c2495c233bb5 +# Source-Hash: 6e4a0b98089ec2cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top landing mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.lantern.1h7o2xb" -msgstr "Lanterneau" +msgid "editor.inspector.field.topLandingMode.zk0h7e" +msgstr "Mode du palier d’arrivée" -# Source-Hash: cc3d601d59e2e26c +# Source-Hash: c182bb3c8a701085 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Levels" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top rail height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.levels.1s6yaru" -msgstr "Niveaux" +msgid "editor.inspector.field.topRailHeight.fscisv" +msgstr "Hauteur de la lisse haute" -# Source-Hash: 1a849e52a46d5087 +# Source-Hash: 8c5502f1d8087b7b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Line" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transition mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.line.166mv5z" -msgstr "Ligne" +msgid "editor.inspector.field.transitionMode.f3evgt" +msgstr "Mode de transition" -# Source-Hash: 9ab4f7a738ebee13 +# Source-Hash: 96eb5997f0aa2dde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lines" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transition width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.lines.12bghr0" -msgstr "Lignes" +msgid "editor.inspector.field.transitionWidth.rtgz3m" +msgstr "Largeur de transition" -# Source-Hash: c0ff16d77ebc9593 +# Source-Hash: 812d27902509339f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Motion" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vane count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.motion.1be7sjr" -msgstr "Mouvement" +msgid "editor.inspector.field.vaneCount.55vtye" +msgstr "Nombre d’ailettes" -# Source-Hash: 81d365ccef73068c +# Source-Hash: 1e7dcd717c8ac239 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.mounting.feutd2" -msgstr "Montage" +msgid "editor.inspector.field.wallHeight.18vmh5c" +msgstr "Hauteur du mur" -# Source-Hash: e04298381837252f +# Source-Hash: f14bdaed6101896a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall shell" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.opening.dfet3" -msgstr "Ouverture" +msgid "editor.inspector.field.wallShell.vqsyhv" +msgstr "Enveloppe murale" -# Source-Hash: f46314c54627858d +# Source-Hash: 801268585c9a679b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel dimensions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall skirt height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.panelDimensions.b59qe6" -msgstr "Dimensions des panneaux" - -# Source-Hash: 4712c449e9a42d3b +msgid "editor.inspector.field.wallSkirtHeight.1uea2ad" +msgstr "Hauteur du soubassement" + +# Source-Hash: 6b377d0ba1565477 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern distribution" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.patternDistribution.fmam51" -msgstr "Répartition du motif" +msgid "editor.inspector.field.wallThickness.17wn4iv" +msgstr "Épaisseur du mur" -# Source-Hash: b3be684ac62fbf53 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.placement.13lcvts" -msgstr "Placement" +msgid "editor.inspector.field.width.gfxz9b" +msgstr "Largeur" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: de05070474f589b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width2" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.position.1quewx6" -msgstr "Position" +msgid "editor.inspector.field.width2.1nqawvr" +msgstr "Largeur 2" -# Source-Hash: 96ad4bd0f7baa40e +# Source-Hash: 6199b641888a83fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "With back" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.profile.1kwlci6" -msgstr "Profil" +msgid "editor.inspector.field.withBack.1ay8nus" +msgstr "Avec fond" -# Source-Hash: 240ed9c77627b9a1 +# Source-Hash: 699934d8b9571b64 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "With bottom" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.railing.19a5bnr" -msgstr "Garde-corps" +msgid "editor.inspector.field.withBottom.1x1z1vo" +msgstr "Avec fond inférieur" -# Source-Hash: 2e0aa7113b021c67 +# Source-Hash: 03987b9aadaab50f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "With sides" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.return.1klrjrz" -msgstr "Reprise" +msgid "editor.inspector.field.withSides.uq066x" +msgstr "Avec côtés" -# Source-Hash: 83909f82446ee9c3 +# Source-Hash: f571cb2d06ae01ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Settings" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Advanced" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.settings.ktdb8o" -msgstr "Paramètres" +msgid "editor.inspector.group.advanced.qwfkor" +msgstr "Avancé" -# Source-Hash: 4fc63ad21de30103 +# Source-Hash: a886619d15bae47e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Air" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.shaft.mad9cv" -msgstr "Gaine" +msgid "editor.inspector.group.air.15jotdj" +msgstr "Air" -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: b69fc1f8128958fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Appearance" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.shape.iq9t52" -msgstr "Forme" +msgid "editor.inspector.group.appearance.dli9wf" +msgstr "Apparence" -# Source-Hash: 8c6e3985459dacf9 +# Source-Hash: faaa4f6b40001667 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Body" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.shoulder.1nyfx25" -msgstr "Épaulement" +msgid "editor.inspector.group.body.ign4wl" +msgstr "Corps" -# Source-Hash: 60bb3338e0ad558c +# Source-Hash: fdf7108a011bd94b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Size" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cab" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.size.1a4x3zw" -msgstr "Taille" +msgid "editor.inspector.group.cab.o4z1ox" +msgstr "Cabine" -# Source-Hash: a20c89205a4448d2 +# Source-Hash: 5737c4567e0f6863 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.structure.gezdra" -msgstr "Structure" +msgid "editor.inspector.group.cabinet.rzvymr" +msgstr "Meuble" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: d52b53241789ee63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.style.nf3vcm" -msgstr "Style" +msgid "editor.inspector.group.cap.s0thej" +msgstr "Chapeau" -# Source-Hash: b45f382a67d6c0eb +# Source-Hash: 93a545688c917e69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.supply.1oy2zwu" -msgstr "Soufflage" +msgid "editor.inspector.group.collar.1am2iqo" +msgstr "Collier" -# Source-Hash: 78a454b7ac7a3cd9 +# Source-Hash: 7a9c55b1c5a6e61d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connection" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.surface.wtamqk" -msgstr "Surface" +msgid "editor.inspector.group.connection.2r1h4p" +msgstr "Raccordement" -# Source-Hash: ccb3afc48bd9a284 +# Source-Hash: d613df280aa13b42 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terminal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connections" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.terminal.1501knl" -msgstr "Terminal" +msgid "editor.inspector.group.connections.ai4w8u" +msgstr "Raccordements" -# Source-Hash: 399fc3e62f491f08 +# Source-Hash: ce1429556f57d7ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Topology" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Construction" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.topology.18t8dyc" -msgstr "Topologie" +msgid "editor.inspector.group.construction.j6p9kc" +msgstr "Construction" -# Source-Hash: f425799b82e085ed +# Source-Hash: f8ba7d73d3006d57 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transform" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.transform.1c55ayj" -msgstr "Transformation" +msgid "editor.inspector.group.cricket.6iwg8g" +msgstr "Costière" -# Source-Hash: b778a315e82065a0 +# Source-Hash: b8ff053666ee326b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curb" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.trap.1qc7vhe" -msgstr "Siphon" +msgid "editor.inspector.group.curb.5xi2ol" +msgstr "Costière" -# Source-Hash: c44f7ab8bbd24858 +# Source-Hash: 3b9c59e996dcc9c5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curve points" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.type.1m2zofh" -msgstr "Type" +msgid "editor.inspector.group.curvePoints.ztdcnn" +msgstr "Points de courbe" -# Source-Hash: c8fd17853839516f +# Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Abs" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.abs.132mz8b" -msgstr "ABS" +msgid "editor.inspector.group.dimensions.pewa8g" +msgstr "Dimensions" -# Source-Hash: fd9eb1a16cb6b996 +# Source-Hash: 20f60b98de67849b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Access panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Doors" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.accessPanel.13sptb5" -msgstr "Trappe de visite" +msgid "editor.inspector.group.doors.18w2kpa" +msgstr "Portes" -# Source-Hash: db8064add8c27a5c +# Source-Hash: 6b6f8068bbc4c902 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Air handler" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dormer" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.airHandler.1crnyg3" -msgstr "Centrale de traitement d’air" +msgid "editor.inspector.group.dormer.1fjs5tq" +msgstr "Lucarne" -# Source-Hash: d8234782848be927 +# Source-Hash: cda262793b4cc754 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Alternating" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dormer roof" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.alternating.5jashi" -msgstr "Alterné" +msgid "editor.inspector.group.dormerRoof.u9uy2g" +msgstr "Toit de lucarne" -# Source-Hash: 63cbda7b09662368 +# Source-Hash: 00a4416e0a33d856 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arched" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drainage" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.arched.14188w0" -msgstr "Cintré" +msgid "editor.inspector.group.drainage.7easy0" +msgstr "Évacuation" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: 8a3bc5111b9e97f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.auto.540b06" -msgstr "Auto" +msgid "editor.inspector.group.elevation.4jbp44" +msgstr "Altitude" -# Source-Hash: d18036b75b2c3e4f +# Source-Hash: a9cba06250228a55 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Automatic" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End caps" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.automatic.r122ro" -msgstr "Automatique" +msgid "editor.inspector.group.endCaps.4fsb5b" +msgstr "Embouts" -# Source-Hash: 7ceade8f25b58fe9 +# Source-Hash: 228f2206862e41cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equipment" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.back.1hzmxtu" -msgstr "Retour" +msgid "editor.inspector.group.equipment.1xtq0ev" +msgstr "Équipement" -# Source-Hash: 3eda29328f91485d +# Source-Hash: a19276baa3688cbf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Balusters" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Face" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.balusters.1j3w6ng" -msgstr "Balustres" +msgid "editor.inspector.group.face.1531fr0" +msgstr "Face" -# Source-Hash: f211248ec8619e4c +# Source-Hash: fb34ee7c59cb84ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Band" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fitting" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.band.160umau" -msgstr "Bandeau" +msgid "editor.inspector.group.fitting.171z1r4" +msgstr "Raccord" -# Source-Hash: 8f9ff05c6a3b08a6 +# Source-Hash: f817c09ef0bb6d69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base plate" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flues" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.basePlate.17fcg8k" -msgstr "Platine" +msgid "editor.inspector.group.flues.nq6pye" +msgstr "Conduits" -# Source-Hash: 19ae2360207ecf5a +# Source-Hash: a3c10560fa3c1612 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Boards" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Footprint" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.boards.u14hig" -msgstr "Planches" +msgid "editor.inspector.group.footprint.g8q2pg" +msgstr "Emprise" -# Source-Hash: c0fee00bdfb09d37 +# Source-Hash: ce3a6c03765dbbd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bookshelf" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.bookshelf.ls0zqk" -msgstr "Bibliothèque" +msgid "editor.inspector.group.frame.q7q9fq" +msgstr "Cadre" -# Source-Hash: 69578b7dd7723fa1 +# Source-Hash: 523b9912e283b644 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Both" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Geometry" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.both.mkyb42" -msgstr "Les deux" +msgid "editor.inspector.group.geometry.a21os1" +msgstr "Géométrie" -# Source-Hash: b3a163b453896bef +# Source-Hash: 7e4a0a38f694be6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.bottom.9mpruy" -msgstr "Bas" +msgid "editor.inspector.group.grid.d8gwxd" +msgstr "Grille" -# Source-Hash: e9a89a5e4ac8cd61 +# Source-Hash: 30d8dba84c42040e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hangers" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.box.1nbjcuq" -msgstr "Boîte" +msgid "editor.inspector.group.hangers.agnfzn" +msgstr "Supports" -# Source-Hash: 2c2815df4f724abe +# Source-Hash: 8c1bc3a078056ff7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Break" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hardware" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.break.17spnvc" -msgstr "Rupture" +msgid "editor.inspector.group.hardware.1nygwm1" +msgstr "Quincaillerie" -# Source-Hash: 0d5a25303d3d8058 +# Source-Hash: 2a47557eb4a5f766 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Butterfly" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hung wall" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.butterfly.pvv0g4" -msgstr "Papillon" +msgid "editor.inspector.group.hungWall.1ftr1gz" +msgstr "Mur suspendu" -# Source-Hash: 5e2429ced8144ab4 +# Source-Hash: 7d6ed24c02ab0c5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cable" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cable.fp50zq" -msgstr "Câble" +msgid "editor.inspector.group.insulation.1kyo5e7" +msgstr "Isolation" -# Source-Hash: 69129e514347672a +# Source-Hash: d4c6c2495c233bb5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cast iron" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.castIron.1q2z4qk" -msgstr "Fonte" +msgid "editor.inspector.group.lantern.1h7o2xb" +msgstr "Lanterneau" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: cc3d601d59e2e26c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Levels" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.ceiling.1t2zaqo" -msgstr "Plafond" +msgid "editor.inspector.group.levels.1s6yaru" +msgstr "Niveaux" -# Source-Hash: 5211341ed18f33f6 +# Source-Hash: 1a849e52a46d5087 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Line" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.center.kzdxno" -msgstr "Centre" +msgid "editor.inspector.group.line.166mv5z" +msgstr "Ligne" -# Source-Hash: 65f410261609060b +# Source-Hash: 9ab4f7a738ebee13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center opening" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lines" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.centerOpening.bn1rvw" -msgstr "Ouverture centrale" +msgid "editor.inspector.group.lines.12bghr0" +msgstr "Lignes" -# Source-Hash: cf5f9756cc866f3e +# Source-Hash: c0ff16d77ebc9593 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cleanout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Motion" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cleanout.lww8bm" -msgstr "Regard de nettoyage" +msgid "editor.inspector.group.motion.1be7sjr" +msgstr "Mouvement" -# Source-Hash: e71d1d949f1d1b41 +# Source-Hash: 81d365ccef73068c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Concrete pad" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.concretePad.m1zdij" -msgstr "Dalle béton" +msgid "editor.inspector.group.mounting.feutd2" +msgstr "Montage" -# Source-Hash: a3804c4f5e6aefbc +# Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Condenser" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.condenser.a74nps" -msgstr "Condenseur" +msgid "editor.inspector.group.opening.dfet3" +msgstr "Ouverture" -# Source-Hash: 6786ac75cbe9af57 +# Source-Hash: f46314c54627858d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corbeled" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel dimensions" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.corbeled.bovs4v" -msgstr "En encorbellement" +msgid "editor.inspector.group.panelDimensions.b59qe6" +msgstr "Dimensions des panneaux" -# Source-Hash: 8a4beb9a57edc26e +# Source-Hash: 4712c449e9a42d3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern distribution" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.count.1qoi4r8" -msgstr "Nombre" +msgid "editor.inspector.group.patternDistribution.fmam51" +msgstr "Répartition du motif" -# Source-Hash: db1f8f141714b363 +# Source-Hash: b3be684ac62fbf53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Coupling" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.coupling.111aap2" -msgstr "Manchon" +msgid "editor.inspector.group.placement.13lcvts" +msgstr "Placement" -# Source-Hash: 7a9a92d2e59a3bbc +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Covering specific" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.coveringSpecific.1h9fo8w" -msgstr "Spécifique au revêtement" +msgid "editor.inspector.group.position.1quewx6" +msgstr "Position" -# Source-Hash: d500c4b7827d3390 +# Source-Hash: 96ad4bd0f7baa40e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cross" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cross.1elubzv" -msgstr "Croix" +msgid "editor.inspector.group.profile.1kwlci6" +msgstr "Profil" -# Source-Hash: 7ca7f00b3ba531f4 +# Source-Hash: 240ed9c77627b9a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cubby" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cubby.ivq4qc" -msgstr "Casier" +msgid "editor.inspector.group.railing.19a5bnr" +msgstr "Garde-corps" -# Source-Hash: a028e08962c388e0 +# Source-Hash: 2e0aa7113b021c67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curved" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.curved.6noz1s" -msgstr "Courbe" +msgid "editor.inspector.group.return.1klrjrz" +msgstr "Reprise" -# Source-Hash: c65f02bcdc3231d6 +# Source-Hash: 83909f82446ee9c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cylinder" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Settings" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cylinder.eol6vj" -msgstr "Cylindre" +msgid "editor.inspector.group.settings.ktdb8o" +msgstr "Paramètres" -# Source-Hash: 53f224e2828d5ab7 +# Source-Hash: 4fc63ad21de30103 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Damper" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.damper.wgri80" -msgstr "Registre" +msgid "editor.inspector.group.shaft.mad9cv" +msgstr "Gaine" -# Source-Hash: 748877ae309c313c +# Source-Hash: 85ea1d3c8b749680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Destination" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.destination.gfzm1r" -msgstr "Destination" +msgid "editor.inspector.group.shape.iq9t52" +msgstr "Forme" -# Source-Hash: bfb3561e28d92a39 +# Source-Hash: 8c6e3985459dacf9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diffuser" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.diffuser.1igj0jh" -msgstr "Diffuseur" +msgid "editor.inspector.group.shoulder.1nyfx25" +msgstr "Épaulement" -# Source-Hash: 6cff941e10ff22b3 +# Source-Hash: 60bb3338e0ad558c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dog ear" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Size" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.dogEar.xhtvjt" -msgstr "Oreille de chien" +msgid "editor.inspector.group.size.1a4x3zw" +msgstr "Taille" -# Source-Hash: de47e23eb81efe02 +# Source-Hash: a20c89205a4448d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dome" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.dome.1c87e56" -msgstr "Dôme" +msgid "editor.inspector.group.structure.gezdra" +msgstr "Structure" -# Source-Hash: 3cd71355956a1821 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.double.13h5354" -msgstr "Double" +msgid "editor.inspector.group.style.nf3vcm" +msgstr "Style" -# Source-Hash: 72a84a9762461745 +# Source-Hash: b45f382a67d6c0eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct board" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.ductBoard.lc3o4t" -msgstr "Panneau de gaine" +msgid "editor.inspector.group.supply.1oy2zwu" +msgstr "Soufflage" -# Source-Hash: 6949d667043bee0b +# Source-Hash: 78a454b7ac7a3cd9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.dutch.1djx429" -msgstr "Demi-croupe" +msgid "editor.inspector.group.surface.wtamqk" +msgstr "Surface" -# Source-Hash: e6637bddef6aabd6 +# Source-Hash: ccb3afc48bd9a284 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elbow" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terminal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.elbow.1flup74" -msgstr "Coude" +msgid "editor.inspector.group.terminal.1501knl" +msgstr "Terminal" -# Source-Hash: 135874d189176d13 +# Source-Hash: 399fc3e62f491f08 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Topology" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.end.1llf32i" -msgstr "Fin" +msgid "editor.inspector.group.topology.18t8dyc" +msgstr "Topologie" -# Source-Hash: ada9fc2eec2c7d61 +# Source-Hash: f425799b82e085ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End cap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transform" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.endCap.1p4v4na" -msgstr "Embout" +msgid "editor.inspector.group.transform.1c55ayj" +msgstr "Transformation" -# Source-Hash: 73916b8395208874 +# Source-Hash: b778a315e82065a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equal fit" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.equalFit.11vw52c" -msgstr "Ajustement égal" +msgid "editor.inspector.group.trap.1qc7vhe" +msgstr "Siphon" -# Source-Hash: 83579a6e420df2ec +# Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fixed count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.fixedCount.1o3dznu" -msgstr "Nombre fixe" +msgid "editor.inspector.group.type.1m2zofh" +msgstr "Type" -# Source-Hash: 4fb65101d0b1a222 +# Source-Hash: c8fd17853839516f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fixed spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Abs" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.fixedSpacing.hl4dr4" -msgstr "Espacement fixe" +msgid "editor.inspector.option.abs.132mz8b" +msgstr "ABS" -# Source-Hash: 9cab4d4c95f63cdd +# Source-Hash: fd9eb1a16cb6b996 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Access panel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.flat.ly0bei" -msgstr "Plat" +msgid "editor.inspector.option.accessPanel.13sptb5" +msgstr "Trappe de visite" -# Source-Hash: a9cad0badcc16693 +# Source-Hash: db8064add8c27a5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flex" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Air handler" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.flex.ktpamq" -msgstr "Flexible" +msgid "editor.inspector.option.airHandler.1crnyg3" +msgstr "Centrale de traitement d’air" -# Source-Hash: 7843c5142b7d066d +# Source-Hash: d8234782848be927 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floating" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Alternating" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.floating.1oadpln" -msgstr "Flottant" +msgid "editor.inspector.option.alternating.5jashi" +msgstr "Alterné" -# Source-Hash: d7148fa065bc709b +# Source-Hash: 63cbda7b09662368 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arched" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.floor.q9caf1" -msgstr "Niveau" +msgid "editor.inspector.option.arched.14188w0" +msgstr "Cintré" -# Source-Hash: eaaa20f3b603140f +# Source-Hash: 05b65242d8c48791 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flush" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.flush.olwwu5" -msgstr "Affleurant" +msgid "editor.inspector.option.auto.540b06" +msgstr "Auto" -# Source-Hash: e360f89d3c0ec456 +# Source-Hash: d18036b75b2c3e4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Automatic" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.front.uhugl4" -msgstr "Avant" +msgid "editor.inspector.option.automatic.r122ro" +msgstr "Automatique" -# Source-Hash: bccfc0565157dae6 +# Source-Hash: 7ceade8f25b58fe9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Furnace" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.furnace.w0mzpf" -msgstr "Chaudière à air chaud" +msgid "editor.inspector.option.back.1hzmxtu" +msgstr "Retour" -# Source-Hash: deaffa095d126dfe +# Source-Hash: 3eda29328f91485d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Balusters" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.gable.1ekyx6" -msgstr "Deux pans" +msgid "editor.inspector.option.balusters.1j3w6ng" +msgstr "Balustres" -# Source-Hash: 7f53d9ffca39984a +# Source-Hash: f211248ec8619e4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Band" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.gambrel.1yo90d9" -msgstr "Brisé" +msgid "editor.inspector.option.band.160umau" +msgstr "Bandeau" -# Source-Hash: 3c4900155c96b139 +# Source-Hash: 8f9ff05c6a3b08a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Generic" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base plate" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.generic.1074oey" -msgstr "Générique" +msgid "editor.inspector.option.basePlate.17fcg8k" +msgstr "Platine" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: 19ae2360207ecf5a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Boards" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.glass.163tc5n" -msgstr "Vitrage" +msgid "editor.inspector.option.boards.u14hig" +msgstr "Planches" -# Source-Hash: 88810658a2b97bc6 +# Source-Hash: c0fee00bdfb09d37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass frame" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bookshelf" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.glassFrame.jp9s3m" -msgstr "Cadre vitré" +msgid "editor.inspector.option.bookshelf.ls0zqk" +msgstr "Bibliothèque" -# Source-Hash: 2d4223f80dc3945c +# Source-Hash: 69578b7dd7723fa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Globe" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Both" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.globe.1avkqoy" -msgstr "Globe" +msgid "editor.inspector.option.both.mkyb42" +msgstr "Les deux" -# Source-Hash: 398af4f45ba60c85 +# Source-Hash: b3a163b453896bef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grounded" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.grounded.jwoq73" -msgstr "Au sol" +msgid "editor.inspector.option.bottom.9mpruy" +msgstr "Bas" -# Source-Hash: 4972a0e68d69be58 +# Source-Hash: e9a89a5e4ac8cd61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guard" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.guard.1m575se" -msgstr "Garde-corps" +msgid "editor.inspector.option.box.1nbjcuq" +msgstr "Boîte" -# Source-Hash: 67be98efb58a7767 +# Source-Hash: 2c2815df4f724abe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Half round" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Break" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.halfRound.m5hob0" -msgstr "Demi-rond" +msgid "editor.inspector.option.break.17spnvc" +msgstr "Rupture" -# Source-Hash: 229199467e9cf2db +# Source-Hash: 0d5a25303d3d8058 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hidden" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Butterfly" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.hidden.gp48rd" -msgstr "Masqué" +msgid "editor.inspector.option.butterfly.pvv0g4" +msgstr "Papillon" -# Source-Hash: 9eda0ea8d447066d +# Source-Hash: 5e2429ced8144ab4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hip" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cable" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.hip.r0jnjy" -msgstr "Croupe" +msgid "editor.inspector.option.cable.fp50zq" +msgstr "Câble" -# Source-Hash: ac9c79f08ef130a1 +# Source-Hash: 69129e514347672a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Horizontal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cast iron" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.horizontal.tyapah" -msgstr "Horizontal" +msgid "editor.inspector.option.castIron.1q2z4qk" +msgstr "Fonte" -# Source-Hash: 6a9b4142ab179557 +# Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Include" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.include.1a27vnr" -msgstr "Inclure" +msgid "editor.inspector.option.ceiling.1t2zaqo" +msgstr "Plafond" -# Source-Hash: 8061b426b9d1b5fa +# Source-Hash: 5211341ed18f33f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Independent high beam" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.independentHighBeam.1tn0zvy" -msgstr "Poutre haute indépendante" +msgid "editor.inspector.option.center.kzdxno" +msgstr "Centre" -# Source-Hash: 1dc686f2068f976b +# Source-Hash: 65f410261609060b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Industrial" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center opening" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.industrial.8sd9u" -msgstr "Industriel" +msgid "editor.inspector.option.centerOpening.bn1rvw" +msgstr "Ouverture centrale" -# Source-Hash: 0c9b1ec8947ee177 +# Source-Hash: cf5f9756cc866f3e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inline" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cleanout" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.inline.1uh05lg" -msgstr "En ligne" +msgid "editor.inspector.option.cleanout.lww8bm" +msgstr "Regard de nettoyage" -# Source-Hash: 88d5b9ecb242c650 +# Source-Hash: e71d1d949f1d1b41 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Integrated" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Concrete pad" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.integrated.1xd9lv0" -msgstr "Intégré" +msgid "editor.inspector.option.concretePad.m1zdij" +msgstr "Dalle béton" -# Source-Hash: bb197b9219f32603 +# Source-Hash: a3804c4f5e6aefbc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Joined" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Condenser" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.joined.1x2o8ds" -msgstr "Joint" +msgid "editor.inspector.option.condenser.a74nps" +msgstr "Condenseur" -# Source-Hash: 0299cc0ee05d17fc +# Source-Hash: 6786ac75cbe9af57 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kickout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corbeled" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.kickout.vt8s6p" -msgstr "Déflecteur" +msgid "editor.inspector.option.corbeled.bovs4v" +msgstr "En encorbellement" -# Source-Hash: a0712c8461bb0758 +# Source-Hash: 8a4beb9a57edc26e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Knee" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.knee.186hcui" -msgstr "Jambette" +msgid "editor.inspector.option.count.1qoi4r8" +msgstr "Nombre" -# Source-Hash: 083febe9876348ec +# Source-Hash: db1f8f141714b363 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "K style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Coupling" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.kStyle.m8kfwz" -msgstr "Style K" +msgid "editor.inspector.option.coupling.111aap2" +msgstr "Manchon" -# Source-Hash: de9566487b17a73b +# Source-Hash: 7a9a92d2e59a3bbc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Covering specific" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.landing.tyqarg" -msgstr "Palier" +msgid "editor.inspector.option.coveringSpecific.1h9fo8w" +msgstr "Spécifique au revêtement" -# Source-Hash: d4c6c2495c233bb5 +# Source-Hash: d500c4b7827d3390 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cross" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.lantern.1h7o2xb" -msgstr "Lanterneau" +msgid "editor.inspector.option.cross.1elubzv" +msgstr "Croix" -# Source-Hash: 9477f663422698ae +# Source-Hash: 7ca7f00b3ba531f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Leave" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cubby" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.leave.1xf0sbk" -msgstr "Quitter" +msgid "editor.inspector.option.cubby.ivq4qc" +msgstr "Casier" -# Source-Hash: f365c6b6dd9ebab9 +# Source-Hash: a028e08962c388e0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curved" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.left.14n06mo" -msgstr "Gauche" +msgid "editor.inspector.option.curved.6noz1s" +msgstr "Courbe" -# Source-Hash: 0608743fc1736d86 +# Source-Hash: c65f02bcdc3231d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cylinder" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.level.i4lhtp" -msgstr "Niveau" +msgid "editor.inspector.option.cylinder.eol6vj" +msgstr "Cylindre" -# Source-Hash: a281a83a9fef6b88 +# Source-Hash: 53f224e2828d5ab7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Damper" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.lowProfile.1h9lgzg" -msgstr "Profil bas" +msgid "editor.inspector.option.damper.wgri80" +msgstr "Registre" -# Source-Hash: 7f7bb0e875af3260 +# Source-Hash: 748877ae309c313c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Destination" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.mansard.dwzck9" -msgstr "Mansarde" +msgid "editor.inspector.option.destination.gfzm1r" +msgstr "Destination" -# Source-Hash: 387082cd5f118bed +# Source-Hash: bfb3561e28d92a39 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Manual" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diffuser" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.manual.1wu7r43" -msgstr "Manuel" +msgid "editor.inspector.option.diffuser.1igj0jh" +msgstr "Diffuseur" -# Source-Hash: 321ca5101ab61db7 +# Source-Hash: 6cff941e10ff22b3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Maximum spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dog ear" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.maximumSpacing.n1fzl4" -msgstr "Espacement maximal" +msgid "editor.inspector.option.dogEar.xhtvjt" +msgstr "Oreille de chien" -# Source-Hash: 8e464a8f52254f27 +# Source-Hash: de47e23eb81efe02 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Metal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dome" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.metal.1az9fgc" -msgstr "Métal" +msgid "editor.inspector.option.dome.1c87e56" +msgstr "Dôme" -# Source-Hash: c6185ecb219a9435 +# Source-Hash: 3cd71355956a1821 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Metal panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.metalPanel.1xdz476" -msgstr "Panneau métallique" +msgid "editor.inspector.option.double.13h5354" +msgstr "Double" -# Source-Hash: 2fd92342f3986843 +# Source-Hash: 72a84a9762461745 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Minimal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct board" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.minimal.fwmiwg" -msgstr "Minimal" +msgid "editor.inspector.option.ductBoard.lc3o4t" +msgstr "Panneau de gaine" -# Source-Hash: 5d8a5912056f83ce +# Source-Hash: 6949d667043bee0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mono" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.mono.oszvd6" -msgstr "Monopente" +msgid "editor.inspector.option.dutch.1djx429" +msgstr "Demi-croupe" -# Source-Hash: f2953d2931e36d0c +# Source-Hash: e6637bddef6aabd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elbow" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.none.deku7v" -msgstr "Aucun" +msgid "editor.inspector.option.elbow.1flup74" +msgstr "Coude" -# Source-Hash: 7b6e4a6b86ba5112 +# Source-Hash: 135874d189176d13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Omit" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.omit.okcs7w" -msgstr "Omettre" +msgid "editor.inspector.option.end.1llf32i" +msgstr "Fin" -# Source-Hash: 3e52f04f92e08070 +# Source-Hash: ada9fc2eec2c7d61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End cap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.open.n6hn1l" -msgstr "Ouvrir" +msgid "editor.inspector.option.endCap.1p4v4na" +msgstr "Embout" -# Source-Hash: e04298381837252f +# Source-Hash: 73916b8395208874 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equal fit" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.opening.dfet3" -msgstr "Ouverture" +msgid "editor.inspector.option.equalFit.11vw52c" +msgstr "Ajustement égal" -# Source-Hash: cc72b9bda6b30b5c +# Source-Hash: 83579a6e420df2ec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open rack" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fixed count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.openRack.mvt1x0" -msgstr "Étagère ouverte" +msgid "editor.inspector.option.fixedCount.1o3dznu" +msgstr "Nombre fixe" -# Source-Hash: ed6d7b3dd9d5fc69 +# Source-Hash: 4fb65101d0b1a222 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Oval" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fixed spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.oval.1jiqzxx" -msgstr "Ovale" +msgid "editor.inspector.option.fixedSpacing.hl4dr4" +msgstr "Espacement fixe" -# Source-Hash: 9295ddc2805b21e2 +# Source-Hash: 9cab4d4c95f63cdd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.picket.zyeoy1" -msgstr "Piquets" - -# Source-Hash: 180ffb8b75c977aa +msgid "editor.inspector.option.flat.ly0bei" +msgstr "Plat" + +# Source-Hash: a9cad0badcc16693 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pointed" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flex" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.pointed.effedk" -msgstr "Pointu" +msgid "editor.inspector.option.flex.ktpamq" +msgstr "Flexible" -# Source-Hash: fca7919fb0c0669c +# Source-Hash: 7843c5142b7d066d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post and rail" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floating" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.postAndRail.lajk2u" -msgstr "Poteaux et lisses" +msgid "editor.inspector.option.floating.1oadpln" +msgstr "Flottant" -# Source-Hash: a78b28a428b27e20 +# Source-Hash: d7148fa065bc709b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preserve high edge" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.preserveHighEdge.y6ywf0" -msgstr "Conserver le bord haut" +msgid "editor.inspector.option.floor.q9caf1" +msgstr "Niveau" -# Source-Hash: 325c6f53f6dc7634 +# Source-Hash: eaaa20f3b603140f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preserve low edge" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flush" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.preserveLowEdge.196m5pk" -msgstr "Conserver le bord bas" +msgid "editor.inspector.option.flush.olwwu5" +msgstr "Affleurant" -# Source-Hash: 95c0b860d22a62cb +# Source-Hash: e360f89d3c0ec456 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preserve pitch" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.preservePitch.1uq973r" -msgstr "Conserver la pente" +msgid "editor.inspector.option.front.uhugl4" +msgstr "Avant" -# Source-Hash: d4e11841abf22593 +# Source-Hash: bccfc0565157dae6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Privacy" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Furnace" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.privacy.1th4hrb" -msgstr "Intimité" +msgid "editor.inspector.option.furnace.w0mzpf" +msgstr "Chaudière à air chaud" -# Source-Hash: 1a8c46c7712a83b6 +# Source-Hash: deaffa095d126dfe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Purlins" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.purlins.od124c" -msgstr "Pannes" +msgid "editor.inspector.option.gable.1ekyx6" +msgstr "Deux pans" -# Source-Hash: a9650f6f94de9247 +# Source-Hash: 7f53d9ffca39984a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pvc" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.pvc.1oc4u2w" -msgstr "PVC" +msgid "editor.inspector.option.gambrel.1yo90d9" +msgstr "Brisé" -# Source-Hash: 47587b825e9a696b +# Source-Hash: 3c4900155c96b139 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pyramid" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Generic" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.pyramid.17ucsqv" -msgstr "Pyramide" +msgid "editor.inspector.option.generic.1074oey" +msgstr "Générique" -# Source-Hash: a9cb232546779779 +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafters" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.rafters.16tzbby" -msgstr "Chevrons" +msgid "editor.inspector.option.glass.163tc5n" +msgstr "Vitrage" -# Source-Hash: 947eacd2689daced +# Source-Hash: 88810658a2b97bc6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rail" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass frame" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.rail.39zqc9" -msgstr "Lisse" +msgid "editor.inspector.option.glassFrame.jp9s3m" +msgstr "Cadre vitré" -# Source-Hash: bd50bd18e682db41 +# Source-Hash: 2d4223f80dc3945c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Globe" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.raised.4kyx9h" -msgstr "Surélevé" +msgid "editor.inspector.option.globe.1avkqoy" +msgstr "Globe" -# Source-Hash: 3b6f225112035fde +# Source-Hash: 398af4f45ba60c85 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rect" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grounded" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.rect.tpfvaf" -msgstr "Rect." +msgid "editor.inspector.option.grounded.jwoq73" +msgstr "Au sol" -# Source-Hash: 68206f70689b2340 +# Source-Hash: 4972a0e68d69be58 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reducer" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guard" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.reducer.18byt67" -msgstr "Réduction" +msgid "editor.inspector.option.guard.1m575se" +msgstr "Garde-corps" -# Source-Hash: 2e0aa7113b021c67 +# Source-Hash: 67be98efb58a7767 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Half round" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.return.1klrjrz" -msgstr "Reprise" +msgid "editor.inspector.option.halfRound.m5hob0" +msgstr "Demi-rond" -# Source-Hash: 63b39b1681f74fe4 +# Source-Hash: 229199467e9cf2db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return grille" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hidden" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.returnGrille.r28ncm" -msgstr "Grille de reprise" +msgid "editor.inspector.option.hidden.gp48rd" +msgstr "Masqué" -# Source-Hash: b34d5ee0f218221d +# Source-Hash: 9eda0ea8d447066d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hip" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.right.8humpx" -msgstr "Droite" +msgid "editor.inspector.option.hip.r0jnjy" +msgstr "Croupe" -# Source-Hash: ad0457800a1f0eb4 +# Source-Hash: ac9c79f08ef130a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Horizontal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.round.1vx0wyj" -msgstr "Rond" +msgid "editor.inspector.option.horizontal.tyapah" +msgstr "Horizontal" -# Source-Hash: fc826da6c99303e6 +# Source-Hash: 6a9b4142ab179557 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rounded" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Include" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.rounded.199nwpm" -msgstr "Arrondi" +msgid "editor.inspector.option.include.1a27vnr" +msgstr "Inclure" -# Source-Hash: dc67a1cdb2482f23 +# Source-Hash: 8061b426b9d1b5fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sanitary tee" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Independent high beam" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.sanitaryTee.oro3d4" -msgstr "Té sanitaire" +msgid "editor.inspector.option.independentHighBeam.1tn0zvy" +msgstr "Poutre haute indépendante" -# Source-Hash: beb3fec22c287185 +# Source-Hash: 1dc686f2068f976b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scalloped" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Industrial" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.scalloped.1eltba0" -msgstr "Festonné" +msgid "editor.inspector.option.industrial.8sd9u" +msgstr "Industriel" -# Source-Hash: e16f85e4bebfefb1 +# Source-Hash: 0c9b1ec8947ee177 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scoop" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inline" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.scoop.qy5zdv" -msgstr "Écope" +msgid "editor.inspector.option.inline.1uh05lg" +msgstr "En ligne" -# Source-Hash: f9a95d8407fafda4 +# Source-Hash: 88d5b9ecb242c650 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segmented panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Integrated" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.segmentedPanel.5r3hwl" -msgstr "Panneau segmenté" +msgid "editor.inspector.option.integrated.1xd9lv0" +msgstr "Intégré" -# Source-Hash: c8d0df27faa3feaa +# Source-Hash: bb197b9219f32603 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Joined" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.shed.6t994v" -msgstr "Appentis" +msgid "editor.inspector.option.joined.1x2o8ds" +msgstr "Joint" -# Source-Hash: 7fbc26cd497cfd12 +# Source-Hash: 0299cc0ee05d17fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sheet metal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kickout" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.sheetMetal.l164lv" -msgstr "Tôle" +msgid "editor.inspector.option.kickout.vt8s6p" +msgstr "Déflecteur" -# Source-Hash: 26e2c261223cbb46 +# Source-Hash: a0712c8461bb0758 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Knee" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.shingle.pfmynh" -msgstr "Bardeau" +msgid "editor.inspector.option.knee.186hcui" +msgstr "Jambette" -# Source-Hash: e9046e9823b400a0 +# Source-Hash: 083febe9876348ec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingled" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "K style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.shingled.1nm9inf" -msgstr "En bardeaux" +msgid "editor.inspector.option.kStyle.m8kfwz" +msgstr "Style K" -# Source-Hash: a05a390ae205fdd8 +# Source-Hash: de9566487b17a73b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Simple" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.simple.12mfu73" -msgstr "Simple" +msgid "editor.inspector.option.landing.tyqarg" +msgstr "Palier" -# Source-Hash: 62ab2eb3c775da95 +# Source-Hash: d4c6c2495c233bb5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.single.1uzxurt" -msgstr "Simple" +msgid "editor.inspector.option.lantern.1h7o2xb" +msgstr "Lanterneau" -# Source-Hash: aee3b2bd78c87d0b +# Source-Hash: 9477f663422698ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single left" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Leave" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.singleLeft.1atdh02" -msgstr "Simple gauche" +msgid "editor.inspector.option.leave.1xf0sbk" +msgstr "Quitter" -# Source-Hash: cc43ffbef4ac7ae0 +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single right" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.singleRight.1axbu67" -msgstr "Simple droite" +msgid "editor.inspector.option.left.14n06mo" +msgstr "Gauche" -# Source-Hash: 7672d2764445c110 +# Source-Hash: 0608743fc1736d86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slant box" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.slantBox.1ta99vy" -msgstr "Boîte inclinée" +msgid "editor.inspector.option.level.i4lhtp" +msgstr "Niveau" -# Source-Hash: 405e07a8cc2c88e1 +# Source-Hash: a281a83a9fef6b88 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slat" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.slat.1p9njbz" -msgstr "Lame" +msgid "editor.inspector.option.lowProfile.1h9lgzg" +msgstr "Profil bas" -# Source-Hash: 18cbc73c5e1590aa +# Source-Hash: 7f7bb0e875af3260 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sliding" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.sliding.cd0jox" -msgstr "Coulissante" +msgid "editor.inspector.option.mansard.dwzck9" +msgstr "Mansarde" -# Source-Hash: e6d82e606b8c9301 +# Source-Hash: 387082cd5f118bed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slope" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Manual" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.slope.1bn2qw" -msgstr "Pente" +msgid "editor.inspector.option.manual.1wu7r43" +msgstr "Manuel" -# Source-Hash: f6998707123fe72d +# Source-Hash: 321ca5101ab61db7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sloped" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Maximum spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.sloped.lo4sh0" -msgstr "En pente" +msgid "editor.inspector.option.maximumSpacing.n1fzl4" +msgstr "Espacement maximal" -# Source-Hash: ef3e765e692faf4c +# Source-Hash: 8e464a8f52254f27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Metal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.solid.o4uy6s" -msgstr "Plein" +msgid "editor.inspector.option.metal.1az9fgc" +msgstr "Métal" -# Source-Hash: 8008b6f17089beaf +# Source-Hash: c6185ecb219a9435 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Metal panel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.solidPanel.2yaw62" -msgstr "Panneau plein" +msgid "editor.inspector.option.metalPanel.1xdz476" +msgstr "Panneau métallique" -# Source-Hash: f9a4a870cb3d3c41 +# Source-Hash: 2fd92342f3986843 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spiral" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Minimal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.spiral.91hcl4" -msgstr "Hélicoïdal" +msgid "editor.inspector.option.minimal.fwmiwg" +msgstr "Minimal" -# Source-Hash: beef1cf79388b77b +# Source-Hash: 5d8a5912056f83ce # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Splash" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mono" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.splash.1uke4cm" -msgstr "Pare-éclaboussures" +msgid "editor.inspector.option.mono.oszvd6" +msgstr "Monopente" -# Source-Hash: 324677a79ab15e22 +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spread" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.spread.1g1zysu" -msgstr "Écartement" +msgid "editor.inspector.option.none.deku7v" +msgstr "Aucun" -# Source-Hash: 39287346366fc206 +# Source-Hash: 7b6e4a6b86ba5112 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Omit" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.square.1xl1lk6" -msgstr "Carré" +msgid "editor.inspector.option.omit.okcs7w" +msgstr "Omettre" -# Source-Hash: 53d7084bc41c1ad6 +# Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.stair.1xf86e" -msgstr "Escalier" +msgid "editor.inspector.option.open.n6hn1l" +msgstr "Ouvrir" -# Source-Hash: d998c212030bc7c2 +# Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.standard.vuco" -msgstr "Standard" +msgid "editor.inspector.option.opening.dfet3" +msgstr "Ouverture" -# Source-Hash: 0a26a1e61c825660 +# Source-Hash: cc72b9bda6b30b5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open rack" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.start.30xvgf" -msgstr "Début" +msgid "editor.inspector.option.openRack.mvt1x0" +msgstr "Étagère ouverte" -# Source-Hash: ed3989f23a2d185e +# Source-Hash: ed6d7b3dd9d5fc69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Step" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Oval" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.step.jtn9kf" -msgstr "Gradin" +msgid "editor.inspector.option.oval.1jiqzxx" +msgstr "Ovale" -# Source-Hash: 2c6b1cf17a973d67 +# Source-Hash: 9295ddc2805b21e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stepped" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.stepped.naxzh0" -msgstr "En gradins" +msgid "editor.inspector.option.picket.zyeoy1" +msgstr "Piquets" -# Source-Hash: 4ee35f740730ae87 +# Source-Hash: 180ffb8b75c977aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pointed" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.straight.lxqbfr" -msgstr "Droit" +msgid "editor.inspector.option.pointed.effedk" +msgstr "Pointu" -# Source-Hash: b9b45ac5ba1daeee +# Source-Hash: fca7919fb0c0669c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Strap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post and rail" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.strap.14q0ps9" -msgstr "Feuillard" +msgid "editor.inspector.option.postAndRail.lajk2u" +msgstr "Poteaux et lisses" -# Source-Hash: b45f382a67d6c0eb +# Source-Hash: a78b28a428b27e20 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preserve high edge" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.supply.1oy2zwu" -msgstr "Soufflage" +msgid "editor.inspector.option.preserveHighEdge.y6ywf0" +msgstr "Conserver le bord haut" -# Source-Hash: 00e7a2b3b2aa36ac +# Source-Hash: 325c6f53f6dc7634 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply register" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preserve low edge" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.supplyRegister.1lzdbbn" -msgstr "Bouche de soufflage" +msgid "editor.inspector.option.preserveLowEdge.196m5pk" +msgstr "Conserver le bord bas" -# Source-Hash: f86f1f22230596b7 +# Source-Hash: 95c0b860d22a62cb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tapered" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preserve pitch" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.tapered.3y5blo" -msgstr "Effilé" +msgid "editor.inspector.option.preservePitch.1uq973r" +msgstr "Conserver la pente" -# Source-Hash: 5fed23c2217b83fb +# Source-Hash: d4e11841abf22593 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Privacy" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.targetSpacing.14uibc9" -msgstr "Espacement cible" +msgid "editor.inspector.option.privacy.1th4hrb" +msgstr "Intimité" -# Source-Hash: f3ceed7f867f090f +# Source-Hash: 1a8c46c7712a83b6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tee" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Purlins" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.tee.7d6tjp" -msgstr "Té" +msgid "editor.inspector.option.purlins.od124c" +msgstr "Pannes" -# Source-Hash: 787005b26aec58a3 +# Source-Hash: a9650f6f94de9247 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilted" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pvc" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.tilted.6n0u5j" -msgstr "Incliné" +msgid "editor.inspector.option.pvc.1oc4u2w" +msgstr "PVC" -# Source-Hash: 27644f0497fd9849 +# Source-Hash: 47587b825e9a696b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pyramid" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.top.2nypcs" -msgstr "Haut" +msgid "editor.inspector.option.pyramid.17ucsqv" +msgstr "Pyramide" -# Source-Hash: e6657000554dfe53 +# Source-Hash: a9cb232546779779 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transition" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafters" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.transition.1rziz9e" -msgstr "Transition" +msgid "editor.inspector.option.rafters.16tzbby" +msgstr "Chevrons" -# Source-Hash: 04bc0909a133a7e9 +# Source-Hash: 947eacd2689daced # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vent" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rail" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.vent.xda5j2" -msgstr "Ventilation" +msgid "editor.inspector.option.rail.39zqc9" +msgstr "Lisse" -# Source-Hash: 7eee9aff0dd520b6 +# Source-Hash: bd50bd18e682db41 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walk on" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.walkOn.1n5sg9l" -msgstr "Marcher sur" +msgid "editor.inspector.option.raised.4kyx9h" +msgstr "Surélevé" -# Source-Hash: 2210e5ee50b74dc9 +# Source-Hash: 3b6f225112035fde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rect" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wall.blj585" -msgstr "Mur" +msgid "editor.inspector.option.rect.tpfvaf" +msgstr "Rect." -# Source-Hash: f3578f7177ad0054 +# Source-Hash: 68206f70689b2340 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall abutment" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reducer" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wallAbutment.lza941" -msgstr "Appui contre le mur" +msgid "editor.inspector.option.reducer.18byt67" +msgstr "Réduction" -# Source-Hash: 8dcf182f91ba3245 +# Source-Hash: 2e0aa7113b021c67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall ledger" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wallLedger.5m8ana" -msgstr "Lisse murale" +msgid "editor.inspector.option.return.1klrjrz" +msgstr "Reprise" -# Source-Hash: 0adda30be5f17975 +# Source-Hash: 63b39b1681f74fe4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall shelf" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return grille" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wallShelf.yiozfl" -msgstr "Étagère murale" +msgid "editor.inspector.option.returnGrille.r28ncm" +msgstr "Grille de reprise" -# Source-Hash: 29d8590334492601 +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waste" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.waste.3xrp79" -msgstr "Eaux usées" +msgid "editor.inspector.option.right.8humpx" +msgstr "Droite" -# Source-Hash: 00249876bb37079f +# Source-Hash: ad0457800a1f0eb4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wye" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wye.14vupc8" -msgstr "Culotte" +msgid "editor.inspector.option.round.1vx0wyj" +msgstr "Rond" -# Source-Hash: 179b025e25f9a091 +# Source-Hash: fc826da6c99303e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collapse" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rounded" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.collapse" -msgstr "Réduire" +msgid "editor.inspector.option.rounded.199nwpm" +msgstr "Arrondi" -# Source-Hash: dbeae4c43f49327f +# Source-Hash: dc67a1cdb2482f23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling ({area})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sanitary tee" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.ceiling" -msgstr "Plafond ({area})" +msgid "editor.inspector.option.sanitaryTee.oro3d4" +msgstr "Té sanitaire" -# Source-Hash: d29165c9d4bfc3cb +# Source-Hash: beb3fec22c287185 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collection" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scalloped" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.collection" -msgstr "Collection" +msgid "editor.inspector.option.scalloped.1eltba0" +msgstr "Festonné" -# Source-Hash: 8f536b859be662a0 +# Source-Hash: e16f85e4bebfefb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flight ({width}×{length}m)" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scoop" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.flight" -msgstr "Volée ({width}×{length}m)" +msgid "editor.inspector.option.scoop.qy5zdv" +msgstr "Écope" -# Source-Hash: 46dcbf4548374073 +# Source-Hash: f9a95d8407fafda4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing ({width}×{length}m)" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segmented panel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.landing" -msgstr "Palier ({width}×{length}m)" +msgid "editor.inspector.option.segmentedPanel.5r3hwl" +msgstr "Panneau segmenté" -# Source-Hash: 3ea44453fcd08a6e +# Source-Hash: c8d0df27faa3feaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Node" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.node" -msgstr "Nœud" +msgid "editor.inspector.option.shed.6t994v" +msgstr "Appentis" -# Source-Hash: 93f3a04e15b6fb49 +# Source-Hash: 7fbc26cd497cfd12 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof ({count, plural, one {# segment} other {# segments}})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sheet metal" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.roof" -msgstr "Toit ({count, plural, one {# segment} many {# segments} other {# segments}})" +msgid "editor.inspector.option.sheetMetal.l164lv" +msgstr "Tôle" -# Source-Hash: a730fab01c172704 +# Source-Hash: 26e2c261223cbb46 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{roofType, select, hip {Hip} gable {Gable} shed {Shed} gambrel {Gambrel} dutch {Dutch} mansard {Mansard} flat {Flat} conical {Conical} barrel {Barrel} other {Roof}} ({width}×{depth}m)" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.roofSegment" -msgstr "{roofType, select, hip {Croupe} gable {Pignon} shed {Monopente} gambrel {Gambrel} dutch {Demi-croupe} mansard {Mansarde} flat {Plat} conical {Conique} barrel {Voûte} other {Toit}} ({width}×{depth}m)" +msgid "editor.inspector.option.shingle.pfmynh" +msgstr "Bardeau" -# Source-Hash: 54efcb0756c2f2c1 +# Source-Hash: e9046e9823b400a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room ({area})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingled" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.room" -msgstr "Pièce ({area})" +msgid "editor.inspector.option.shingled.1nm9inf" +msgstr "En bardeaux" -# Source-Hash: e38a4b9986a9d21a +# Source-Hash: a05a390ae205fdd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab ({area})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Simple" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.slab" -msgstr "Dalle ({area})" +msgid "editor.inspector.option.simple.12mfu73" +msgstr "Simple" -# Source-Hash: 57398365d4b9066f +# Source-Hash: 62ab2eb3c775da95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Staircase ({count, plural, one {# segment} other {# segments}})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.staircase" -msgstr "Escalier ({count, plural, one {# segment} many {# segments} other {# segments}})" +msgid "editor.inspector.option.single.1uzxurt" +msgstr "Simple" -# Source-Hash: a17f8fc29aae896e +# Source-Hash: aee3b2bd78c87d0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone ({area})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single left" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.zone" -msgstr "Zone ({area})" +msgid "editor.inspector.option.singleLeft.1atdh02" +msgstr "Simple gauche" -# Source-Hash: 5cabcabb8bc14809 +# Source-Hash: cc43ffbef4ac7ae0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Expand" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single right" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.expand" -msgstr "Développer" +msgid "editor.inspector.option.singleRight.1axbu67" +msgstr "Simple droite" -# Source-Hash: 6731e9dd94e8b268 +# Source-Hash: 7672d2764445c110 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{levelName} options" -#: packages/editor/src/components/ui/floating-level-selector.tsx -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slant box" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.levelOptions" -msgstr "Options de {levelName}" +msgid "editor.inspector.option.slantBox.1ta99vy" +msgstr "Boîte inclinée" -# Source-Hash: d6952b4e54d246dd +# Source-Hash: 405e07a8cc2c88e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rename" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slat" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.rename" -msgstr "Renommer" +msgid "editor.inspector.option.slat.1p9njbz" +msgstr "Lame" -# Source-Hash: 21eafa019ad62fea +# Source-Hash: 18cbc73c5e1590aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{role, select, room {Room colour} other {Zone colour}}" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx -#: packages/editor/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sliding" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.spaceColour" -msgstr "{role, select, room {Couleur de la pièce} other {Couleur de la zone}}" +msgid "editor.inspector.option.sliding.cd0jox" +msgstr "Coulissante" -# Source-Hash: f5de042416a2c04f +# Source-Hash: e6d82e606b8c9301 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unit colour" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slope" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.unitColour" -msgstr "Couleur du logement" +msgid "editor.inspector.option.slope.1bn2qw" +msgstr "Pente" -# Source-Hash: c0774c185060fc13 +# Source-Hash: f6998707123fe72d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sloped" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.cancel" -msgstr "Annuler" +msgid "editor.inspector.option.sloped.lo4sh0" +msgstr "En pente" -# Source-Hash: 07c11e7e4d4681d6 +# Source-Hash: ef3e765e692faf4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose what to copy from {levelName}." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.chooseWhatToCopyFromLevel" -msgstr "Choisissez ce qu’il faut copier depuis {levelName}." +msgid "editor.inspector.option.solid.o4uy6s" +msgstr "Plein" -# Source-Hash: 9500d4378a319532 +# Source-Hash: 8008b6f17089beaf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose what to copy from this level." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid panel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.chooseWhatToCopyFromThisLevel" -msgstr "Choisissez ce qu’il faut copier depuis ce niveau." +msgid "editor.inspector.option.solidPanel.2yaw62" +msgstr "Panneau plein" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: f9a4a870cb3d3c41 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spiral" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.duplicate" -msgstr "Dupliquer" +msgid "editor.inspector.option.spiral.91hcl4" +msgstr "Hélicoïdal" -# Source-Hash: a56e3eb43e60b45c +# Source-Hash: beef1cf79388b77b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate Level" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Splash" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.duplicateLevel" -msgstr "Dupliquer le niveau" +msgid "editor.inspector.option.splash.1uke4cm" +msgstr "Pare-éclaboussures" -# Source-Hash: e4c6ab1ea473a082 +# Source-Hash: 324677a79ab15e22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Everything" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spread" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.everything" -msgstr "Tout" +msgid "editor.inspector.option.spread.1g1zysu" +msgstr "Écartement" -# Source-Hash: ac3f119e560388ab +# Source-Hash: 39287346366fc206 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure, finishes, and placed items, without guide references." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureFinishesAndPlacedItemsWithout" -msgstr "Structure, finitions et éléments placés, sans références de calque." +msgid "editor.inspector.option.square.1xl1lk6" +msgstr "Carré" -# Source-Hash: acbdf968391d5273 +# Source-Hash: 53d7084bc41c1ad6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure + furniture" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureFurniture" -msgstr "Structure + mobilier" +msgid "editor.inspector.option.stair.1xf86e" +msgstr "Escalier" -# Source-Hash: ce682864a140fe75 +# Source-Hash: d998c212030bc7c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure + materials" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureMaterials" -msgstr "Structure + matériaux" +msgid "editor.inspector.option.standard.vuco" +msgstr "Standard" -# Source-Hash: 5ee44d53847c5ea2 +# Source-Hash: 0a26a1e61c825660 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure, materials, furniture, and references." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureMaterialsFurnitureAndReferences" -msgstr "Structure, matériaux, mobilier et références." +msgid "editor.inspector.option.start.30xvgf" +msgstr "Début" -# Source-Hash: 95aa1b43dbdb3f02 +# Source-Hash: ed3989f23a2d185e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure only" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Step" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureOnly" -msgstr "Structure seule" +msgid "editor.inspector.option.step.jtn9kf" +msgstr "Gradin" -# Source-Hash: 2c53b46c9ca9fe2f +# Source-Hash: 2c6b1cf17a973d67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure with the current material and finish assignments." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stepped" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureWithTheCurrentMaterialAnd" -msgstr "Structure avec les matériaux et finitions actuellement attribués." +msgid "editor.inspector.option.stepped.naxzh0" +msgstr "En gradins" -# Source-Hash: 3350e9008eaba15d +# Source-Hash: 4ee35f740730ae87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls, slabs, roofs, stairs, windows, and doors without finishes." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.wallsSlabsRoofsStairsWindowsAnd" -msgstr "Murs, dalles, toits, escaliers, fenêtres et portes, sans finitions." +msgid "editor.inspector.option.straight.lxqbfr" +msgstr "Droit" -# Source-Hash: 395fd0821b203517 +# Source-Hash: b9b45ac5ba1daeee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add or remove objects from the selection" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Strap" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.addOrRemoveObjectsFromThe" -msgstr "Ajouter ou retirer des objets de la sélection" +msgid "editor.inspector.option.strap.14q0ps9" +msgstr "Feuillard" -# Source-Hash: 8428cb0af9c6d6a0 +# Source-Hash: b45f382a67d6c0eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Adjust one side’s corner radius" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.adjustOneSideSCornerRadius" -msgstr "Ajuster le rayon d’angle d’un côté" +msgid "editor.inspector.option.supply.1oy2zwu" +msgstr "Soufflage" -# Source-Hash: d63b45c195713993 +# Source-Hash: 00e7a2b3b2aa36ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear the selection (or click outside)" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply register" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.clearTheSelectionOrClickOutside" -msgstr "Effacer la sélection (ou cliquer à l’extérieur)" +msgid "editor.inspector.option.supplyRegister.1lzdbbn" +msgstr "Bouche de soufflage" -# Source-Hash: 40b1afbeadbd6213 +# Source-Hash: f86f1f22230596b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click a handle dot to show move arrows" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tapered" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.clickAHandleDotToShow" -msgstr "Cliquez sur une poignée pour afficher les flèches de déplacement" +msgid "editor.inspector.option.tapered.3y5blo" +msgstr "Effilé" -# Source-Hash: 0b82a35c71549580 +# Source-Hash: 5fed23c2217b83fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click or drag the selection to move it as one" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target spacing" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.clickOrDragTheSelectionTo" -msgstr "Cliquez ou faites glisser la sélection pour la déplacer d’un bloc" +msgid "editor.inspector.option.targetSpacing.14uibc9" +msgstr "Espacement cible" -# Source-Hash: 73a761f393f69cb9 +# Source-Hash: f3ceed7f867f090f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click the handle dot to show move + rotate handles" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tee" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.clickTheHandleDotToShow" -msgstr "Cliquez sur la poignée pour afficher les poignées de déplacement et de rotation" +msgid "editor.inspector.option.tee.7d6tjp" +msgstr "Té" -# Source-Hash: c0045cef191fee69 +# Source-Hash: 787005b26aec58a3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Detach the joint while dragging an arrow" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilted" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.detachTheJointWhileDraggingAn" -msgstr "Détacher la jonction en faisant glisser une flèche" +msgid "editor.inspector.option.tilted.6n0u5j" +msgstr "Incliné" -# Source-Hash: a019c8948c104a9e +# Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag left or right to rotate selected object" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.dragLeftOrRightToRotate" -msgstr "Faites glisser à gauche ou à droite pour faire pivoter l’objet sélectionné" +msgid "editor.inspector.option.top.2nypcs" +msgstr "Haut" -# Source-Hash: 7db0364deb12f06e +# Source-Hash: e6657000554dfe53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag selected movable object" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transition" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.dragSelectedMovableObject" -msgstr "Faire glisser l’objet mobile sélectionné" +msgid "editor.inspector.option.transition.1rziz9e" +msgstr "Transition" -# Source-Hash: 0f258dd389afdc73 +# Source-Hash: 04bc0909a133a7e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Group selection (session only)" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vent" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.groupSelectionSessionOnly" -msgstr "Grouper la sélection (session uniquement)" +msgid "editor.inspector.option.vent.xda5j2" +msgstr "Ventilation" -# Source-Hash: 85330d62893a45c3 +# Source-Hash: 7eee9aff0dd520b6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hold to rotate freely" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walk on" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.holdToRotateFreely" -msgstr "Maintenez pour pivoter librement" +msgid "editor.inspector.option.walkOn.1n5sg9l" +msgstr "Marcher sur" -# Source-Hash: 8a665ecaeffa9308 +# Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ±45°" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.rotate45" -msgstr "Pivoter de ±45°" +msgid "editor.inspector.option.wall.blj585" +msgstr "Mur" -# Source-Hash: 6099ee99f8c38700 +# Source-Hash: f3578f7177ad0054 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate the selection ±45°" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall abutment" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.rotateTheSelection45" -msgstr "Pivoter la sélection de ±45°" +msgid "editor.inspector.option.wallAbutment.lza941" +msgstr "Appui contre le mur" -# Source-Hash: 0f6b418b18ff96f3 +# Source-Hash: 8dcf182f91ba3245 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotating freely (no angle step)" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall ledger" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.rotatingFreely" -msgstr "Rotation libre (sans pas d’angle)" +msgid "editor.inspector.option.wallLedger.5m8ana" +msgstr "Lisse murale" -# Source-Hash: 7ed174d6b03563b1 +# Source-Hash: 0adda30be5f17975 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Switch the rotation axis (Y → X → Z)" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall shelf" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.switchTheRotationAxisYX" -msgstr "Changer l’axe de rotation (Y → X → Z)" +msgid "editor.inspector.option.wallShelf.yiozfl" +msgstr "Étagère murale" -# Source-Hash: d6f2c5cea683de62 +# Source-Hash: 29d8590334492601 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ungroup session selection" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waste" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.ungroupSessionSelection" -msgstr "Dissocier la sélection de session" +msgid "editor.inspector.option.waste.3xrp79" +msgstr "Eaux usées" -# Source-Hash: 384842ae1e1c6825 +# Source-Hash: 00249876bb37079f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuous" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wye" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.continuation.continuous" -msgstr "Continu" +msgid "editor.inspector.option.wye.14vupc8" +msgstr "Culotte" -# Source-Hash: ebf0eb7af4636a16 +# Source-Hash: 179b025e25f9a091 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuous canopy" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collapse" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx #, fuzzy -msgid "editor.lib.continuation.continuousCanopy" -msgstr "Auvent continu" +msgid "editor.layers.collapse" +msgstr "Réduire" -# Source-Hash: 1d8e87cd807e8d40 +# Source-Hash: dbeae4c43f49327f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuous run" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling ({area})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.continuousRun" -msgstr "Rangée continue" +msgid "editor.layers.defaultName.ceiling" +msgstr "Plafond ({area})" -# Source-Hash: 8990683667567c6b +# Source-Hash: d29165c9d4bfc3cb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curved fence" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collection" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx #, fuzzy -msgid "editor.lib.continuation.curvedFence" -msgstr "Clôture courbe" +msgid "editor.layers.defaultName.collection" +msgstr "Collection" -# Source-Hash: edf1b9a2ad3ab910 +# Source-Hash: 8f536b859be662a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Freehand fence" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight ({width}×{length}m)" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.freehandFence" -msgstr "Clôture libre" +msgid "editor.layers.defaultName.flight" +msgstr "Volée ({width}×{length}m)" -# Source-Hash: 2cdb7c1c7cd7c4fd +# Source-Hash: 46dcbf4548374073 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place multiple" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing ({width}×{length}m)" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.placeMultiple" -msgstr "Placer plusieurs" +msgid "editor.layers.defaultName.landing" +msgstr "Palier ({width}×{length}m)" -# Source-Hash: 90bf945df6f9c979 +# Source-Hash: 3ea44453fcd08a6e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place once" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Node" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx #, fuzzy -msgid "editor.lib.continuation.placeOnce" -msgstr "Placer une fois" +msgid "editor.layers.defaultName.node" +msgstr "Nœud" -# Source-Hash: 8ec6152e139b0e3f +# Source-Hash: 93f3a04e15b6fb49 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Polygon room" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof ({count, plural, one {# segment} other {# segments}})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.polygonRoom" -msgstr "Pièce polygonale" +msgid "editor.layers.defaultName.roof" +msgstr "Toit ({count, plural, one {# segment} many {# segments} other {# segments}})" -# Source-Hash: 83a45603ac7f41e8 +# Source-Hash: a730fab01c172704 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangle room" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{roofType, select, hip {Hip} gable {Gable} shed {Shed} gambrel {Gambrel} dutch {Dutch} mansard {Mansard} flat {Flat} conical {Conical} barrel {Barrel} other {Roof}} ({width}×{depth}m)" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.rectangleRoom" -msgstr "Pièce rectangulaire" +msgid "editor.layers.defaultName.roofSegment" +msgstr "{roofType, select, hip {Croupe} gable {Pignon} shed {Monopente} gambrel {Gambrel} dutch {Demi-croupe} mansard {Mansarde} flat {Plat} conical {Conique} barrel {Voûte} other {Toit}} ({width}×{depth}m)" -# Source-Hash: 7fd85d0408141157 +# Source-Hash: 54efcb0756c2f2c1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single cabinet" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room ({area})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.singleCabinet" -msgstr "Meuble seul" +msgid "editor.layers.defaultName.room" +msgstr "Pièce ({area})" -# Source-Hash: dd1bdbc26165baa5 +# Source-Hash: e38a4b9986a9d21a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single canopy" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab ({area})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.singleCanopy" -msgstr "Auvent seul" +msgid "editor.layers.defaultName.slab" +msgstr "Dalle ({area})" -# Source-Hash: 5fb1a69316be983e +# Source-Hash: 57398365d4b9066f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single fence" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Staircase ({count, plural, one {# segment} other {# segments}})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.singleFence" -msgstr "Clôture simple" +msgid "editor.layers.defaultName.staircase" +msgstr "Escalier ({count, plural, one {# segment} many {# segments} other {# segments}})" -# Source-Hash: aac9a732d2159ccc +# Source-Hash: a17f8fc29aae896e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone ({area})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.walls" -msgstr "Murs" +msgid "editor.layers.defaultName.zone" +msgstr "Zone ({area})" -# Source-Hash: 4e4f1a24e4a9d61e +# Source-Hash: 5cabcabb8bc14809 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut opening" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Expand" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx #, fuzzy -msgid "editor.lib.hudTitle.cutOpening" -msgstr "Découper une ouverture" +msgid "editor.layers.expand" +msgstr "Développer" -# Source-Hash: 60e8d235f3084a9e +# Source-Hash: 6731e9dd94e8b268 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Divide room" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{levelName} options" +#: packages/editor/src/components/ui/floating-level-selector.tsx +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.lib.hudTitle.divideRoom" -msgstr "Diviser la pièce" +msgid "editor.layers.levelOptions" +msgstr "Options de {levelName}" -# Source-Hash: aa496ec33d21ab03 +# Source-Hash: d6952b4e54d246dd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit {kind}" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rename" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx #, fuzzy -msgid "editor.lib.hudTitle.editKind" -msgstr "Modifier : {kind}" +msgid "editor.layers.rename" +msgstr "Renommer" -# Source-Hash: f3ea3efa7102844f +# Source-Hash: 21eafa019ad62fea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Erase" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{role, select, room {Room colour} other {Zone colour}}" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#: packages/editor/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.lib.hudTitle.erase" -msgstr "Effacer" +msgid "editor.layers.spaceColour" +msgstr "{role, select, room {Couleur de la pièce} other {Couleur de la zone}}" -# Source-Hash: 3f907e76526472bf +# Source-Hash: f5de042416a2c04f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level terrain" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unit colour" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.lib.hudTitle.levelTerrain" -msgstr "Niveler le terrain" +msgid "editor.layers.unitColour" +msgstr "Couleur du logement" -# Source-Hash: 4e911c300d74eb47 +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lower terrain" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.lowerTerrain" -msgstr "Abaisser le terrain" +msgid "editor.levelDuplicateDialog.cancel" +msgstr "Annuler" -# Source-Hash: 194a147d4618a994 +# Source-Hash: 07c11e7e4d4681d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose what to copy from {levelName}." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.mezzanine" -msgstr "Mezzanine" +msgid "editor.levelDuplicateDialog.chooseWhatToCopyFromLevel" +msgstr "Choisissez ce qu’il faut copier depuis {levelName}." -# Source-Hash: c48c4129c9ed249a +# Source-Hash: 9500d4378a319532 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move {kind}" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose what to copy from this level." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.moveKind" -msgstr "Déplacer : {kind}" +msgid "editor.levelDuplicateDialog.chooseWhatToCopyFromThisLevel" +msgstr "Choisissez ce qu’il faut copier depuis ce niveau." -# Source-Hash: 89f6b7ca8904c656 +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move room" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.moveRoom" -msgstr "Déplacer la pièce" +msgid "editor.levelDuplicateDialog.duplicate" +msgstr "Dupliquer" -# Source-Hash: 9c707069572fb3db +# Source-Hash: a56e3eb43e60b45c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move selection" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate Level" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.moveSelection" -msgstr "Déplacer la sélection" +msgid "editor.levelDuplicateDialog.duplicateLevel" +msgstr "Dupliquer le niveau" -# Source-Hash: cf2e870fce0f2f51 +# Source-Hash: e4c6ab1ea473a082 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Everything" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.paint" -msgstr "Peindre" +msgid "editor.levelDuplicateDialog.everything" +msgstr "Tout" -# Source-Hash: ca197314cb70aa56 +# Source-Hash: ac3f119e560388ab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint a rectangle" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure, finishes, and placed items, without guide references." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.paintARectangle" -msgstr "Peindre un rectangle" +msgid "editor.levelDuplicateDialog.structureFinishesAndPlacedItemsWithout" +msgstr "Structure, finitions et éléments placés, sans références de calque." -# Source-Hash: ea4ce729e17254f8 +# Source-Hash: acbdf968391d5273 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint a shape" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure + furniture" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.paintAShape" -msgstr "Peindre une forme" +msgid "editor.levelDuplicateDialog.structureFurniture" +msgstr "Structure + mobilier" -# Source-Hash: 01359502b07284d4 +# Source-Hash: ce682864a140fe75 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick material" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure + materials" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.pickMaterial" -msgstr "Prélever un matériau" +msgid "editor.levelDuplicateDialog.structureMaterials" +msgstr "Structure + matériaux" -# Source-Hash: 4066e8a3f60b1711 +# Source-Hash: 5ee44d53847c5ea2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raise terrain" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure, materials, furniture, and references." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.raiseTerrain" -msgstr "Surélever le terrain" +msgid "editor.levelDuplicateDialog.structureMaterialsFurnitureAndReferences" +msgstr "Structure, matériaux, mobilier et références." -# Source-Hash: f85bdac0a1d16603 +# Source-Hash: 95aa1b43dbdb3f02 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Resize" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure only" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.resize" -msgstr "Redimensionner" +msgid "editor.levelDuplicateDialog.structureOnly" +msgstr "Structure seule" -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: 2c53b46c9ca9fe2f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure with the current material and finish assignments." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.rotate" -msgstr "Pivoter" +msgid "editor.levelDuplicateDialog.structureWithTheCurrentMaterialAnd" +msgstr "Structure avec les matériaux et finitions actuellement attribués." -# Source-Hash: a4395168488bb476 +# Source-Hash: 3350e9008eaba15d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls, slabs, roofs, stairs, windows, and doors without finishes." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.select" -msgstr "Sélectionner" +msgid "editor.levelDuplicateDialog.wallsSlabsRoofsStairsWindowsAnd" +msgstr "Murs, dalles, toits, escaliers, fenêtres et portes, sans finitions." -# Source-Hash: ec1f1d68af469867 +# Source-Hash: 4f60d1e142affa9c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Smart measure" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Copy" +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx #, fuzzy -msgid "editor.lib.hudTitle.smartMeasure" -msgstr "Mesure intelligente" +msgid "editor.levelWallCopyPrompt.copy" +msgstr "Copier" -# Source-Hash: 5ba5f22bd1a69e09 +# Source-Hash: 8ccaf4c98e335cc8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Smooth terrain" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Copy exterior walls from the level {direction}?" +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx #, fuzzy -msgid "editor.lib.hudTitle.smoothTerrain" -msgstr "Lisser le terrain" +msgid "editor.levelWallCopyPrompt.copyExteriorWallsFromTheLevel" +msgstr "Copier les murs extérieurs du niveau {direction, select, below {inférieur} above {supérieur} other {{direction}}} ?" -# Source-Hash: cbb4687261739397 +# Source-Hash: f6ad0e813d2945bb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Split {kind}" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No thanks" +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx #, fuzzy -msgid "editor.lib.hudTitle.splitKind" -msgstr "Diviser : {kind}" +msgid "editor.levelWallCopyPrompt.noThanks" +msgstr "Non merci" -# Source-Hash: 96281876ce53ba08 +# Source-Hash: d2aecc3c47120ad5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terrace" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{sourceName}’s outside walls, in place, so this level lines up with it." +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx #, fuzzy -msgid "editor.lib.hudTitle.terrace" -msgstr "Terrasse" +msgid "editor.levelWallCopyPrompt.sourcenameSOutsideWallsInPlace" +msgstr "Les murs extérieurs du niveau {sourceName}, au même emplacement, pour que ce niveau s’y aligne." -# Source-Hash: 8ec6152e139b0e3f +# Source-Hash: 395fd0821b203517 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Polygon room" -#: packages/editor/src/lib/wall-draw-variant.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add or remove objects from the selection" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.lib.wallDrawVariant.polygonRoom" -msgstr "Pièce polygonale" +msgid "editor.lib.contextualHelp.addOrRemoveObjectsFromThe" +msgstr "Ajouter ou retirer des objets de la sélection" -# Source-Hash: 83a45603ac7f41e8 +# Source-Hash: 8428cb0af9c6d6a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangle room" -#: packages/editor/src/lib/wall-draw-variant.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Adjust one side’s corner radius" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.lib.wallDrawVariant.rectangleRoom" -msgstr "Pièce rectangulaire" +msgid "editor.lib.contextualHelp.adjustOneSideSCornerRadius" +msgstr "Ajuster le rayon d’angle d’un côté" -# Source-Hash: aac9a732d2159ccc +# Source-Hash: d63b45c195713993 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls" -#: packages/editor/src/lib/wall-draw-variant.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear the selection (or click outside)" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.lib.wallDrawVariant.walls" -msgstr "Murs" +msgid "editor.lib.contextualHelp.clearTheSelectionOrClickOutside" +msgstr "Effacer la sélection (ou cliquer à l’extérieur)" +# Source-Hash: 40b1afbeadbd6213 # Review: required -# Source-Hash: c2626e1fbf89b3c9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{action, select, close {Close} open {Open} stop {Stop} other {Play}}" -#: packages/editor/src/components/editor/registry-action-contributions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click a handle dot to show move arrows" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.mechanismAction" -msgstr "{action, select, close {Fermer} open {Ouvrir} stop {Arrêter} other {Lancer}}" +msgid "editor.lib.contextualHelp.clickAHandleDotToShow" +msgstr "Cliquez sur une poignée pour afficher les flèches de déplacement" +# Source-Hash: 0b82a35c71549580 # Review: required -# Source-Hash: f08fbb462e9afc0e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curve" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click or drag the selection to move it as one" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.curve" -msgstr "Courbe" +msgid "editor.lib.contextualHelp.clickOrDragTheSelectionTo" +msgstr "Cliquez ou faites glisser la sélection pour la déplacer d’un bloc" +# Source-Hash: 73a761f393f69cb9 # Review: required -# Source-Hash: 5af05fb6661e4d6a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut out" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click the handle dot to show move + rotate handles" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.cutOut" -msgstr "Découper" +msgid "editor.lib.contextualHelp.clickTheHandleDotToShow" +msgstr "Cliquez sur la poignée pour afficher les poignées de déplacement et de rotation" +# Source-Hash: c0045cef191fee69 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Detach the joint while dragging an arrow" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.delete" -msgstr "Supprimer" +msgid "editor.lib.contextualHelp.detachTheJointWhileDraggingAn" +msgstr "Détacher la jonction en faisant glisser une flèche" +# Source-Hash: a019c8948c104a9e # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag left or right to rotate selected object" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.duplicate" -msgstr "Dupliquer" +msgid "editor.lib.contextualHelp.dragLeftOrRightToRotate" +msgstr "Faites glisser à gauche ou à droite pour faire pivoter l’objet sélectionné" +# Source-Hash: 7db0364deb12f06e # Review: required -# Source-Hash: 94b212bd79c05141 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit mesh" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag selected movable object" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.editMesh" -msgstr "Modifier le maillage" +msgid "editor.lib.contextualHelp.dragSelectedMovableObject" +msgstr "Faire glisser l’objet mobile sélectionné" +# Source-Hash: 0f258dd389afdc73 # Review: required -# Source-Hash: ce90cf37224f73cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Find in catalog" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Group selection (session only)" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.findInCatalog" -msgstr "Trouver dans le catalogue" +msgid "editor.lib.contextualHelp.groupSelectionSessionOnly" +msgstr "Grouper la sélection (session uniquement)" +# Source-Hash: 85330d62893a45c3 # Review: required -# Source-Hash: d5e550c345e7161c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Group selection" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hold to rotate freely" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.groupSelection" -msgstr "Grouper la sélection" +msgid "editor.lib.contextualHelp.holdToRotateFreely" +msgstr "Maintenez pour pivoter librement" +# Source-Hash: 8a665ecaeffa9308 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ±45°" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.move" -msgstr "Déplacer" +msgid "editor.lib.contextualHelp.rotate45" +msgstr "Pivoter de ±45°" +# Source-Hash: 6099ee99f8c38700 # Review: required -# Source-Hash: 473a9d4463761107 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate left" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate the selection ±45°" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.rotateLeft" -msgstr "Pivoter à gauche" +msgid "editor.lib.contextualHelp.rotateTheSelection45" +msgstr "Pivoter la sélection de ±45°" +# Source-Hash: 0f6b418b18ff96f3 # Review: required -# Source-Hash: b1bf4e65c8d8c8ef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate right" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotating freely (no angle step)" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.rotateRight" -msgstr "Pivoter à droite" +msgid "editor.lib.contextualHelp.rotatingFreely" +msgstr "Rotation libre (sans pas d’angle)" +# Source-Hash: 7ed174d6b03563b1 # Review: required -# Source-Hash: 6f4dbbc4a3f58fca -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ungroup selection" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Switch the rotation axis (Y → X → Z)" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.ungroupSelection" -msgstr "Dissocier la sélection" +msgid "editor.lib.contextualHelp.switchTheRotationAxisYX" +msgstr "Changer l’axe de rotation (Y → X → Z)" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: d6f2c5cea683de62 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ungroup session selection" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeDisplay.ceiling" -msgstr "Plafond" +msgid "editor.lib.contextualHelp.ungroupSessionSelection" +msgstr "Dissocier la sélection de session" -# Source-Hash: 3530ac1f4046cd22 +# Source-Hash: 384842ae1e1c6825 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Column" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuous" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.column" -msgstr "Poteau" +msgid "editor.lib.continuation.continuous" +msgstr "Continu" -# Source-Hash: 787e10f5db16904e +# Source-Hash: ebf0eb7af4636a16 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuous canopy" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.door" -msgstr "Porte" +msgid "editor.lib.continuation.continuousCanopy" +msgstr "Auvent continu" -# Source-Hash: ab5cbab7be160a1c +# Source-Hash: 1d8e87cd807e8d40 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevator" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuous run" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.elevator" -msgstr "Ascenseur" +msgid "editor.lib.continuation.continuousRun" +msgstr "Rangée continue" -# Source-Hash: 02042fde61b5aa11 +# Source-Hash: 8990683667567c6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fence" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curved fence" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.fence" -msgstr "Clôture" +msgid "editor.lib.continuation.curvedFence" +msgstr "Clôture courbe" -# Source-Hash: 4c3ff8cdc6feda97 +# Source-Hash: edf1b9a2ad3ab910 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guide image" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Freehand fence" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.guide" -msgstr "Image de calque" +msgid "editor.lib.continuation.freehandFence" +msgstr "Clôture libre" -# Source-Hash: 2743a0e9d2743807 +# Source-Hash: 2cdb7c1c7cd7c4fd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Item" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place multiple" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.item" -msgstr "Élément" +msgid "editor.lib.continuation.placeMultiple" +msgstr "Placer plusieurs" -# Source-Hash: f5f730969df63d1d +# Source-Hash: 90bf945df6f9c979 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place once" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.roof" -msgstr "Toit" +msgid "editor.lib.continuation.placeOnce" +msgstr "Placer une fois" -# Source-Hash: a130b4eec084c79a +# Source-Hash: 8ec6152e139b0e3f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof segment" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Polygon room" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.roofSegment" -msgstr "Segment de toit" +msgid "editor.lib.continuation.polygonRoom" +msgstr "Pièce polygonale" -# Source-Hash: 612dcd5bf06a79c4 +# Source-Hash: 83a45603ac7f41e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangle room" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.room" -msgstr "Pièce" +msgid "editor.lib.continuation.rectangleRoom" +msgstr "Pièce rectangulaire" -# Source-Hash: b22b2f20cc7cd416 +# Source-Hash: 7fd85d0408141157 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "3D Scan" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single cabinet" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.scan" -msgstr "Relevé 3D" +msgid "editor.lib.continuation.singleCabinet" +msgstr "Meuble seul" -# Source-Hash: 170b2049ef0f9131 +# Source-Hash: dd1bdbc26165baa5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Selection" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single canopy" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.selection" -msgstr "Sélection" +msgid "editor.lib.continuation.singleCanopy" +msgstr "Auvent seul" -# Source-Hash: 8775bc8dc9593964 +# Source-Hash: 5fb1a69316be983e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single fence" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.slab" -msgstr "Dalle" +msgid "editor.lib.continuation.singleFence" +msgstr "Clôture simple" -# Source-Hash: 53d7084bc41c1ad6 +# Source-Hash: aac9a732d2159ccc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.stair" -msgstr "Escalier" +msgid "editor.lib.continuation.walls" +msgstr "Murs" -# Source-Hash: 52de428c16bb81e6 +# Source-Hash: 4e4f1a24e4a9d61e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair segment" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut opening" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.nodeDisplay.stairSegment" -msgstr "Segment d’escalier" +msgid "editor.lib.hudTitle.cutOpening" +msgstr "Découper une ouverture" -# Source-Hash: 2210e5ee50b74dc9 +# Source-Hash: 60e8d235f3084a9e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divide room" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.nodeDisplay.wall" -msgstr "Mur" +msgid "editor.lib.hudTitle.divideRoom" +msgstr "Diviser la pièce" -# Source-Hash: aa3c35ed33e181e5 +# Source-Hash: aa496ec33d21ab03 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Window" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit {kind}" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.nodeDisplay.window" -msgstr "Fenêtre" +msgid "editor.lib.hudTitle.editKind" +msgstr "Modifier : {kind}" -# Source-Hash: a107b4d76d6972e3 +# Source-Hash: f3ea3efa7102844f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Erase" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.nodeDisplay.zone" -msgstr "Zone" +msgid "editor.lib.hudTitle.erase" +msgstr "Effacer" -# Source-Hash: c0774c185060fc13 +# Source-Hash: 3f907e76526472bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level terrain" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.cancel" -msgstr "Annuler" +msgid "editor.lib.hudTitle.levelTerrain" +msgstr "Niveler le terrain" -# Source-Hash: 6dbabf32ff8c6f37 +# Source-Hash: 4e911c300d74eb47 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collection name…" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lower terrain" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.collectionName" -msgstr "Nom de la collection…" +msgid "editor.lib.hudTitle.lowerTerrain" +msgstr "Abaisser le terrain" -# Source-Hash: 135af27a14a4cda7 +# Source-Hash: 194a147d4618a994 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collections" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.collections" -msgstr "Collections" +msgid "editor.lib.hudTitle.mezzanine" +msgstr "Mezzanine" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: c48c4129c9ed249a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move {kind}" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.delete" -msgstr "Supprimer" +msgid "editor.lib.hudTitle.moveKind" +msgstr "Déplacer : {kind}" -# Source-Hash: c53d71b05b8163b2 +# Source-Hash: 89f6b7ca8904c656 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete \"{name}\"?" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move room" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.deleteName" -msgstr "Supprimer « {name} » ?" +msgid "editor.lib.hudTitle.moveRoom" +msgstr "Déplacer la pièce" -# Source-Hash: e9f7cceb39860c56 +# Source-Hash: 9c707069572fb3db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "New" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move selection" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.new" -msgstr "Nouveau" +msgid "editor.lib.hudTitle.moveSelection" +msgstr "Déplacer la sélection" -# Source-Hash: 649bc1b1799f2311 +# Source-Hash: cf2e870fce0f2f51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No collections yet. Create one to group elements together." -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.noCollectionsYetCreateOneTo" -msgstr "Aucune collection pour l’instant. Créez-en une pour regrouper des éléments." +msgid "editor.lib.hudTitle.paint" +msgstr "Peindre" -# Source-Hash: d6952b4e54d246dd +# Source-Hash: ca197314cb70aa56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rename" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint a rectangle" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.rename" -msgstr "Renommer" +msgid "editor.lib.hudTitle.paintARectangle" +msgstr "Peindre un rectangle" -# Source-Hash: 2000cf124b4e1139 +# Source-Hash: ea4ce729e17254f8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A thicker floor grows upward: the rooms below keep their height." -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx -#, fuzzy -msgid "editor.panels.floorFoundationPanel.aThickerFloorGrowsUpwardThe" -msgstr "Un plancher plus épais croît vers le haut : les pièces du dessous gardent leur hauteur." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint a shape" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.paintAShape" +msgstr "Peindre une forme" -# Source-Hash: 0d57958b99b6b352 +# Source-Hash: 01359502b07284d4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edge finish" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick material" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.edgeFinish" -msgstr "Finition de rive" +msgid "editor.lib.hudTitle.pickMaterial" +msgstr "Prélever un matériau" -# Source-Hash: 8e458d8b21f26f09 +# Source-Hash: 4066e8a3f60b1711 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raise terrain" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorPlate" -msgstr "Plancher" +msgid "editor.lib.hudTitle.raiseTerrain" +msgstr "Surélever le terrain" -# Source-Hash: 2bb71e5633801afb +# Source-Hash: f85bdac0a1d16603 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate {thicknessLabel} thick, resting on the walls below" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Resize" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorPlateThicknesslabelThickRestingOn" -msgstr "Plancher de {thicknessLabel} d’épaisseur, reposant sur les murs du dessous" +msgid "editor.lib.hudTitle.resize" +msgstr "Redimensionner" -# Source-Hash: 73614b8faa059cd6 +# Source-Hash: 306d409f8a1cf480 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor thickness" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorThickness" -msgstr "Épaisseur du plancher" +msgid "editor.lib.hudTitle.rotate" +msgstr "Pivoter" -# Source-Hash: a40a1fbacd5d2551 +# Source-Hash: a4395168488bb476 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor top +{height}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorTopAbove" -msgstr "Dessus du plancher +{height}" +msgid "editor.lib.hudTitle.select" +msgstr "Sélectionner" -# Source-Hash: 5c3849e15933737f +# Source-Hash: ec1f1d68af469867 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor top {height}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Smart measure" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorTopValue" -msgstr "Dessus du plancher {height}" +msgid "editor.lib.hudTitle.smartMeasure" +msgstr "Mesure intelligente" -# Source-Hash: 19802dd369749ea7 +# Source-Hash: 5ba5f22bd1a69e09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation finish" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Smooth terrain" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.foundationFinish" -msgstr "Finition de la fondation" +msgid "editor.lib.hudTitle.smoothTerrain" +msgstr "Lisser le terrain" -# Source-Hash: 3a4599be1ad687be +# Source-Hash: cbb4687261739397 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation height" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Split {kind}" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.foundationHeight" -msgstr "Hauteur de fondation" +msgid "editor.lib.hudTitle.splitKind" +msgstr "Diviser : {kind}" -# Source-Hash: 8e458d8b21f26f09 +# Source-Hash: 96281876ce53ba08 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terrace" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.kicker" -msgstr "Plancher" +msgid "editor.lib.hudTitle.terrace" +msgstr "Terrasse" -# Source-Hash: 66d52bfbb94f7bb3 +# Source-Hash: 472d127eb9416ec5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate · {level}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invisible" +#: packages/editor/src/lib/wall-draw-variant.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.kickerLevel" -msgstr "Plancher · {level}" +msgid "editor.lib.wallDrawVariant.kind.invisible" +msgstr "Invisible" -# Source-Hash: 0189e5a1987b4ec0 +# Source-Hash: 240ed9c77627b9a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate · {level} · rests on {below}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" +#: packages/editor/src/lib/wall-draw-variant.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.kickerRestsOn" -msgstr "Plancher · {level} · repose sur {below}" +msgid "editor.lib.wallDrawVariant.kind.railing" +msgstr "Garde-corps" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 648ef10535b0af73 +# Source-Hash: d998c212030bc7c2 # Review: required -# English: "{count, plural, =2 {Lower both} other {Lower all {number}}}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/editor/src/lib/wall-draw-variant.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.lowerTogether" -msgstr "{count, plural, =2 {Abaisser les deux} one {Abaisser les {number}} many {Abaisser les {number}} other {Abaisser les {number}}}" +msgid "editor.lib.wallDrawVariant.kind.standard" +msgstr "Standard" -# Source-Hash: c2fcc43bb7f1c5e2 +# Source-Hash: 8ec6152e139b0e3f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Not to scale" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Polygon room" +#: packages/editor/src/lib/wall-draw-variant.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.notToScale" -msgstr "Pas à l’échelle" +msgid "editor.lib.wallDrawVariant.polygonRoom" +msgstr "Pièce polygonale" -# Source-Hash: e9440fa9f770b7a4 +# Source-Hash: 83a45603ac7f41e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "On the ground" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangle room" +#: packages/editor/src/lib/wall-draw-variant.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.onTheGround" -msgstr "Au sol" +msgid "editor.lib.wallDrawVariant.rectangleRoom" +msgstr "Pièce rectangulaire" -# Source-Hash: 7c3692a361075ecf +# Source-Hash: aac9a732d2159ccc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised on a foundation" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls" +#: packages/editor/src/lib/wall-draw-variant.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.raisedOnAFoundation" -msgstr "Surélevé sur une fondation" +msgid "editor.lib.wallDrawVariant.walls" +msgstr "Murs" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 769c3ca1ca0cd4f0 +# Source-Hash: c2626e1fbf89b3c9 # Review: required -# English: "{count, plural, =2 {Raise both} other {Raise all {number}}}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{action, select, close {Close} open {Open} stop {Stop} other {Play}}" +#: packages/editor/src/components/editor/registry-action-contributions.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.raiseTogether" -msgstr "{count, plural, =2 {Relever les deux} one {Relever les {number}} many {Relever les {number}} other {Relever les {number}}}" +msgid "editor.mechanismAction" +msgstr "{action, select, close {Fermer} open {Ouvrir} stop {Arrêter} other {Lancer}}" -# Source-Hash: 719ae422da204ca7 +# Source-Hash: f08fbb462e9afc0e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate · {thickness}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curve" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.floorPlate" -msgstr "Plancher · {thickness}" +msgid "editor.nodeActionMenu.curve" +msgstr "Courbe" -# Source-Hash: 069d64adffa05db7 +# Source-Hash: 5af05fb6661e4d6a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor top" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut out" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.floorTop" -msgstr "Dessus du plancher" +msgid "editor.nodeActionMenu.cutOut" +msgstr "Découper" -# Source-Hash: 48c832c1fc389290 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.foundation" -msgstr "Fondation" +msgid "editor.nodeActionMenu.delete" +msgstr "Supprimer" -# Source-Hash: 7759a59b8685c885 +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation · {foundation}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx -#, fuzzy -msgid "editor.panels.floorFoundationPanel.section.foundationKind" -msgstr "Fondation · {foundation}" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/editor/node-action-menu.tsx +#, fuzzy +msgid "editor.nodeActionMenu.duplicate" +msgstr "Dupliquer" -# Source-Hash: 94cc8e9f1ee16edb +# Source-Hash: 94b212bd79c05141 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit mesh" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.ground" -msgstr "Sol" +msgid "editor.nodeActionMenu.editMesh" +msgstr "Modifier le maillage" -# Source-Hash: 51e274b2c90e2cf3 +# Source-Hash: ce90cf37224f73cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab · {thickness}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Find in catalog" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.slab" -msgstr "Dalle · {thickness}" +msgid "editor.nodeActionMenu.findInCatalog" +msgstr "Trouver dans le catalogue" -# Source-Hash: 790a0b5c6dbf0e9b +# Source-Hash: d5e550c345e7161c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls below" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Group selection" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.wallsBelow" -msgstr "Murs du dessous" +msgid "editor.nodeActionMenu.groupSelection" +msgstr "Grouper la sélection" -# Source-Hash: 90e96ae5f3d3f69c +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab {thickness} thick on the ground, floor top {top} above the ground" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.sectionOnGround" -msgstr "Dalle de {thickness} d’épaisseur sur le sol, dessus du plancher à {top} au-dessus du sol" +msgid "editor.nodeActionMenu.move" +msgstr "Déplacer" -# Source-Hash: 71ed2295d9932ed0 +# Source-Hash: 473a9d4463761107 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab {thickness} thick on a {foundation} foundation, floor top {top} above the ground" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate left" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.sectionRaised" -msgstr "Dalle de {thickness} d’épaisseur sur une fondation {foundation}, dessus du plancher à {top} au-dessus du sol" +msgid "editor.nodeActionMenu.rotateLeft" +msgstr "Pivoter à gauche" -# Source-Hash: 8775bc8dc9593964 +# Source-Hash: b1bf4e65c8d8c8ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate right" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.slab" -msgstr "Dalle" +msgid "editor.nodeActionMenu.rotateRight" +msgstr "Pivoter à droite" -# Source-Hash: ca51d643691c29ae +# Source-Hash: 6f4dbbc4a3f58fca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab thickness" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ungroup selection" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.slabThickness" -msgstr "Épaisseur de dalle" +msgid "editor.nodeActionMenu.ungroupSelection" +msgstr "Dissocier la sélection" -# Source-Hash: 678c39468593275b +# Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The floor's outside edge, all around the footprint." -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.theFloorSOutsideEdgeAll" -msgstr "Le bord extérieur du plancher, tout autour de l’emprise." +msgid "editor.nodeDisplay.ceiling" +msgstr "Plafond" -# Source-Hash: 6638ed5caa43bdb9 +# Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The foundation stands on the ground; the slab sits on it." -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Column" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.theFoundationStandsOnTheGround" -msgstr "La fondation repose sur le sol ; la dalle repose sur elle." +msgid "editor.nodeDisplay.column" +msgstr "Poteau" -# Source-Hash: 5321416b442f23b4 +# Source-Hash: 787e10f5db16904e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The slab sits on the foundation (or the ground): a thicker slab raises the floor top and everything on it." -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.theSlabSitsOnTheFoundation" -msgstr "La dalle repose sur la fondation (ou le sol) : une dalle plus épaisse relève le dessus du plancher et tout ce qui s’y trouve." +msgid "editor.nodeDisplay.door" +msgstr "Porte" -# Source-Hash: 044ccae8bec574e7 +# Source-Hash: ab5cbab7be160a1c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Under the floor" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevator" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.underTheFloor" -msgstr "Sous le plancher" +msgid "editor.nodeDisplay.elevator" +msgstr "Ascenseur" -# Source-Hash: 6aca44df3e582a81 +# Source-Hash: 02042fde61b5aa11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A hatch in the mezzanine: it cuts only the mezzanine’s floor." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fence" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.aHatchInTheMezzanineIt" -msgstr "Trappe dans la mezzanine : elle ne coupe que le plancher de la mezzanine." +msgid "editor.nodeDisplay.fence" +msgstr "Clôture" -# Source-Hash: 2ce79639d42da658 +# Source-Hash: 4c3ff8cdc6feda97 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Also cut the ceiling below" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guide image" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.alsoCutTheCeilingBelow" -msgstr "Couper aussi le plafond en dessous" +msgid "editor.nodeDisplay.guide" +msgstr "Image de calque" -# Source-Hash: e360814f64792300 +# Source-Hash: 2743a0e9d2743807 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Also cut the floor above" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Item" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.alsoCutTheFloorAbove" -msgstr "Couper aussi le plancher au-dessus" +msgid "editor.nodeDisplay.item" +msgstr "Élément" -# Source-Hash: c25cddf8b831c2b2 +# Source-Hash: f5f730969df63d1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{area} · Drag its corners to change the shape." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.areaDragCorners" -msgstr "{area} · Faites glisser ses angles pour changer la forme." +msgid "editor.nodeDisplay.roof" +msgstr "Toit" -# Source-Hash: 32b168cf010a5daa +# Source-Hash: a130b4eec084c79a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{area} · Shape follows its owner." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof segment" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.areaOwned" -msgstr "{area} · La forme suit son propriétaire." +msgid "editor.nodeDisplay.roofSegment" +msgstr "Segment de toit" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.delete" -msgstr "Supprimer" +msgid "editor.nodeDisplay.room" +msgstr "Pièce" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: b22b2f20cc7cd416 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "3D Scan" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.done" -msgstr "Terminé" +msgid "editor.nodeDisplay.scan" +msgstr "Relevé 3D" -# Source-Hash: e04298381837252f +# Source-Hash: 170b2049ef0f9131 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selection" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.kicker" -msgstr "Ouverture" +msgid "editor.nodeDisplay.selection" +msgstr "Sélection" -# Source-Hash: 079ad92dac7947cf +# Source-Hash: 8775bc8dc9593964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening · {level}" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.kickerLevel" -msgstr "Ouverture · {level}" +msgid "editor.nodeDisplay.slab" +msgstr "Dalle" -# Source-Hash: baf2c2c209637e5f +# Source-Hash: 53d7084bc41c1ad6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening · in {room}" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.kickerRoom" -msgstr "Ouverture · dans {room}" +msgid "editor.nodeDisplay.stair" +msgstr "Escalier" -# Source-Hash: 1712c164335ecd86 +# Source-Hash: 52de428c16bb81e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening · in {room} · {level}" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair segment" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.kickerRoomLevel" -msgstr "Ouverture · dans {room} · {level}" +msgid "editor.nodeDisplay.stairSegment" +msgstr "Segment d’escalier" -# Source-Hash: 88e673123b9dbfe1 +# Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "On {level}, as one void with this opening." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.oneVoidWith" -msgstr "Sur {level}, en un seul vide avec cette ouverture." +msgid "editor.nodeDisplay.wall" +msgstr "Mur" -# Source-Hash: c38959fc8fd3e59d +# Source-Hash: aa3c35ed33e181e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Owned by Elevator" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Window" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.ownedByElevator" -msgstr "Appartient à l’ascenseur" +msgid "editor.nodeDisplay.window" +msgstr "Fenêtre" -# Source-Hash: 01494805cf60d78d +# Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Owned by Staircase" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.ownedByStaircase" -msgstr "Appartient à l’escalier" +msgid "editor.nodeDisplay.zone" +msgstr "Zone" -# Source-Hash: 612dcd5bf06a79c4 +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.room" -msgstr "Pièce" +msgid "editor.panels.collections.collectionsPopover.cancel" +msgstr "Annuler" -# Source-Hash: 1405b914a324b153 +# Source-Hash: 6dbabf32ff8c6f37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "There is no floor above this storey." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collection name…" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.thereIsNoFloorAboveThis" -msgstr "Il n’y a pas de plancher au-dessus de cet étage." +msgid "editor.panels.collections.collectionsPopover.collectionName" +msgstr "Nom de la collection…" -# Source-Hash: 776170dcae88e969 +# Source-Hash: 135af27a14a4cda7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "There is no storey below." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collections" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.thereIsNoStoreyBelow" -msgstr "Il n’y a pas d’étage en dessous." +msgid "editor.panels.collections.collectionsPopover.collections" +msgstr "Collections" -# Source-Hash: 0fdd1877a0f2d777 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{source, select, stair {Stair opening} elevator {Elevator opening} ceiling {Ceiling opening} other {Floor opening}}" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.title" -msgstr "{source, select, stair {Trémie d’escalier} elevator {Trémie d’ascenseur} ceiling {Ouverture de plafond} other {Trémie de plancher}}" +msgid "editor.panels.collections.collectionsPopover.delete" +msgstr "Supprimer" -# Source-Hash: fa35c7653e1f649e +# Source-Hash: c53d71b05b8163b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "One of them already wraps another corner. Unwrap it first." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete \"{name}\"?" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.alreadyJoined" -msgstr "L’une d’elles occupe déjà un autre angle. Détachez-la d’abord." +msgid "editor.panels.collections.collectionsPopover.deleteName" +msgstr "Supprimer « {name} » ?" -# Source-Hash: dd87eb1983876459 +# Source-Hash: e9f7cceb39860c56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{kind, select, item {There is an item between them.} door {There is a door between them.} window {There is a window between them.} shelf {There is a shelf between them.} other {There is something between them.}}" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.between" -msgstr "{kind, select, item {Un objet se trouve entre elles.} door {Une porte se trouve entre elles.} window {Une fenêtre se trouve entre elles.} shelf {Une étagère se trouve entre elles.} other {Il y a quelque chose entre elles.}}" +msgid "editor.panels.collections.collectionsPopover.new" +msgstr "Nouveau" -# Source-Hash: 58aea0b9789ae280 +# Source-Hash: 649bc1b1799f2311 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "These windows cannot be merged." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No collections yet. Create one to group elements together." +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.cannotMerge" -msgstr "Ces fenêtres ne peuvent pas être fusionnées." +msgid "editor.panels.collections.collectionsPopover.noCollectionsYetCreateOneTo" +msgstr "Aucune collection pour l’instant. Créez-en une pour regrouper des éléments." -# Source-Hash: 15170cfd9d666c4f +# Source-Hash: d6952b4e54d246dd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Their walls meet at too sharp or too flat an angle for a corner window." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rename" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.cornerAngle" -msgstr "Leurs murs se rejoignent à un angle trop aigu ou trop plat pour une fenêtre d’angle." +msgid "editor.panels.collections.collectionsPopover.rename" +msgstr "Renommer" -# Source-Hash: f2818a1e20ebd6ca +# Source-Hash: 0a605a51555bb514 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The window selected first is taller than the other wall. Select the other one first." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Along house" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.heightExceedsWall" -msgstr "La fenêtre sélectionnée en premier est plus haute que l’autre mur. Sélectionnez d’abord l’autre." +msgid "editor.panels.deckBoardsFields.alongHouse" +msgstr "Parallèle" -# Source-Hash: 7c97fb4af929d4db +# Source-Hash: 19ae2360207ecf5a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "They are too far apart. Windows merge with at most {reach} between them." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Boards" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.notAdjacent" -msgstr "Elles sont trop éloignées. Les fenêtres fusionnent avec au plus {reach} entre elles." +msgid "editor.panels.deckBoardsFields.boards" +msgstr "Lames" -# Source-Hash: 57a281bdc4229b6d +# Source-Hash: 2bc05aaf1fc289b3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "One of them is too far from the corner. A window joins one within {reach} of it." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label} boards {thickness} × {width} in, {gap} in apart, {direction, select, parallel {along the house, on joists square to it} diagonal {at 45° to the house} other {out from the house, on joists along it, carried by beams square to the house}}; joists {spacing} in on centre." +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.notAtCorner" -msgstr "L’une d’elles est trop loin de l’angle. Une fenêtre en rejoint une autre à moins de {reach}." +msgid "editor.panels.deckBoardsFields.boardsSummary" +msgstr "Lames {label} de {thickness} × {width} in, espacées de {gap} in, {direction, select, parallel {parallèles à la maison, sur des solives perpendiculaires à celle-ci} diagonal {à 45° par rapport à la maison} other {perpendiculaires à la maison, sur des solives parallèles à celle-ci, portées par des poutres perpendiculaires à la maison}} ; solives à {spacing} in d’entraxe." -# Source-Hash: e7d41ce7879ec075 +# Source-Hash: 24c6255bfa1abd8f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A roof or dormer window cannot join another window." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck boards" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.notOnWall" -msgstr "Une fenêtre de toit ou de lucarne ne peut pas rejoindre une autre fenêtre." +msgid "editor.panels.deckBoardsFields.deckBoards" +msgstr "Lames de terrasse" -# Source-Hash: eaad567d5e4257dc +# Source-Hash: 7420c0d2caee1c22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{kind, select, item {Sliding them to the corner would overlap an item.} door {Sliding them to the corner would overlap a door.} window {Sliding them to the corner would overlap a window.} shelf {Sliding them to the corner would overlap a shelf.} other {Sliding them to the corner would overlap something.}}" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diagonal" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.overlap" -msgstr "{kind, select, item {Les faire glisser jusqu’à l’angle chevaucherait un objet.} door {Les faire glisser jusqu’à l’angle chevaucherait une porte.} window {Les faire glisser jusqu’à l’angle chevaucherait une fenêtre.} shelf {Les faire glisser jusqu’à l’angle chevaucherait une étagère.} other {Les faire glisser jusqu’à l’angle chevaucherait un autre élément.}}" +msgid "editor.panels.deckBoardsFields.diagonal" +msgstr "Diagonale" -# Source-Hash: ecb092821ed5b5e8 +# Source-Hash: df708ece3529bcba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Their walls do not meet at a corner." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.wallsNotMeeting" -msgstr "Leurs murs ne se rejoignent pas en angle." +msgid "editor.panels.deckBoardsFields.gap" +msgstr "Joint" -# Source-Hash: 37d9f63758abdb67 +# Source-Hash: 3660fcdd12159277 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mixed" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx -#: packages/editor/src/components/ui/panels/parametric-field-control.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Out from house" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mixed" -msgstr "Mixte" +msgid "editor.panels.deckBoardsFields.outFromHouse" +msgstr "Perpendiculaire" -# Source-Hash: d7cf5045c01b2eb9 +# Source-Hash: 9ac7e4955593cc34 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close" -#: packages/editor/src/components/ui/panels/mobile-panel-sheet.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Run" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mobilePanelSheet.close" -msgstr "Fermer" +msgid "editor.panels.deckBoardsFields.run" +msgstr "Sens" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 2000cf124b4e1139 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A thicker floor grows upward: the rooms below keep their height." +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.delete" -msgstr "Supprimer" +msgid "editor.panels.floorFoundationPanel.aThickerFloorGrowsUpwardThe" +msgstr "Un plancher plus épais croît vers le haut : les pièces du dessous gardent leur hauteur." -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 0d57958b99b6b352 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edge finish" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.duplicate" -msgstr "Dupliquer" +msgid "editor.panels.floorFoundationPanel.edgeFinish" +msgstr "Finition de rive" -# Source-Hash: 7eb955d866c2668b +# Source-Hash: 8e458d8b21f26f09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit properties" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.editProperties" -msgstr "Modifier les propriétés" +msgid "editor.panels.floorFoundationPanel.floorPlate" +msgstr "Plancher" -# Source-Hash: 89f25aa13e8192bc +# Source-Hash: 2bb71e5633801afb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit {resolvedLabel}" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate {thicknessLabel} thick, resting on the walls below" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.editResolvedlabel" -msgstr "Modifier {resolvedLabel}" +msgid "editor.panels.floorFoundationPanel.floorPlateThicknesslabelThickRestingOn" +msgstr "Plancher de {thicknessLabel} d’épaisseur, reposant sur les murs du dessous" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 73614b8faa059cd6 # Review: required # AI-Provider: cursor-agent # AI-Model: claude-opus -# English: "Move" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# English: "Floor thickness" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.move" -msgstr "Déplacer" +msgid "editor.panels.floorFoundationPanel.floorThickness" +msgstr "Épaisseur du plancher" -# Source-Hash: 72be05e1796526c9 +# Source-Hash: a40a1fbacd5d2551 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Currently {currentLabel}" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor top +{height}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.currentlyCurrentlabel" -msgstr "Actuellement {currentLabel}" +msgid "editor.panels.floorFoundationPanel.floorTopAbove" +msgstr "Dessus du plancher +{height}" -# Source-Hash: b2a1b3bc9676fe05 +# Source-Hash: 5c3849e15933737f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom height" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor top {height}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.customHeight" -msgstr "Hauteur personnalisée" +msgid "editor.panels.floorFoundationPanel.floorTopValue" +msgstr "Dessus du plancher {height}" -# Source-Hash: a5c2353769b603d5 +# Source-Hash: 19802dd369749ea7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows level" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation finish" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.followsLevel" -msgstr "Suit le niveau" +msgid "editor.panels.floorFoundationPanel.foundationFinish" +msgstr "Finition de la fondation" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: 3a4599be1ad687be # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation height" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.height" -msgstr "Hauteur" +msgid "editor.panels.floorFoundationPanel.foundationHeight" +msgstr "Hauteur de fondation" -# Source-Hash: 27644f0497fd9849 +# Source-Hash: 8e458d8b21f26f09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.top" -msgstr "Haut" +msgid "editor.panels.floorFoundationPanel.kicker" +msgstr "Plancher" -# Source-Hash: 70f48b0141b656f2 +# Source-Hash: 66d52bfbb94f7bb3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{label} (session only). Plain click reselects all members. Not saved with the project." -#: packages/editor/src/components/ui/panels/multi-parametric-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate · {level}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiParametricInspector.labelSessionOnlyPlainClickReselects" -msgstr "{label} (session uniquement). Un clic simple resélectionne tous les membres. Non enregistré avec le projet." +msgid "editor.panels.floorFoundationPanel.kickerLevel" +msgstr "Plancher · {level}" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 0189e5a1987b4ec0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate · {level} · rests on {below}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.delete" -msgstr "Supprimer" +msgid "editor.panels.floorFoundationPanel.kickerRestsOn" +msgstr "Plancher · {level} · repose sur {below}" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 648ef10535b0af73 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, =2 {Lower both} other {Lower all {number}}}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.duplicate" -msgstr "Dupliquer" +msgid "editor.panels.floorFoundationPanel.lowerTogether" +msgstr "{count, plural, =2 {Abaisser les deux} one {Abaisser les {number}} many {Abaisser les {number}} other {Abaisser les {number}}}" -# Source-Hash: b0e7e3b47dfb5a0b +# Source-Hash: c2fcc43bb7f1c5e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Group" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not to scale" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.group" -msgstr "Grouper" +msgid "editor.panels.floorFoundationPanel.notToScale" +msgstr "Pas à l’échelle" -# Source-Hash: ca0a95fe0b08b8b6 +# Source-Hash: e9440fa9f770b7a4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Group (Ctrl/Cmd+G)" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On the ground" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.groupCtrlCmdG" -msgstr "Grouper (Ctrl/Cmd+G)" +msgid "editor.panels.floorFoundationPanel.onTheGround" +msgstr "Au sol" -# Source-Hash: 70f48b0141b656f2 +# Source-Hash: 7c3692a361075ecf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{label} (session only). Plain click reselects all members. Not saved with the project." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised on a foundation" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.labelSessionOnlyPlainClickReselects" -msgstr "{label} (session uniquement). Un clic simple resélectionne tous les membres. Non enregistré avec le projet." +msgid "editor.panels.floorFoundationPanel.raisedOnAFoundation" +msgstr "Surélevé sur une fondation" -# Source-Hash: fc98ef29c2842341 +# Source-Hash: 769c3ca1ca0cd4f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{length} selected" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, =2 {Raise both} other {Raise all {number}}}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.lengthSelected" -msgstr "{length} sélectionnés" +msgid "editor.panels.floorFoundationPanel.raiseTogether" +msgstr "{count, plural, =2 {Relever les deux} one {Relever les {number}} many {Relever les {number}} other {Relever les {number}}}" -# Source-Hash: 323aaf1ebd04ada7 +# Source-Hash: 719ae422da204ca7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Merge windows" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate · {thickness}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.mergeWindows" -msgstr "Fusionner les fenêtres" +msgid "editor.panels.floorFoundationPanel.section.floorPlate" +msgstr "Plancher · {thickness}" -# Source-Hash: 7855d03a6140af77 +# Source-Hash: 069d64adffa05db7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Merge windows into a corner window: both take the height, sill and type of the one you selected first" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor top" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.mergeWindowsIntoACornerWindow" -msgstr "Fusionner en fenêtre d’angle : les deux prennent la hauteur, l’appui et le type de la première sélectionnée" +msgid "editor.panels.floorFoundationPanel.section.floorTop" +msgstr "Dessus du plancher" -# Source-Hash: b79da96502d2e1c0 +# Source-Hash: 48c832c1fc389290 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Merge windows into one across both: it keeps the type and style of the one you selected first" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.mergeWindowsIntoOneAcrossBoth" -msgstr "Fusionner en une seule fenêtre sur les deux : elle garde le type et le style de la première sélectionnée" +msgid "editor.panels.floorFoundationPanel.section.foundation" +msgstr "Fondation" -# Source-Hash: f409934681a046e8 +# Source-Hash: 7759a59b8685c885 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select building" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx -#, fuzzy -msgid "editor.panels.multiSelectionPanel.selectBuilding" -msgstr "Sélectionner le bâtiment" - -# Source-Hash: c62a73873bd0164d -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select the whole building to move all its levels" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation · {foundation}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.selectTheWholeBuildingToMove" -msgstr "Sélectionnez tout le bâtiment pour déplacer tous ses niveaux" +msgid "editor.panels.floorFoundationPanel.section.foundationKind" +msgstr "Fondation · {foundation}" -# Source-Hash: 7bd5f29203a28efb +# Source-Hash: 94cc8e9f1ee16edb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ungroup" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.ungroup" -msgstr "Dissocier" +msgid "editor.panels.floorFoundationPanel.section.ground" +msgstr "Sol" -# Source-Hash: aec9c3983a440d4a +# Source-Hash: 51e274b2c90e2cf3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ungroup (Ctrl/Cmd+Shift+G)" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab · {thickness}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.ungroupCtrlCmdShiftG" -msgstr "Dissocier (Ctrl/Cmd+Maj+G)" +msgid "editor.panels.floorFoundationPanel.section.slab" +msgstr "Dalle · {thickness}" -# Source-Hash: 420385f27c627cee +# Source-Hash: 790a0b5c6dbf0e9b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unwrap the corner" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.unwrapTheCorner" -msgstr "Détacher l’angle" +msgid "editor.panels.floorFoundationPanel.section.wallsBelow" +msgstr "Murs du dessous" -# Source-Hash: 7906c9f4baebc70b +# Source-Hash: 90e96ae5f3d3f69c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unwrap the corner: both windows stay, each framed at the corner" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab {thickness} thick on the ground, floor top {top} above the ground" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.unwrapTheCornerBothWindowsStay" -msgstr "Détacher l’angle : les deux fenêtres restent, chacune avec un cadre à l’angle" +msgid "editor.panels.floorFoundationPanel.sectionOnGround" +msgstr "Dalle de {thickness} d’épaisseur sur le sol, dessus du plancher à {top} au-dessus du sol" -# Source-Hash: 170b2049ef0f9131 +# Source-Hash: 71ed2295d9932ed0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Selection" -#: packages/editor/src/components/ui/panels/panel-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab {thickness} thick on a {foundation} foundation, floor top {top} above the ground" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelManager.selection" -msgstr "Sélection" +msgid "editor.panels.floorFoundationPanel.sectionRaised" +msgstr "Dalle de {thickness} d’épaisseur sur une fondation {foundation}, dessus du plancher à {top} au-dessus du sol" -# Source-Hash: 7ceade8f25b58fe9 +# Source-Hash: 8775bc8dc9593964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.back" -msgstr "Retour" +msgid "editor.panels.floorFoundationPanel.slab" +msgstr "Dalle" -# Source-Hash: d7cf5045c01b2eb9 +# Source-Hash: ca51d643691c29ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab thickness" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.close" -msgstr "Fermer" +msgid "editor.panels.floorFoundationPanel.slabThickness" +msgstr "Épaisseur de dalle" -# Source-Hash: 2dff25ca30c80559 +# Source-Hash: 678c39468593275b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close {title}" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The floor's outside edge, all around the footprint." +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.closeTitle" -msgstr "Fermer {title}" +msgid "editor.panels.floorFoundationPanel.theFloorSOutsideEdgeAll" +msgstr "Le bord extérieur du plancher, tout autour de l’emprise." -# Source-Hash: 4f15c3e0fe6178b5 +# Source-Hash: 6638ed5caa43bdb9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collapse panel" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The foundation stands on the ground; the slab sits on it." +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.collapsePanel" -msgstr "Réduire le panneau" +msgid "editor.panels.floorFoundationPanel.theFoundationStandsOnTheGround" +msgstr "La fondation repose sur le sol ; la dalle repose sur elle." -# Source-Hash: 135af27a14a4cda7 +# Source-Hash: 5321416b442f23b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collections" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The slab sits on the foundation (or the ground): a thicker slab raises the floor top and everything on it." +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.collections" -msgstr "Collections" +msgid "editor.panels.floorFoundationPanel.theSlabSitsOnTheFoundation" +msgstr "La dalle repose sur la fondation (ou le sol) : une dalle plus épaisse relève le dessus du plancher et tout ce qui s’y trouve." -# Source-Hash: 64916cc9ea80f43f +# Source-Hash: 044ccae8bec574e7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Expand panel" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Under the floor" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.expandPanel" -msgstr "Développer le panneau" +msgid "editor.panels.floorFoundationPanel.underTheFloor" +msgstr "Sous le plancher" -# Source-Hash: 8a9a25621f200922 +# Source-Hash: 6aca44df3e582a81 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Manage collections…" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A hatch in the mezzanine: it cuts only the mezzanine’s floor." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.manageCollections" -msgstr "Gérer les collections…" +msgid "editor.panels.floorOpeningPanel.aHatchInTheMezzanineIt" +msgstr "Trappe dans la mezzanine : elle ne coupe que le plancher de la mezzanine." -# Source-Hash: 2ff02ed91f54235c +# Source-Hash: 2ce79639d42da658 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open {title}" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Also cut the ceiling below" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.openTitle" -msgstr "Ouvrir {title}" +msgid "editor.panels.floorOpeningPanel.alsoCutTheCeilingBelow" +msgstr "Couper aussi le plafond en dessous" -# Source-Hash: bf91b71a9aa76e94 +# Source-Hash: e360814f64792300 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Also cut the floor above" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.reset" -msgstr "Réinitialiser" +msgid "editor.panels.floorOpeningPanel.alsoCutTheFloorAbove" +msgstr "Couper aussi le plancher au-dessus" -# Source-Hash: 04a212d6317f6787 +# Source-Hash: c25cddf8b831c2b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "“{title}” hit an error and was unloaded for this session." -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} · Drag its corners to change the shape." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.titleHitAnErrorAndWas" -msgstr "« {title} » a rencontré une erreur et a été déchargé pour cette session." +msgid "editor.panels.floorOpeningPanel.areaDragCorners" +msgstr "{area} · Faites glisser ses angles pour changer la forme." -# Source-Hash: 37d9f63758abdb67 +# Source-Hash: 32b168cf010a5daa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mixed" -#: packages/editor/src/components/ui/panels/parametric-field-control.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} · Shape follows its owner." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.parametricFieldControl.mixed" -msgstr "Mixte" +msgid "editor.panels.floorOpeningPanel.areaOwned" +msgstr "{area} · La forme suit son propriétaire." -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 71b5c7184cbd2e5d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/editor/src/components/ui/panels/parametric-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} · Drag its sides or corners to resize it; it moves with the stair." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.parametricInspector.actions" -msgstr "Actions" +msgid "editor.panels.floorOpeningPanel.areaStairResize" +msgstr "{area} · Faites glisser ses côtés ou ses angles pour la redimensionner ; elle suit l’escalier." # Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" -#: packages/editor/src/components/ui/panels/parametric-inspector.tsx +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.parametricInspector.delete" +msgid "editor.panels.floorOpeningPanel.delete" msgstr "Supprimer" -# Source-Hash: e2411929697b7ed4 +# Source-Hash: 16552c2580bbe8b8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete with contents" -#: packages/editor/src/components/ui/panels/parametric-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.parametricInspector.deleteWithContents" -msgstr "Supprimer avec le contenu" +msgid "editor.panels.floorOpeningPanel.done" +msgstr "Terminé" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/editor/src/components/ui/panels/parametric-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.parametricInspector.move" -msgstr "Déplacer" +msgid "editor.panels.floorOpeningPanel.kicker" +msgstr "Ouverture" -# Source-Hash: c0774c185060fc13 +# Source-Hash: 079ad92dac7947cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening · {level}" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.cancel" -msgstr "Annuler" +msgid "editor.panels.floorOpeningPanel.kickerLevel" +msgstr "Ouverture · {level}" -# Source-Hash: 3a0701ebcb9f26cb +# Source-Hash: baf2c2c209637e5f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Capture" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening · in {room}" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.capture" -msgstr "Capture" +msgid "editor.panels.floorOpeningPanel.kickerRoom" +msgstr "Ouverture · dans {room}" -# Source-Hash: 5211341ed18f33f6 +# Source-Hash: 1712c164335ecd86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening · in {room} · {level}" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.center" -msgstr "Centre" +msgid "editor.panels.floorOpeningPanel.kickerRoomLevel" +msgstr "Ouverture · dans {room} · {level}" -# Source-Hash: a5b965dfb0bf2cd3 +# Source-Hash: 88e673123b9dbfe1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On {level}, as one void with this opening." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.clearScale" -msgstr "Effacer l’échelle" +msgid "editor.panels.floorOpeningPanel.oneVoidWith" +msgstr "Sur {level}, en un seul vide avec cette ouverture." -# Source-Hash: 4edc6e45b0c19447 +# Source-Hash: c38959fc8fd3e59d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click both ends of a known distance on the plan, then type its real length." -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Owned by Elevator" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.clickBothEndsOfAKnown" -msgstr "Cliquez les deux extrémités d’une distance connue sur le plan, puis saisissez sa longueur réelle." +msgid "editor.panels.floorOpeningPanel.ownedByElevator" +msgstr "Appartient à l’ascenseur" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 01494805cf60d78d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Owned by Staircase" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.delete" -msgstr "Supprimer" +msgid "editor.panels.floorOpeningPanel.ownedByStaircase" +msgstr "Appartient à l’escalier" -# Source-Hash: 59f7d81e8d36a157 +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw a line over a known dimension on the plan, then type its real length to scale the image exactly." -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.drawALineOverAKnown" -msgstr "Tracez une ligne sur une cote connue du plan, puis saisissez sa longueur réelle pour mettre l’image exactement à l’échelle." +msgid "editor.panels.floorOpeningPanel.room" +msgstr "Pièce" -# Source-Hash: 42f6d0e4f065f114 +# Source-Hash: 1405b914a324b153 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "There is no floor above this storey." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.editScale" -msgstr "Modifier l’échelle" +msgid "editor.panels.floorOpeningPanel.thereIsNoFloorAboveThis" +msgstr "Il n’y a pas de plancher au-dessus de cet étage." -# Source-Hash: e156c84cbc90e0a7 +# Source-Hash: 776170dcae88e969 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guide Image" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "There is no storey below." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.guideImage" -msgstr "Image de calque" +msgid "editor.panels.floorOpeningPanel.thereIsNoStoreyBelow" +msgstr "Il n’y a pas d’étage en dessous." -# Source-Hash: 591087ea83a48ead +# Source-Hash: 0fdd1877a0f2d777 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{source, select, stair {Stair opening} elevator {Elevator opening} ceiling {Ceiling opening} other {Floor opening}}" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.hide" -msgstr "Masquer" +msgid "editor.panels.floorOpeningPanel.title" +msgstr "{source, select, stair {Trémie d’escalier} elevator {Trémie d’ascenseur} ceiling {Ouverture de plafond} other {Trémie de plancher}}" -# Source-Hash: dd282ce13b9085ba +# Source-Hash: fa35c7653e1f649e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "One of them already wraps another corner. Unwrap it first." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.hideScale" -msgstr "Masquer l’échelle" +msgid "editor.panels.mergeRefusal.alreadyJoined" +msgstr "L’une d’elles occupe déjà un autre angle. Détachez-la d’abord." -# Source-Hash: fc6eaa65315f601d +# Source-Hash: dd87eb1983876459 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Image" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{kind, select, item {There is an item between them.} door {There is a door between them.} window {There is a window between them.} shelf {There is a shelf between them.} other {There is something between them.}}" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.image" -msgstr "Image" +msgid "editor.panels.mergeRefusal.between" +msgstr "{kind, select, item {Un objet se trouve entre elles.} door {Une porte se trouve entre elles.} window {Une fenêtre se trouve entre elles.} shelf {Une étagère se trouve entre elles.} other {Il y a quelque chose entre elles.}}" -# Source-Hash: 241399e11d93bd7b +# Source-Hash: 58aea0b9789ae280 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lock" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "These windows cannot be merged." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.lock" -msgstr "Verrouiller" +msgid "editor.panels.mergeRefusal.cannotMerge" +msgstr "Ces fenêtres ne peuvent pas être fusionnées." -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 15170cfd9d666c4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Their walls meet at too sharp or too flat an angle for a corner window." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.move" -msgstr "Déplacer" +msgid "editor.panels.mergeRefusal.cornerAngle" +msgstr "Leurs murs se rejoignent à un angle trop aigu ou trop plat pour une fenêtre d’angle." -# Source-Hash: 1c0b8a5503c5daeb +# Source-Hash: f2818a1e20ebd6ca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opacity" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The window selected first is taller than the other wall. Select the other one first." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.opacity" -msgstr "Opacité" +msgid "editor.panels.mergeRefusal.heightExceedsWall" +msgstr "La fenêtre sélectionnée en premier est plus haute que l’autre mur. Sélectionnez d’abord l’autre." -# Source-Hash: 6ca213a6b299f19f +# Source-Hash: 7c97fb4af929d4db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overlay image unavailable. Replace the image to restore it." -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "They are too far apart. Windows merge with at most {reach} between them." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.overlayImageUnavailableReplaceTheImage" -msgstr "Image superposée indisponible. Remplacez l’image pour la rétablir." +msgid "editor.panels.mergeRefusal.notAdjacent" +msgstr "Elles sont trop éloignées. Les fenêtres fusionnent avec au plus {reach} entre elles." -# Source-Hash: 28fe6e9deddde6e8 +# Source-Hash: 57a281bdc4229b6d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "pos" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "One of them is too far from the corner. A window joins one within {reach} of it." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.pos" -msgstr "pos" +msgid "editor.panels.mergeRefusal.notAtCorner" +msgstr "L’une d’elles est trop loin de l’angle. Une fenêtre en rejoint une autre à moins de {reach}." -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: e7d41ce7879ec075 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A roof or dormer window cannot join another window." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.position" -msgstr "Position" +msgid "editor.panels.mergeRefusal.notOnWall" +msgstr "Une fenêtre de toit ou de lucarne ne peut pas rejoindre une autre fenêtre." -# Source-Hash: 8b003432b36230c4 +# Source-Hash: eaad567d5e4257dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Quick Actions" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{kind, select, item {Sliding them to the corner would overlap an item.} door {Sliding them to the corner would overlap a door.} window {Sliding them to the corner would overlap a window.} shelf {Sliding them to the corner would overlap a shelf.} other {Sliding them to the corner would overlap something.}}" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.quickActions" -msgstr "Actions rapides" +msgid "editor.panels.mergeRefusal.overlap" +msgstr "{kind, select, item {Les faire glisser jusqu’à l’angle chevaucherait un objet.} door {Les faire glisser jusqu’à l’angle chevaucherait une porte.} window {Les faire glisser jusqu’à l’angle chevaucherait une fenêtre.} shelf {Les faire glisser jusqu’à l’angle chevaucherait une étagère.} other {Les faire glisser jusqu’à l’angle chevaucherait un autre élément.}}" -# Source-Hash: dcd4728e9ca90181 +# Source-Hash: ecb092821ed5b5e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reference Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Their walls do not meet at a corner." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.referenceScale" -msgstr "Échelle de référence" +msgid "editor.panels.mergeRefusal.wallsNotMeeting" +msgstr "Leurs murs ne se rejoignent pas en angle." -# Source-Hash: 0cb87327b8076151 +# Source-Hash: 37d9f63758abdb67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mixed" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +#: packages/editor/src/components/ui/panels/parametric-field-control.tsx #, fuzzy -msgid "editor.panels.referencePanel.replace" -msgstr "Remplacer" +msgid "editor.panels.mixed" +msgstr "Mixte" -# Source-Hash: 08b45f9ba66eab3b +# Source-Hash: d7cf5045c01b2eb9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replacing..." -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close" +#: packages/editor/src/components/ui/panels/mobile-panel-sheet.tsx #, fuzzy -msgid "editor.panels.referencePanel.replacing" -msgstr "Remplacement..." +msgid "editor.panels.mobilePanelSheet.close" +msgstr "Fermer" -# Source-Hash: 2714b5a81cedb625 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset Image Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx #, fuzzy -msgid "editor.panels.referencePanel.resetImageScale" -msgstr "Réinitialiser l’échelle de l’image" +msgid "editor.panels.mobileSelectionBar.delete" +msgstr "Supprimer" -# Source-Hash: a05d3e429ae259ae +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset Rotation" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx #, fuzzy -msgid "editor.panels.referencePanel.resetRotation" -msgstr "Réinitialiser la rotation" +msgid "editor.panels.mobileSelectionBar.duplicate" +msgstr "Dupliquer" -# Source-Hash: 5f433581c8f404fa +# Source-Hash: 7eb955d866c2668b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "rot" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit properties" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx #, fuzzy -msgid "editor.panels.referencePanel.rot" -msgstr "rot" +msgid "editor.panels.mobileSelectionBar.editProperties" +msgstr "Modifier les propriétés" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: 89f25aa13e8192bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit {resolvedLabel}" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx #, fuzzy -msgid "editor.panels.referencePanel.rotation" -msgstr "Rotation" +msgid "editor.panels.mobileSelectionBar.editResolvedlabel" +msgstr "Modifier {resolvedLabel}" -# Source-Hash: 58fee802997c811c +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx #, fuzzy -msgid "editor.panels.referencePanel.scale" -msgstr "échelle" +msgid "editor.panels.mobileSelectionBar.move" +msgstr "Déplacer" -# Source-Hash: e7d0e7d41a775fd8 +# Source-Hash: 72be05e1796526c9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scaled · {scale}" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Currently {currentLabel}" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.panels.referencePanel.scaled" -msgstr "Mis à l’échelle · {scale}" +msgid "editor.panels.multiHeightMode.currentlyCurrentlabel" +msgstr "Actuellement {currentLabel}" -# Source-Hash: cd92eebfb30e708f +# Source-Hash: b2a1b3bc9676fe05 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scaled (hidden) · {scale}" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom height" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.panels.referencePanel.scaledHidden" -msgstr "Mis à l’échelle (masqué) · {scale}" +msgid "editor.panels.multiHeightMode.customHeight" +msgstr "Hauteur personnalisée" -# Source-Hash: bfd20999de7f216a +# Source-Hash: a5c2353769b603d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scale & Opacity" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows level" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.panels.referencePanel.scaleOpacity" -msgstr "Échelle et opacité" +msgid "editor.panels.multiHeightMode.followsLevel" +msgstr "Suit le niveau" -# Source-Hash: 8d8777505acdf78e +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.panels.referencePanel.setScale" -msgstr "Définir l’échelle" +msgid "editor.panels.multiHeightMode.height" +msgstr "Hauteur" -# Source-Hash: 827e0c6ac9936b69 +# Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.panels.referencePanel.show" -msgstr "Afficher" +msgid "editor.panels.multiHeightMode.top" +msgstr "Haut" -# Source-Hash: 78be2337f0e81973 +# Source-Hash: 70f48b0141b656f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label} (session only). Plain click reselects all members. Not saved with the project." +#: packages/editor/src/components/ui/panels/multi-parametric-inspector.tsx #, fuzzy -msgid "editor.panels.referencePanel.showScale" -msgstr "Afficher l’échelle" +msgid "editor.panels.multiParametricInspector.labelSessionOnlyPlainClickReselects" +msgstr "{label} (session uniquement). Un clic simple resélectionne tous les membres. Non enregistré avec le projet." -# Source-Hash: ad85a193442c8f76 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Uncalibrated" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.uncalibrated" -msgstr "Non calibré" +msgid "editor.panels.multiSelectionPanel.delete" +msgstr "Supprimer" -# Source-Hash: 6c500cc253ab3fd4 +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unlock" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.unlock" -msgstr "Déverrouiller" +msgid "editor.panels.multiSelectionPanel.duplicate" +msgstr "Dupliquer" -# Source-Hash: 4b8d7e52013d1691 +# Source-Hash: b0e7e3b47dfb5a0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "XYZ" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Group" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.xyz" -msgstr "XYZ" +msgid "editor.panels.multiSelectionPanel.group" +msgstr "Grouper" -# Source-Hash: e01549105012f8d2 +# Source-Hash: ca0a95fe0b08b8b6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "+ Add mezzanine" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Group (Ctrl/Cmd+G)" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.addMezzanine" -msgstr "+ Ajouter une mezzanine" +msgid "editor.panels.multiSelectionPanel.groupCtrlCmdG" +msgstr "Grouper (Ctrl/Cmd+G)" -# Source-Hash: 167b0fe7fdbcd51d +# Source-Hash: 70f48b0141b656f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A drawn slab: set its thickness and finishes here. It has no footprint height or foundation." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label} (session only). Plain click reselects all members. Not saved with the project." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.aDrawnSlabSetItsThickness" -msgstr "Dalle dessinée : définissez ici son épaisseur et ses finitions. Elle n’a ni hauteur d’emprise ni fondation." +msgid "editor.panels.multiSelectionPanel.labelSessionOnlyPlainClickReselects" +msgstr "{label} (session uniquement). Un clic simple resélectionne tous les membres. Non enregistré avec le projet." -# Source-Hash: 6cb0969b65fb60bf +# Source-Hash: fc98ef29c2842341 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "At floor level" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{length} selected" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.atFloorLevel" -msgstr "Au niveau du plancher" +msgid "editor.panels.multiSelectionPanel.lengthSelected" +msgstr "{length} sélectionnés" -# Source-Hash: e8563d5ae1ee7390 +# Source-Hash: 323aaf1ebd04ada7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Built on" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Merge windows" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.builtOn" -msgstr "Construit sur" +msgid "editor.panels.multiSelectionPanel.mergeWindows" +msgstr "Fusionner les fenêtres" -# Source-Hash: 8e5ca7510677460c +# Source-Hash: 7855d03a6140af77 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Built with" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Merge windows into a corner window: both take the height, sill and type of the one you selected first" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.builtWith" -msgstr "Construit avec" +msgid "editor.panels.multiSelectionPanel.mergeWindowsIntoACornerWindow" +msgstr "Fusionner en fenêtre d’angle : les deux prennent la hauteur, l’appui et le type de la première sélectionnée" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: b79da96502d2e1c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Merge windows into one across both: it keeps the type and style of the one you selected first" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.ceiling" -msgstr "Plafond" +msgid "editor.panels.multiSelectionPanel.mergeWindowsIntoOneAcrossBoth" +msgstr "Fusionner en une seule fenêtre sur les deux : elle garde le type et le style de la première sélectionnée" -# Source-Hash: 9bf177f59f971033 +# Source-Hash: f409934681a046e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "At {height}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select building" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.ceilingAt" -msgstr "À {height}" +msgid "editor.panels.multiSelectionPanel.selectBuilding" +msgstr "Sélectionner le bâtiment" -# Source-Hash: 48768dc0fc7b86a4 +# Source-Hash: c62a73873bd0164d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close with walls" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select the whole building to move all its levels" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.closeWithWalls" -msgstr "Fermer avec des murs" +msgid "editor.panels.multiSelectionPanel.selectTheWholeBuildingToMove" +msgstr "Sélectionnez tout le bâtiment pour déplacer tous ses niveaux" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 75c84b4f21aefde4 +# Source-Hash: 7bd5f29203a28efb # Review: required -# English: "{ambiguous, select, yes {Floor is several drawn slabs, mostly {name}} other {Floor is a drawn slab: {name}}}{shared, plural, =0 {} one { (shared with {sharedCount} room)} other { (shared with {sharedCount} rooms)}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ungroup" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.drawnFloor" -msgstr "{ambiguous, select, yes {Le plancher est composé de plusieurs dalles dessinées, surtout {name}} other {Le plancher est une dalle dessinée : {name}}}{shared, plural, =0 {} one { (partagée avec {sharedCount} pièce)} many { (partagée avec {sharedCount} pièces)} other { (partagée avec {sharedCount} pièces)}}" +msgid "editor.panels.multiSelectionPanel.ungroup" +msgstr "Dissocier" -# Source-Hash: 97e0fab8ffda6d6c +# Source-Hash: aec9c3983a440d4a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "This floor is a drawn slab: select it to edit or delete it." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ungroup (Ctrl/Cmd+Shift+G)" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.drawnFloorSwitchHint" -msgstr "Ce plancher est une dalle dessinée : sélectionnez-la pour la modifier ou la supprimer." +msgid "editor.panels.multiSelectionPanel.ungroupCtrlCmdShiftG" +msgstr "Dissocier (Ctrl/Cmd+Maj+G)" -# Source-Hash: ad5426620188242c +# Source-Hash: 420385f27c627cee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawn slab" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unwrap the corner" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.drawnSlab" -msgstr "Dalle dessinée" +msgid "editor.panels.multiSelectionPanel.unwrapTheCorner" +msgstr "Détacher l’angle" -# Source-Hash: 0da0d104eaefbbad +# Source-Hash: 7906c9f4baebc70b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawn slab at {height}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unwrap the corner: both windows stay, each framed at the corner" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.drawnSlabAt" -msgstr "Dalle dessinée à {height}" +msgid "editor.panels.multiSelectionPanel.unwrapTheCornerBothWindowsStay" +msgstr "Détacher l’angle : les deux fenêtres restent, chacune avec un cadre à l’angle" -# Source-Hash: 5dfead58503dbc86 +# Source-Hash: 170b2049ef0f9131 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit shape" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selection" +#: packages/editor/src/components/ui/panels/panel-manager.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.editShape" -msgstr "Modifier la forme" +msgid "editor.panels.panelManager.selection" +msgstr "Sélection" -# Source-Hash: fadf264be55063e5 +# Source-Hash: 7ceade8f25b58fe9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat, at wall height" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.flatAtWallHeight" -msgstr "Plat, à hauteur des murs" +msgid "editor.panels.panelWrapper.back" +msgstr "Retour" -# Source-Hash: d7148fa065bc709b +# Source-Hash: d7cf5045c01b2eb9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.floor" -msgstr "Niveau" +msgid "editor.panels.panelWrapper.close" +msgstr "Fermer" -# Source-Hash: 996e8191c069e779 +# Source-Hash: 4f15c3e0fe6178b5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{distance} down" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collapse panel" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.floorDown" -msgstr "{distance} plus bas" +msgid "editor.panels.panelWrapper.collapsePanel" +msgstr "Réduire le panneau" -# Source-Hash: 73614b8faa059cd6 +# Source-Hash: 135af27a14a4cda7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor thickness" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collections" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.floorThickness" -msgstr "Épaisseur du plancher" +msgid "editor.panels.panelWrapper.collections" +msgstr "Collections" -# Source-Hash: 79cdde853c3e8f61 +# Source-Hash: 64916cc9ea80f43f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{distance} up" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Expand panel" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.floorUp" -msgstr "{distance} plus haut" +msgid "editor.panels.panelWrapper.expandPanel" +msgstr "Développer le panneau" -# Source-Hash: 77bc12b7aba0eb60 +# Source-Hash: 8a9a25621f200922 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hand-drawn ceiling" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Manage collections…" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.handDrawnCeiling" -msgstr "Plafond dessiné à la main" +msgid "editor.panels.panelWrapper.manageCollections" +msgstr "Gérer les collections…" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: bf91b71a9aa76e94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.height" -msgstr "Hauteur" +msgid "editor.panels.panelWrapper.reset" +msgstr "Réinitialiser" -# Source-Hash: 4d35023efe090b82 +# Source-Hash: 04a212d6317f6787 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Include floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "“{title}” hit an error and was unloaded for this session." +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.includeFloor" -msgstr "Inclure le plancher" +msgid "editor.panels.panelWrapper.titleHitAnErrorAndWas" +msgstr "« {title} » a rencontré une erreur et a été déchargé pour cette session." -# Source-Hash: 6398ac77644eb5f6 +# Source-Hash: 37d9f63758abdb67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{part, select, floor {Include floor} walls {Include walls} other {Include ceiling}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mixed" +#: packages/editor/src/components/ui/panels/parametric-field-control.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.includePart" -msgstr "{part, select, floor {Inclure le plancher} walls {Inclure les murs} other {Inclure le plafond}}" +msgid "editor.panels.parametricFieldControl.mixed" +msgstr "Mixte" -# Source-Hash: 3629e64a6e796ca9 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Include walls" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/editor/src/components/ui/panels/parametric-inspector.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.includeWalls" -msgstr "Inclure les murs" +msgid "editor.panels.parametricInspector.actions" +msgstr "Actions" -# Source-Hash: f6d07fc7f239278b +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Keep outside dimensions" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/parametric-inspector.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.keepOutsideDimensions" -msgstr "Conserver les dimensions extérieures" +msgid "editor.panels.parametricInspector.delete" +msgstr "Supprimer" -# Source-Hash: 544410e3cb0e0b07 +# Source-Hash: e2411929697b7ed4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lowered {lift}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete with contents" +#: packages/editor/src/components/ui/panels/parametric-inspector.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.lowered" -msgstr "Abaissé de {lift}" +msgid "editor.panels.parametricInspector.deleteWithContents" +msgstr "Supprimer avec le contenu" -# Source-Hash: c2daf78b740e4397 +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "+ New floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/editor/src/components/ui/panels/parametric-inspector.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.newFloor" -msgstr "+ Nouveau plancher" +msgid "editor.panels.parametricInspector.move" +msgstr "Déplacer" -# Source-Hash: ba9edc7910a60cea +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.noFloor" -msgstr "Pas de plancher" +msgid "editor.panels.referencePanel.cancel" +msgstr "Annuler" -# Source-Hash: ea2675041df74f40 +# Source-Hash: 3a0701ebcb9f26cb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Nothing to change." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Capture" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.nothingToChange" -msgstr "Rien à modifier." +msgid "editor.panels.referencePanel.capture" +msgstr "Capture" -# Source-Hash: ebe0d375d7938c93 +# Source-Hash: 5211341ed18f33f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Not included" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.notIncluded" -msgstr "Non inclus" +msgid "editor.panels.referencePanel.center" +msgstr "Centre" -# Source-Hash: e9440fa9f770b7a4 +# Source-Hash: a5b965dfb0bf2cd3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "On the ground" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.onTheGround" -msgstr "Au sol" +msgid "editor.panels.referencePanel.clearScale" +msgstr "Effacer l’échelle" -# Source-Hash: a5deb36c485d91bd +# Source-Hash: 4edc6e45b0c19447 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "On the walls below" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click both ends of a known distance on the plan, then type its real length." +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.onTheWallsBelow" -msgstr "Sur les murs du dessous" +msgid "editor.panels.referencePanel.clickBothEndsOfAKnown" +msgstr "Cliquez les deux extrémités d’une distance connue sur le plan, puis saisissez sa longueur réelle." -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 2256aec0d5bdc3ea +# Source-Hash: b26de372b4b0eaac # Review: required -# English: "{openSides, plural, one {{openSideCount} open side} other {{openSideCount} open sides}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.openSides" -msgstr "{openSides, plural, one {{openSideCount} côté ouvert} many {{openSideCount} côtés ouverts} other {{openSideCount} côtés ouverts}}" +msgid "editor.panels.referencePanel.delete" +msgstr "Supprimer" -# Source-Hash: f704520c5e5b92b2 +# Source-Hash: 59f7d81e8d36a157 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Partial · {coverage, number, percent} covered" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw a line over a known dimension on the plan, then type its real length to scale the image exactly." +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.partialCovered" -msgstr "Partiel · {coverage, number, percent} couvert" +msgid "editor.panels.referencePanel.drawALineOverAKnown" +msgstr "Tracez une ligne sur une cote connue du plan, puis saisissez sa longueur réelle pour mettre l’image exactement à l’échelle." -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: b648bee0231a41cd +# Source-Hash: 42f6d0e4f065f114 # Review: required -# English: "Partial · {walls, plural, one {{wallCount} wall} other {{wallCount} walls}}, {openSides, plural, one {{openSideCount} open side} other {{openSideCount} open sides}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.partialWalls" -msgstr "Partiel · {walls, plural, one {{wallCount} mur} many {{wallCount} murs} other {{wallCount} murs}}, {openSides, plural, one {{openSideCount} côté ouvert} many {{openSideCount} côtés ouverts} other {{openSideCount} côtés ouverts}}" +msgid "editor.panels.referencePanel.editScale" +msgstr "Modifier l’échelle" -# Source-Hash: e503250e8ecb0030 +# Source-Hash: e156c84cbc90e0a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised {lift}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guide Image" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.raised" -msgstr "Surélevé de {lift}" +msgid "editor.panels.referencePanel.guideImage" +msgstr "Image de calque" -# Source-Hash: 0cb87327b8076151 +# Source-Hash: 591087ea83a48ead # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.replace" -msgstr "Remplacer" +msgid "editor.panels.referencePanel.hide" +msgstr "Masquer" -# Source-Hash: a4395168488bb476 +# Source-Hash: dd282ce13b9085ba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.select" -msgstr "Sélectionner" +msgid "editor.panels.referencePanel.hideScale" +msgstr "Masquer l’échelle" -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: fc6eaa65315f601d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Image" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.shape" -msgstr "Forme" +msgid "editor.panels.referencePanel.image" +msgstr "Image" -# Source-Hash: aafd84823715d698 +# Source-Hash: 241399e11d93bd7b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Turning walls off keeps the ones shared with {rooms}." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lock" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.sharedWallsNote" -msgstr "Désactiver les murs conserve ceux partagés avec {rooms}." +msgid "editor.panels.referencePanel.lock" +msgstr "Verrouiller" -# Source-Hash: c98df900d43f77bc +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sits on: {name} · {preset}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.sitsOnPreset" -msgstr "Repose sur : {name} · {preset}" +msgid "editor.panels.referencePanel.move" +msgstr "Déplacer" -# Source-Hash: a17a79e835fa2064 +# Source-Hash: 1c0b8a5503c5daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "the next room" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opacity" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.theNextRoom" -msgstr "la pièce voisine" +msgid "editor.panels.referencePanel.opacity" +msgstr "Opacité" -# Source-Hash: ebae699e0cb18ea6 +# Source-Hash: 6ca213a6b299f19f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use existing" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overlay image unavailable. Replace the image to restore it." +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.useExisting" -msgstr "Utiliser l’existant" +msgid "editor.panels.referencePanel.overlayImageUnavailableReplaceTheImage" +msgstr "Image superposée indisponible. Remplacez l’image pour la rétablir." -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 9976021d9162cd5e +# Source-Hash: 28fe6e9deddde6e8 # Review: required -# English: "{walls, plural, one {{wallCount} wall} other {{wallCount} walls}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "pos" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.wallCount" -msgstr "{walls, plural, one {{wallCount} mur} many {{wallCount} murs} other {{wallCount} murs}}" +msgid "editor.panels.referencePanel.pos" +msgstr "pos" -# Source-Hash: aac9a732d2159ccc +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.walls" -msgstr "Murs" +msgid "editor.panels.referencePanel.position" +msgstr "Position" -# Source-Hash: 6c69eb46a0c40d52 +# Source-Hash: 8b003432b36230c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls thicken inward, so the building's outer size stays the same." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Quick Actions" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.wallsThickenInwardSoTheBuilding" -msgstr "Les murs s’épaississent vers l’intérieur : la taille extérieure du bâtiment reste la même." +msgid "editor.panels.referencePanel.quickActions" +msgstr "Actions rapides" -# Source-Hash: 4e4f1a24e4a9d61e +# Source-Hash: dcd4728e9ca90181 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut opening" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reference Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.cutOpening" -msgstr "Découper une ouverture" +msgid "editor.panels.referencePanel.referenceScale" +msgstr "Échelle de référence" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: 0cb87327b8076151 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.done" -msgstr "Terminé" +msgid "editor.panels.referencePanel.replace" +msgstr "Remplacer" -# Source-Hash: 2c89abb1778a3f9b +# Source-Hash: 08b45f9ba66eab3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit floor" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replacing..." +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.editFloor" -msgstr "Modifier le plancher" +msgid "editor.panels.referencePanel.replacing" +msgstr "Remplacement..." -# Source-Hash: ca18a6c5398fc8ab +# Source-Hash: 2714b5a81cedb625 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevator opening" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset Image Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.elevatorOpening" -msgstr "Trémie d’ascenseur" +msgid "editor.panels.referencePanel.resetImageScale" +msgstr "Réinitialiser l’échelle de l’image" -# Source-Hash: eafea43e795f3708 +# Source-Hash: a05d3e429ae259ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No openings yet. Cut one for a stair void or a hatch." -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset Rotation" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.noOpeningsYetCutOneFor" -msgstr "Aucune ouverture pour l’instant. Découpez-en une pour une trémie d’escalier ou une trappe." +msgid "editor.panels.referencePanel.resetRotation" +msgstr "Réinitialiser la rotation" -# Source-Hash: 60fac94ffa614238 +# Source-Hash: 5f433581c8f404fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening {number}" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "rot" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.openingNumber" -msgstr "Ouverture {number}" +msgid "editor.panels.referencePanel.rot" +msgstr "rot" -# Source-Hash: 7aafbf90d659dcf6 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, =0 {No openings} one {{number} opening} other {{number} openings}}" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.openings" -msgstr "{count, plural, =0 {Aucune ouverture} one {{number} ouverture} many {{number} ouvertures} other {{number} ouvertures}}" +msgid "editor.panels.referencePanel.rotation" +msgstr "Rotation" -# Source-Hash: c1a1794d31990f5a +# Source-Hash: 58fee802997c811c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair opening" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.stairOpening" -msgstr "Trémie d’escalier" +msgid "editor.panels.referencePanel.scale" +msgstr "échelle" -# Source-Hash: f0a46329fef44d94 +# Source-Hash: e7d0e7d41a775fd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add stairs" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scaled · {scale}" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.addStairs" -msgstr "Ajouter un escalier" +msgid "editor.panels.referencePanel.scaled" +msgstr "Mis à l’échelle · {scale}" -# Source-Hash: 8a2ab34a61b9d181 +# Source-Hash: cd92eebfb30e708f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add to a unit" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scaled (hidden) · {scale}" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.addToAUnit" -msgstr "Ajouter à un logement" +msgid "editor.panels.referencePanel.scaledHidden" +msgstr "Mis à l’échelle (masqué) · {scale}" -# Source-Hash: 8332ab41e22958f1 +# Source-Hash: bfd20999de7f216a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Area" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scale & Opacity" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.area" -msgstr "Surface" +msgid "editor.panels.referencePanel.scaleOpacity" +msgstr "Échelle et opacité" -# Source-Hash: 88f1a727e5528c10 +# Source-Hash: 8d8777505acdf78e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Browse" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.browse" -msgstr "Parcourir" +msgid "editor.panels.referencePanel.setScale" +msgstr "Définir l’échelle" -# Source-Hash: 8e5ca7510677460c +# Source-Hash: 827e0c6ac9936b69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Built with" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.builtWith" -msgstr "Construit avec" +msgid "editor.panels.referencePanel.show" +msgstr "Afficher" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: 78be2337f0e81973 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.ceiling" -msgstr "Plafond" +msgid "editor.panels.referencePanel.showScale" +msgstr "Afficher l’échelle" -# Source-Hash: a5e4fe4960deced9 +# Source-Hash: ad85a193442c8f76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete room" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Uncalibrated" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.deleteRoom" -msgstr "Supprimer la pièce" +msgid "editor.panels.referencePanel.uncalibrated" +msgstr "Non calibré" -# Source-Hash: 5dfead58503dbc86 +# Source-Hash: 6c500cc253ab3fd4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit shape" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unlock" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.editShape" -msgstr "Modifier la forme" +msgid "editor.panels.referencePanel.unlock" +msgstr "Déverrouiller" -# Source-Hash: d7148fa065bc709b +# Source-Hash: 4b8d7e52013d1691 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "XYZ" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.floor" -msgstr "Niveau" +msgid "editor.panels.referencePanel.xyz" +msgstr "XYZ" -# Source-Hash: d17c3b63449c052b +# Source-Hash: e01549105012f8d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{height} headroom" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "+ Add mezzanine" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.headroom" -msgstr "Échappée de {height}" +msgid "editor.panels.roomConstructionRows.addMezzanine" +msgstr "+ Ajouter une mezzanine" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: 167b0fe7fdbcd51d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A drawn slab: set its thickness and finishes here. It has no footprint height or foundation." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.height" -msgstr "Hauteur" +msgid "editor.panels.roomConstructionRows.aDrawnSlabSetItsThickness" +msgstr "Dalle dessinée : définissez ici son épaisseur et ses finitions. Elle n’a ni hauteur d’emprise ni fondation." -# Source-Hash: 2d89c1638aa8dd7e +# Source-Hash: 6cb0969b65fb60bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide code" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "At floor level" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.hideCode" -msgstr "Masquer le code" +msgid "editor.panels.roomConstructionRows.atFloorLevel" +msgstr "Au niveau du plancher" -# Source-Hash: e93969f5a7cbb140 +# Source-Hash: e14858b33b6e2623 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room · {level}" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.kickerLevel" -msgstr "Pièce · {level}" +msgid "editor.panels.roomConstructionRows.beam" +msgstr "Poutre" -# Source-Hash: f4ad56b4e0c014b3 +# Source-Hash: 4b03c226d5f88a42 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine · in {room}" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam size" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.kickerMezzanineIn" -msgstr "Mezzanine · dans {room}" +msgid "editor.panels.roomConstructionRows.beamSize" +msgstr "Taille de la poutre" -# Source-Hash: de37205633316011 +# Source-Hash: e8563d5ae1ee7390 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room · not enclosed" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Built on" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.kickerNotEnclosed" -msgstr "Pièce · non fermée" +msgid "editor.panels.roomConstructionRows.builtOn" +msgstr "Construit sur" -# Source-Hash: 9e84d6d7b9885c4f +# Source-Hash: 8e5ca7510677460c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Loading…" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Built with" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.loading" -msgstr "Chargement…" +msgid "editor.panels.roomConstructionRows.builtWith" +msgstr "Construit avec" -# Source-Hash: 194a147d4618a994 +# Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.mezzanine" -msgstr "Mezzanine" +msgid "editor.panels.roomConstructionRows.ceiling" +msgstr "Plafond" -# Source-Hash: 97de3df03c4a0be6 +# Source-Hash: 9bf177f59f971033 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine name" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "At {height}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.mezzanineName" -msgstr "Nom de la mezzanine" +msgid "editor.panels.roomConstructionRows.ceilingAt" +msgstr "À {height}" -# Source-Hash: 42cfb1bcb80d09e7 +# Source-Hash: 48768dc0fc7b86a4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine names" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close with walls" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.mezzanineNames" -msgstr "Noms de mezzanine" +msgid "editor.panels.roomConstructionRows.closeWithWalls" +msgstr "Fermer avec des murs" -# Source-Hash: 13b3e6a6afe319d1 +# Source-Hash: 75c84b4f21aefde4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "New unit" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{ambiguous, select, yes {Floor is several drawn slabs, mostly {name}} other {Floor is a drawn slab: {name}}}{shared, plural, =0 {} one { (shared with {sharedCount} room)} other { (shared with {sharedCount} rooms)}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.newUnit" -msgstr "Nouveau logement" +msgid "editor.panels.roomConstructionRows.drawnFloor" +msgstr "{ambiguous, select, yes {Le plancher est composé de plusieurs dalles dessinées, surtout {name}} other {Le plancher est une dalle dessinée : {name}}}{shared, plural, =0 {} one { (partagée avec {sharedCount} pièce)} many { (partagée avec {sharedCount} pièces)} other { (partagée avec {sharedCount} pièces)}}" -# Source-Hash: f2953d2931e36d0c +# Source-Hash: 97e0fab8ffda6d6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This floor is a drawn slab: select it to edit or delete it." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.none" -msgstr "Aucun" +msgid "editor.panels.roomConstructionRows.drawnFloorSwitchHint" +msgstr "Ce plancher est une dalle dessinée : sélectionnez-la pour la modifier ou la supprimer." -# Source-Hash: e92d6108b57df9e1 +# Source-Hash: ad5426620188242c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Not enough headroom" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawn slab" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.notEnoughHeadroom" -msgstr "Échappée insuffisante" +msgid "editor.panels.roomConstructionRows.drawnSlab" +msgstr "Dalle dessinée" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 81a6770092b05d48 +# Source-Hash: 0da0d104eaefbbad # Review: required -# English: "{doors, plural, one {{doorCount} door} other {{doorCount} doors}} · {windows, plural, one {{windowCount} window} other {{windowCount} windows}}" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawn slab at {height}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.openingCounts" -msgstr "{doors, plural, one {{doorCount} porte} many {{doorCount} portes} other {{doorCount} portes}} · {windows, plural, one {{windowCount} fenêtre} many {{windowCount} fenêtres} other {{windowCount} fenêtres}}" +msgid "editor.panels.roomConstructionRows.drawnSlabAt" +msgstr "Dalle dessinée à {height}" -# Source-Hash: a8cd9507ce472a48 +# Source-Hash: 5dfead58503dbc86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{area} · Close its walls to build its floor and ceiling." -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit shape" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.openRoomArea" -msgstr "{area} · Fermez ses murs pour construire son plancher et son plafond." +msgid "editor.panels.roomConstructionRows.editShape" +msgstr "Modifier la forme" -# Source-Hash: f8aa48ec39a15616 +# Source-Hash: fadf264be55063e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Over the mezzanine" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat, at wall height" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.overTheMezzanine" -msgstr "Au-dessus de la mezzanine" +msgid "editor.panels.roomConstructionRows.flatAtWallHeight" +msgstr "Plat, à hauteur des murs" -# Source-Hash: ac87e14dabd5a256 +# Source-Hash: d7148fa065bc709b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Perimeter" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.perimeter" -msgstr "Périmètre" +msgid "editor.panels.roomConstructionRows.floor" +msgstr "Niveau" -# Source-Hash: ed2aaf0a8d5a9b7b +# Source-Hash: 996e8191c069e779 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{distance} down" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.pick" -msgstr "Choisir" +msgid "editor.panels.roomConstructionRows.floorDown" +msgstr "{distance} plus bas" -# Source-Hash: 7baaebbd411cc837 +# Source-Hash: 73614b8faa059cd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picking it adds a number" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor thickness" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.pickingItAddsANumber" -msgstr "Le choisir ajoute un numéro" +msgid "editor.panels.roomConstructionRows.floorThickness" +msgstr "Épaisseur du plancher" -# Source-Hash: 9469a102f04ea196 +# Source-Hash: 79cdde853c3e8f61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{distance} up" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.remove" -msgstr "Retirer" +msgid "editor.panels.roomConstructionRows.floorUp" +msgstr "{distance} plus haut" -# Source-Hash: 41ac9dd23bb558d7 +# Source-Hash: b6b724f9f4db6d3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove from unit" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{posts, plural, one {{postCount} post} other {{postCount} posts}} and {beams, plural, one {{beamCount} beam} other {{beamCount} beams}}, a post on each outside corner, kept with {room, select, deck {the deck} patio {the patio} other {the porch}}." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.removeFromUnit" -msgstr "Retirer du logement" +msgid "editor.panels.roomConstructionRows.framingAutoHint" +msgstr "{posts, plural, one {{postCount} poteau} many {{postCount} poteaux} other {{postCount} poteaux}} et {beams, plural, one {{beamCount} poutre} many {{beamCount} poutres} other {{beamCount} poutres}}, un poteau à chaque angle extérieur, rattachés {room, select, deck {à la terrasse} patio {au patio} other {au porche}}." -# Source-Hash: a11d13b92b3cefdb +# Source-Hash: d18036b75b2c3e4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove from {unit}" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Automatic" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.removeFromUnitNamed" -msgstr "Retirer de {unit}" +msgid "editor.panels.roomConstructionRows.framingAutomatic" +msgstr "Automatique" -# Source-Hash: d6952b4e54d246dd +# Source-Hash: 387082cd5f118bed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rename" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Manual" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.rename" -msgstr "Renommer" +msgid "editor.panels.roomConstructionRows.framingManual" +msgstr "Manuel" -# Source-Hash: 3562f9bea0a4a8f3 +# Source-Hash: 287400b1b4b46abd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{name} · Rename" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kept as you edited them. Automatic rebuilds them from these settings." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.renameNamed" -msgstr "{name} · Renommer" +msgid "editor.panels.roomConstructionRows.framingManualHint" +msgstr "Conservés tels que vous les avez modifiés. Automatique les reconstruit à partir de ces réglages." -# Source-Hash: d0d4e919bb58a977 +# Source-Hash: 50accd740fa2e736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Revert" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Off" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.revert" -msgstr "Rétablir" +msgid "editor.panels.roomConstructionRows.framingOff" +msgstr "Désactivé" -# Source-Hash: 612dcd5bf06a79c4 +# Source-Hash: 4dfa7082b7e30280 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None. Automatic puts a post on each outside corner and a beam on them, to carry a roof over {room, select, deck {the deck} patio {the patio} other {the porch}}." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.room" -msgstr "Pièce" +msgid "editor.panels.roomConstructionRows.framingOffHint" +msgstr "Aucun. Automatique place un poteau à chaque angle extérieur et une poutre dessus, pour porter un toit au-dessus {room, select, deck {de la terrasse} patio {du patio} other {du porche}}." -# Source-Hash: 15ae260fae44f42f +# Source-Hash: 77bc12b7aba0eb60 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room colour — used in the plan and labels" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hand-drawn ceiling" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.roomColourUsedInThePlan" -msgstr "Couleur de la pièce — utilisée dans le plan et les étiquettes" +msgid "editor.panels.roomConstructionRows.handDrawnCeiling" +msgstr "Plafond dessiné à la main" -# Source-Hash: bf75e739dd7e5877 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room name" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.roomName" -msgstr "Nom de la pièce" +msgid "editor.panels.roomConstructionRows.height" +msgstr "Hauteur" -# Source-Hash: 2ecf8c059646873b +# Source-Hash: 4d35023efe090b82 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room names" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Include floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.roomNames" -msgstr "Noms des pièces" +msgid "editor.panels.roomConstructionRows.includeFloor" +msgstr "Inclure le plancher" -# Source-Hash: e9a0a3688faba18b +# Source-Hash: 6398ac77644eb5f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scripted finish" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{part, select, floor {Include floor} walls {Include walls} other {Include ceiling}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.scriptedFinish" -msgstr "Finition scriptée" +msgid "editor.panels.roomConstructionRows.includePart" +msgstr "{part, select, floor {Inclure le plancher} walls {Inclure les murs} other {Inclure le plafond}}" -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: 3629e64a6e796ca9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Include walls" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.shape" -msgstr "Forme" +msgid "editor.panels.roomConstructionRows.includeWalls" +msgstr "Inclure les murs" -# Source-Hash: e51144ca1759a7bf +# Source-Hash: f6d07fc7f239278b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show mezzanine names" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keep outside dimensions" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.showMezzanineNames" -msgstr "Afficher les noms de mezzanine" +msgid "editor.panels.roomConstructionRows.keepOutsideDimensions" +msgstr "Conserver les dimensions extérieures" -# Source-Hash: 875b7303c47df33f +# Source-Hash: 544410e3cb0e0b07 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show room names" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lowered {lift}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.showRoomNames" -msgstr "Afficher les noms des pièces" +msgid "editor.panels.roomConstructionRows.lowered" +msgstr "Abaissé de {lift}" -# Source-Hash: f05bc67c57e4d530 +# Source-Hash: c2daf78b740e4397 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stairs" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "+ New floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.stairs" -msgstr "Escalier" +msgid "editor.panels.roomConstructionRows.newFloor" +msgstr "+ Nouveau plancher" -# Source-Hash: 062cc0f1afef0c52 +# Source-Hash: ba9edc7910a60cea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unit" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.unit" -msgstr "Lot" +msgid "editor.panels.roomConstructionRows.noFloor" +msgstr "Pas de plancher" -# Source-Hash: 91436d6b374e8263 +# Source-Hash: ea2675041df74f40 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Nothing to change." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.use" -msgstr "Utiliser" +msgid "editor.panels.roomConstructionRows.nothingToChange" +msgstr "Rien à modifier." -# Source-Hash: 61880aff6cd698c9 +# Source-Hash: ebe0d375d7938c93 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{used} on this level" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not included" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.usedOnThisLevel" -msgstr "{used} sur ce niveau" +msgid "editor.panels.roomConstructionRows.notIncluded" +msgstr "Non inclus" -# Source-Hash: 611604740ed4549c +# Source-Hash: e9440fa9f770b7a4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{use} “{name}”" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On the ground" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.useTyped" -msgstr "{use} « {name} »" +msgid "editor.panels.roomConstructionRows.onTheGround" +msgstr "Au sol" -# Source-Hash: 21242af83a2a6d17 +# Source-Hash: a5deb36c485d91bd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "View code" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On the walls below" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.viewCode" -msgstr "Voir le code" +msgid "editor.panels.roomConstructionRows.onTheWallsBelow" +msgstr "Sur les murs du dessous" -# Source-Hash: ba15840e60ce672b +# Source-Hash: 2256aec0d5bdc3ea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The script could not be read." -#: packages/editor/src/components/ui/panels/room-panel.tsx -#: packages/nodes/src/wall/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{openSides, plural, one {{openSideCount} open side} other {{openSideCount} open sides}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.scriptUnreadable" -msgstr "Le script n’a pas pu être lu." +msgid "editor.panels.roomConstructionRows.openSides" +msgstr "{openSides, plural, one {{openSideCount} côté ouvert} many {{openSideCount} côtés ouverts} other {{openSideCount} côtés ouverts}}" -# Source-Hash: 4e186fc057733162 +# Source-Hash: f704520c5e5b92b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Polygon" -#: packages/editor/src/components/ui/panels/shape-choice.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Partial · {coverage, number, percent} covered" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.shapeChoice.polygon" -msgstr "Polygone" - -# Source-Hash: 2c2c20272b0370cc +msgid "editor.panels.roomConstructionRows.partialCovered" +msgstr "Partiel · {coverage, number, percent} couvert" + +# Source-Hash: b648bee0231a41cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangle" -#: packages/editor/src/components/ui/panels/shape-choice.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Partial · {walls, plural, one {{wallCount} wall} other {{wallCount} walls}}, {openSides, plural, one {{openSideCount} open side} other {{openSideCount} open sides}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.shapeChoice.rectangle" -msgstr "Rectangle" +msgid "editor.panels.roomConstructionRows.partialWalls" +msgstr "Partiel · {walls, plural, one {{wallCount} mur} many {{wallCount} murs} other {{wallCount} murs}}, {openSides, plural, one {{openSideCount} côté ouvert} many {{openSideCount} côtés ouverts} other {{openSideCount} côtés ouverts}}" -# Source-Hash: 5dc88f90e6aa4129 +# Source-Hash: 4b2a51c39b382184 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete region" -#: packages/editor/src/components/ui/panels/wall-region-list.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Posts and beam" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.wallRegionList.deleteRegion" -msgstr "Supprimer la zone" +msgid "editor.panels.roomConstructionRows.postsAndBeam" +msgstr "Poteaux et poutre" -# Source-Hash: d81d8cbadf5d4f33 +# Source-Hash: faa36308c1ecb2a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint regions" -#: packages/editor/src/components/ui/panels/wall-region-list.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post size" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.wallRegionList.paintRegions" -msgstr "Zones de peinture" +msgid "editor.panels.roomConstructionRows.postSize" +msgstr "Taille des poteaux" +# Source-Hash: cc25439729a97f76 # Review: required -# Source-Hash: 89ee318aad485f83 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Adjust design" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post spacing (max)" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.adjustDesign" -msgstr "Ajuster le modèle" +msgid "editor.panels.roomConstructionRows.postSpacingMax" +msgstr "Espacement des poteaux (max.)" +# Source-Hash: e503250e8ecb0030 # Review: required -# Source-Hash: 7ceade8f25b58fe9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised {lift}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.back" -msgstr "Retour" +msgid "editor.panels.roomConstructionRows.raised" +msgstr "Surélevé de {lift}" +# Source-Hash: 0cb87327b8076151 # Review: required -# Source-Hash: ba9b68175315e177 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit parts" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.editParts" -msgstr "Modifier les pièces" +msgid "editor.panels.roomConstructionRows.replace" +msgstr "Remplacer" +# Source-Hash: be1c56bb3ddc63c7 # Review: required -# Source-Hash: 07c62820f014ed6c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid attachment" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room type" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidAttachment" -msgstr "Fixation non valide" +msgid "editor.panels.roomConstructionRows.roomType" +msgstr "Type de pièce" +# Source-Hash: f3aa561772702108 # Review: required -# Source-Hash: f862aea8d7957c55 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid edit" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidEdit" -msgstr "Modification non valide" +msgid "editor.panels.roomConstructionRows.roomTypeDeck" +msgstr "Terrasse" +# Source-Hash: f0028986efecf7d1 # Review: required -# Source-Hash: 190cf30b8edd8dd1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid placement" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outdoors: deck boards on a wood frame and posts, 1 in down from the house; no ceiling." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidPlacement" -msgstr "Placement non valide" +msgid "editor.panels.roomConstructionRows.roomTypeDeckHint" +msgstr "Extérieur : lames de terrasse sur ossature bois et poteaux, 1 in plus bas que la maison ; pas de plafond." +# Source-Hash: 78dbe13192c0894b # Review: required -# Source-Hash: 45bd2ec690cc48dc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid position" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Patio" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidPosition" -msgstr "Position non valide" +msgid "editor.panels.roomConstructionRows.roomTypePatio" +msgstr "Patio" +# Source-Hash: 5e4ea6a084f67808 # Review: required -# Source-Hash: faccab895717c598 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid reset" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outdoors and open: a concrete slab 1½ in down from the house, no ceiling." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidReset" -msgstr "Réinitialisation non valide" +msgid "editor.panels.roomConstructionRows.roomTypePatioHint" +msgstr "Extérieur ouvert : dalle béton 1½ in plus bas que la maison, sans plafond." +# Source-Hash: 97d20e41044a3235 # Review: required -# Source-Hash: 28fe6e9deddde6e8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "pos" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Porch" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.pos" -msgstr "pos" +msgid "editor.panels.roomConstructionRows.roomTypePorch" +msgstr "Porche" +# Source-Hash: af2c941e8ef874bf # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outdoors under a ceiling: a concrete slab 1½ in down from the house, ceiling at the house’s." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.position" -msgstr "Position" +msgid "editor.panels.roomConstructionRows.roomTypePorchHint" +msgstr "Extérieur couvert : dalle béton 1½ in plus bas que la maison, plafond à la hauteur de celui de la maison." +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# Source-Hash: 3fce677837d5a876 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset this part" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.resetThisPart" -msgstr "Réinitialiser cette pièce" +msgid "editor.panels.roomConstructionRows.roomTypeRoom" +msgstr "Pièce" -# Source-Hash: 5eab376947d29a50 +# Source-Hash: fb0a6cc444058631 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reload editor" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An ordinary room inside the house." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.reloadEditor" -msgstr "Recharger l’éditeur" +msgid "editor.panels.roomConstructionRows.roomTypeRoomHint" +msgstr "Une pièce ordinaire, à l’intérieur de la maison." +# Source-Hash: a4395168488bb476 # Review: required -# Source-Hash: 1063f1e315258b20 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close riser diagram" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.close" -msgstr "Fermer le schéma de colonnes" +msgid "editor.panels.roomConstructionRows.select" +msgstr "Sélectionner" +# Source-Hash: 85ea1d3c8b749680 # Review: required -# Source-Hash: c2d59ee62035974c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV plumbing isometric" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.dwvPlumbingIsometric" -msgstr "Isométrie d'évacuation et de ventilation" +msgid "editor.panels.roomConstructionRows.shape" +msgstr "Forme" +# Source-Hash: aafd84823715d698 # Review: required -# Source-Hash: 3501a7c8a93d3b19 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV riser diagram" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turning walls off keeps the ones shared with {rooms}." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.dwvRiserDiagram" -msgstr "Schéma des colonnes d'évacuation" +msgid "editor.panels.roomConstructionRows.sharedWallsNote" +msgstr "Désactiver les murs conserve ceux partagés avec {rooms}." +# Source-Hash: c98df900d43f77bc # Review: required -# Source-Hash: 225e3e3dc3bb01ee -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No drain, waste, or vent pipes yet. Draw plumbing to see the riser diagram." -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sits on: {name} · {preset}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.noDrainWasteOrVentPipes" -msgstr "Aucun tuyau d'évacuation ou de ventilation pour l'instant. Dessinez la plomberie pour voir le schéma de colonnes." +msgid "editor.panels.roomConstructionRows.sitsOnPreset" +msgstr "Repose sur : {name} · {preset}" +# Source-Hash: a17a79e835fa2064 # Review: required -# Source-Hash: bc8e172ba55160ae -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Riser Diagram" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "the next room" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.riserDiagram" -msgstr "Schéma de colonnes" +msgid "editor.panels.roomConstructionRows.theNextRoom" +msgstr "la pièce voisine" +# Source-Hash: ebae699e0cb18ea6 # Review: required -# Source-Hash: 6a1132961f17f320 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{diameter}\" P-trap" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use existing" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.trap" -msgstr "Siphon {diameter}\"" +msgid "editor.panels.roomConstructionRows.useExisting" +msgstr "Utiliser l’existant" +# Source-Hash: 9976021d9162cd5e # Review: required -# Source-Hash: 04bc0909a133a7e9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vent" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{walls, plural, one {{wallCount} wall} other {{wallCount} walls}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.vent" -msgstr "Ventilation" +msgid "editor.panels.roomConstructionRows.wallCount" +msgstr "{walls, plural, one {{wallCount} mur} many {{wallCount} murs} other {{wallCount} murs}}" +# Source-Hash: aac9a732d2159ccc # Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +#, fuzzy +msgid "editor.panels.roomConstructionRows.walls" +msgstr "Murs" + +# Source-Hash: 6c69eb46a0c40d52 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls thicken inward, so the building's outer size stays the same." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +#, fuzzy +msgid "editor.panels.roomConstructionRows.wallsThickenInwardSoTheBuilding" +msgstr "Les murs s’épaississent vers l’intérieur : la taille extérieure du bâtiment reste la même." + +# Source-Hash: 4e4f1a24e4a9d61e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut opening" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx +#, fuzzy +msgid "editor.panels.roomOpeningsField.cutOpening" +msgstr "Découper une ouverture" + +# Source-Hash: 16552c2580bbe8b8 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx +#, fuzzy +msgid "editor.panels.roomOpeningsField.done" +msgstr "Terminé" + +# Source-Hash: 2c89abb1778a3f9b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit floor" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx +#, fuzzy +msgid "editor.panels.roomOpeningsField.editFloor" +msgstr "Modifier le plancher" + +# Source-Hash: ca18a6c5398fc8ab +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevator opening" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx +#, fuzzy +msgid "editor.panels.roomOpeningsField.elevatorOpening" +msgstr "Trémie d’ascenseur" + +# Source-Hash: eafea43e795f3708 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No openings yet. Cut one for a stair void or a hatch." +#: packages/editor/src/components/ui/panels/room-openings-field.tsx +#, fuzzy +msgid "editor.panels.roomOpeningsField.noOpeningsYetCutOneFor" +msgstr "Aucune ouverture pour l’instant. Découpez-en une pour une trémie d’escalier ou une trappe." + +# Source-Hash: 60fac94ffa614238 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening {number}" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx +#, fuzzy +msgid "editor.panels.roomOpeningsField.openingNumber" +msgstr "Ouverture {number}" + +# Source-Hash: 7aafbf90d659dcf6 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, =0 {No openings} one {{number} opening} other {{number} openings}}" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx +#, fuzzy +msgid "editor.panels.roomOpeningsField.openings" +msgstr "{count, plural, =0 {Aucune ouverture} one {{number} ouverture} many {{number} ouvertures} other {{number} ouvertures}}" + +# Source-Hash: c1a1794d31990f5a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair opening" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx +#, fuzzy +msgid "editor.panels.roomOpeningsField.stairOpening" +msgstr "Trémie d’escalier" + +# Source-Hash: f0a46329fef44d94 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add stairs" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.addStairs" +msgstr "Ajouter un escalier" + +# Source-Hash: 8a2ab34a61b9d181 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add to a unit" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.addToAUnit" +msgstr "Ajouter à un logement" + +# Source-Hash: 8332ab41e22958f1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Area" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.area" +msgstr "Surface" + +# Source-Hash: 88f1a727e5528c10 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Browse" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.browse" +msgstr "Parcourir" + +# Source-Hash: 8e5ca7510677460c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Built with" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.builtWith" +msgstr "Construit avec" + +# Source-Hash: 4275c05172abd7fb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.ceiling" +msgstr "Plafond" + +# Source-Hash: a5e4fe4960deced9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete room" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.deleteRoom" +msgstr "Supprimer la pièce" + +# Source-Hash: 5dfead58503dbc86 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit shape" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.editShape" +msgstr "Modifier la forme" + +# Source-Hash: d7148fa065bc709b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.floor" +msgstr "Niveau" + +# Source-Hash: d17c3b63449c052b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{height} headroom" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.headroom" +msgstr "Échappée de {height}" + +# Source-Hash: 646ef0fbcbc58edf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.height" +msgstr "Hauteur" + +# Source-Hash: 2d89c1638aa8dd7e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide code" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.hideCode" +msgstr "Masquer le code" + +# Source-Hash: e93969f5a7cbb140 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room · {level}" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.kickerLevel" +msgstr "Pièce · {level}" + +# Source-Hash: f4ad56b4e0c014b3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine · in {room}" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.kickerMezzanineIn" +msgstr "Mezzanine · dans {room}" + +# Source-Hash: de37205633316011 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room · not enclosed" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.kickerNotEnclosed" +msgstr "Pièce · non fermée" + +# Source-Hash: 9e84d6d7b9885c4f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Loading…" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.loading" +msgstr "Chargement…" + +# Source-Hash: 194a147d4618a994 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.mezzanine" +msgstr "Mezzanine" + +# Source-Hash: 97de3df03c4a0be6 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine name" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.mezzanineName" +msgstr "Nom de la mezzanine" + +# Source-Hash: 42cfb1bcb80d09e7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine names" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.mezzanineNames" +msgstr "Noms de mezzanine" + +# Source-Hash: 13b3e6a6afe319d1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New unit" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.newUnit" +msgstr "Nouveau logement" + +# Source-Hash: f2953d2931e36d0c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.none" +msgstr "Aucun" + +# Source-Hash: e92d6108b57df9e1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not enough headroom" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.notEnoughHeadroom" +msgstr "Échappée insuffisante" + +# Source-Hash: 81a6770092b05d48 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{doors, plural, one {{doorCount} door} other {{doorCount} doors}} · {windows, plural, one {{windowCount} window} other {{windowCount} windows}}" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.openingCounts" +msgstr "{doors, plural, one {{doorCount} porte} many {{doorCount} portes} other {{doorCount} portes}} · {windows, plural, one {{windowCount} fenêtre} many {{windowCount} fenêtres} other {{windowCount} fenêtres}}" + +# Source-Hash: a8cd9507ce472a48 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} · Close its walls to build its floor and ceiling." +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.openRoomArea" +msgstr "{area} · Fermez ses murs pour construire son plancher et son plafond." + +# Source-Hash: f8aa48ec39a15616 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Over the mezzanine" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.overTheMezzanine" +msgstr "Au-dessus de la mezzanine" + +# Source-Hash: ac87e14dabd5a256 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Perimeter" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.perimeter" +msgstr "Périmètre" + +# Source-Hash: ed2aaf0a8d5a9b7b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.pick" +msgstr "Choisir" + +# Source-Hash: 7baaebbd411cc837 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picking it adds a number" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.pickingItAddsANumber" +msgstr "Le choisir ajoute un numéro" + +# Source-Hash: 9469a102f04ea196 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.remove" +msgstr "Retirer" + +# Source-Hash: 41ac9dd23bb558d7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove from unit" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.removeFromUnit" +msgstr "Retirer du logement" + +# Source-Hash: a11d13b92b3cefdb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove from {unit}" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.removeFromUnitNamed" +msgstr "Retirer de {unit}" + +# Source-Hash: d6952b4e54d246dd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rename" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.rename" +msgstr "Renommer" + +# Source-Hash: 3562f9bea0a4a8f3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{name} · Rename" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.renameNamed" +msgstr "{name} · Renommer" + +# Source-Hash: d0d4e919bb58a977 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Revert" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.revert" +msgstr "Rétablir" + +# Source-Hash: 612dcd5bf06a79c4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.room" +msgstr "Pièce" + +# Source-Hash: 15ae260fae44f42f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room colour — used in the plan and labels" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.roomColourUsedInThePlan" +msgstr "Couleur de la pièce — utilisée dans le plan et les étiquettes" + +# Source-Hash: bf75e739dd7e5877 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room name" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.roomName" +msgstr "Nom de la pièce" + +# Source-Hash: 2ecf8c059646873b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room names" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.roomNames" +msgstr "Noms des pièces" + +# Source-Hash: e9a0a3688faba18b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scripted finish" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.scriptedFinish" +msgstr "Finition scriptée" + +# Source-Hash: 85ea1d3c8b749680 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.shape" +msgstr "Forme" + +# Source-Hash: e51144ca1759a7bf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show mezzanine names" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.showMezzanineNames" +msgstr "Afficher les noms de mezzanine" + +# Source-Hash: 875b7303c47df33f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show room names" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.showRoomNames" +msgstr "Afficher les noms des pièces" + +# Source-Hash: f05bc67c57e4d530 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stairs" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.stairs" +msgstr "Escalier" + +# Source-Hash: 062cc0f1afef0c52 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unit" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.unit" +msgstr "Lot" + +# Source-Hash: 91436d6b374e8263 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.use" +msgstr "Utiliser" + +# Source-Hash: 61880aff6cd698c9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{used} on this level" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.usedOnThisLevel" +msgstr "{used} sur ce niveau" + +# Source-Hash: 611604740ed4549c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{use} “{name}”" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.useTyped" +msgstr "{use} « {name} »" + +# Source-Hash: 21242af83a2a6d17 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "View code" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.viewCode" +msgstr "Voir le code" + +# Source-Hash: ba15840e60ce672b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The script could not be read." +#: packages/editor/src/components/ui/panels/room-panel.tsx +#: packages/nodes/src/wall/panel.tsx +#, fuzzy +msgid "editor.panels.scriptUnreadable" +msgstr "Le script n’a pas pu être lu." + +# Source-Hash: 4e186fc057733162 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Polygon" +#: packages/editor/src/components/ui/panels/shape-choice.tsx +#, fuzzy +msgid "editor.panels.shapeChoice.polygon" +msgstr "Polygone" + +# Source-Hash: 2c2c20272b0370cc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangle" +#: packages/editor/src/components/ui/panels/shape-choice.tsx +#, fuzzy +msgid "editor.panels.shapeChoice.rectangle" +msgstr "Rectangle" + +# Source-Hash: 5dc88f90e6aa4129 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete region" +#: packages/editor/src/components/ui/panels/wall-region-list.tsx +#, fuzzy +msgid "editor.panels.wallRegionList.deleteRegion" +msgstr "Supprimer la zone" + +# Source-Hash: d81d8cbadf5d4f33 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint regions" +#: packages/editor/src/components/ui/panels/wall-region-list.tsx +#, fuzzy +msgid "editor.panels.wallRegionList.paintRegions" +msgstr "Zones de peinture" + +# Source-Hash: 89ee318aad485f83 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Adjust design" +#: packages/editor/src/components/procedural-items/inspector.tsx +#, fuzzy +msgid "editor.proceduralItems.inspector.adjustDesign" +msgstr "Ajuster le modèle" + +# Source-Hash: 7ceade8f25b58fe9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" +#: packages/editor/src/components/procedural-items/inspector.tsx +#, fuzzy +msgid "editor.proceduralItems.inspector.back" +msgstr "Retour" + +# Source-Hash: ba9b68175315e177 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit parts" +#: packages/editor/src/components/procedural-items/inspector.tsx +#, fuzzy +msgid "editor.proceduralItems.inspector.editParts" +msgstr "Modifier les pièces" + +# Source-Hash: 07c62820f014ed6c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid attachment" +#: packages/editor/src/components/procedural-items/inspector.tsx +#, fuzzy +msgid "editor.proceduralItems.inspector.invalidAttachment" +msgstr "Fixation non valide" + +# Source-Hash: f862aea8d7957c55 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid edit" +#: packages/editor/src/components/procedural-items/inspector.tsx +#, fuzzy +msgid "editor.proceduralItems.inspector.invalidEdit" +msgstr "Modification non valide" + +# Source-Hash: 190cf30b8edd8dd1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid placement" +#: packages/editor/src/components/procedural-items/inspector.tsx +#, fuzzy +msgid "editor.proceduralItems.inspector.invalidPlacement" +msgstr "Placement non valide" + +# Source-Hash: 45bd2ec690cc48dc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid position" +#: packages/editor/src/components/procedural-items/inspector.tsx +#, fuzzy +msgid "editor.proceduralItems.inspector.invalidPosition" +msgstr "Position non valide" + +# Source-Hash: faccab895717c598 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid reset" +#: packages/editor/src/components/procedural-items/inspector.tsx +#, fuzzy +msgid "editor.proceduralItems.inspector.invalidReset" +msgstr "Réinitialisation non valide" + +# Source-Hash: 28fe6e9deddde6e8 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "pos" +#: packages/editor/src/components/procedural-items/inspector.tsx +#, fuzzy +msgid "editor.proceduralItems.inspector.pos" +msgstr "pos" + +# Source-Hash: 9da0cbfad144d737 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/editor/src/components/procedural-items/inspector.tsx +#, fuzzy +msgid "editor.proceduralItems.inspector.position" +msgstr "Position" + +# Source-Hash: 3fce677837d5a876 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset this part" +#: packages/editor/src/components/procedural-items/inspector.tsx +#, fuzzy +msgid "editor.proceduralItems.inspector.resetThisPart" +msgstr "Réinitialiser cette pièce" + +# Source-Hash: 5eab376947d29a50 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reload editor" +#: packages/editor/src/components/editor/index.tsx +#, fuzzy +msgid "editor.reloadEditor" +msgstr "Recharger l’éditeur" + +# Source-Hash: 1063f1e315258b20 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close riser diagram" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx +#, fuzzy +msgid "editor.riserDiagramPanel.close" +msgstr "Fermer le schéma de colonnes" + +# Source-Hash: c2d59ee62035974c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV plumbing isometric" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx +#, fuzzy +msgid "editor.riserDiagramPanel.dwvPlumbingIsometric" +msgstr "Isométrie d'évacuation et de ventilation" + +# Source-Hash: 3501a7c8a93d3b19 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV riser diagram" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx +#, fuzzy +msgid "editor.riserDiagramPanel.dwvRiserDiagram" +msgstr "Schéma des colonnes d'évacuation" + +# Source-Hash: 225e3e3dc3bb01ee +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No drain, waste, or vent pipes yet. Draw plumbing to see the riser diagram." +#: packages/editor/src/components/editor/riser-diagram-panel.tsx +#, fuzzy +msgid "editor.riserDiagramPanel.noDrainWasteOrVentPipes" +msgstr "Aucun tuyau d'évacuation ou de ventilation pour l'instant. Dessinez la plomberie pour voir le schéma de colonnes." + +# Source-Hash: bc8e172ba55160ae +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Riser Diagram" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx +#, fuzzy +msgid "editor.riserDiagramPanel.riserDiagram" +msgstr "Schéma de colonnes" + +# Source-Hash: 6a1132961f17f320 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{diameter}\" P-trap" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx +#, fuzzy +msgid "editor.riserDiagramPanel.trap" +msgstr "Siphon {diameter}\"" + +# Source-Hash: 04bc0909a133a7e9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vent" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx +#, fuzzy +msgid "editor.riserDiagramPanel.vent" +msgstr "Ventilation" + # Source-Hash: 02f3eef9f0fb6d9e -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{diameter}\" VTR" #. Vent through roof: where a plumbing vent stack exits the roof. #: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.riserDiagramPanel.ventTermination" -msgstr "Sortie de toit {diameter}\"" +msgid "editor.riserDiagramPanel.ventTermination" +msgstr "Sortie de toit {diameter}\"" + +# Source-Hash: 29d8590334492601 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waste" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx +#, fuzzy +msgid "editor.riserDiagramPanel.waste" +msgstr "Eaux usées" + +# Source-Hash: 0f8d128255bf4afa +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{current} · {distance} above {shared}" +#: packages/editor/src/lib/room-built-on.ts +#, fuzzy +msgid "editor.room.builtOn.above" +msgstr "{current} · {distance} au-dessus de {shared}" + +# Source-Hash: 8416f433385a2936 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{current} · {distance} below {shared}" +#: packages/editor/src/lib/room-built-on.ts +#, fuzzy +msgid "editor.room.builtOn.below" +msgstr "{current} · {distance} sous {shared}" + +# Source-Hash: 6dc18e9fada391f2 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{current} · level with {shared}" +#: packages/editor/src/lib/room-built-on.ts +#, fuzzy +msgid "editor.room.builtOn.levelWith" +msgstr "{current} · au niveau de {shared}" + +# Source-Hash: 782bc47cb30d5c66 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cannot read \"{input}\"" +#: packages/editor/src/components/editor/room-handles.tsx +#, fuzzy +msgid "editor.roomHandles.cannotReadInput" +msgstr "Impossible de lire « {input} »" + +# Source-Hash: 70ca08939d758332 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimension value" +#: packages/editor/src/components/editor/room-handles.tsx +#, fuzzy +msgid "editor.roomHandles.dimensionValue" +msgstr "Valeur de la cote" + +# Source-Hash: d7148fa065bc709b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/editor/src/components/editor/room-handles.tsx +#, fuzzy +msgid "editor.roomHandles.floor" +msgstr "Plancher" + +# Source-Hash: de281c37906e7d14 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type a size to move the wall" +#: packages/editor/src/components/editor/room-handles.tsx +#, fuzzy +msgid "editor.roomHandles.typeASizeToMoveThe" +msgstr "Saisissez une cote pour déplacer le mur" + +# Source-Hash: 612dcd5bf06a79c4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/editor/room-labels.tsx +#: packages/editor/src/lib/viewer-selection.ts +#, fuzzy +msgid "editor.roomLabel.room" +msgstr "Pièce" + +# Source-Hash: a107b4d76d6972e3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone" +#: packages/editor/src/components/editor/room-labels.tsx +#: packages/editor/src/lib/viewer-selection.ts +#, fuzzy +msgid "editor.roomLabel.zone" +msgstr "Zone" + +# Source-Hash: 7da15e7c88dab485 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Attic" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.attic" +msgstr "Combles" + +# Source-Hash: 52adf6ccf54fd772 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Balcony" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.balcony" +msgstr "Balcon" + +# Source-Hash: 8caa959c0ae800c3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Basement" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.basement" +msgstr "Sous-sol" + +# Source-Hash: 0655333424a8b6fb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bathroom" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.bathroom" +msgstr "Salle de bain" + +# Source-Hash: f25239fe3891ea8f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bedroom" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.bedroom" +msgstr "Chambre" + +# Source-Hash: 77d15570e2eba719 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Boiler room" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.boilerRoom" +msgstr "Chaufferie" + +# Source-Hash: 5fbe77592f8f0ca9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Carport" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.carport" +msgstr "Abri de voiture" + +# Source-Hash: f31dc305ce3a803a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cellar" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.cellar" +msgstr "Cave" + +# Source-Hash: e9af4141e3f8bdd1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Closet" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.closet" +msgstr "Placard" + +# Source-Hash: 388530b7b9c6647d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corridor" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.corridor" +msgstr "Couloir" + +# Source-Hash: 4d4a23b87e911d2b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Courtyard" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.courtyard" +msgstr "Cour" + +# Source-Hash: f3aa561772702108 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.deck" +msgstr "Terrasse" + +# Source-Hash: 18d7f85ff03c43c9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Den" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.den" +msgstr "Petit salon" + +# Source-Hash: 4424343cad1f08b0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dining room" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.diningRoom" +msgstr "Salle à manger" + +# Source-Hash: 5efd0185e89ee84e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dressing room" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.dressingRoom" +msgstr "Dressing" + +# Source-Hash: f45768e27780dc72 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "En-suite" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.enSuite" +msgstr "Salle d’eau attenante" + +# Source-Hash: 51c664d19e5ea703 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Entrance" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.entrance" +msgstr "Entrée" + +# Source-Hash: 4b32a81a5abf006a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Family room" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.familyRoom" +msgstr "Salle familiale" + +# Source-Hash: e87e6bd9a7d6d667 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gallery" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.gallery" +msgstr "Galerie" + +# Source-Hash: cf7cc0ba06d5eea1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Games room" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.gamesRoom" +msgstr "Salle de jeux" + +# Source-Hash: 53aa825a4737190a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Garage" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.garage" +msgstr "Garage" + +# Source-Hash: 5073b3c2989a626d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Garden" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.garden" +msgstr "Jardin" + +# Source-Hash: 52fe13434cdb7b27 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Garden shed" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.gardenShed" +msgstr "Abri de jardin" + +# Source-Hash: a2712156dcaec1ba +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guest room" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.guestRoom" +msgstr "Chambre d’amis" + +# Source-Hash: a1128cf188432bb1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gym" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.gym" +msgstr "Salle de sport" + +# Source-Hash: 18664ee5a1abd06d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hallway" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.hallway" +msgstr "Couloir" + +# Source-Hash: 7dd957fc73d4d73a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Home cinema" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.homeCinema" +msgstr "Home cinéma" + +# Source-Hash: e1579515f44233ca +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kids' room" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.kidsRoom" +msgstr "Chambre d’enfant" + +# Source-Hash: 1176d2568d093bf1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchen" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.kitchen" +msgstr "Cuisine" + +# Source-Hash: 06eb4c431b9b09b6 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchenette" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.kitchenette" +msgstr "Kitchenette" + +# Source-Hash: de9566487b17a73b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.landing" +msgstr "Palier" + +# Source-Hash: 558bcafa2ec70ded +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Laundry" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.laundry" +msgstr "Buanderie" + +# Source-Hash: 8d211c78417ed1b0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Library" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.library" +msgstr "Bibliothèque" + +# Source-Hash: 2204538bab0e77ac +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Living room" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.livingRoom" +msgstr "Salon" + +# Source-Hash: bb14c08f0c3db4ad +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Loft" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.loft" +msgstr "Loft" + +# Source-Hash: a6a0e8bf816cbcb9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lounge" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.lounge" +msgstr "Salon" + +# Source-Hash: 194a147d4618a994 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.mezzanine" +msgstr "Mezzanine" + +# Source-Hash: 6b2c82e5fbccb28b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mudroom" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.mudroom" +msgstr "Vestiaire d’entrée" + +# Source-Hash: e3c3b9b917744680 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Nursery" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.nursery" +msgstr "Chambre de bébé" + +# Source-Hash: c1f1fcd9cb418340 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Office" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.office" +msgstr "Bureau" + +# Source-Hash: 5d98d41ec10bd05e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pantry" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.pantry" +msgstr "Garde-manger" + +# Source-Hash: 78dbe13192c0894b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Patio" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.patio" +msgstr "Patio" + +# Source-Hash: c3cfcccc167b1c19 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Playroom" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.playroom" +msgstr "Salle de jeux" + +# Source-Hash: 2e6324beaed18dd5 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pool area" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.poolArea" +msgstr "Espace piscine" + +# Source-Hash: 97d20e41044a3235 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Porch" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.porch" +msgstr "Porche" + +# Source-Hash: 04cb81f4a4ae4ff3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Powder room" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.powderRoom" +msgstr "Toilettes invités" + +# Source-Hash: 599c44d857832cd0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Primary bedroom" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.primaryBedroom" +msgstr "Chambre principale" + +# Source-Hash: 9a6ac3f1cdd8de2b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reading nook" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.readingNook" +msgstr "Coin lecture" + +# Source-Hash: 01f8cc22989822c4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bathrooms" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.section.bathrooms" +msgstr "Salles de bain" + +# Source-Hash: 9ec82561de8cb788 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Circulation" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.section.circulation" +msgstr "Circulations" + +# Source-Hash: f74a48b6b49644d7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Living" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.section.living" +msgstr "Séjour" + +# Source-Hash: 194a147d4618a994 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.section.mezzanine" +msgstr "Mezzanine" + +# Source-Hash: a5a7af5e5fff1c81 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outdoor" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.section.outdoor" +msgstr "Extérieur" + +# Source-Hash: 5df703d5b5e6ef7e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sleeping" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.section.sleeping" +msgstr "Nuit" + +# Source-Hash: c9d15ec19f814524 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Utility & storage" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.section.utility" +msgstr "Service et rangement" + +# Source-Hash: fbe13f7ab45e4cca +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Work & hobbies" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.section.work" +msgstr "Travail et loisirs" + +# Source-Hash: 10ccb6591f6ad207 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shower room" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.showerRoom" +msgstr "Salle de douche" + +# Source-Hash: 5254168cc5712cb2 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stairwell" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.stairwell" +msgstr "Cage d’escalier" + +# Source-Hash: d1596647cd84ade3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Storage" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.storage" +msgstr "Rangement" + +# Source-Hash: 7abc2dc6e39b1747 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Studio" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.studio" +msgstr "Studio" + +# Source-Hash: ebe68e83e73021ae +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Study" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.study" +msgstr "Bureau" + +# Source-Hash: d69a0244649771ef +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sunroom" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.sunroom" +msgstr "Véranda" + +# Source-Hash: 96281876ce53ba08 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terrace" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.terrace" +msgstr "Terrasse" + +# Source-Hash: a0cb3e6f5cf4fbec +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Toilet" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.toilet" +msgstr "WC" + +# Source-Hash: 6c01526f89f3106b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Utility room" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.utilityRoom" +msgstr "Cellier" + +# Source-Hash: fc42d89621ae7bac +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Veranda" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.veranda" +msgstr "Véranda" + +# Source-Hash: b45d7730e896fd99 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walk-in closet" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.walkInCloset" +msgstr "Dressing" + +# Source-Hash: 399f27253ef956cb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Workshop" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.workshop" +msgstr "Atelier" + +# Source-Hash: 83909f82446ee9c3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Settings" +#: packages/editor/src/components/ui/sidebar/icon-rail.tsx +#, fuzzy +msgid "editor.sidebar.iconRail.settings" +msgstr "Paramètres" + +# Source-Hash: 91f90818d42a984e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Site" +#: packages/editor/src/components/ui/sidebar/icon-rail.tsx +#, fuzzy +msgid "editor.sidebar.iconRail.site" +msgstr "Terrain" + +# Source-Hash: 663175a9c461a96d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.itemsPanel.all" +msgstr "Tout" + +# Source-Hash: fce9814c289e6b71 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Community" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.itemsPanel.community" +msgstr "Communauté" + +# Source-Hash: 663175a9c461a96d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +#, fuzzy +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.all" +msgstr "Tout" + +# Source-Hash: fce9814c289e6b71 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Community" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +#, fuzzy +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.community" +msgstr "Communauté" + +# Source-Hash: 8d211c78417ed1b0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Library" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +#, fuzzy +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.library" +msgstr "Bibliothèque" + +# Source-Hash: a0b7adfdfdec7307 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mine" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +#, fuzzy +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.mine" +msgstr "Les miens" + +# Source-Hash: 6024b7778b392ec3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No results for “{search}”" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +#, fuzzy +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.noResultsForSearch" +msgstr "Aucun résultat pour « {search} »" + +# Source-Hash: 4ceb6dcb7827db7f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Search..." +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +#, fuzzy +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.search" +msgstr "Rechercher..." + +# Source-Hash: 8d211c78417ed1b0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Library" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.itemsPanel.library" +msgstr "Bibliothèque" + +# Source-Hash: a0b7adfdfdec7307 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mine" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.itemsPanel.mine" +msgstr "Les miens" + +# Source-Hash: 6024b7778b392ec3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No results for “{search}”" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.itemsPanel.noResultsForSearch" +msgstr "Aucun résultat pour « {search} »" + +# Source-Hash: 4ceb6dcb7827db7f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Search..." +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.itemsPanel.search" +msgstr "Rechercher..." + +# Source-Hash: fb66c49eee49a3bc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Build Tools" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +#, fuzzy +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.buildTools" +msgstr "Outils de construction" + +# Source-Hash: 14622745dbf93f4c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +#, fuzzy +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.camera" +msgstr "Caméra" + +# Source-Hash: 677783232bea72a2 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Direct Manipulation" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +#, fuzzy +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.directManipulation" +msgstr "Manipulation directe" + +# Source-Hash: 8e67947d43b76596 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawing Tools" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +#, fuzzy +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.drawingTools" +msgstr "Outils de dessin" + +# Source-Hash: 8cdda30f3be2bac2 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Editor Navigation" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +#, fuzzy +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.editorNavigation" +msgstr "Navigation dans l’éditeur" + +# Source-Hash: 9a996e3570d615ed +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Item Placement" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +#, fuzzy +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.itemPlacement" +msgstr "Placement des éléments" + +# Source-Hash: fc18926f9bd9eebd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keyboard shortcuts" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +#, fuzzy +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.keyboardShortcuts" +msgstr "Raccourcis clavier" + +# Source-Hash: cbb4c3e007d70aa0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modes & History" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +#, fuzzy +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.modesHistory" +msgstr "Modes et historique" + +# Source-Hash: 170b2049ef0f9131 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selection" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +#, fuzzy +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.selection" +msgstr "Sélection" + +# Source-Hash: 0da1c4d163df2953 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shortcuts are context-aware. Snapping is a visible mode: tap Shift to cycle it, hold Alt during a gesture to place freely." +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +#, fuzzy +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.shortcutsAreContextAwareGuidedConstraints" +msgstr "Les raccourcis dépendent du contexte. L’aimantation est un mode visible : appuyez brièvement sur Maj pour en changer, maintenez Alt pendant un geste pour placer librement." + +# Source-Hash: 3c67cde0578ac829 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.addLevel" +msgstr "Ajouter un niveau" + +# Source-Hash: 9a56d90d461b4bca +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add point" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.addPoint" +msgstr "Ajouter un point" + +# Source-Hash: fedccec504a9ae33 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Area:" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.area" +msgstr "Surface :" + +# Source-Hash: 87b6880f6de7a45a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base elevation" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.baseElevation" +msgstr "Altitude de base" + +# Source-Hash: d42f7d29e3fc4af7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Building" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.building" +msgstr "Bâtiment" + +# Source-Hash: 7c90f458259d5cd8 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add new level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.buildingTreeNode.addNewLevel" +msgstr "Ajouter un nouveau niveau" + +# Source-Hash: d42f7d29e3fc4af7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Building" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.buildingTreeNode.building" +msgstr "Bâtiment" + +# Source-Hash: bbc65c039ae86e11 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.cameraSnapshot" +msgstr "Instantané de caméra" + +# Source-Hash: 3a0701ebcb9f26cb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Capture" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.capture" +msgstr "Capture" + +# Source-Hash: 71f2343818c55e0c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear selection" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.clearSelection" +msgstr "Effacer la sélection" + +# Source-Hash: 67d29724469fa8d3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.clearSnapshot" +msgstr "Effacer l’instantané" + +# Source-Hash: def517c77fda49ea +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close walls around a space to make a room." +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.closeWallsAroundASpaceTo" +msgstr "Fermez des murs autour d’un espace pour créer une pièce." + +# Source-Hash: 2b9af8da4b34cbfa +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collection colour" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.collectionColour" +msgstr "Couleur de la collection" + +# Source-Hash: 135af27a14a4cda7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collections" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.collections" +msgstr "Collections" + +# Source-Hash: 6f4751c26f12aef9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete collection" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.deleteCollection" +msgstr "Supprimer la collection" + +# Source-Hash: b26de372b4b0eaac +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.delete" +msgstr "Supprimer" + +# Source-Hash: 8e29375893d63408 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.deleteLevel" +msgstr "Supprimer le niveau" + +# Source-Hash: 6552e45eecc0a227 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw a zone" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.drawAZone" +msgstr "Dessiner une zone" + +# Source-Hash: 34dc96fe77a31e51 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.duplicate" +msgstr "Dupliquer" + +# Source-Hash: 933177338f5a03ed +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.duplicateLevel" +msgstr "Dupliquer le niveau" + +# Source-Hash: c038947f317cabba +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate level with options" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.duplicateLevelWithOptions" +msgstr "Dupliquer le niveau avec options" + +# Source-Hash: 9614c6825a7c67bf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate with options..." +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.duplicateWithOptions" +msgstr "Dupliquer avec options..." + +# Source-Hash: 7c4196b9e791c195 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elements" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.elements" +msgstr "Éléments" + +# Source-Hash: 1344ea2602e3aa9e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guide" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.guide" +msgstr "Guide" + +# Source-Hash: 591087ea83a48ead +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.hide" +msgstr "Masquer" + +# Source-Hash: 0608743fc1736d86 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.level" +msgstr "Niveau" + +# Source-Hash: 13b3e6a6afe319d1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New unit" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.newUnit" +msgstr "Nouveau logement" + +# Source-Hash: 0192748d50f0e5f7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No buildings yet" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.noBuildingsYet" +msgstr "Aucun bâtiment pour l’instant" + +# Source-Hash: 1be310702a12e433 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No elements on this level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.noElementsOnThisLevel" +msgstr "Aucun élément sur ce niveau" +# Source-Hash: 0956af88ced36992 # Review: required -# Source-Hash: 29d8590334492601 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waste" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No levels yet" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.riserDiagramPanel.waste" -msgstr "Eaux usées" +msgid "editor.sidebar.panels.sitePanel.noLevelsYet" +msgstr "Aucun niveau pour l’instant" -# Source-Hash: 0f8d128255bf4afa +# Source-Hash: 45c41bfb2ae19627 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{current} · {distance} above {shared}" -#: packages/editor/src/lib/room-built-on.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# object selected} other {# objects selected}}" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.room.builtOn.above" -msgstr "{current} · {distance} au-dessus de {shared}" +msgid "editor.sidebar.panels.sitePanel.objectsSelected" +msgstr "{count, plural, one {# objet sélectionné} many {# objets sélectionnés} other {# objets sélectionnés}}" -# Source-Hash: 8416f433385a2936 +# Source-Hash: a5434e26e5cb1b26 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{current} · {distance} below {shared}" -#: packages/editor/src/lib/room-built-on.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Other zones" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.room.builtOn.below" -msgstr "{current} · {distance} sous {shared}" +msgid "editor.sidebar.panels.sitePanel.otherZones" +msgstr "Autres zones" -# Source-Hash: 6dc18e9fada391f2 +# Source-Hash: 2aa38d84079d4dba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{current} · level with {shared}" -#: packages/editor/src/lib/room-built-on.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Perimeter:" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.room.builtOn.levelWith" -msgstr "{current} · au niveau de {shared}" +msgid "editor.sidebar.panels.sitePanel.perimeter" +msgstr "Périmètre :" -# Source-Hash: 612dcd5bf06a79c4 +# Source-Hash: 4004b9a8e4f8c9d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room" -#: packages/editor/src/components/editor/room-labels.tsx -#: packages/editor/src/lib/viewer-selection.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Property Line" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomLabel.room" -msgstr "Pièce" +msgid "editor.sidebar.panels.sitePanel.propertyLine" +msgstr "Limite de propriété" -# Source-Hash: a107b4d76d6972e3 +# Source-Hash: 3e7408ed44676176 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone" -#: packages/editor/src/components/editor/room-labels.tsx -#: packages/editor/src/lib/viewer-selection.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rooms" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomLabel.zone" -msgstr "Zone" +msgid "editor.sidebar.panels.sitePanel.rooms" +msgstr "Pièces" -# Source-Hash: 7da15e7c88dab485 +# Source-Hash: ca39c0581c7318e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Attic" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select a level to view content" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomName.attic" -msgstr "Combles" +msgid "editor.sidebar.panels.sitePanel.selectALevelToViewContent" +msgstr "Sélectionnez un niveau pour voir son contenu" -# Source-Hash: 52adf6ccf54fd772 +# Source-Hash: 827e0c6ac9936b69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Balcony" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomName.balcony" -msgstr "Balcon" +msgid "editor.sidebar.panels.sitePanel.show" +msgstr "Afficher" -# Source-Hash: 8caa959c0ae800c3 +# Source-Hash: 91f90818d42a984e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Basement" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Site" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomName.basement" -msgstr "Sous-sol" +msgid "editor.sidebar.panels.sitePanel.site" +msgstr "Terrain" -# Source-Hash: 0655333424a8b6fb +# Source-Hash: c40163620df24a76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bathroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Take snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomName.bathroom" -msgstr "Salle de bain" +msgid "editor.sidebar.panels.sitePanel.takeSnapshot" +msgstr "Prendre un instantané" -# Source-Hash: f25239fe3891ea8f +# Source-Hash: d6b381247066a7aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bedroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The ground level cannot be deleted" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomName.bedroom" -msgstr "Chambre" +msgid "editor.sidebar.panels.sitePanel.theGroundLevelCannotBeDeleted" +msgstr "Le niveau du rez-de-chaussée ne peut pas être supprimé" -# Source-Hash: 77d15570e2eba719 +# Source-Hash: bbc65c039ae86e11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Boiler room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.roomName.boilerRoom" -msgstr "Chaufferie" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.cameraSnapshot" +msgstr "Instantané de caméra" -# Source-Hash: 5fbe77592f8f0ca9 +# Source-Hash: 67d29724469fa8d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Carport" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.roomName.carport" -msgstr "Abri de voiture" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.clearSnapshot" +msgstr "Effacer l’instantané" -# Source-Hash: f31dc305ce3a803a +# Source-Hash: 591087ea83a48ead # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cellar" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.roomName.cellar" -msgstr "Cave" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.hide" +msgstr "Masquer" -# Source-Hash: e9af4141e3f8bdd1 +# Source-Hash: 827e0c6ac9936b69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Closet" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.roomName.closet" -msgstr "Placard" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.show" +msgstr "Afficher" -# Source-Hash: 388530b7b9c6647d +# Source-Hash: c40163620df24a76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corridor" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Take snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.roomName.corridor" -msgstr "Couloir" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.takeSnapshot" +msgstr "Prendre un instantané" -# Source-Hash: 4d4a23b87e911d2b +# Source-Hash: faecab10b69d4863 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Courtyard" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Update snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.roomName.courtyard" -msgstr "Cour" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.updateSnapshot" +msgstr "Mettre à jour l’instantané" -# Source-Hash: f3aa561772702108 +# Source-Hash: 8a1fd8827a68f236 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Deck" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "View snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.viewSnapshot" +msgstr "Voir l’instantané" + +# Source-Hash: b404dded35241274 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Units" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.units" +msgstr "Unités" + +# Source-Hash: 149fec3fd1f08042 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete unit" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.roomName.deck" -msgstr "Terrasse" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.deleteUnit" +msgstr "Supprimer le logement" -# Source-Hash: 18d7f85ff03c43c9 +# Source-Hash: 930399d3fb247a7c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Den" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Focused" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.roomName.den" -msgstr "Petit salon" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.focused" +msgstr "Ciblé" -# Source-Hash: 4424343cad1f08b0 +# Source-Hash: 41ac9dd23bb558d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dining room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove from unit" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.roomName.diningRoom" -msgstr "Salle à manger" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.removeFromUnit" +msgstr "Retirer du logement" -# Source-Hash: 5efd0185e89ee84e +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dressing room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.roomName.dressingRoom" -msgstr "Dressing" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.room" +msgstr "Pièce" -# Source-Hash: f45768e27780dc72 +# Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "En-suite" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.roomName.enSuite" -msgstr "Salle d’eau attenante" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.zone" +msgstr "Zone" -# Source-Hash: 51c664d19e5ea703 +# Source-Hash: faecab10b69d4863 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Entrance" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Update snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomName.entrance" -msgstr "Entrée" +msgid "editor.sidebar.panels.sitePanel.updateSnapshot" +msgstr "Mettre à jour l’instantané" -# Source-Hash: 4b32a81a5abf006a +# Source-Hash: 28a12e6806c091b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Family room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{assetType, select, guide {Uploading guide... {progress}%} other {Uploading scan... {progress}%}}" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomName.familyRoom" -msgstr "Salle familiale" +msgid "editor.sidebar.panels.sitePanel.uploadingProgress" +msgstr "{assetType, select, guide {Import du calque... {progress} %} other {Import du relevé 3D... {progress} %}}" -# Source-Hash: e87e6bd9a7d6d667 +# Source-Hash: de389a2a46d53384 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gallery" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Upload scan/floorplan" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomName.gallery" -msgstr "Galerie" +msgid "editor.sidebar.panels.sitePanel.uploadScanFloorplan" +msgstr "Importer un relevé 3D ou un plan" -# Source-Hash: cf7cc0ba06d5eea1 +# Source-Hash: 8a1fd8827a68f236 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Games room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "View snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomName.gamesRoom" -msgstr "Salle de jeux" +msgid "editor.sidebar.panels.sitePanel.viewSnapshot" +msgstr "Voir l’instantané" -# Source-Hash: 53aa825a4737190a +# Source-Hash: ba9f809cb032ee57 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Garage" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "In {unitName}" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/zone-membership-checkbox.tsx #, fuzzy -msgid "editor.roomName.garage" -msgstr "Garage" +msgid "editor.sidebar.panels.sitePanel.zoneMembershipCheckbox.inUnitname" +msgstr "Dans {unitName}" -# Source-Hash: 5073b3c2989a626d +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Garden" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.garden" -msgstr "Jardin" +msgid "editor.sidebar.panels.zonePanel.actions" +msgstr "Actions" -# Source-Hash: 52fe13434cdb7b27 +# Source-Hash: fcc43f22937d1536 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Garden shed" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add one" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.gardenShed" -msgstr "Abri de jardin" +msgid "editor.sidebar.panels.zonePanel.addOne" +msgstr "En ajouter une" -# Source-Hash: a2712156dcaec1ba +# Source-Hash: bbc65c039ae86e11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guest room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.guestRoom" -msgstr "Chambre d’amis" +msgid "editor.sidebar.panels.zonePanel.cameraSnapshot" +msgstr "Instantané de caméra" -# Source-Hash: a1128cf188432bb1 +# Source-Hash: 67d29724469fa8d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gym" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.gym" -msgstr "Salle de sport" +msgid "editor.sidebar.panels.zonePanel.clearSnapshot" +msgstr "Effacer l’instantané" -# Source-Hash: 18664ee5a1abd06d +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hallway" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.hallway" -msgstr "Couloir" +msgid "editor.sidebar.panels.zonePanel.delete" +msgstr "Supprimer" -# Source-Hash: 7dd957fc73d4d73a +# Source-Hash: e2411929697b7ed4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Home cinema" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete with contents" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.homeCinema" -msgstr "Home cinéma" +msgid "editor.sidebar.panels.zonePanel.deleteWithContents" +msgstr "Supprimer avec le contenu" -# Source-Hash: e1579515f44233ca +# Source-Hash: 22ca3935e8754072 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kids' room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No zones on this level." +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.kidsRoom" -msgstr "Chambre d’enfant" +msgid "editor.sidebar.panels.zonePanel.noZonesOnThisLevel" +msgstr "Aucune zone sur ce niveau." -# Source-Hash: 1176d2568d093bf1 +# Source-Hash: 941ea30f406dcfa2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchen" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Save to catalog" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.kitchen" -msgstr "Cuisine" +msgid "editor.sidebar.panels.zonePanel.saveToCatalog" +msgstr "Enregistrer dans le catalogue" -# Source-Hash: 06eb4c431b9b09b6 +# Source-Hash: 98662dfb371cac13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchenette" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select a level to view and create zones" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.kitchenette" -msgstr "Kitchenette" +msgid "editor.sidebar.panels.zonePanel.selectALevelToViewAnd" +msgstr "Sélectionnez un niveau pour voir et créer des zones" -# Source-Hash: de9566487b17a73b +# Source-Hash: c40163620df24a76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Take snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.landing" -msgstr "Palier" +msgid "editor.sidebar.panels.zonePanel.takeSnapshot" +msgstr "Prendre un instantané" -# Source-Hash: 558bcafa2ec70ded +# Source-Hash: faecab10b69d4863 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Laundry" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Update snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.laundry" -msgstr "Buanderie" +msgid "editor.sidebar.panels.zonePanel.updateSnapshot" +msgstr "Mettre à jour l’instantané" -# Source-Hash: 8d211c78417ed1b0 +# Source-Hash: 8a1fd8827a68f236 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Library" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "View snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.library" -msgstr "Bibliothèque" +msgid "editor.sidebar.panels.zonePanel.viewSnapshot" +msgstr "Voir l’instantané" -# Source-Hash: 2204538bab0e77ac +# Source-Hash: 58b05af5b5724efb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Living room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "\"{label}\" plugin crashed" +#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx #, fuzzy -msgid "editor.roomName.livingRoom" -msgstr "Salon" +msgid "editor.sidebar.usePluginPanels.labelPluginCrashed" +msgstr "Le plugin « {label} » a planté" -# Source-Hash: bb14c08f0c3db4ad +# Source-Hash: 9e84d6d7b9885c4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Loft" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Loading…" +#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx #, fuzzy -msgid "editor.roomName.loft" -msgstr "Loft" +msgid "editor.sidebar.usePluginPanels.loading" +msgstr "Chargement…" -# Source-Hash: a6a0e8bf816cbcb9 +# Source-Hash: 9fc7a39bc32f287a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lounge" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plugins" +#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx #, fuzzy -msgid "editor.roomName.lounge" -msgstr "Salon" +msgid "editor.sidebar.usePluginPanels.plugins" +msgstr "Plugins" -# Source-Hash: 194a147d4618a994 +# Source-Hash: c6312309378aaaea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This panel hit an error and was unloaded for this session. The rest of the editor is unaffected — reload to try again." +#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx #, fuzzy -msgid "editor.roomName.mezzanine" -msgstr "Mezzanine" +msgid "editor.sidebar.usePluginPanels.thisPanelHitAnErrorAnd" +msgstr "Ce panneau a rencontré une erreur et a été déchargé pour cette session. Le reste de l’éditeur n’est pas affecté — rechargez pour réessayer." -# Source-Hash: 6b2c82e5fbccb28b +# Source-Hash: 2ab3b6983e384ecc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mudroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling attachment" +#: packages/editor/src/components/ui/snap-target-badge.tsx #, fuzzy -msgid "editor.roomName.mudroom" -msgstr "Vestiaire d’entrée" +msgid "editor.snapTarget.ceiling" +msgstr "Fixation au plafond" -# Source-Hash: e3c3b9b917744680 +# Source-Hash: 54a00bbb699e3778 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Nursery" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof attachment" +#: packages/editor/src/components/ui/snap-target-badge.tsx #, fuzzy -msgid "editor.roomName.nursery" -msgstr "Chambre de bébé" +msgid "editor.snapTarget.roof" +msgstr "Fixation à la toiture" -# Source-Hash: c1f1fcd9cb418340 +# Source-Hash: e45fee9c27f6ae69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Office" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall attachment" +#: packages/editor/src/components/ui/snap-target-badge.tsx #, fuzzy -msgid "editor.roomName.office" -msgstr "Bureau" +msgid "editor.snapTarget.wall" +msgstr "Fixation murale" -# Source-Hash: 5d98d41ec10bd05e +# Source-Hash: 834de1a7027c4da1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pantry" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The editor scene failed to render" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.roomName.pantry" -msgstr "Garde-manger" +msgid "editor.theEditorSceneFailedToRender" +msgstr "La scène de l’éditeur n’a pas pu s’afficher" -# Source-Hash: 78dbe13192c0894b +# Source-Hash: 151f7c7e4110016f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Patio" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A curtain wall takes no corner window" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.patio" -msgstr "Patio" +msgid "editor.toolHint.aCurtainWallTakesNoCorner.1qxjv5i" +msgstr "Un mur-rideau n’accepte pas de fenêtre d’angle" -# Source-Hash: c3cfcccc167b1c19 +# Source-Hash: 97f5e044d46501fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Playroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A curved wall takes no corner window" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.playroom" -msgstr "Salle de jeux" +msgid "editor.toolHint.aCurvedWallTakesNoCorner.1vdnaw5" +msgstr "Un mur courbe n’accepte pas de fenêtre d’angle" -# Source-Hash: 2e6324beaed18dd5 +# Source-Hash: 776d8ebece7fe1bb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pool area" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add a corner · click the first to close" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.poolArea" -msgstr "Espace piscine" +msgid "editor.toolHint.addACornerClickTheFirst.o4r67t" +msgstr "Ajouter un angle · cliquez sur le premier pour fermer" -# Source-Hash: 97d20e41044a3235 +# Source-Hash: 6a0745dd047b149a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Porch" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Another opening is in the way at the corner" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.porch" -msgstr "Porche" +msgid "editor.toolHint.anotherOpeningIsInTheWay.11l9dd0" +msgstr "Une autre ouverture gêne à l’angle" -# Source-Hash: 04cb81f4a4ae4ff3 +# Source-Hash: 441124187e7da2fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Powder room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.powderRoom" -msgstr "Toilettes invités" +msgid "editor.toolHint.autoHangers.10554ka" +msgstr "Suspentes auto" -# Source-Hash: 599c44d857832cd0 +# Source-Hash: 47a7f9a6a81156c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Primary bedroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers - click or press H to toggle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.primaryBedroom" -msgstr "Chambre principale" +msgid "editor.toolHint.autoHangersClickOrPressH.rwa3ka" +msgstr "Suspentes auto - cliquez ou appuyez sur H pour basculer" -# Source-Hash: 9a6ac3f1cdd8de2b +# Source-Hash: d7944f31cba90e26 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reading nook" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers: Off" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.readingNook" -msgstr "Coin lecture" +msgid "editor.toolHint.autoHangersOff.7yx01x" +msgstr "Suspentes auto : désactivées" -# Source-Hash: 01f8cc22989822c4 +# Source-Hash: 295882d015d08742 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bathrooms" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers: On" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.section.bathrooms" -msgstr "Salles de bain" +msgid "editor.toolHint.autoHangersOn.10b1umh" +msgstr "Suspentes auto : activées" -# Source-Hash: 9ec82561de8cb788 +# Source-Hash: 8c039e5182b01c4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Circulation" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bypass snapping" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.section.circulation" -msgstr "Circulations" +msgid "editor.toolHint.bypassSnapping.w5lmdv" +msgstr "Ignorer l’aimantation" -# Source-Hash: f74a48b6b49644d7 +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Living" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.section.living" -msgstr "Séjour" +msgid "editor.toolHint.cancel.ew9em3" +msgstr "Annuler" -# Source-Hash: 194a147d4618a994 +# Source-Hash: 5b33b576fd30b74e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel move" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.section.mezzanine" -msgstr "Mezzanine" +msgid "editor.toolHint.cancelMove.lvp31c" +msgstr "Annuler le déplacement" -# Source-Hash: a5a7af5e5fff1c81 +# Source-Hash: 136fa29b9ae419bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Outdoor" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel run / exit" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.section.outdoor" -msgstr "Extérieur" +msgid "editor.toolHint.cancelRunExit.zqjf3h" +msgstr "Annuler le tronçon / quitter" -# Source-Hash: 5df703d5b5e6ef7e +# Source-Hash: 75b406824be91ac2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sleeping" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel start point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.section.sleeping" -msgstr "Nuit" +msgid "editor.toolHint.cancelStartPoint.1xbq2lh" +msgstr "Annuler le point de départ" -# Source-Hash: c9d15ec19f814524 +# Source-Hash: ffa5aaa1746303c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Utility & storage" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner window" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.section.utility" -msgstr "Service et rangement" +msgid "editor.toolHint.cornerWindow.1avkzpo" +msgstr "Fenêtre d’angle" -# Source-Hash: fbe13f7ab45e4cca +# Source-Hash: b0afdd855a02e4a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Work & hobbies" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cuts" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.section.work" -msgstr "Travail et loisirs" +msgid "editor.toolHint.cuts.1y0axps" +msgstr "Coupes" -# Source-Hash: 10ccb6591f6ad207 +# Source-Hash: dc9fe7601cc525f8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shower room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cuts: {value}" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.showerRoom" -msgstr "Salle de douche" +msgid "editor.toolHint.cutsValue.ouzhvb" +msgstr "Coupes : {value}" -# Source-Hash: 5254168cc5712cb2 +# Source-Hash: a2e13bc4dc82624c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stairwell" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cuts: {value}, even" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.stairwell" -msgstr "Cage d’escalier" +msgid "editor.toolHint.cutsValueEven.1ngsz3" +msgstr "Coupes : {value}, régulières" -# Source-Hash: d1596647cd84ade3 +# Source-Hash: 04152b4cec726f34 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Storage" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cycle mono / gable / butterfly" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.storage" -msgstr "Rangement" +msgid "editor.toolHint.cycleMonoGableButterfly.1poga3m" +msgstr "Basculer un pan / deux pans / papillon" -# Source-Hash: 7abc2dc6e39b1747 +# Source-Hash: 4fb6c83edb6652b5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Studio" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cycle snapping mode" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.studio" -msgstr "Studio" +msgid "editor.toolHint.cycleSnappingMode.1ct0gn6" +msgstr "Changer le mode d’aimantation" -# Source-Hash: ebe68e83e73021ae +# Source-Hash: 5d550a3ac76279de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Study" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door style — click or press L to cycle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.study" -msgstr "Bureau" +msgid "editor.toolHint.doorStyleClickOrPressL.33pe65" +msgstr "Style de porte — cliquez ou appuyez sur L pour changer" -# Source-Hash: d69a0244649771ef +# Source-Hash: 3272a7df5d7c6a9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sunroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door type — click or press O to cycle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.sunroom" -msgstr "Véranda" +msgid "editor.toolHint.doorTypeClickOrPressO.1hhh8gt" +msgstr "Type de porte — cliquez ou appuyez sur O pour changer" -# Source-Hash: 96281876ce53ba08 +# Source-Hash: 366222b4435eefda # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terrace" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drop downspout from outlet" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.terrace" -msgstr "Terrasse" +msgid "editor.toolHint.dropDownspoutFromOutlet.1k4h1m4" +msgstr "Descendre la descente depuis la sortie" -# Source-Hash: a0cb3e6f5cf4fbec +# Source-Hash: 03f306371f345007 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Toilet" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct diameter down / up" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.toilet" -msgstr "WC" +msgid "editor.toolHint.ductDiameterDownUp.1wdz5vq" +msgstr "Diamètre de gaine moins / plus" -# Source-Hash: 6c01526f89f3106b +# Source-Hash: 7b4137e27f8327d9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Utility room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End run / cancel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.utilityRoom" -msgstr "Cellier" +msgid "editor.toolHint.endRunCancel.59dh2w" +msgstr "Terminer le tronçon / annuler" -# Source-Hash: fc42d89621ae7bac +# Source-Hash: b714e91c31108a71 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Veranda" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End the run" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.veranda" -msgstr "Véranda" +msgid "editor.toolHint.endTheRun.1c1raig" +msgstr "Terminer le tracé" -# Source-Hash: b45d7730e896fd99 +# Source-Hash: 938aacb119b29dc1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walk-in closet" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Exit" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.walkInCloset" -msgstr "Dressing" +msgid "editor.toolHint.exit.engmg5" +msgstr "Quitter" -# Source-Hash: 399f27253ef956cb +# Source-Hash: 7cb4e0688cabcb00 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Workshop" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Exit drawing" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.workshop" -msgstr "Atelier" +msgid "editor.toolHint.exitDrawing.9noxyb" +msgstr "Quitter le tracé" -# Source-Hash: 83909f82446ee9c3 +# Source-Hash: 47025a103c456125 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Settings" -#: packages/editor/src/components/ui/sidebar/icon-rail.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish and continue" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.iconRail.settings" -msgstr "Paramètres" +msgid "editor.toolHint.finishAndContinue.1gpfsks" +msgstr "Terminer et continuer" -# Source-Hash: 91f90818d42a984e +# Source-Hash: 000918429b74128f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Site" -#: packages/editor/src/components/ui/sidebar/icon-rail.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish ceiling" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.iconRail.site" -msgstr "Terrain" +msgid "editor.toolHint.finishCeiling.1c1lfel" +msgstr "Terminer le plafond" -# Source-Hash: 663175a9c461a96d +# Source-Hash: 51a80a0dba5a6f30 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish grid axis" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.all" -msgstr "Tout" +msgid "editor.toolHint.finishGridAxis.1wvrfhr" +msgstr "Terminer l’axe de trame" -# Source-Hash: fce9814c289e6b71 +# Source-Hash: 87c7b98fc2e010e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Community" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish measurement" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.community" -msgstr "Communauté" +msgid "editor.toolHint.finishMeasurement.1e4gv16" +msgstr "Terminer la mesure" -# Source-Hash: 663175a9c461a96d +# Source-Hash: 5e1a0af7dc506826 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish multi-point witnesses" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.all" -msgstr "Tout" +msgid "editor.toolHint.finishMultiPointWitnesses.8wzskz" +msgstr "Terminer les repères multipoints" -# Source-Hash: fce9814c289e6b71 +# Source-Hash: 30fc0862501ba2e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Community" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish slab" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.community" -msgstr "Communauté" +msgid "editor.toolHint.finishSlab.xmnm8e" +msgstr "Terminer la dalle" -# Source-Hash: 8d211c78417ed1b0 +# Source-Hash: 66ed7c7598d3aa29 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Library" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip side" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.library" -msgstr "Bibliothèque" +msgid "editor.toolHint.flipSide.172xku9" +msgstr "Inverser le côté" -# Source-Hash: a0b7adfdfdec7307 +# Source-Hash: f5717f6a0905ffab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mine" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow: trace a lineset" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.mine" -msgstr "Les miens" +msgid "editor.toolHint.followTraceALineset.mgquwe" +msgstr "Suivre : longer une liaison frigorifique" -# Source-Hash: 6024b7778b392ec3 +# Source-Hash: ed7f3d8417a3e074 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No results for “{search}”" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Force place" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.noResultsForSearch" -msgstr "Aucun résultat pour « {search} »" +msgid "editor.toolHint.forcePlace.1hq1nr" +msgstr "Forcer le placement" -# Source-Hash: 4ceb6dcb7827db7f +# Source-Hash: 64b4ac6d3da25183 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Search..." -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free angle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.search" -msgstr "Rechercher..." +msgid "editor.toolHint.freeAngle.1ptblho" +msgstr "Angle libre" -# Source-Hash: 8d211c78417ed1b0 +# Source-Hash: 446b8aac1e5e8422 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Library" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free place" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.library" -msgstr "Bibliothèque" +msgid "editor.toolHint.freePlace.1s1uusw" +msgstr "Placement libre" -# Source-Hash: a0b7adfdfdec7307 +# Source-Hash: cc0c14065951444d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mine" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free placement" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.mine" -msgstr "Les miens" +msgid "editor.toolHint.freePlacement.1nztdac" +msgstr "Placement libre" -# Source-Hash: 6024b7778b392ec3 +# Source-Hash: f098a27096a9c1ea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No results for “{search}”" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Go vertical ↕, click to place" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.noResultsForSearch" -msgstr "Aucun résultat pour « {search} »" +msgid "editor.toolHint.goVerticalClickToPlace.dg8g6m" +msgstr "Passer en vertical ↕, cliquez pour placer" -# Source-Hash: 4ceb6dcb7827db7f +# Source-Hash: fd47f1820d8799c8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Search..." -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Highlight outlet" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.search" -msgstr "Rechercher..." +msgid "editor.toolHint.highlightOutlet.65hoq8" +msgstr "Mettre en évidence la sortie" -# Source-Hash: 3c67cde0578ac829 +# Source-Hash: eb90058d0f856f67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Join as a corner window" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.addLevel" -msgstr "Ajouter un niveau" +msgid "editor.toolHint.joinAsACornerWindow.jvdp4j" +msgstr "Joindre en fenêtre d’angle" -# Source-Hash: 9a56d90d461b4bca +# Source-Hash: 225b3161f2e59757 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add point" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Alt + drag" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.addPoint" -msgstr "Ajouter un point" +msgid "editor.toolHint.key.altDrag.ai3wn9" +msgstr "Alt + glisser" -# Source-Hash: fedccec504a9ae33 +# Source-Hash: dd66f883b173fc72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Area:" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Backspace" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.area" -msgstr "Surface :" +msgid "editor.toolHint.key.backspace.qy6qx8" +msgstr "Retour arrière" -# Source-Hash: 87b6880f6de7a45a +# Source-Hash: a18387bc0be54c32 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base elevation" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.baseElevation" -msgstr "Altitude de base" +msgid "editor.toolHint.key.click.m8sun" +msgstr "Clic" -# Source-Hash: d42f7d29e3fc4af7 +# Source-Hash: db9e60c1d30b8499 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Building" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click again" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.building" -msgstr "Bâtiment" +msgid "editor.toolHint.key.clickAgain.190ws9j" +msgstr "Cliquer à nouveau" -# Source-Hash: 7c90f458259d5cd8 +# Source-Hash: f400330b9c9c12e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add new level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Command" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.buildingTreeNode.addNewLevel" -msgstr "Ajouter un nouveau niveau" +msgid "editor.toolHint.key.command.1j2mkia" +msgstr "Commande" -# Source-Hash: d42f7d29e3fc4af7 +# Source-Hash: 976c63285a510b09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Building" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Control" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.buildingTreeNode.building" -msgstr "Bâtiment" +msgid "editor.toolHint.key.control.10fbl8e" +msgstr "Contrôle" -# Source-Hash: bbc65c039ae86e11 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Camera snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.cameraSnapshot" -msgstr "Instantané de caméra" +msgid "editor.toolHint.key.delete.oay2cq" +msgstr "Supprimer" -# Source-Hash: 3a0701ebcb9f26cb +# Source-Hash: 88888c9d2719fa92 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Capture" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double click" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.capture" -msgstr "Capture" +msgid "editor.toolHint.key.doubleClick.vlma6o" +msgstr "Double-clic" -# Source-Hash: 71f2343818c55e0c +# Source-Hash: dfb85b2addb7b9fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear selection" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.clearSelection" -msgstr "Effacer la sélection" +msgid "editor.toolHint.key.drag.8pwtpf" +msgstr "Glisser" -# Source-Hash: 67d29724469fa8d3 +# Source-Hash: ed9140d42148c99b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Enter" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.clearSnapshot" -msgstr "Effacer l’instantané" +msgid "editor.toolHint.key.enter.1ctpui5" +msgstr "Entrée" -# Source-Hash: def517c77fda49ea +# Source-Hash: 9195fa8b9c8ebdfb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close walls around a space to make a room." -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.closeWallsAroundASpaceTo" -msgstr "Fermez des murs autour d’un espace pour créer une pièce." +msgid "editor.toolHint.key.hover.6xw79p" +msgstr "Survoler" -# Source-Hash: 2b9af8da4b34cbfa +# Source-Hash: 2d78441b741bc562 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collection colour" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a duct end" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.collectionColour" -msgstr "Couleur de la collection" +msgid "editor.toolHint.key.hoverADuctEnd.19axr3b" +msgstr "Survolez une extrémité de gaine" -# Source-Hash: 135af27a14a4cda7 +# Source-Hash: 6083405086f61c76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collections" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a pipe end" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.collections" -msgstr "Collections" +msgid "editor.toolHint.key.hoverAPipeEnd.1jbum5f" +msgstr "Survolez une extrémité de tuyau" -# Source-Hash: 6f4751c26f12aef9 +# Source-Hash: a5a337eb76fdb066 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete collection" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover gutter" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.deleteCollection" -msgstr "Supprimer la collection" +msgid "editor.toolHint.key.hoverGutter.1dwcsno" +msgstr "Survolez la gouttière" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: a58533594411e088 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left click" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.delete" -msgstr "Supprimer" +msgid "editor.toolHint.key.leftClick.s4gwfc" +msgstr "Clic gauche" -# Source-Hash: 8e29375893d63408 +# Source-Hash: bc4ab608ec3d3b4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Middle click" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.deleteLevel" -msgstr "Supprimer le niveau" +msgid "editor.toolHint.key.middleClick.1jbaan4" +msgstr "Clic central" -# Source-Hash: 6552e45eecc0a227 +# Source-Hash: 6791879c651108c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw a zone" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right click" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.drawAZone" -msgstr "Dessiner une zone" +msgid "editor.toolHint.key.rightClick.1ovld0h" +msgstr "Clic droit" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.duplicate" -msgstr "Dupliquer" +msgid "editor.toolHint.key.room.1f3jkpm" +msgstr "Pièce" -# Source-Hash: 933177338f5a03ed +# Source-Hash: c836b21b42198868 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R / Shift+R" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.duplicateLevel" -msgstr "Dupliquer le niveau" +msgid "editor.toolHint.key.rShiftR.13bnobh" +msgstr "R / Maj+R" -# Source-Hash: c038947f317cabba +# Source-Hash: 9812aa06d8bb7544 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate level with options" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scroll" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.duplicateLevelWithOptions" -msgstr "Dupliquer le niveau avec options" +msgid "editor.toolHint.key.scroll.ai6wr0" +msgstr "Défilement" -# Source-Hash: 9614c6825a7c67bf +# Source-Hash: f2174536230657c8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate with options..." -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scroll wheel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.duplicateWithOptions" -msgstr "Dupliquer avec options..." +msgid "editor.toolHint.key.scrollWheel.18j0ix7" +msgstr "Molette" -# Source-Hash: 7c4196b9e791c195 +# Source-Hash: 82dd231086d87f3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elements" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Space" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.elements" -msgstr "Éléments" +msgid "editor.toolHint.key.space.1hrh82t" +msgstr "Espace" -# Source-Hash: 1344ea2602e3aa9e +# Source-Hash: 9e68aa2f472cad56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guide" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tab" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.guide" -msgstr "Guide" +msgid "editor.toolHint.key.tab.1xsal0s" +msgstr "Tab" -# Source-Hash: 591087ea83a48ead +# Source-Hash: 4b221b73f9496a49 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mount: floor / ceiling / wall" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.hide" -msgstr "Masquer" +msgid "editor.toolHint.mountFloorCeilingWall.32dxpv" +msgstr "Pose : sol / plafond / mur" -# Source-Hash: 0608743fc1736d86 +# Source-Hash: 225edfb1e45aed95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No room for the matching window on the other wall" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.level" -msgstr "Niveau" +msgid "editor.toolHint.noRoomForTheMatchingWindow.1755948" +msgstr "Pas de place pour la fenêtre correspondante sur l’autre mur" -# Source-Hash: 13b3e6a6afe319d1 +# Source-Hash: e367d28a655f1cca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "New unit" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not a rectangle: draw this roof instead" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.newUnit" -msgstr "Nouveau logement" +msgid "editor.toolHint.notARectangleDrawThisRoof.100pa5g" +msgstr "Non rectangulaire : dessinez plutôt ce toit" -# Source-Hash: 0192748d50f0e5f7 +# Source-Hash: a7045d6b678bcd13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No buildings yet" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No wall meets here" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.noBuildingsYet" -msgstr "Aucun bâtiment pour l’instant" +msgid "editor.toolHint.noWallMeetsHere.19n99yc" +msgstr "Aucun mur ne se rejoint ici" -# Source-Hash: 1be310702a12e433 +# Source-Hash: a639341dc21fed2c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No elements on this level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx -#, fuzzy -msgid "editor.sidebar.panels.sitePanel.noElementsOnThisLevel" -msgstr "Aucun élément sur ce niveau" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Number of cuts — scroll or click to change" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "editor.toolHint.numberOfCutsScrollOrClick.1kqe84b" +msgstr "Nombre de coupes — faites défiler ou cliquez pour modifier" -# Source-Hash: 0956af88ced36992 +# Source-Hash: af01bde3ae4b7e59 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No levels yet" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick witness point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.noLevelsYet" -msgstr "Aucun niveau pour l’instant" +msgid "editor.toolHint.pickWitnessPoint.k3hgh1" +msgstr "Choisir un point de repère" -# Source-Hash: 45c41bfb2ae19627 +# Source-Hash: ecfd58576b28a9f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {# object selected} other {# objects selected}}" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pipe size down / up" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.objectsSelected" -msgstr "{count, plural, one {# objet sélectionné} many {# objets sélectionnés} other {# objets sélectionnés}}" +msgid "editor.toolHint.pipeSizeDownUp.wp04og" +msgstr "Diamètre de tuyau moins / plus" -# Source-Hash: a5434e26e5cb1b26 +# Source-Hash: 7a1eb7b64f06bad0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Other zones" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place and continue" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.otherZones" -msgstr "Autres zones" +msgid "editor.toolHint.placeAndContinue.qfwkrq" +msgstr "Placer et continuer" -# Source-Hash: 2aa38d84079d4dba +# Source-Hash: c6cda39e2e4b5d3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Perimeter:" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place block" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.perimeter" -msgstr "Périmètre :" +msgid "editor.toolHint.placeBlock.1aylwrx" +msgstr "Placer le bloc" -# Source-Hash: 4004b9a8e4f8c9d0 +# Source-Hash: 45a743c52a1d72de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Property Line" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place box vent on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.propertyLine" -msgstr "Limite de propriété" +msgid "editor.toolHint.placeBoxVentOnRoof.kf88e5" +msgstr "Placer l’aérateur sur le toit" -# Source-Hash: 3e7408ed44676176 +# Source-Hash: 75142dd1d557efe2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rooms" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place cabinet" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.rooms" -msgstr "Pièces" +msgid "editor.toolHint.placeCabinet.b0ouyk" +msgstr "Placer le meuble" -# Source-Hash: ca39c0581c7318e6 +# Source-Hash: da603a713d4c9909 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select a level to view content" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place canopy or set the next run point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.selectALevelToViewContent" -msgstr "Sélectionnez un niveau pour voir son contenu" +msgid "editor.toolHint.placeCanopyOrSetTheNext.12l7zf8" +msgstr "Placer l’auvent ou le point suivant" -# Source-Hash: 827e0c6ac9936b69 +# Source-Hash: 8b3a30c6b7a5612d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place chimney on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.show" -msgstr "Afficher" +msgid "editor.toolHint.placeChimneyOnRoof.19dbqu" +msgstr "Placer la cheminée sur le toit" -# Source-Hash: 91f90818d42a984e +# Source-Hash: 710d41e4e2f259fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Site" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place column" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.site" -msgstr "Terrain" +msgid "editor.toolHint.placeColumn.1w2vq86" +msgstr "Placer le poteau" -# Source-Hash: c40163620df24a76 +# Source-Hash: ee1da4e12a71d9a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Take snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place cupola on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.takeSnapshot" -msgstr "Prendre un instantané" +msgid "editor.toolHint.placeCupolaOnRoof.ofx3bn" +msgstr "Placer le lanterneau sur le toit" -# Source-Hash: d6b381247066a7aa +# Source-Hash: 19c1fe8c46d213a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The ground level cannot be deleted" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place dimension line when needed" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.theGroundLevelCannotBeDeleted" -msgstr "Le niveau du rez-de-chaussée ne peut pas être supprimé" +msgid "editor.toolHint.placeDimensionLineWhenNeeded.bjw2cj" +msgstr "Placer la ligne de cote si nécessaire" -# Source-Hash: bbc65c039ae86e11 +# Source-Hash: 58f3e7efb6ea120b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Camera snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place door on wall" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.cameraSnapshot" -msgstr "Instantané de caméra" +msgid "editor.toolHint.placeDoorOnWall.1jwadf" +msgstr "Placer la porte sur le mur" -# Source-Hash: 67d29724469fa8d3 +# Source-Hash: de04e9d03d937c97 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place dormer on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.clearSnapshot" -msgstr "Effacer l’instantané" +msgid "editor.toolHint.placeDormerOnRoof.1w518a6" +msgstr "Placer la lucarne sur le toit" -# Source-Hash: 591087ea83a48ead +# Source-Hash: c581645f2ee447c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place elevator" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.hide" -msgstr "Masquer" +msgid "editor.toolHint.placeElevator.1f65zva" +msgstr "Placer l’ascenseur" -# Source-Hash: 827e0c6ac9936b69 +# Source-Hash: 096b8d6482717358 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place eyebrow vent on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.show" -msgstr "Afficher" +msgid "editor.toolHint.placeEyebrowVentOnRoof.1h1tqxn" +msgstr "Placer le chien-assis sur le toit" -# Source-Hash: c40163620df24a76 +# Source-Hash: e8d42c1c8370773f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Take snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place fitting" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.takeSnapshot" -msgstr "Prendre un instantané" +msgid "editor.toolHint.placeFitting.1pmx3vn" +msgstr "Placer le raccord" -# Source-Hash: faecab10b69d4863 +# Source-Hash: 2340a4b70cb0d9ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Update snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place gutter on roof eave" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.updateSnapshot" -msgstr "Mettre à jour l’instantané" +msgid "editor.toolHint.placeGutterOnRoofEave.llwzf9" +msgstr "Placer la gouttière sur l’égout du toit" -# Source-Hash: 8a1fd8827a68f236 +# Source-Hash: 706a8eafb6212833 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "View snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place item" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.viewSnapshot" -msgstr "Voir l’instantané" +msgid "editor.toolHint.placeItem.teynf" +msgstr "Placer l’élément" -# Source-Hash: b404dded35241274 +# Source-Hash: 1815c482e249932e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Units" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place it (locked to 45°)" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.units" -msgstr "Unités" +msgid "editor.toolHint.placeItLockedTo45.16e4csk" +msgstr "Placer (verrouillé à 45°)" -# Source-Hash: 149fec3fd1f08042 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete unit" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# Source-Hash: 4a14340657532838 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place measurement point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.deleteUnit" -msgstr "Supprimer le logement" +msgid "editor.toolHint.placeMeasurementPoint.bsatli" +msgstr "Placer le point de mesure" -# Source-Hash: 930399d3fb247a7c +# Source-Hash: b3be684ac62fbf53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Focused" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.focused" -msgstr "Ciblé" +msgid "editor.toolHint.placement.13lcvts" +msgstr "Placement" -# Source-Hash: 41ac9dd23bb558d7 +# Source-Hash: 2bb2ce6276c69b1e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove from unit" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement: Auto" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.removeFromUnit" -msgstr "Retirer du logement" +msgid "editor.toolHint.placementAuto.1caa52d" +msgstr "Placement : auto" -# Source-Hash: 612dcd5bf06a79c4 +# Source-Hash: ed78ac5354a1dcd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement: Ground" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.room" -msgstr "Pièce" +msgid "editor.toolHint.placementGround.1ruz145" +msgstr "Placement : sol" -# Source-Hash: a107b4d76d6972e3 +# Source-Hash: a066a2c9d5e65a1a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement: Roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.zone" -msgstr "Zone" +msgid "editor.toolHint.placementRoof.renkw8" +msgstr "Placement : toit" -# Source-Hash: faecab10b69d4863 +# Source-Hash: 8f74dbe5064c4c66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Update snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement surface - click or press P to cycle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.updateSnapshot" -msgstr "Mettre à jour l’instantané" +msgid "editor.toolHint.placementSurfaceClickOrPressP.w56h19" +msgstr "Surface de placement - cliquez ou appuyez sur P pour changer" -# Source-Hash: 28a12e6806c091b0 +# Source-Hash: fe119955c925feaf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{assetType, select, guide {Uploading guide... {progress}%} other {Uploading scan... {progress}%}}" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement type" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.uploadingProgress" -msgstr "{assetType, select, guide {Import du calque... {progress} %} other {Import du relevé 3D... {progress} %}}" +msgid "editor.toolHint.placementType.1mdpl60" +msgstr "Type de placement" -# Source-Hash: de389a2a46d53384 +# Source-Hash: 33043a35500168f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Upload scan/floorplan" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement type — click or press I to toggle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.uploadScanFloorplan" -msgstr "Importer un relevé 3D ou un plan" +msgid "editor.toolHint.placementTypeClickOrPressI.10cgxh2" +msgstr "Type de placement — cliquez ou appuyez sur I pour basculer" -# Source-Hash: 8a1fd8827a68f236 +# Source-Hash: 9945f412e6a9a446 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "View snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place on a fence" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.viewSnapshot" -msgstr "Voir l’instantané" +msgid "editor.toolHint.placeOnAFence.1dptstr" +msgstr "Placer sur une clôture" -# Source-Hash: ba9f809cb032ee57 +# Source-Hash: 6708118775a7da7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "In {unitName}" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/zone-membership-checkbox.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place register" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.zoneMembershipCheckbox.inUnitname" -msgstr "Dans {unitName}" +msgid "editor.toolHint.placeRegister.1uebycd" +msgstr "Placer la bouche" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: ebd2731f5c79306e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place ridge vent on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.actions" -msgstr "Actions" +msgid "editor.toolHint.placeRidgeVentOnRoof.2tpd8r" +msgstr "Placer la ventilation de faîtage sur le toit" -# Source-Hash: fcc43f22937d1536 +# Source-Hash: 9b3c66a867c23326 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add one" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place shelf" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.addOne" -msgstr "En ajouter une" +msgid "editor.toolHint.placeShelf.y4l3iw" +msgstr "Placer l’étagère" -# Source-Hash: bbc65c039ae86e11 +# Source-Hash: f11cf5c1c9fe862d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Camera snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place skylight on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.cameraSnapshot" -msgstr "Instantané de caméra" +msgid "editor.toolHint.placeSkylightOnRoof.e215pe" +msgstr "Placer la fenêtre de toit" -# Source-Hash: 67d29724469fa8d3 +# Source-Hash: e989a58d6709cc16 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place solar panel array on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.clearSnapshot" -msgstr "Effacer l’instantané" +msgid "editor.toolHint.placeSolarPanelArrayOnRoof.kk11fn" +msgstr "Placer les panneaux solaires sur le toit" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: b67f7036d5180cf5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place spawn point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.delete" -msgstr "Supprimer" +msgid "editor.toolHint.placeSpawnPoint.205o25" +msgstr "Placer le point d’apparition" -# Source-Hash: e2411929697b7ed4 +# Source-Hash: 6c7f32a17e5636c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete with contents" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place stairs" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.deleteWithContents" -msgstr "Supprimer avec le contenu" +msgid "editor.toolHint.placeStairs.zwxxu2" +msgstr "Placer l’escalier" -# Source-Hash: 22ca3935e8754072 +# Source-Hash: 641c0d3debd798a8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No zones on this level." -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place trap" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.noZonesOnThisLevel" -msgstr "Aucune zone sur ce niveau." +msgid "editor.toolHint.placeTrap.1gxemn3" +msgstr "Placer le siphon" -# Source-Hash: 941ea30f406dcfa2 +# Source-Hash: 6f0a6f6c4b7588a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Save to catalog" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place turbine vent on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.saveToCatalog" -msgstr "Enregistrer dans le catalogue" +msgid "editor.toolHint.placeTurbineVentOnRoof.1iqeluf" +msgstr "Placer l’extracteur éolien sur le toit" -# Source-Hash: 98662dfb371cac13 +# Source-Hash: e65cf5edb4f51ed5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select a level to view and create zones" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place unit" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.selectALevelToViewAnd" -msgstr "Sélectionnez un niveau pour voir et créer des zones" +msgid "editor.toolHint.placeUnit.8zkx4q" +msgstr "Placer l’unité" -# Source-Hash: c40163620df24a76 +# Source-Hash: 86ce1c730154f68b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Take snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place window on wall" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.takeSnapshot" -msgstr "Prendre un instantané" +msgid "editor.toolHint.placeWindowOnWall.1k3qnfb" +msgstr "Placer la fenêtre sur le mur" -# Source-Hash: faecab10b69d4863 +# Source-Hash: 2b612180a7617901 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Update snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place without the corner snap" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.updateSnapshot" -msgstr "Mettre à jour l’instantané" +msgid "editor.toolHint.placeWithoutTheCornerSnap.1nifqew" +msgstr "Placer sans l’aimantation d’angle" -# Source-Hash: 8a1fd8827a68f236 +# Source-Hash: dd2ea442152dca5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "View snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Point inside a room, porch or deck" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.viewSnapshot" -msgstr "Voir l’instantané" +msgid "editor.toolHint.pointInsideARoomPorchOr.58w64l" +msgstr "Pointez dans une pièce, un porche ou une terrasse" -# Source-Hash: 58b05af5b5724efb +# Source-Hash: 0dc6d121791696f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "\"{label}\" plugin crashed" -#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove last point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.usePluginPanels.labelPluginCrashed" -msgstr "Le plugin « {label} » a planté" +msgid "editor.toolHint.removeLastPoint.2dmdcx" +msgstr "Retirer le dernier point" -# Source-Hash: 9e84d6d7b9885c4f +# Source-Hash: 8b74b1d962be10fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Loading…" -#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove last witness" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.usePluginPanels.loading" -msgstr "Chargement…" +msgid "editor.toolHint.removeLastWitness.1b6vvzw" +msgstr "Retirer le dernier repère" -# Source-Hash: 9fc7a39bc32f287a +# Source-Hash: 1185bd2407dd9172 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Plugins" -#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge direction" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.usePluginPanels.plugins" -msgstr "Plugins" +msgid "editor.toolHint.ridgeDirection.5m1369" +msgstr "Sens du faîtage" -# Source-Hash: c6312309378aaaea +# Source-Hash: 4352028e50450055 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "This panel hit an error and was unloaded for this session. The rest of the editor is unaffected — reload to try again." -#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge direction - click or press R to turn it 90°" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.usePluginPanels.thisPanelHitAnErrorAnd" -msgstr "Ce panneau a rencontré une erreur et a été déchargé pour cette session. Le reste de l’éditeur n’est pas affecté — rechargez pour réessayer." +msgid "editor.toolHint.ridgeDirectionClickOrPressR.1t14dyk" +msgstr "Sens du faîtage - cliquez ou appuyez sur R pour le tourner de 90°" +# Source-Hash: 96c889f047db9de5 # Review: required -# Source-Hash: 2ab3b6983e384ecc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling attachment" -#: packages/editor/src/components/ui/snap-target-badge.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge: Long side" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.snapTarget.ceiling" -msgstr "Fixation au plafond" +msgid "editor.toolHint.ridgeLongSide.ew0euv" +msgstr "Faîtage : côté long" +# Source-Hash: 58143198d3f2a265 # Review: required -# Source-Hash: 54a00bbb699e3778 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof attachment" -#: packages/editor/src/components/ui/snap-target-badge.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge: Short side" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.snapTarget.roof" -msgstr "Fixation à la toiture" +msgid "editor.toolHint.ridgeShortSide.gye8pb" +msgstr "Faîtage : côté court" +# Source-Hash: 306d409f8a1cf480 # Review: required -# Source-Hash: e45fee9c27f6ae69 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall attachment" -#: packages/editor/src/components/ui/snap-target-badge.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.snapTarget.wall" -msgstr "Fixation murale" +msgid "editor.toolHint.rotate.1thqa0a" +msgstr "Pivoter" -# Source-Hash: 834de1a7027c4da1 +# Source-Hash: 8a665ecaeffa9308 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The editor scene failed to render" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ±45°" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.theEditorSceneFailedToRender" -msgstr "La scène de l’éditeur n’a pas pu s’afficher" +msgid "editor.toolHint.rotate45.9zq68u" +msgstr "Pivoter de ±45°" -# Source-Hash: 151f7c7e4110016f +# Source-Hash: be2240289aa74df5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A curtain wall takes no corner window" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ±45° (floor / ceiling)" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.aCurtainWallTakesNoCorner.1qxjv5i" -msgstr "Un mur-rideau n’accepte pas de fenêtre d’angle" +msgid "editor.toolHint.rotate45FloorCeiling.m9t57d" +msgstr "Pivoter de ±45° (sol / plafond)" -# Source-Hash: 97f5e044d46501fb +# Source-Hash: d5fb78b07c0f8138 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A curved wall takes no corner window" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ghost ±15°" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.aCurvedWallTakesNoCorner.1vdnaw5" -msgstr "Un mur courbe n’accepte pas de fenêtre d’angle" +msgid "editor.toolHint.rotateGhost15.rsa52c" +msgstr "Pivoter l’aperçu de ±15°" -# Source-Hash: 776d8ebece7fe1bb +# Source-Hash: 912d340cd16e27fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add a corner · click the first to close" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate or flip the run side" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.addACornerClickTheFirst.o4r67t" -msgstr "Ajouter un angle · cliquez sur le premier pour fermer" +msgid "editor.toolHint.rotateOrFlipTheRunSide.t5ior7" +msgstr "Pivoter ou inverser le côté de la rangée" -# Source-Hash: 6a0745dd047b149a +# Source-Hash: fa24651e9e5f595a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Another opening is in the way at the corner" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate spawn point" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.anotherOpeningIsInTheWay.11l9dd0" -msgstr "Une autre ouverture gêne à l’angle" +msgid "editor.toolHint.rotateSpawnPoint.1opcuu7" +msgstr "Pivoter le point d’apparition" -# Source-Hash: 441124187e7da2fc +# Source-Hash: 2d693d87fe9b59e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round / rectangular / oval" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.autoHangers.10554ka" -msgstr "Suspentes auto" +msgid "editor.toolHint.roundRectangularOval.e4nh6x" +msgstr "Rond / rectangulaire / oblong" -# Source-Hash: 47a7f9a6a81156c3 +# Source-Hash: ee4ca2612f1ea085 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers - click or press H to toggle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set beam start / end; the next beam starts there" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.autoHangersClickOrPressH.rwa3ka" -msgstr "Suspentes auto - cliquez ou appuyez sur H pour basculer" +msgid "editor.toolHint.setBeamStartEndTheNext.di3bzj" +msgstr "Définir le début / la fin de la poutre ; la suivante part de là" -# Source-Hash: d7944f31cba90e26 +# Source-Hash: f7d2c9cdcc637c97 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers: Off" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set fence start / end" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.autoHangersOff.7yx01x" -msgstr "Suspentes auto : désactivées" +msgid "editor.toolHint.setFenceStartEnd.1phbwsq" +msgstr "Définir le début / la fin de la clôture" -# Source-Hash: 295882d015d08742 +# Source-Hash: c93ae898b4d59f6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers: On" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set one corner, then the opposite" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.autoHangersOn.10b1umh" -msgstr "Suspentes auto : activées" +msgid "editor.toolHint.setOneCornerThenTheOpposite.8tsl49" +msgstr "Placez un angle, puis l’angle opposé" -# Source-Hash: 8c039e5182b01c4d +# Source-Hash: 4f55171f10c6ceeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bypass snapping" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set roof footprint" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.bypassSnapping.w5lmdv" -msgstr "Ignorer l’aimantation" +msgid "editor.toolHint.setRoofFootprint.p50n0o" +msgstr "Définir l’emprise du toit" -# Source-Hash: c0774c185060fc13 +# Source-Hash: 0243859b1d64c21e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set wall start / end" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cancel.ew9em3" -msgstr "Annuler" +msgid "editor.toolHint.setWallStartEnd.1r8ubcx" +msgstr "Définir le début / la fin du mur" -# Source-Hash: 5b33b576fd30b74e +# Source-Hash: c2806cce9612fa50 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel move" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slope / level" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cancelMove.lvp31c" -msgstr "Annuler le déplacement" +msgid "editor.toolHint.slopeLevel.ftqp67" +msgstr "Pente / à plat" -# Source-Hash: 136fa29b9ae419bf +# Source-Hash: 06c0ec40606db679 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel run / exit" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snap onto the run" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cancelRunExit.zqjf3h" -msgstr "Annuler le tronçon / quitter" +msgid "editor.toolHint.snapOntoTheRun.86yhmp" +msgstr "Aimanter sur le tronçon" -# Source-Hash: 75b406824be91ac2 +# Source-Hash: e214cccbac9c4fd2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel start point" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Split at the marks" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cancelStartPoint.1xbq2lh" -msgstr "Annuler le point de départ" +msgid "editor.toolHint.splitAtTheMarks.x5tpdd" +msgstr "Diviser aux repères" -# Source-Hash: ffa5aaa1746303c4 +# Source-Hash: 94455c35bfeac6b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner window" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start grid axis" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cornerWindow.1avkzpo" -msgstr "Fenêtre d’angle" +msgid "editor.toolHint.startGridAxis.k92yza" +msgstr "Commencer l’axe de trame" -# Source-Hash: b0afdd855a02e4a7 +# Source-Hash: 2edb4c29bbe7c513 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cuts" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start lineset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cuts.1y0axps" -msgstr "Coupes" +msgid "editor.toolHint.startLineset.23q8dh" +msgstr "Commencer la liaison frigorifique" -# Source-Hash: dc9fe7601cc525f8 +# Source-Hash: 9e50f1b30e325208 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cuts: {value}" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start liquid line" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cutsValue.ouzhvb" -msgstr "Coupes : {value}" +msgid "editor.toolHint.startLiquidLine.1rlxsgd" +msgstr "Commencer la ligne liquide" -# Source-Hash: a2e13bc4dc82624c +# Source-Hash: 877ddcb778c211cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cuts: {value}, even" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start run" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cutsValueEven.1ngsz3" -msgstr "Coupes : {value}, régulières" +msgid "editor.toolHint.startRun.r6fc5u" +msgstr "Commencer le tronçon" -# Source-Hash: 04152b4cec726f34 +# Source-Hash: 8a62bee64174bbc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cycle mono / gable / butterfly" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start segment" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cycleMonoGableButterfly.1poga3m" -msgstr "Basculer un pan / deux pans / papillon" +msgid "editor.toolHint.startSegment.rolym6" +msgstr "Commencer le segment" -# Source-Hash: 4fb6c83edb6652b5 +# Source-Hash: 6cc5dc51a8e66779 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cycle snapping mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Step back or cancel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cycleSnappingMode.1ct0gn6" -msgstr "Changer le mode d’aimantation" +msgid "editor.toolHint.stepBackOrCancel.zbfdkn" +msgstr "Revenir en arrière ou annuler" -# Source-Hash: 5d550a3ac76279de +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door style — click or press L to cycle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.doorStyleClickOrPressL.33pe65" -msgstr "Style de porte — cliquez ou appuyez sur L pour changer" +msgid "editor.toolHint.style.nf3vcm" +msgstr "Style" -# Source-Hash: 3272a7df5d7c6a9a +# Source-Hash: 81f595b1c47c0080 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door type — click or press O to cycle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Barn" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.doorTypeClickOrPressO.1hhh8gt" -msgstr "Type de porte — cliquez ou appuyez sur O pour changer" +msgid "editor.toolHint.styleBarn.k9n1x" +msgstr "Style : grange" -# Source-Hash: 366222b4435eefda +# Source-Hash: 3a82c718fe215273 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drop downspout from outlet" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Casement" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.dropDownspoutFromOutlet.1k4h1m4" -msgstr "Descendre la descente depuis la sortie" +msgid "editor.toolHint.styleCasement.ziklec" +msgstr "Style : battant" -# Source-Hash: 03f306371f345007 +# Source-Hash: 072e3331d1d105c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct diameter down / up" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Craftsman" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.ductDiameterDownUp.1wdz5vq" -msgstr "Diamètre de gaine moins / plus" +msgid "editor.toolHint.styleCraftsman.52e6a9" +msgstr "Style : artisan" -# Source-Hash: 7b4137e27f8327d9 +# Source-Hash: b64d07557dec1714 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End run / cancel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Double-hung" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.endRunCancel.59dh2w" -msgstr "Terminer le tronçon / annuler" +msgid "editor.toolHint.styleDoubleHung.1lg8pkg" +msgstr "Style : guillotine double" -# Source-Hash: 938aacb119b29dc1 +# Source-Hash: 55ef8761a537637f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Exit" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: French" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.exit.engmg5" -msgstr "Quitter" +msgid "editor.toolHint.styleFrench.1ue3j64" +msgstr "Style : à la française" -# Source-Hash: 7cb4e0688cabcb00 +# Source-Hash: bc8a751d87536dc3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Exit drawing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Glass" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.exitDrawing.9noxyb" -msgstr "Quitter le tracé" +msgid "editor.toolHint.styleGlass.qudnb4" +msgstr "Style : vitré" -# Source-Hash: 47025a103c456125 +# Source-Hash: 40c1eb0bc83e207d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish and continue" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Grid" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.finishAndContinue.1gpfsks" -msgstr "Terminer et continuer" +msgid "editor.toolHint.styleGrid.1vuq4po" +msgstr "Style : petits bois" -# Source-Hash: 000918429b74128f +# Source-Hash: f516886bab2e7f10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish ceiling" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Half-louvered" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.finishCeiling.1c1lfel" -msgstr "Terminer le plafond" +msgid "editor.toolHint.styleHalfLouvered.13b1few" +msgstr "Style : demi-persienne" -# Source-Hash: 51a80a0dba5a6f30 +# Source-Hash: 64e4389a695371a2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish grid axis" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Horizontal bands" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.finishGridAxis.1wvrfhr" -msgstr "Terminer l’axe de trame" +msgid "editor.toolHint.styleHorizontalBands.12ethxk" +msgstr "Style : bandes horizontales" -# Source-Hash: 87c7b98fc2e010e1 +# Source-Hash: ff6d226a425b00c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish measurement" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Modern" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.finishMeasurement.1e4gv16" -msgstr "Terminer la mesure" +msgid "editor.toolHint.styleModern.1fh8hhn" +msgstr "Style : moderne" -# Source-Hash: 5e1a0af7dc506826 +# Source-Hash: c6d17ba078ff47e7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish multi-point witnesses" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Panel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.finishMultiPointWitnesses.8wzskz" -msgstr "Terminer les repères multipoints" +msgid "editor.toolHint.stylePanel.922jze" +msgstr "Style : panneau" -# Source-Hash: 30fc0862501ba2e8 +# Source-Hash: 5e6baad0d2ce3a62 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish slab" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Paneled glass" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.finishSlab.xmnm8e" -msgstr "Terminer la dalle" +msgid "editor.toolHint.stylePaneledGlass.17a17en" +msgstr "Style : vitré à panneaux" -# Source-Hash: 66ed7c7598d3aa29 +# Source-Hash: 6314388e6832c252 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip side" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Shaker" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.flipSide.172xku9" -msgstr "Inverser le côté" +msgid "editor.toolHint.styleShaker.49z17k" +msgstr "Style : shaker" -# Source-Hash: f5717f6a0905ffab +# Source-Hash: a0f8e524f3ca121f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follow: trace a lineset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Single" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.followTraceALineset.mgquwe" -msgstr "Suivre : longer une liaison frigorifique" +msgid "editor.toolHint.styleSingle.6f3cm0" +msgstr "Style : simple" -# Source-Hash: ed7f3d8417a3e074 +# Source-Hash: 368279df3a472c86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Force place" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Six-panel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.forcePlace.1hq1nr" -msgstr "Forcer le placement" +msgid "editor.toolHint.styleSixPanel.u49laj" +msgstr "Style : six panneaux" -# Source-Hash: cc0c14065951444d +# Source-Hash: 8f3c2571d8168fee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Free placement" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Sliding" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.freePlacement.1nztdac" -msgstr "Placement libre" +msgid "editor.toolHint.styleSliding.q81s0i" +msgstr "Style : coulissant" -# Source-Hash: f098a27096a9c1ea +# Source-Hash: aa9d9eb137ca38d4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Go vertical ↕, click to place" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Tall grid" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.goVerticalClickToPlace.dg8g6m" -msgstr "Passer en vertical ↕, cliquez pour placer" +msgid "editor.toolHint.styleTallGrid.1eotg3x" +msgstr "Style : petits bois hauts" -# Source-Hash: fd47f1820d8799c8 +# Source-Hash: bc164648722b63e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Highlight outlet" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Transom" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.highlightOutlet.65hoq8" -msgstr "Mettre en évidence la sortie" +msgid "editor.toolHint.styleTransom.kb9bh6" +msgstr "Style : imposte" -# Source-Hash: eb90058d0f856f67 +# Source-Hash: 9a218f0c9ceb4697 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Join as a corner window" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Triple-hung" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.joinAsACornerWindow.jvdp4j" -msgstr "Joindre en fenêtre d’angle" +msgid "editor.toolHint.styleTripleHung.pxnqi3" +msgstr "Style : guillotine triple" -# Source-Hash: 225b3161f2e59757 +# Source-Hash: 9f6df1344bd3d694 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Alt + drag" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Wide grid" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.altDrag.ai3wn9" -msgstr "Alt + glisser" +msgid "editor.toolHint.styleWideGrid.12n27et" +msgstr "Style : petits bois larges" -# Source-Hash: dd66f883b173fc72 +# Source-Hash: 711d4050c0cb95d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Backspace" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Switch rotation axis (Y → X → Z)" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.backspace.qy6qx8" -msgstr "Retour arrière" +msgid "editor.toolHint.switchRotationAxisYXZ.15lohm6" +msgstr "Changer l’axe de rotation (Y → X → Z)" -# Source-Hash: a18387bc0be54c32 +# Source-Hash: d650c71e042c2598 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The walls meet at too sharp or too flat an angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.click.m8sun" -msgstr "Clic" +msgid "editor.toolHint.theWallsMeetAtTooSharp.kh3wi3" +msgstr "Les murs se rejoignent selon un angle trop aigu ou trop plat" -# Source-Hash: db9e60c1d30b8499 +# Source-Hash: ab206ac56e65f190 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click again" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The window waiting there is taller than this wall" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.clickAgain.190ws9j" -msgstr "Cliquer à nouveau" +msgid "editor.toolHint.theWindowWaitingThereIsTaller.1tqwez4" +msgstr "La fenêtre prévue à cet endroit est plus haute que ce mur" -# Source-Hash: f400330b9c9c12e8 +# Source-Hash: 9c1f47138ed5c7ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Command" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Three or more walls meet here" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.command.1j2mkia" -msgstr "Commande" +msgid "editor.toolHint.threeOrMoreWallsMeetHere.rgifif" +msgstr "Trois murs ou plus se rejoignent ici" -# Source-Hash: 976c63285a510b09 +# Source-Hash: c3ca56fa28e15f07 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Control" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trace ceiling outline" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.control.10fbl8e" -msgstr "Contrôle" +msgid "editor.toolHint.traceCeilingOutline.1b639wv" +msgstr "Tracer le contour du plafond" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: bdf71499d30a29de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trace slab outline" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.delete.oay2cq" -msgstr "Supprimer" +msgid "editor.toolHint.traceSlabOutline.z0j2lc" +msgstr "Tracer le contour de la dalle" -# Source-Hash: 88888c9d2719fa92 +# Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double click" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.doubleClick.vlma6o" -msgstr "Double-clic" +msgid "editor.toolHint.type.1m2zofh" +msgstr "Type" -# Source-Hash: dfb85b2addb7b9fa +# Source-Hash: b54eaaff3349dcb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Awning" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.drag.8pwtpf" -msgstr "Glisser" +msgid "editor.toolHint.typeAwning.1cj59al" +msgstr "Type : à l’italienne" -# Source-Hash: ed9140d42148c99b +# Source-Hash: f399572a27417c66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Enter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Barn" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.enter.1ctpui5" -msgstr "Entrée" +msgid "editor.toolHint.typeBarn.sbnygq" +msgstr "Type : grange" -# Source-Hash: 9195fa8b9c8ebdfb +# Source-Hash: a1df9782200b5f1e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Bay" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.hover.6xw79p" -msgstr "Survoler" +msgid "editor.toolHint.typeBay.1200hc1" +msgstr "Type : oriel" -# Source-Hash: 2d78441b741bc562 +# Source-Hash: ff069a390e8e3f66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a duct end" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Bow" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.hoverADuctEnd.19axr3b" -msgstr "Survolez une extrémité de gaine" +msgid "editor.toolHint.typeBow.14s2t9p" +msgstr "Type : bow-window" -# Source-Hash: 6083405086f61c76 +# Source-Hash: bdac5f3f2ea70fff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a pipe end" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Cabinet" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.hoverAPipeEnd.1jbum5f" -msgstr "Survolez une extrémité de tuyau" +msgid "editor.toolHint.typeCabinet.1r68je5" +msgstr "Type : placard" -# Source-Hash: a5a337eb76fdb066 +# Source-Hash: e0754fc03997cbf9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover gutter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Casement" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.hoverGutter.1dwcsno" -msgstr "Survolez la gouttière" +msgid "editor.toolHint.typeCasement.176uo9j" +msgstr "Type : battant" -# Source-Hash: a58533594411e088 +# Source-Hash: 47d873446d6e173b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left click" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Double" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.leftClick.s4gwfc" -msgstr "Clic gauche" +msgid "editor.toolHint.typeDouble.af7w4i" +msgstr "Type : double" -# Source-Hash: bc4ab608ec3d3b4f +# Source-Hash: 5942e484513aaab5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Middle click" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Double Hung" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.middleClick.1jbaan4" -msgstr "Clic central" +msgid "editor.toolHint.typeDoubleHung.t482fu" +msgstr "Type : guillotine double" -# Source-Hash: 6791879c651108c7 +# Source-Hash: f9497fbfceefda27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right click" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Fixed" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.rightClick.1ovld0h" -msgstr "Clic droit" +msgid "editor.toolHint.typeFixed.v1cjez" +msgstr "Type : fixe" -# Source-Hash: c836b21b42198868 +# Source-Hash: 0dcf07acc9cbf000 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R / Shift+R" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Folding" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.rShiftR.13bnobh" -msgstr "R / Maj+R" +msgid "editor.toolHint.typeFolding.sxxyng" +msgstr "Type : pliante" -# Source-Hash: 9812aa06d8bb7544 +# Source-Hash: bff7331f87f279aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scroll" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: French" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.scroll.ai6wr0" -msgstr "Défilement" +msgid "editor.toolHint.typeFrench.1y57z1b" +msgstr "Type : à la française" -# Source-Hash: f2174536230657c8 +# Source-Hash: 9d2c3b82079eb769 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scroll wheel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Hinged" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.scrollWheel.18j0ix7" -msgstr "Molette" +msgid "editor.toolHint.typeHinged.1xrcfju" +msgstr "Type : battante" -# Source-Hash: 82dd231086d87f3b +# Source-Hash: b8001b90ff522838 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Space" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Island" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.space.1hrh82t" -msgstr "Espace" +msgid "editor.toolHint.typeIsland.ufr3ce" +msgstr "Type : îlot" -# Source-Hash: 9e68aa2f472cad56 +# Source-Hash: 516833c5160d412e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tab" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Louvered" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.tab.1xsal0s" -msgstr "Tab" +msgid "editor.toolHint.typeLouvered.oxl1cz" +msgstr "Type : à persiennes" -# Source-Hash: 4b221b73f9496a49 +# Source-Hash: 291272bf848ad6ab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mount: floor / ceiling / wall" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Pocket" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.mountFloorCeilingWall.32dxpv" -msgstr "Pose : sol / plafond / mur" +msgid "editor.toolHint.typePocket.hc65x9" +msgstr "Type : galandage" -# Source-Hash: 225edfb1e45aed95 +# Source-Hash: 46d0e53d6ae07c72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No room for the matching window on the other wall" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Single Hung" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.noRoomForTheMatchingWindow.1755948" -msgstr "Pas de place pour la fenêtre correspondante sur l’autre mur" +msgid "editor.toolHint.typeSingleHung.p53pyl" +msgstr "Type : guillotine simple" -# Source-Hash: a7045d6b678bcd13 +# Source-Hash: b11115b50df8faac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No wall meets here" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Sliding" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.noWallMeetsHere.19n99yc" -msgstr "Aucun mur ne se rejoint ici" +msgid "editor.toolHint.typeSliding.nwmr3f" +msgstr "Type : coulissante" -# Source-Hash: a639341dc21fed2c +# Source-Hash: bff0c1694ee0a37e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Number of cuts — scroll or click to change" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical stack ↕, click to place" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.numberOfCutsScrollOrClick.1kqe84b" -msgstr "Nombre de coupes — faites défiler ou cliquez pour modifier" +msgid "editor.toolHint.verticalStackClickToPlace.ijcn4q" +msgstr "Colonne verticale ↕, cliquez pour placer" -# Source-Hash: af01bde3ae4b7e59 +# Source-Hash: bac471ee67af6412 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick witness point" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waste / vent" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.pickWitnessPoint.k3hgh1" -msgstr "Choisir un point de repère" +msgid "editor.toolHint.wasteVent.1hvi3vj" +msgstr "Évacuation / ventilation" -# Source-Hash: ecfd58576b28a9f6 +# Source-Hash: 1c744b7e24fc786e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pipe size down / up" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Window style — click or press L to cycle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.pipeSizeDownUp.wp04og" -msgstr "Diamètre de tuyau moins / plus" +msgid "editor.toolHint.windowStyleClickOrPressL.ah7qm9" +msgstr "Style de fenêtre — cliquez ou appuyez sur L pour changer" -# Source-Hash: 7a1eb7b64f06bad0 +# Source-Hash: dd6f0ab314fea26c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place and continue" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Window type — click or press O to cycle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeAndContinue.qfwkrq" -msgstr "Placer et continuer" +msgid "editor.toolHint.windowTypeClickOrPressO.wv4x35" +msgstr "Type de fenêtre — cliquez ou appuyez sur O pour changer" -# Source-Hash: c6cda39e2e4b5d3a +# Source-Hash: a48c4b2e4d71b08d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place block" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length: {field} m" +#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx #, fuzzy -msgid "editor.toolHint.placeBlock.1aylwrx" -msgstr "Placer le bloc" +msgid "editor.tools.distribution.distributionRunTool.lengthField" +msgstr "Longueur : {field} m" -# Source-Hash: 45a743c52a1d72de +# Source-Hash: e53695d6669245c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place box vent on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tab: direction" +#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx #, fuzzy -msgid "editor.toolHint.placeBoxVentOnRoof.kf88e5" -msgstr "Placer l’aérateur sur le toit" +msgid "editor.tools.distribution.distributionRunTool.tabDirection" +msgstr "Tab : direction" -# Source-Hash: 75142dd1d557efe2 +# Source-Hash: abb1d8c8bfb41acf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place cabinet" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "type a length" +#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx #, fuzzy -msgid "editor.toolHint.placeCabinet.b0ouyk" -msgstr "Placer le meuble" +msgid "editor.tools.distribution.distributionRunTool.typeALength" +msgstr "saisir une longueur" -# Source-Hash: da603a713d4c9909 +# Source-Hash: 9fc7a39bc32f287a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place canopy or set the next run point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plugins" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeCanopyOrSetTheNext.12l7zf8" -msgstr "Placer l’auvent ou le point suivant" +msgid "editor.views.plugins" +msgstr "Plugins" -# Source-Hash: 8b3a30c6b7a5612d +# Source-Hash: c54f9bac358893d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place chimney on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "2D" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeChimneyOnRoof.19dbqu" -msgstr "Placer la cheminée sur le toit" +msgid "editor.views.view2d" +msgstr "2D" -# Source-Hash: 710d41e4e2f259fa +# Source-Hash: f78f2fa035f25f85 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place column" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "3D" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeColumn.1w2vq86" -msgstr "Placer le poteau" +msgid "editor.views.view3d" +msgstr "3D" -# Source-Hash: ee1da4e12a71d9a9 +# Source-Hash: 05b65242d8c48791 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place cupola on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeCupolaOnRoof.ofx3bn" -msgstr "Placer le lanterneau sur le toit" +msgid "editor.views.viewBar.auto" +msgstr "Auto" -# Source-Hash: 19c1fe8c46d213a5 +# Source-Hash: 7890c110650ad1e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place dimension line when needed" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Browse plugins" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeDimensionLineWhenNeeded.bjw2cj" -msgstr "Placer la ligne de cote si nécessaire" +msgid "editor.views.viewBar.browsePlugins" +msgstr "Parcourir les plugins" -# Source-Hash: 58f3e7efb6ea120b +# Source-Hash: 3b11e7af681a9dcd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place door on wall" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close {label}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeDoorOnWall.1jwadf" -msgstr "Placer la porte sur le mur" +msgid "editor.views.viewBar.closeLabel" +msgstr "Fermer {label}" -# Source-Hash: de04e9d03d937c97 +# Source-Hash: 3f00e92517e3f4a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place dormer on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close split (\\)" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeDormerOnRoof.1w518a6" -msgstr "Placer la lucarne sur le toit" +msgid "editor.views.viewBar.closeSplit" +msgstr "Fermer la vue partagée (\\)" -# Source-Hash: c581645f2ee447c2 +# Source-Hash: 94cc8e9f1ee16edb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place elevator" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeElevator.1f65zva" -msgstr "Placer l’ascenseur" +msgid "editor.views.viewBar.ground" +msgstr "Sol" -# Source-Hash: 096b8d6482717358 +# Source-Hash: 0d472502a4d36e86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place eyebrow vent on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{standing, select, partly {Partly below grade · ground solid} below {Below grade · ground solid} other {Ground solid}}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeEyebrowVentOnRoof.1h1tqxn" -msgstr "Placer le chien-assis sur le toit" +msgid "editor.views.viewBar.groundSolid" +msgstr "{standing, select, partly {Partiellement sous le terrain · sol plein} below {Sous le terrain · sol plein} other {Sol plein}}" -# Source-Hash: e8d42c1c8370773f +# Source-Hash: 1b6798c307ac1b96 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place fitting" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{standing, select, partly {Partly below grade · ground veiled} below {Below grade · ground veiled} other {Ground veiled}}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeFitting.1pmx3vn" -msgstr "Placer le raccord" +msgid "editor.views.viewBar.groundVeiled" +msgstr "{standing, select, partly {Partiellement sous le terrain · sol voilé} below {Sous le terrain · sol voilé} other {Sol voilé}}" -# Source-Hash: 2340a4b70cb0d9ad +# Source-Hash: ebdc976a98e82626 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place gutter on roof eave" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keep the ground solid" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeGutterOnRoofEave.llwzf9" -msgstr "Placer la gouttière sur l’égout du toit" +msgid "editor.views.viewBar.keepTheGroundSolid" +msgstr "Garder le sol plein" -# Source-Hash: 706a8eafb6212833 +# Source-Hash: 5f827686a006d88c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place item" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "More views" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeItem.teynf" -msgstr "Placer l’élément" +msgid "editor.views.viewBar.moreViews" +msgstr "Plus de vues" -# Source-Hash: 1815c482e249932e +# Source-Hash: f175bbcf457ab73c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place it (locked to 45°)" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pane {pane} views" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeItLockedTo45.16e4csk" -msgstr "Placer (verrouillé à 45°)" +msgid "editor.views.viewBar.paneViews" +msgstr "Vues du volet {pane}" -# Source-Hash: 4a14340657532838 +# Source-Hash: 33c20cc33dce9a9b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place measurement point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pin {label}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeMeasurementPoint.bsatli" -msgstr "Placer le point de mesure" +msgid "editor.views.viewBar.pinLabel" +msgstr "Épingler {label}" -# Source-Hash: b3be684ac62fbf53 +# Source-Hash: 3f7231b1eb2f93f3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pin to the view bar" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placement.13lcvts" -msgstr "Placement" +msgid "editor.views.viewBar.pinToTheViewBar" +msgstr "Épingler à la barre de vues" -# Source-Hash: 2bb2ce6276c69b1e +# Source-Hash: ef3e765e692faf4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement: Auto" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placementAuto.1caa52d" -msgstr "Placement : auto" +msgid "editor.views.viewBar.solid" +msgstr "Plein" -# Source-Hash: ed78ac5354a1dcd8 +# Source-Hash: 98f22f3f89f17686 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement: Ground" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Split (\\)" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placementGround.1ruz145" -msgstr "Placement : sol" +msgid "editor.views.viewBar.split" +msgstr "Vue partagée (\\)" -# Source-Hash: a066a2c9d5e65a1a +# Source-Hash: e4cd64b1680ac0d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement: Roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Split" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placementRoof.renkw8" -msgstr "Placement : toit" +msgid "editor.views.viewBar.split2" +msgstr "Partager" -# Source-Hash: 8f74dbe5064c4c66 +# Source-Hash: 15b0adc705923a27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement surface - click or press P to cycle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap panes" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placementSurfaceClickOrPressP.w56h19" -msgstr "Surface de placement - cliquez ou appuyez sur P pour changer" +msgid "editor.views.viewBar.swapPanes" +msgstr "Inverser les volets" -# Source-Hash: fe119955c925feaf +# Source-Hash: 9781bcdb7a8549e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement type" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unpin from the view bar" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placementType.1mdpl60" -msgstr "Type de placement" +msgid "editor.views.viewBar.unpinFromTheViewBar" +msgstr "Désépingler de la barre de vues" -# Source-Hash: 33043a35500168f5 +# Source-Hash: f667358dec4abdea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement type — click or press I to toggle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unpin {label}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placementTypeClickOrPressI.10cgxh2" -msgstr "Type de placement — cliquez ou appuyez sur I pour basculer" +msgid "editor.views.viewBar.unpinLabel" +msgstr "Désépingler {label}" -# Source-Hash: 9945f412e6a9a446 +# Source-Hash: e96581f0bbf9fa91 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place on a fence" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Veil the ground over a level below grade" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeOnAFence.1dptstr" -msgstr "Placer sur une clôture" +msgid "editor.views.viewBar.veilTheGroundOverALevel" +msgstr "Voiler le sol au-dessus d’un niveau sous le terrain" -# Source-Hash: 6708118775a7da7f +# Source-Hash: fb82f09f8ed3059e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place register" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Views" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeRegister.1uebycd" -msgstr "Placer la bouche" +msgid "editor.views.viewBar.views" +msgstr "Vues" -# Source-Hash: ebd2731f5c79306e +# Source-Hash: 57c1428fe2d28745 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place ridge vent on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "List the layers from the outside in, around one framing core. The type is saved with the project and applied to this wall; other walls keep their layers." +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.toolHint.placeRidgeVentOnRoof.2tpd8r" -msgstr "Placer la ventilation de faîtage sur le toit" +msgid "editor.wallTypeEditorDialog.listTheLayersAppliedToThisWall" +msgstr "Listez les couches de l’extérieur vers l’intérieur, autour d’une seule ossature. Le type est enregistré avec le projet et appliqué à ce mur ; les autres murs gardent leurs couches." -# Source-Hash: 9b3c66a867c23326 +# Source-Hash: 9e9715d52410c86f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place shelf" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.toolHint.placeShelf.y4l3iw" -msgstr "Placer l’étagère" +msgid "editor.wallTypeMenu.custom" +msgstr "Personnalisé" -# Source-Hash: f11cf5c1c9fe862d +# Source-Hash: 0e2a2a8b90ba9c7e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place skylight on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall types: new, edit or duplicate {label}" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.toolHint.placeSkylightOnRoof.e215pe" -msgstr "Placer la fenêtre de toit" +msgid "editor.wallTypeMenu.wallTypesOf" +msgstr "Types de mur : créer, modifier ou dupliquer {label}" -# Source-Hash: e989a58d6709cc16 +# Source-Hash: fdece5c2158dfe88 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place solar panel array on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "You can retry the scene or return home without reloading the whole app shell." +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.toolHint.placeSolarPanelArrayOnRoof.kk11fn" -msgstr "Placer les panneaux solaires sur le toit" +msgid "editor.youCanRetryTheSceneOr" +msgstr "Vous pouvez relancer la scène ou revenir à l’accueil sans recharger toute l’application." -# Source-Hash: b67f7036d5180cf5 +# Source-Hash: bafa390e07160f3c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place spawn point" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A framing beam drawn end to end: a porch header, a deck beam, a girder." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeSpawnPoint.205o25" -msgstr "Placer le point d’apparition" +msgid "node.beam.description" +msgstr "Une poutre de charpente tracée d’une extrémité à l’autre : linteau de porche, poutre de terrasse, poutre maîtresse." -# Source-Hash: 6c7f32a17e5636c3 +# Source-Hash: e14858b33b6e2623 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place stairs" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeStairs.zwxxu2" -msgstr "Placer l’escalier" +msgid "node.beam.label" +msgstr "Poutre" -# Source-Hash: 641c0d3debd798a8 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place trap" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.placeTrap.1gxemn3" -msgstr "Placer le siphon" +msgid "node.beam.panel.actions" +msgstr "Actions" -# Source-Hash: 6f0a6f6c4b7588a0 +# Source-Hash: 59f845b250e0df6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place turbine vent on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add posts" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.placeTurbineVentOnRoof.1iqeluf" -msgstr "Placer l’extracteur éolien sur le toit" +msgid "node.beam.panel.addPosts" +msgstr "Ajouter des poteaux" -# Source-Hash: e65cf5edb4f51ed5 +# Source-Hash: e14858b33b6e2623 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place unit" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.placeUnit.8zkx4q" -msgstr "Placer l’unité" +msgid "node.beam.panel.beam" +msgstr "Poutre" -# Source-Hash: 86ce1c730154f68b +# Source-Hash: 26e977da636cc882 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place window on wall" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam {size}" +#: packages/nodes/src/beam/panel.tsx +#, fuzzy +msgid "node.beam.panel.beamSize" +msgstr "Poutre {size}" + +# Source-Hash: b26de372b4b0eaac +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.placeWindowOnWall.1k3qnfb" -msgstr "Placer la fenêtre sur le mur" +msgid "node.beam.panel.delete" +msgstr "Supprimer" -# Source-Hash: 2b612180a7617901 +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place without the corner snap" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.placeWithoutTheCornerSnap.1nifqew" -msgstr "Placer sans l’aimantation d’angle" +msgid "node.beam.panel.depth" +msgstr "Hauteur" -# Source-Hash: 0dc6d121791696f7 +# Source-Hash: 73694f3f45cf2ee1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove last point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dropped" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.removeLastPoint.2dmdcx" -msgstr "Retirer le dernier point" +msgid "node.beam.panel.dropped" +msgstr "En retombée" -# Source-Hash: 8b74b1d962be10fc +# Source-Hash: eaaa20f3b603140f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove last witness" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flush" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.removeLastWitness.1b6vvzw" -msgstr "Retirer le dernier repère" +msgid "node.beam.panel.flush" +msgstr "Noyée" -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: 0ee3edea19fd153e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow the ceiling plane" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.rotate.1thqa0a" -msgstr "Pivoter" +msgid "node.beam.panel.followTheCeilingPlane" +msgstr "Suivre le plan du plafond" -# Source-Hash: 8a665ecaeffa9308 +# Source-Hash: 193b75ac869c251d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ±45°" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{length} long; its underside {underside} over the floor, the ceiling plane {plane}." +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.rotate45.9zq68u" -msgstr "Pivoter de ±45°" +msgid "node.beam.panel.lengthLongItsUnderside" +msgstr "{length} de long ; sous-face à {underside} au-dessus du plancher, plan du plafond à {plane}." -# Source-Hash: be2240289aa74df5 +# Source-Hash: 964b86ae1474ff98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ±45° (floor / ceiling)" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Material" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.rotate45FloorCeiling.m9t57d" -msgstr "Pivoter de ±45° (sol / plafond)" +msgid "node.beam.panel.material" +msgstr "Matériau" -# Source-Hash: d5fb78b07c0f8138 +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ghost ±15°" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.rotateGhost15.rsa52c" -msgstr "Pivoter l’aperçu de ±15°" +msgid "node.beam.panel.move" +msgstr "Déplacer" -# Source-Hash: 912d340cd16e27fa +# Source-Hash: fa876c632c284d81 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate or flip the run side" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "1 ply" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.rotateOrFlipTheRunSide.t5ior7" -msgstr "Pivoter ou inverser le côté de la rangée" +msgid "node.beam.panel.n1Ply" +msgstr "1 pli" -# Source-Hash: ad1dc0b5536cceef +# Source-Hash: b3be684ac62fbf53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate roof direction 90°" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.rotateRoofDirection90.tvbji2" -msgstr "Pivoter l’orientation du toit de 90°" +msgid "node.beam.panel.placement" +msgstr "Position" -# Source-Hash: fa24651e9e5f595a +# Source-Hash: 6ac7987d650b9742 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate spawn point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{plies} plies" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.rotateSpawnPoint.1opcuu7" -msgstr "Pivoter le point d’apparition" +msgid "node.beam.panel.pliesPlies" +msgstr "{plies} plis" -# Source-Hash: 2d693d87fe9b59e6 +# Source-Hash: 60bb3338e0ad558c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round / rectangular / oval" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Size" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.roundRectangularOval.e4nh6x" -msgstr "Rond / rectangulaire / oblong" +msgid "node.beam.panel.size" +msgstr "Taille" -# Source-Hash: f7d2c9cdcc637c97 +# Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set fence start / end" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.setFenceStartEnd.1phbwsq" -msgstr "Définir le début / la fin de la clôture" +msgid "node.beam.panel.top" +msgstr "Dessus" -# Source-Hash: c93ae898b4d59f6f +# Source-Hash: 5b4c960036b3d05b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set one corner, then the opposite" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top elevation" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.setOneCornerThenTheOpposite.8tsl49" -msgstr "Placez un angle, puis l’angle opposé" +msgid "node.beam.panel.topElevation" +msgstr "Cote du dessus" -# Source-Hash: 4f55171f10c6ceeb +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set roof footprint" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.setRoofFootprint.p50n0o" -msgstr "Définir l’emprise du toit" +msgid "node.beam.panel.width" +msgstr "Largeur" -# Source-Hash: 0243859b1d64c21e +# Source-Hash: a273dacdf51b26f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set wall start / end" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A topology-backed solid edited directly in the canvas." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.setWallStartEnd.1r8ubcx" -msgstr "Définir le début / la fin du mur" +msgid "node.block.description" +msgstr "Solide à topologie, modifiable directement dans le canevas." -# Source-Hash: c2806cce9612fa50 +# Source-Hash: 279f456ebb2f5da0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slope / level" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Block" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.slopeLevel.ftqp67" -msgstr "Pente / à plat" +msgid "node.block.label" +msgstr "Bloc" -# Source-Hash: 06c0ec40606db679 +# Source-Hash: b2a371b4041b5e38 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snap onto the run" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Small louvered exhaust vent that sits on a roof slope." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.snapOntoTheRun.86yhmp" -msgstr "Aimanter sur le tronçon" +msgid "node.boxVent.description" +msgstr "Petit aérateur d’extraction à persiennes posé sur un versant." -# Source-Hash: e214cccbac9c4fd2 +# Source-Hash: f736ca24e84825c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Split at the marks" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box Vent" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.splitAtTheMarks.x5tpdd" -msgstr "Diviser aux repères" +msgid "node.boxVent.label" +msgstr "Aérateur de toit" -# Source-Hash: 94455c35bfeac6b4 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start grid axis" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.startGridAxis.k92yza" -msgstr "Commencer l’axe de trame" +msgid "node.boxVent.panel.actions" +msgstr "Actions" -# Source-Hash: 2edb4c29bbe7c513 +# Source-Hash: c0e9837e67038e92 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start lineset" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base Flange" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.startLineset.23q8dh" -msgstr "Commencer la liaison frigorifique" +msgid "node.boxVent.panel.baseFlange" +msgstr "Bride de base" -# Source-Hash: 9e50f1b30e325208 +# Source-Hash: fa9118f6f4f020d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start liquid line" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base Height" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.startLiquidLine.1rlxsgd" -msgstr "Commencer la ligne liquide" +msgid "node.boxVent.panel.baseHeight" +msgstr "Hauteur de base" -# Source-Hash: 877ddcb778c211cc +# Source-Hash: 0869f5a92dabb4e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start run" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base Inset" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.startRun.r6fc5u" -msgstr "Commencer le tronçon" +msgid "node.boxVent.panel.baseInset" +msgstr "Retrait de base" -# Source-Hash: 8a62bee64174bbc0 +# Source-Hash: e9a89a5e4ac8cd61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start segment" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.startSegment.rolym6" -msgstr "Commencer le segment" +msgid "node.boxVent.panel.box" +msgstr "Boîte" -# Source-Hash: 6cc5dc51a8e66779 +# Source-Hash: f736ca24e84825c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Step back or cancel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box Vent" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.stepBackOrCancel.zbfdkn" -msgstr "Revenir en arrière ou annuler" +msgid "node.boxVent.panel.boxVent" +msgstr "Aérateur de toit" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: d52b53241789ee63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.style.nf3vcm" -msgstr "Style" +msgid "node.boxVent.panel.cap" +msgstr "Chapeau" -# Source-Hash: 81f595b1c47c0080 +# Source-Hash: 0ce3b53766b550e7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Barn" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap Height" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleBarn.k9n1x" -msgstr "Style : grange" +msgid "node.boxVent.panel.capHeight" +msgstr "Hauteur du chapeau" -# Source-Hash: 3a82c718fe215273 +# Source-Hash: 89eba9f077fba348 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Casement" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner Bevel" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleCasement.ziklec" -msgstr "Style : battant" +msgid "node.boxVent.panel.cornerBevel" +msgstr "Chanfrein d'angle" -# Source-Hash: 072e3331d1d105c0 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Craftsman" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleCraftsman.52e6a9" -msgstr "Style : artisan" +msgid "node.boxVent.panel.delete" +msgstr "Supprimer" -# Source-Hash: b64d07557dec1714 +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Double-hung" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleDoubleHung.1lg8pkg" -msgstr "Style : guillotine double" +msgid "node.boxVent.panel.depth" +msgstr "Profondeur" -# Source-Hash: 55ef8761a537637f +# Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: French" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleFrench.1ue3j64" -msgstr "Style : à la française" +msgid "node.boxVent.panel.dimensions" +msgstr "Dimensions" -# Source-Hash: bc8a751d87536dc3 +# Source-Hash: de47e23eb81efe02 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Glass" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dome" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleGlass.qudnb4" -msgstr "Style : vitré" +msgid "node.boxVent.panel.dome" +msgstr "Dôme" -# Source-Hash: 40c1eb0bc83e207d +# Source-Hash: 1c5c81aa21193d07 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Grid" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dome Curvature" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleGrid.1vuq4po" -msgstr "Style : petits bois" +msgid "node.boxVent.panel.domeCurvature" +msgstr "Courbure du dôme" -# Source-Hash: f516886bab2e7f10 +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Half-louvered" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleHalfLouvered.13b1few" -msgstr "Style : demi-persienne" +msgid "node.boxVent.panel.duplicate" +msgstr "Dupliquer" -# Source-Hash: 64e4389a695371a2 +# Source-Hash: 8cac057f7ae6804d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Horizontal bands" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap Height" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleHorizontalBands.12ethxk" -msgstr "Style : bandes horizontales" +msgid "node.boxVent.panel.gapHeight" +msgstr "Hauteur de l'interstice" -# Source-Hash: ff6d226a425b00c0 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Modern" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleModern.1fh8hhn" -msgstr "Style : moderne" +msgid "node.boxVent.panel.height" +msgstr "Hauteur" -# Source-Hash: c6d17ba078ff47e7 +# Source-Hash: 8a9c2ea0783a0e53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Panel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hood Overhang" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.stylePanel.922jze" -msgstr "Style : panneau" +msgid "node.boxVent.panel.hoodOverhang" +msgstr "Débord du capot" -# Source-Hash: 5e6baad0d2ce3a62 +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Paneled glass" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.stylePaneledGlass.17a17en" -msgstr "Style : vitré à panneaux" +msgid "node.boxVent.panel.move" +msgstr "Déplacer" -# Source-Hash: 6314388e6832c252 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Shaker" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleShaker.49z17k" -msgstr "Style : shaker" +msgid "node.boxVent.panel.position" +msgstr "Position" -# Source-Hash: a0f8e524f3ca121f +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Single" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleSingle.6f3cm0" -msgstr "Style : simple" +msgid "node.boxVent.panel.rotation" +msgstr "Rotation" -# Source-Hash: 368279df3a472c86 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Six-panel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleSixPanel.u49laj" -msgstr "Style : six panneaux" +msgid "node.boxVent.panel.style" +msgstr "Style" -# Source-Hash: 8f3c2571d8168fee +# Source-Hash: 71d82d47e11d2564 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Sliding" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Taper" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleSliding.q81s0i" -msgstr "Style : coulissant" +msgid "node.boxVent.panel.topTaper" +msgstr "Rétrécissement du haut" -# Source-Hash: aa9d9eb137ca38d4 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Tall grid" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleTallGrid.1eotg3x" -msgstr "Style : petits bois hauts" +msgid "node.boxVent.panel.width" +msgstr "Largeur" -# Source-Hash: bc164648722b63e5 +# Source-Hash: f49d8836ae037dde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Transom" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A building container holding one or more levels." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleTransom.kb9bh6" -msgstr "Style : imposte" +msgid "node.building.description" +msgstr "Conteneur de bâtiment contenant un ou plusieurs niveaux." -# Source-Hash: 9a218f0c9ceb4697 +# Source-Hash: d42f7d29e3fc4af7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Triple-hung" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Building" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleTripleHung.pxnqi3" -msgstr "Style : guillotine triple" +msgid "node.building.label" +msgstr "Bâtiment" + +# Source-Hash: 5a8274cbe3034558 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Baskets" +#: packages/nodes/src/cabinet/compartment-card.tsx +#, fuzzy +msgid "node.cabinet.compartmentCard.baskets" +msgstr "Paniers" -# Source-Hash: 9f6df1344bd3d694 +# Source-Hash: b3a163b453896bef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Wide grid" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.styleWideGrid.12n27et" -msgstr "Style : petits bois larges" +msgid "node.cabinet.compartmentCard.bottom" +msgstr "Bas" -# Source-Hash: 711d4050c0cb95d7 +# Source-Hash: 486501f027037732 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Switch rotation axis (Y → X → Z)" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Freezer" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.switchRotationAxisYXZ.15lohm6" -msgstr "Changer l’axe de rotation (Y → X → Z)" +msgid "node.cabinet.compartmentCard.bottomFreezer" +msgstr "Congélateur en bas" -# Source-Hash: d650c71e042c2598 +# Source-Hash: 375acc0016b3aa14 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The walls meet at too sharp or too flat an angle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bowls" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.theWallsMeetAtTooSharp.kh3wi3" -msgstr "Les murs se rejoignent selon un angle trop aigu ou trop plat" +msgid "node.cabinet.compartmentCard.bowls" +msgstr "Bacs" -# Source-Hash: ab206ac56e65f190 +# Source-Hash: 8449b59bf054c27d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The window waiting there is taller than this wall" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Burners on" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.theWindowWaitingThereIsTaller.1tqwez4" -msgstr "La fenêtre prévue à cet endroit est plus haute que ce mur" +msgid "node.cabinet.compartmentCard.burnersOn" +msgstr "Feux allumés" -# Source-Hash: 9c1f47138ed5c7ee +# Source-Hash: 95169058fec6db14 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Three or more walls meet here" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Chimney" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.threeOrMoreWallsMeetHere.rgifif" -msgstr "Trois murs ou plus se rejoignent ici" +msgid "node.cabinet.compartmentCard.chimney" +msgstr "Cheminée" -# Source-Hash: c3ca56fa28e15f07 +# Source-Hash: a6b76187db231ae7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trace ceiling outline" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Decrease {label}" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.traceCeilingOutline.1b639wv" -msgstr "Tracer le contour du plafond" +msgid "node.cabinet.compartmentCard.decrease" +msgstr "Diminuer {label}" -# Source-Hash: bdf71499d30a29de +# Source-Hash: 787e10f5db16904e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trace slab outline" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.traceSlabOutline.z0j2lc" -msgstr "Tracer le contour de la dalle" +msgid "node.cabinet.compartmentCard.door" +msgstr "Porte" -# Source-Hash: c44f7ab8bbd24858 +# Source-Hash: 3cd71355956a1821 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.type.1m2zofh" -msgstr "Type" +msgid "node.cabinet.compartmentCard.double" +msgstr "Double" -# Source-Hash: b54eaaff3349dcb1 +# Source-Hash: 63fe49d73892aac8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Awning" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawer" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeAwning.1cj59al" -msgstr "Type : à l’italienne" +msgid "node.cabinet.compartmentCard.drawer" +msgstr "Tiroir" -# Source-Hash: f399572a27417c66 +# Source-Hash: f98242a5dacd33f3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Barn" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawers" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeBarn.sbnygq" -msgstr "Type : grange" +msgid "node.cabinet.compartmentCard.drawers" +msgstr "Tiroirs" -# Source-Hash: a1df9782200b5f1e +# Source-Hash: 3af5347c94ae6443 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Bay" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip hinge" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeBay.1200hc1" -msgstr "Type : oriel" +msgid "node.cabinet.compartmentCard.flipHinge" +msgstr "Inverser la charnière" -# Source-Hash: ff069a390e8e3f66 +# Source-Hash: c930f681e61c029c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Bow" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip the door hinge to the opposite side" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeBow.14s2t9p" -msgstr "Type : bow-window" +msgid "node.cabinet.compartmentCard.flipTheDoorHingeToThe" +msgstr "Placer la charnière de la porte du côté opposé" -# Source-Hash: bdac5f3f2ea70fff +# Source-Hash: 85724031c91952a3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Cabinet" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fridge" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeCabinet.1r68je5" -msgstr "Type : placard" +msgid "node.cabinet.compartmentCard.fridge" +msgstr "Réfrigérateur" -# Source-Hash: e0754fc03997cbf9 +# Source-Hash: e67f11024d683ea9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Casement" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gas" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeCasement.176uo9j" -msgstr "Type : battant" +msgid "node.cabinet.compartmentCard.gas" +msgstr "Gaz" -# Source-Hash: 47d873446d6e173b +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Double" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeDouble.af7w4i" -msgstr "Type : double" +msgid "node.cabinet.compartmentCard.glass" +msgstr "Vitrage" -# Source-Hash: 5942e484513aaab5 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Double Hung" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeDoubleHung.t482fu" -msgstr "Type : guillotine double" +msgid "node.cabinet.compartmentCard.height" +msgstr "Hauteur" -# Source-Hash: f9497fbfceefda27 +# Source-Hash: 6f434b84c8b59b8c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Fixed" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hob" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeFixed.v1cjez" -msgstr "Type : fixe" +msgid "node.cabinet.compartmentCard.hob" +msgstr "Plaque" -# Source-Hash: 0dcf07acc9cbf000 +# Source-Hash: d52570d41b4df776 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Folding" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Increase {label}" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeFolding.sxxyng" -msgstr "Type : pliante" +msgid "node.cabinet.compartmentCard.increase" +msgstr "Augmenter {label}" -# Source-Hash: bff7331f87f279aa +# Source-Hash: d298f259163e868e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: French" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Induction" +#: packages/nodes/src/cabinet/compartment-card.tsx +#, fuzzy +msgid "node.cabinet.compartmentCard.induction" +msgstr "Induction" + +# Source-Hash: 54800340a0eeab23 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layout" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeFrench.1y57z1b" -msgstr "Type : à la française" +msgid "node.cabinet.compartmentCard.layout" +msgstr "Disposition" -# Source-Hash: 9d2c3b82079eb769 +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Hinged" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeHinged.1xrcfju" -msgstr "Type : battante" +msgid "node.cabinet.compartmentCard.left" +msgstr "Gauche" -# Source-Hash: b8001b90ff522838 +# Source-Hash: 12ade82be3830a0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Island" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Micro" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeIsland.ufr3ce" -msgstr "Type : îlot" +msgid "node.cabinet.compartmentCard.micro" +msgstr "Micro-ondes" -# Source-Hash: 516833c5160d412e +# Source-Hash: a06a50e63f0c240e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Louvered" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move down" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeLouvered.oxl1cz" -msgstr "Type : à persiennes" +msgid "node.cabinet.compartmentCard.moveDown" +msgstr "Descendre" -# Source-Hash: 291272bf848ad6ab +# Source-Hash: d49ea60a2312df2f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Pocket" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move up" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typePocket.hc65x9" -msgstr "Type : galandage" +msgid "node.cabinet.compartmentCard.moveUp" +msgstr "Monter" -# Source-Hash: 46d0e53d6ae07c72 +# Source-Hash: 596023c8b9a8f2e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Single Hung" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Oven" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeSingleHung.p53pyl" -msgstr "Type : guillotine simple" +msgid "node.cabinet.compartmentCard.oven" +msgstr "Four" -# Source-Hash: b11115b50df8faac +# Source-Hash: 83b20797fb0a01a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Sliding" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pullout" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeSliding.nwmr3f" -msgstr "Type : coulissante" +msgid "node.cabinet.compartmentCard.pullout" +msgstr "Coulissant" -# Source-Hash: bff0c1694ee0a37e +# Source-Hash: 43c251f465b647ce # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical stack ↕, click to place" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rack" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.verticalStackClickToPlace.ijcn4q" -msgstr "Colonne verticale ↕, cliquez pour placer" +msgid "node.cabinet.compartmentCard.rack" +msgstr "Rangement" -# Source-Hash: bac471ee67af6412 +# Source-Hash: 3c2b3026d37cbcc2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waste / vent" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove compartment" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.wasteVent.1hvi3vj" -msgstr "Évacuation / ventilation" +msgid "node.cabinet.compartmentCard.removeCompartment" +msgstr "Supprimer le compartiment" -# Source-Hash: 1c744b7e24fc786e +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Window style — click or press L to cycle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.windowStyleClickOrPressL.ah7qm9" -msgstr "Style de fenêtre — cliquez ou appuyez sur L pour changer" +msgid "node.cabinet.compartmentCard.right" +msgstr "Droite" -# Source-Hash: dd6f0ab314fea26c +# Source-Hash: d7145f84f8e0e3fe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Window type — click or press O to cycle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shelf" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.windowTypeClickOrPressO.wv4x35" -msgstr "Type de fenêtre — cliquez ou appuyez sur O pour changer" +msgid "node.cabinet.compartmentCard.shelf" +msgstr "Étagère" +# Source-Hash: 5fbb88f1f079b6db # Review: required -# Source-Hash: a48c4b2e4d71b08d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length: {field} m" -#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shelves" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.tools.distribution.distributionRunTool.lengthField" -msgstr "Longueur : {field} m" +msgid "node.cabinet.compartmentCard.shelves" +msgstr "Étagères" +# Source-Hash: 47173085127029f0 # Review: required -# Source-Hash: e53695d6669245c7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tab: direction" -#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shelves inside" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.tools.distribution.distributionRunTool.tabDirection" -msgstr "Tab : direction" +msgid "node.cabinet.compartmentCard.shelvesInside" +msgstr "Étagères intérieures" +# Source-Hash: 62ab2eb3c775da95 # Review: required -# Source-Hash: abb1d8c8bfb41acf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "type a length" -#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.tools.distribution.distributionRunTool.typeALength" -msgstr "saisir une longueur" +msgid "node.cabinet.compartmentCard.single" +msgstr "Simple" -# Source-Hash: 9fc7a39bc32f287a +# Source-Hash: 522a7535fc93fb4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Plugins" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sink" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.plugins" -msgstr "Plugins" +msgid "node.cabinet.compartmentCard.sink" +msgstr "Évier" -# Source-Hash: c54f9bac358893d8 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "2D" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.view2d" -msgstr "2D" +msgid "node.cabinet.compartmentCard.style" +msgstr "Style" -# Source-Hash: f78f2fa035f25f85 +# Source-Hash: 78a454b7ac7a3cd9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "3D" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.view3d" -msgstr "3D" +msgid "node.cabinet.compartmentCard.surface" +msgstr "Surface" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.viewBar.auto" -msgstr "Auto" +msgid "node.cabinet.compartmentCard.top" +msgstr "Haut" -# Source-Hash: 7890c110650ad1e5 +# Source-Hash: eaadfd2d19b27d87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Browse plugins" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Freezer" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.viewBar.browsePlugins" -msgstr "Parcourir les plugins" +msgid "node.cabinet.compartmentCard.topFreezer" +msgstr "Congélateur en haut" -# Source-Hash: 3b11e7af681a9dcd +# Source-Hash: 04f3a3462ef5d247 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close {label}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top grate" +#: packages/nodes/src/cabinet/compartment-card.tsx +#, fuzzy +msgid "node.cabinet.compartmentCard.topGrate" +msgstr "Grille supérieure" + +# Source-Hash: 4a616e1d2ca55bd5 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tray" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.viewBar.closeLabel" -msgstr "Fermer {label}" +msgid "node.cabinet.compartmentCard.tray" +msgstr "Plateau" -# Source-Hash: 3f00e92517e3f4a5 +# Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close split (\\)" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.viewBar.closeSplit" -msgstr "Fermer la vue partagée (\\)" +msgid "node.cabinet.compartmentCard.type" +msgstr "Type" -# Source-Hash: 94cc8e9f1ee16edb +# Source-Hash: 6c4de540d19316ab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Washer" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.viewBar.ground" -msgstr "Sol" +msgid "node.cabinet.compartmentCard.washer" +msgstr "Lave-vaisselle" -# Source-Hash: 0d472502a4d36e86 +# Source-Hash: 5211a0caf3518125 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{standing, select, partly {Partly below grade · ground solid} below {Below grade · ground solid} other {Ground solid}}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wire" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.viewBar.groundSolid" -msgstr "{standing, select, partly {Partiellement sous le terrain · sol plein} below {Sous le terrain · sol plein} other {Sol plein}}" +msgid "node.cabinet.compartmentCard.wire" +msgstr "Fil" -# Source-Hash: 1b6798c307ac1b96 +# Source-Hash: 693a0d8896f5cc43 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{standing, select, partly {Partly below grade · ground veiled} below {Below grade · ground veiled} other {Ground veiled}}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A configurable parametric base cabinet." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.groundVeiled" -msgstr "{standing, select, partly {Partiellement sous le terrain · sol voilé} below {Sous le terrain · sol voilé} other {Sol voilé}}" +msgid "node.cabinet.description" +msgstr "Meuble bas paramétrique configurable." -# Source-Hash: ebdc976a98e82626 +# Source-Hash: b0568ea943addd5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Keep the ground solid" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom freezer" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.keepTheGroundSolid" -msgstr "Garder le sol plein" +msgid "node.cabinet.essentialControls.bottomFreezer" +msgstr "Congélateur en bas" -# Source-Hash: 5f827686a006d88c +# Source-Hash: da78819903ae0863 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "More views" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cooktop type" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.moreViews" -msgstr "Plus de vues" +msgid "node.cabinet.essentialControls.cooktopType" +msgstr "Type de plaque" -# Source-Hash: f175bbcf457ab73c +# Source-Hash: c608188f58ed1cfc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pane {pane} views" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door direction" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.paneViews" -msgstr "Vues du volet {pane}" +msgid "node.cabinet.essentialControls.doorDirection" +msgstr "Sens d'ouverture" -# Source-Hash: 33c20cc33dce9a9b +# Source-Hash: 3cd71355956a1821 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pin {label}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.pinLabel" -msgstr "Épingler {label}" +msgid "node.cabinet.essentialControls.double" +msgstr "Double" -# Source-Hash: 3f7231b1eb2f93f3 +# Source-Hash: f7fb8f6393cc4cfc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pin to the view bar" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fridge type" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.pinToTheViewBar" -msgstr "Épingler à la barre de vues" +msgid "node.cabinet.essentialControls.fridgeType" +msgstr "Type de réfrigérateur" -# Source-Hash: ef3e765e692faf4c +# Source-Hash: e67f11024d683ea9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gas" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.solid" -msgstr "Plein" +msgid "node.cabinet.essentialControls.gas" +msgstr "Gaz" -# Source-Hash: 98f22f3f89f17686 +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Split (\\)" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.split" -msgstr "Vue partagée (\\)" +msgid "node.cabinet.essentialControls.glass" +msgstr "Vitrage" -# Source-Hash: e4cd64b1680ac0d2 +# Source-Hash: d298f259163e868e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Split" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Induction" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.split2" -msgstr "Partager" +msgid "node.cabinet.essentialControls.induction" +msgstr "Induction" -# Source-Hash: 15b0adc705923a27 +# Source-Hash: 76df477d42cec629 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swap panes" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Item options" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.swapPanes" -msgstr "Inverser les volets" +msgid "node.cabinet.essentialControls.itemOptions" +msgstr "Options de l'élément" -# Source-Hash: 9781bcdb7a8549e2 +# Source-Hash: bca1b184af1c0c4b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unpin from the view bar" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left hinge" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.unpinFromTheViewBar" -msgstr "Désépingler de la barre de vues" +msgid "node.cabinet.essentialControls.leftHinge" +msgstr "Charnière à gauche" -# Source-Hash: f667358dec4abdea +# Source-Hash: e32da7429c85f1a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unpin {label}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right hinge" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.unpinLabel" -msgstr "Désépingler {label}" +msgid "node.cabinet.essentialControls.rightHinge" +msgstr "Charnière à droite" -# Source-Hash: e96581f0bbf9fa91 +# Source-Hash: 62ab2eb3c775da95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Veil the ground over a level below grade" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.veilTheGroundOverALevel" -msgstr "Voiler le sol au-dessus d’un niveau sous le terrain" +msgid "node.cabinet.essentialControls.single" +msgstr "Simple" -# Source-Hash: fb82f09f8ed3059e +# Source-Hash: 4bc3042055df1e85 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Views" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sink layout" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.views" -msgstr "Vues" +msgid "node.cabinet.essentialControls.sinkLayout" +msgstr "Configuration de l'évier" -# Source-Hash: fdece5c2158dfe88 +# Source-Hash: 29cffe75281dbea6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "You can retry the scene or return home without reloading the whole app shell." -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top freezer" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.youCanRetryTheSceneOr" -msgstr "Vous pouvez relancer la scène ou revenir à l’accueil sans recharger toute l’application." +msgid "node.cabinet.essentialControls.topFreezer" +msgstr "Congélateur en haut" -# Source-Hash: a273dacdf51b26f2 +# Source-Hash: 09c2cb2ea7b1be3c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A topology-backed solid edited directly in the canvas." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose {label}" +#: packages/nodes/src/cabinet/kitchen-collection.tsx +#, fuzzy +msgid "node.cabinet.kitchenCollection.chooseLabel" +msgstr "Choisir {label}" + +# Source-Hash: 1dd2cac6488ddc30 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No kitchen items match. Try “fridge”, “sink”, or “cabinet”." +#: packages/nodes/src/cabinet/kitchen-collection.tsx #, fuzzy -msgid "node.block.description" -msgstr "Solide à topologie, modifiable directement dans le canevas." +msgid "node.cabinet.kitchenCollection.noKitchenItemsMatchTryFridge" +msgstr "Aucun élément de cuisine ne correspond. Essayez « réfrigérateur », « évier » ou « meuble »." -# Source-Hash: 279f456ebb2f5da0 +# Source-Hash: 6752675ca6280ddd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Block" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Search fridge, sink, cabinets…" +#: packages/nodes/src/cabinet/kitchen-collection.tsx #, fuzzy -msgid "node.block.label" -msgstr "Bloc" +msgid "node.cabinet.kitchenCollection.searchFridgeSinkCabinets" +msgstr "Rechercher réfrigérateur, évier, meubles…" -# Source-Hash: b2a371b4041b5e38 +# Source-Hash: fe3c6d57a07c323d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Small louvered exhaust vent that sits on a roof slope." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Search kitchen items" +#: packages/nodes/src/cabinet/kitchen-collection.tsx #, fuzzy -msgid "node.boxVent.description" -msgstr "Petit aérateur d’extraction à persiennes posé sur un versant." +msgid "node.cabinet.kitchenCollection.searchKitchenItems" +msgstr "Rechercher des éléments de cuisine" -# Source-Hash: f736ca24e84825c3 +# Source-Hash: d44a46146db2e44c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box Vent" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Appliances & fixtures" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.boxVent.label" -msgstr "Aérateur de toit" +msgid "node.cabinet.kitchenGroup.appliances" +msgstr "Électroménager et équipements" +# Source-Hash: d4d3ad7c099b6513 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinets" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.boxVent.panel.actions" -msgstr "Actions" +msgid "node.cabinet.kitchenGroup.cabinets" +msgstr "Meubles" +# Source-Hash: 465db52f98c2d94f # Review: required -# Source-Hash: c0e9837e67038e92 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base Flange" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add beside" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.baseFlange" -msgstr "Bride de base" +msgid "node.cabinet.kitchenModuleActions.addBeside" +msgstr "Ajouter à côté" +# Source-Hash: 9733e2ad85deb6d5 # Review: required -# Source-Hash: fa9118f6f4f020d7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base Height" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add beside selected item" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.baseHeight" -msgstr "Hauteur de base" +msgid "node.cabinet.kitchenModuleActions.addBesideSelectedItem" +msgstr "Ajouter à côté de l'élément sélectionné" +# Source-Hash: 4b2f676fb4c9ec63 # Review: required -# Source-Hash: 0869f5a92dabb4e1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base Inset" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add {label}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.baseInset" -msgstr "Retrait de base" +msgid "node.cabinet.kitchenModuleActions.addLabel" +msgstr "Ajouter {label}" +# Source-Hash: 5122b8e9b4ec6a00 # Review: required -# Source-Hash: e9a89a5e4ac8cd61 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An upper cabinet attached to this item will be removed to make room." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.box" -msgstr "Boîte" +msgid "node.cabinet.kitchenModuleActions.anUpperCabinetAttachedToThis" +msgstr "Un meuble haut fixé à cet élément sera supprimé pour faire de la place." +# Source-Hash: 5737c4567e0f6863 # Review: required -# Source-Hash: f736ca24e84825c3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box Vent" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.boxVent" -msgstr "Aérateur de toit" +msgid "node.cabinet.kitchenModuleActions.cabinet" +msgstr "Meuble" +# Source-Hash: c0774c185060fc13 # Review: required -# Source-Hash: d52b53241789ee63 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.cap" -msgstr "Chapeau" +msgid "node.cabinet.kitchenModuleActions.cancel" +msgstr "Annuler" +# Source-Hash: f42912b116015f58 # Review: required -# Source-Hash: 0ce3b53766b550e7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap Height" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This {width} item cannot fit within the current run and its wall or corner limits. Move an end cabinet or free space, then try again." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.capHeight" -msgstr "Hauteur du chapeau" +msgid "node.cabinet.kitchenModuleActions.cannotFit" +msgstr "Cet élément de {width} ne tient pas dans le linéaire actuel et ses limites de mur ou d'angle. Déplacez un meuble d'extrémité ou libérez de l'espace, puis réessayez." +# Source-Hash: b7eeb26a356d03c3 # Review: required -# Source-Hash: 89eba9f077fba348 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner Bevel" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{side, select, left {Inserts on the left of the selected item.} other {Inserts on the right of the selected item.}}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.cornerBevel" -msgstr "Chanfrein d'angle" +msgid "node.cabinet.kitchenModuleActions.insertsBeside" +msgstr "{side, select, left {Insère à gauche de l'élément sélectionné.} other {Insère à droite de l'élément sélectionné.}}" +# Source-Hash: f65332177316d11d # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The kitchen changed. Select an item again to refresh the preview." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.delete" -msgstr "Supprimer" +msgid "node.cabinet.kitchenModuleActions.kitchenChanged" +msgstr "La cuisine a changé. Sélectionnez de nouveau un élément pour actualiser l'aperçu." +# Source-Hash: 5b6990b17111fd6b # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchen run preview, highlighted item is the proposed change" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.depth" -msgstr "Profondeur" +msgid "node.cabinet.kitchenModuleActions.kitchenRunPreviewHighlightedItemIs" +msgstr "Aperçu du linéaire de cuisine ; l’élément en surbrillance est la modification proposée" +# Source-Hash: cb59562ba7eb1d25 # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left side" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.dimensions" -msgstr "Dimensions" +msgid "node.cabinet.kitchenModuleActions.leftSide" +msgstr "Côté gauche" +# Source-Hash: 766354d53f17d78c # Review: required -# Source-Hash: de47e23eb81efe02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dome" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{name}: moves {distance}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.dome" -msgstr "Dôme" +msgid "node.cabinet.kitchenModuleActions.moved" +msgstr "{name} : se déplace de {distance}" +# Source-Hash: df1083d9ffc2c59d # Review: required -# Source-Hash: 1c5c81aa21193d07 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dome Curvature" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{name}: {width}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.domeCurvature" -msgstr "Courbure du dôme" +msgid "node.cabinet.kitchenModuleActions.previewItem" +msgstr "{name} : {width}" +# Source-Hash: ada7fbece9ca9e3c # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace selected item" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.duplicate" -msgstr "Dupliquer" +msgid "node.cabinet.kitchenModuleActions.replaceSelectedItem" +msgstr "Remplacer l'élément sélectionné" +# Source-Hash: ab8b52d2704537d2 # Review: required -# Source-Hash: 8cac057f7ae6804d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap Height" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replaces only the selected item." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +#, fuzzy +msgid "node.cabinet.kitchenModuleActions.replacesOnlyTheSelectedItem" +msgstr "Remplace uniquement l'élément sélectionné." + +# Source-Hash: 03cb6dea6e4a4c5e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace with…" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.gapHeight" -msgstr "Hauteur de l'interstice" +msgid "node.cabinet.kitchenModuleActions.replaceWith" +msgstr "Remplacer par…" +# Source-Hash: 948fe657641f298c # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace with {label}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.height" -msgstr "Hauteur" +msgid "node.cabinet.kitchenModuleActions.replaceWithLabel" +msgstr "Remplacer par {label}" +# Source-Hash: 154f9fa86b7670ba # Review: required -# Source-Hash: 8a9c2ea0783a0e53 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hood Overhang" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{name}: {before} → {after}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.hoodOverhang" -msgstr "Débord du capot" +msgid "node.cabinet.kitchenModuleActions.resized" +msgstr "{name} : {before} → {after}" +# Source-Hash: 4ecc493400fb6aa2 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right side" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.move" -msgstr "Déplacer" +msgid "node.cabinet.kitchenModuleActions.rightSide" +msgstr "Côté droit" +# Source-Hash: f2c30e7e21cf27e6 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unable to update this kitchen." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.position" -msgstr "Position" +msgid "node.cabinet.kitchenModuleActions.unableToUpdateThisKitchen" +msgstr "Impossible de mettre à jour cette cuisine." +# Source-Hash: 2e6d8cda361c648d # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modular Cabinet" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.rotation" -msgstr "Rotation" +msgid "node.cabinet.label" +msgstr "Meuble modulaire" +# Source-Hash: 740e0a4e4afa78ea # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finished height extends {overflow} mm above the ceiling." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.boxVent.panel.style" -msgstr "Style" +msgid "node.cabinet.panel.aboveCeiling" +msgstr "La hauteur finie dépasse le plafond de {overflow} mm." +# Source-Hash: e3b4d2ed4f6f5efb # Review: required -# Source-Hash: 71d82d47e11d2564 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Taper" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add chimney" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.boxVent.panel.topTaper" -msgstr "Rétrécissement du haut" +msgid "node.cabinet.panel.addChimney" +msgstr "Ajouter une hotte" +# Source-Hash: 90bdc92c0a91d060 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add compartment" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.boxVent.panel.width" -msgstr "Largeur" +msgid "node.cabinet.panel.addCompartment" +msgstr "Ajouter un compartiment" -# Source-Hash: f49d8836ae037dde +# Source-Hash: ece05d9b6f4b616d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A building container holding one or more levels." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add wall cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.building.description" -msgstr "Conteneur de bâtiment contenant un ou plusieurs niveaux." +msgid "node.cabinet.panel.addWallCabinet" +msgstr "Ajouter un meuble haut" -# Source-Hash: d42f7d29e3fc4af7 +# Source-Hash: f571cb2d06ae01ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Building" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Advanced" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.building.label" -msgstr "Bâtiment" +msgid "node.cabinet.panel.advanced" +msgstr "Avancé" +# Source-Hash: 7f4dcb90defe1ac2 # Review: required -# Source-Hash: 5a8274cbe3034558 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Baskets" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Appliance" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.baskets" -msgstr "Paniers" +msgid "node.cabinet.panel.appliance" +msgstr "Électroménager" +# Source-Hash: bd5e3f533412ff6a # Review: required -# Source-Hash: b3a163b453896bef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Appliance front" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.bottom" -msgstr "Bas" +msgid "node.cabinet.panel.applianceFront" +msgstr "Façade d'appareil" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: 486501f027037732 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Freezer" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.bottomFreezer" -msgstr "Congélateur en bas" +msgid "node.cabinet.panel.auto" +msgstr "Auto" +# Source-Hash: 9cf3754f15467c50 # Review: required -# Source-Hash: 375acc0016b3aa14 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bowls" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.bowls" -msgstr "Bacs" +msgid "node.cabinet.panel.bar" +msgstr "Barre" +# Source-Hash: 133893b177bd05d6 # Review: required -# Source-Hash: 8449b59bf054c27d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Burners on" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base Cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.burnersOn" -msgstr "Feux allumés" +msgid "node.cabinet.panel.baseCabinet" +msgstr "Meuble bas" +# Source-Hash: d63f16df2c754126 # Review: required -# Source-Hash: 95169058fec6db14 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Chimney" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet construction, compartments, and opening preview." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.chimney" -msgstr "Cheminée" +msgid "node.cabinet.panel.cabinetConstructionCompartmentsAndOpeningPreview" +msgstr "Construction du meuble, compartiments et aperçu d'ouverture." +# Source-Hash: d62dc35dac835228 # Review: required -# Source-Hash: a6b76187db231ae7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Decrease {label}" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet panel" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.decrease" -msgstr "Diminuer {label}" +msgid "node.cabinet.panel.cabinetPanel" +msgstr "Panneau du meuble" +# Source-Hash: 81caf4809d58b5f5 # Review: required -# Source-Hash: 787e10f5db16904e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet Type" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.door" -msgstr "Porte" +msgid "node.cabinet.panel.cabinetType" +msgstr "Type de meuble" +# Source-Hash: 5211341ed18f33f6 # Review: required -# Source-Hash: 3cd71355956a1821 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" +#: packages/nodes/src/cabinet/panel.tsx +#, fuzzy +msgid "node.cabinet.panel.center" +msgstr "Centre" + +# Source-Hash: d7cf5045c01b2eb9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.double" -msgstr "Double" +msgid "node.cabinet.panel.close" +msgstr "Fermer" +# Source-Hash: cf29134333e47184 # Review: required -# Source-Hash: 63fe49d73892aac8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawer" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.drawer" -msgstr "Tiroir" +msgid "node.cabinet.panel.closeCabinet" +msgstr "Fermer le meuble" +# Source-Hash: b1ab1ba948bb77b0 # Review: required -# Source-Hash: f98242a5dacd33f3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawers" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Common wall-cabinet heights. Use the slider below for a custom height." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.drawers" -msgstr "Tiroirs" +msgid "node.cabinet.panel.commonWallCabinetHeightsUseThe" +msgstr "Hauteurs courantes de meubles hauts. Utilisez le curseur ci-dessous pour une hauteur personnalisée." +# Source-Hash: fe9e63d5c5087386 # Review: required -# Source-Hash: 3af5347c94ae6443 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip hinge" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Compartments" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.flipHinge" -msgstr "Inverser la charnière" +msgid "node.cabinet.panel.compartments" +msgstr "Compartiments" +# Source-Hash: 7984b1c42abd9c02 # Review: required -# Source-Hash: c930f681e61c029c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip the door hinge to the opposite side" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cutout" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.flipTheDoorHingeToThe" -msgstr "Placer la charnière de la porte du côté opposé" +msgid "node.cabinet.panel.cutout" +msgstr "Découpe" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: 85724031c91952a3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fridge" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.fridge" -msgstr "Réfrigérateur" +msgid "node.cabinet.panel.depth" +msgstr "Profondeur" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: e67f11024d683ea9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gas" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.gas" -msgstr "Gaz" +msgid "node.cabinet.panel.dimensions" +msgstr "Dimensions" +# Source-Hash: 82c9ea6f403fc934 # Review: required -# Source-Hash: 8ab91094cf650204 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit kitchen run" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.glass" -msgstr "Vitrage" +msgid "node.cabinet.panel.editKitchenRun" +msgstr "Modifier le linéaire de cuisine" +# Source-Hash: 7e9bbeb035fc73e2 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fill to ceiling" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.height" -msgstr "Hauteur" +msgid "node.cabinet.panel.fillToCeiling" +msgstr "Jusqu'au plafond" +# Source-Hash: b3907da0ad234f10 # Review: required -# Source-Hash: 6f434b84c8b59b8c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hob" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.hob" -msgstr "Plaque" +msgid "node.cabinet.panel.finish" +msgstr "Terminer" +# Source-Hash: c1796152935221ef # Review: required -# Source-Hash: d52570d41b4df776 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Increase {label}" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front construction" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.increase" -msgstr "Augmenter {label}" +msgid "node.cabinet.panel.frontConstruction" +msgstr "Construction de la façade" +# Source-Hash: 58884f99d64e6d00 # Review: required -# Source-Hash: d298f259163e868e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Induction" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handles" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.induction" -msgstr "Induction" +msgid "node.cabinet.panel.handles" +msgstr "Poignées" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 54800340a0eeab23 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Layout" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.layout" -msgstr "Disposition" +msgid "node.cabinet.panel.height" +msgstr "Hauteur" +# Source-Hash: d73589d7c04b1121 # Review: required -# Source-Hash: f365c6b6dd9ebab9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height preset" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.left" -msgstr "Gauche" +msgid "node.cabinet.panel.heightPreset" +msgstr "Hauteur prédéfinie" +# Source-Hash: 590bfdd02dcdb857 # Review: required -# Source-Hash: 12ade82be3830a0b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Micro" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hole" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.micro" -msgstr "Micro-ondes" +msgid "node.cabinet.panel.hole" +msgstr "Trou" +# Source-Hash: 3db1dea825785a30 # Review: required -# Source-Hash: a06a50e63f0c240e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move down" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inset" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.moveDown" -msgstr "Descendre" +msgid "node.cabinet.panel.inset" +msgstr "Encastré" +# Source-Hash: 1176d2568d093bf1 # Review: required -# Source-Hash: d49ea60a2312df2f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move up" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchen" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.moveUp" -msgstr "Monter" +msgid "node.cabinet.panel.kitchen" +msgstr "Cuisine" +# Source-Hash: a74f10dadc92c8bb # Review: required -# Source-Hash: 596023c8b9a8f2e4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Oven" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchen run" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.oven" -msgstr "Four" +msgid "node.cabinet.panel.kitchenRun" +msgstr "Linéaire de cuisine" +# Source-Hash: 103e15b39c909210 # Review: required -# Source-Hash: 83b20797fb0a01a0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pullout" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Knob" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.pullout" -msgstr "Coulissant" +msgid "node.cabinet.panel.knob" +msgstr "Bouton" +# Source-Hash: 81d365ccef73068c # Review: required -# Source-Hash: 43c251f465b647ce -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rack" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting" +#: packages/nodes/src/cabinet/panel.tsx +#, fuzzy +msgid "node.cabinet.panel.mounting" +msgstr "Montage" + +# Source-Hash: f2953d2931e36d0c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.rack" -msgstr "Rangement" +msgid "node.cabinet.panel.none" +msgstr "Aucun" +# Source-Hash: 3e52f04f92e08070 # Review: required -# Source-Hash: 3c2b3026d37cbcc2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove compartment" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.removeCompartment" -msgstr "Supprimer le compartiment" +msgid "node.cabinet.panel.open" +msgstr "Ouvrir" +# Source-Hash: b8ecc16c07d66f42 # Review: required -# Source-Hash: b34d5ee0f218221d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open Animation" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.right" -msgstr "Droite" +msgid "node.cabinet.panel.openAnimation" +msgstr "Animation d'ouverture" +# Source-Hash: 2d4adbbd70c3ae6a # Review: required -# Source-Hash: d7145f84f8e0e3fe -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shelf" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.shelf" -msgstr "Étagère" +msgid "node.cabinet.panel.openCabinet" +msgstr "Ouvrir le meuble" +# Source-Hash: 9c215dc512e57fa4 # Review: required -# Source-Hash: 5fbb88f1f079b6db -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shelves" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overlay" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.shelves" -msgstr "Étagères" +msgid "node.cabinet.panel.overlay" +msgstr "Recouvrement" +# Source-Hash: a35b7357943a5cae # Review: required -# Source-Hash: 47173085127029f0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shelves inside" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel-ready" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.shelvesInside" -msgstr "Étagères intérieures" +msgid "node.cabinet.panel.panelReady" +msgstr "Prêt à habiller" +# Source-Hash: 3d0d4eee59177824 # Review: required -# Source-Hash: 62ab2eb3c775da95 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Planning checks" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.single" -msgstr "Simple" +msgid "node.cabinet.panel.planningChecks" +msgstr "Vérifications de conception" +# Source-Hash: c7b10382e01914ad # Review: required -# Source-Hash: 522a7535fc93fb4f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sink" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Play" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.sink" -msgstr "Évier" +msgid "node.cabinet.panel.play" +msgstr "Lancer" +# Source-Hash: c530f8af9dfd846f # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Play animation" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.style" -msgstr "Style" +msgid "node.cabinet.panel.playAnimation" +msgstr "Lancer l'animation" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: 78a454b7ac7a3cd9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.surface" -msgstr "Surface" +msgid "node.cabinet.panel.position" +msgstr "Position" +# Source-Hash: efca749fc4463623 # Review: required -# Source-Hash: 27644f0497fd9849 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised Arch" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.top" -msgstr "Haut" +msgid "node.cabinet.panel.raisedArch" +msgstr "Arche en relief" +# Source-Hash: a8639a97ab07cd59 # Review: required -# Source-Hash: eaadfd2d19b27d87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Freezer" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove wall cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.topFreezer" -msgstr "Congélateur en haut" +msgid "node.cabinet.panel.removeWallCabinet" +msgstr "Supprimer le meuble haut" +# Source-Hash: 03cb6dea6e4a4c5e # Review: required -# Source-Hash: 04f3a3462ef5d247 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top grate" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace with…" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.topGrate" -msgstr "Grille supérieure" +msgid "node.cabinet.panel.replaceWith" +msgstr "Remplacer par…" +# Source-Hash: 5d6956c21fde6418 # Review: required -# Source-Hash: 4a616e1d2ca55bd5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tray" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reveal gap" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.tray" -msgstr "Plateau" +msgid "node.cabinet.panel.revealGap" +msgstr "Jeu entre façades" +# Source-Hash: 5b68e435b7210876 # Review: required -# Source-Hash: c44f7ab8bbd24858 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaker" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.type" -msgstr "Type" +msgid "node.cabinet.panel.shaker" +msgstr "Shaker" +# Source-Hash: c378ed346bf83375 # Review: required -# Source-Hash: 6c4de540d19316ab -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Washer" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shared countertop, plinth, and finishes" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.washer" -msgstr "Lave-vaisselle" +msgid "node.cabinet.panel.sharedCountertopPlinthAndFinishes" +msgstr "Plan de travail, socle et finitions communs" +# Source-Hash: 8775bc8dc9593964 # Review: required -# Source-Hash: 5211a0caf3518125 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wire" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.wire" -msgstr "Fil" +msgid "node.cabinet.panel.slab" +msgstr "Dalle" -# Source-Hash: 693a0d8896f5cc43 +# Source-Hash: 8606fe2c60764a95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A configurable parametric base cabinet." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid matching front between the cabinet and wall. Countertop and toe-kick continue across this filler." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.description" -msgstr "Meuble bas paramétrique configurable." +msgid "node.cabinet.panel.solidMatchingFrontBetweenTheCabinet" +msgstr "Façade pleine assortie entre le meuble et le mur. Le plan de travail et la plinthe continuent sur cette fileuse." +# Source-Hash: 5a4d5353cc496a63 # Review: required -# Source-Hash: b0568ea943addd5b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom freezer" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard width" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.bottomFreezer" -msgstr "Congélateur en bas" +msgid "node.cabinet.panel.standardWidth" +msgstr "Largeur standard" +# Source-Hash: 4a784e3e95a08715 # Review: required -# Source-Hash: da78819903ae0863 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cooktop type" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stop" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.cooktopType" -msgstr "Type de plaque" +msgid "node.cabinet.panel.stop" +msgstr "Arrêter" +# Source-Hash: 72c9fcd7a0eb5380 # Review: required -# Source-Hash: c608188f58ed1cfc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door direction" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stop animation" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.doorDirection" -msgstr "Sens d'ouverture" +msgid "node.cabinet.panel.stopAnimation" +msgstr "Arrêter l'animation" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: 3cd71355956a1821 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.double" -msgstr "Double" +msgid "node.cabinet.panel.style" +msgstr "Style" +# Source-Hash: bfd618690e0c2f24 # Review: required -# Source-Hash: f7fb8f6393cc4cfc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fridge type" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tall Cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.fridgeType" -msgstr "Type de réfrigérateur" +msgid "node.cabinet.panel.tallCabinet" +msgstr "Colonne" +# Source-Hash: 27644f0497fd9849 # Review: required -# Source-Hash: e67f11024d683ea9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gas" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.gas" -msgstr "Gaz" +msgid "node.cabinet.panel.top" +msgstr "Haut" +# Source-Hash: d09654ebd12a538a # Review: required -# Source-Hash: 8ab91094cf650204 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.glass" -msgstr "Vitrage" +msgid "node.cabinet.panel.topCabinet" +msgstr "Meuble haut" +# Source-Hash: bc19e7805b3e3703 # Review: required -# Source-Hash: d298f259163e868e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Induction" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top / Ceiling" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.induction" -msgstr "Induction" +msgid "node.cabinet.panel.topCeiling" +msgstr "Haut / Plafond" +# Source-Hash: 29ea8a68eed99925 # Review: required -# Source-Hash: 76df477d42cec629 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Item options" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top depth" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.itemOptions" -msgstr "Options de l'élément" +msgid "node.cabinet.panel.topDepth" +msgstr "Profondeur du haut" +# Source-Hash: 2d40f591e7dcbf5a # Review: required -# Source-Hash: bca1b184af1c0c4b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left hinge" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top height" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.leftHinge" -msgstr "Charnière à gauche" +msgid "node.cabinet.panel.topHeight" +msgstr "Hauteur du haut" +# Source-Hash: 3b878d6015c03945 # Review: required -# Source-Hash: e32da7429c85f1a5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right hinge" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trim / Soffit" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.rightHinge" -msgstr "Charnière à droite" +msgid "node.cabinet.panel.trimSoffit" +msgstr "Bandeau / Soffite" +# Source-Hash: a6e5be20001e8d26 # Review: required -# Source-Hash: 62ab2eb3c775da95 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Uses the cabinet front style, reveal, handle, and front material settings below." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.single" -msgstr "Simple" +msgid "node.cabinet.panel.usesTheCabinetFrontStyleReveal" +msgstr "Utilise le style de façade, le jeu, la poignée et le matériau de façade définis ci-dessous." +# Source-Hash: cd55643590c64a42 # Review: required -# Source-Hash: 4bc3042055df1e85 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sink layout" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall filler" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.sinkLayout" -msgstr "Configuration de l'évier" +msgid "node.cabinet.panel.wallFiller" +msgstr "Fileuse murale" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: 29cffe75281dbea6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top freezer" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.topFreezer" -msgstr "Congélateur en haut" +msgid "node.cabinet.panel.width" +msgstr "Largeur" +# Source-Hash: 4ef03cfd6782316b # Review: required -# Source-Hash: 09c2cb2ea7b1be3c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose {label}" -#: packages/nodes/src/cabinet/kitchen-collection.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base cabinet" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.kitchenCollection.chooseLabel" -msgstr "Choisir {label}" +msgid "node.cabinet.preset.baseCabinet" +msgstr "Meuble bas" +# Source-Hash: d353fff221a78228 # Review: required -# Source-Hash: 1dd2cac6488ddc30 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No kitchen items match. Try “fridge”, “sink”, or “cabinet”." -#: packages/nodes/src/cabinet/kitchen-collection.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dishwasher" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.kitchenCollection.noKitchenItemsMatchTryFridge" -msgstr "Aucun élément de cuisine ne correspond. Essayez « réfrigérateur », « évier » ou « meuble »." +msgid "node.cabinet.preset.dishwasher" +msgstr "Lave-vaisselle" +# Source-Hash: ecb596567b8b7179 # Review: required -# Source-Hash: 6752675ca6280ddd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Search fridge, sink, cabinets…" -#: packages/nodes/src/cabinet/kitchen-collection.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawer cabinet" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.kitchenCollection.searchFridgeSinkCabinets" -msgstr "Rechercher réfrigérateur, évier, meubles…" +msgid "node.cabinet.preset.drawerCabinet" +msgstr "Meuble à tiroirs" +# Source-Hash: 85724031c91952a3 # Review: required -# Source-Hash: fe3c6d57a07c323d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Search kitchen items" -#: packages/nodes/src/cabinet/kitchen-collection.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fridge" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.kitchenCollection.searchKitchenItems" -msgstr "Rechercher des éléments de cuisine" +msgid "node.cabinet.preset.fridge" +msgstr "Réfrigérateur" +# Source-Hash: 72d587d58b645a81 # Review: required -# Source-Hash: d44a46146db2e44c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Appliances & fixtures" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gas cooktop" #: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.kitchenGroup.appliances" -msgstr "Électroménager et équipements" +msgid "node.cabinet.preset.gasCooktop" +msgstr "Plaque gaz" +# Source-Hash: 6b02c36e6aac2cd6 # Review: required -# Source-Hash: d4d3ad7c099b6513 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinets" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Induction cooktop" #: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.kitchenGroup.cabinets" -msgstr "Meubles" +msgid "node.cabinet.preset.inductionCooktop" +msgstr "Plaque à induction" +# Source-Hash: d5fcb790aef707bf # Review: required -# Source-Hash: 465db52f98c2d94f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add beside" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Oven Tower" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.kitchenModuleActions.addBeside" -msgstr "Ajouter à côté" +msgid "node.cabinet.preset.ovenTower" +msgstr "Colonne four" +# Source-Hash: edd4d1ab7525dcaa # Review: required -# Source-Hash: 9733e2ad85deb6d5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add beside selected item" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx -#, fuzzy -msgid "node.cabinet.kitchenModuleActions.addBesideSelectedItem" -msgstr "Ajouter à côté de l'élément sélectionné" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sink cabinet" +#: packages/nodes/src/cabinet/kitchen-catalog.ts +#, fuzzy +msgid "node.cabinet.preset.sinkCabinet" +msgstr "Meuble sous-évier" +# Source-Hash: 9b7427a8954f618b # Review: required -# Source-Hash: 4b2f676fb4c9ec63 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add {label}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tall Pantry" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.kitchenModuleActions.addLabel" -msgstr "Ajouter {label}" +msgid "node.cabinet.preset.tallPantry" +msgstr "Colonne garde-manger" +# Source-Hash: 3bd9629eb17cc572 # Review: required -# Source-Hash: 5122b8e9b4ec6a00 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "An upper cabinet attached to this item will be removed to make room." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall cabinet" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.kitchenModuleActions.anUpperCabinetAttachedToThis" -msgstr "Un meuble haut fixé à cet élément sera supprimé pour faire de la place." +msgid "node.cabinet.preset.wallCabinet" +msgstr "Meuble haut" +# Source-Hash: 7c40d26770eede82 # Review: required -# Source-Hash: 5737c4567e0f6863 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add left" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.cabinet" -msgstr "Meuble" +msgid "node.cabinet.runPanel.addLeft" +msgstr "Ajouter à gauche" +# Source-Hash: 25082cdf77e219c3 # Review: required -# Source-Hash: c0774c185060fc13 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add right" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.cancel" -msgstr "Annuler" +msgid "node.cabinet.runPanel.addRight" +msgstr "Ajouter à droite" +# Source-Hash: 4b1204c1b706f618 # Review: required -# Source-Hash: f42912b116015f58 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "This {width} item cannot fit within the current run and its wall or corner limits. Move an end cabinet or free space, then try again." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Align cabinets & handles" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.cannotFit" -msgstr "Cet élément de {width} ne tient pas dans le linéaire actuel et ses limites de mur ou d'angle. Déplacez un meuble d'extrémité ou libérez de l'espace, puis réessayez." +msgid "node.cabinet.runPanel.alignCabinetsHandles" +msgstr "Aligner meubles et poignées" +# Source-Hash: 8c73c7a9406db5ad # Review: required -# Source-Hash: b7eeb26a356d03c3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{side, select, left {Inserts on the left of the selected item.} other {Inserts on the right of the selected item.}}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Applies depth, carcass, plinth, and countertop thickness to this run." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.insertsBeside" -msgstr "{side, select, left {Insère à gauche de l'élément sélectionné.} other {Insère à droite de l'élément sélectionné.}}" +msgid "node.cabinet.runPanel.appliesDepthCarcassPlinthAndCountertop" +msgstr "Applique à ce linéaire la profondeur, le caisson, le socle et l'épaisseur du plan de travail." +# Source-Hash: ef576e6c8f9ebe5f # Review: required -# Source-Hash: f65332177316d11d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The kitchen changed. Select an item again to refresh the preview." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {Create {number} module copy} other {Create {number} module copies}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.kitchenChanged" -msgstr "La cuisine a changé. Sélectionnez de nouveau un élément pour actualiser l'aperçu." +msgid "node.cabinet.runPanel.arrayCreate" +msgstr "{count, plural, one {Créer {number} copie de module} many {Créer {number} copies de module} other {Créer {number} copies de module}}" +# Source-Hash: 0eec3888096306a1 # Review: required -# Source-Hash: 5b6990b17111fd6b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchen run preview, highlighted item is the proposed change" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {Create {number} {name} copy} other {Create {number} {name} copies}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.kitchenRunPreviewHighlightedItemIs" -msgstr "Aperçu du linéaire de cuisine ; l’élément en surbrillance est la modification proposée" +msgid "node.cabinet.runPanel.arrayCreateNamed" +msgstr "{count, plural, one {Créer {number} copie de {name}} many {Créer {number} copies de {name}} other {Créer {number} copies de {name}}}" +# Source-Hash: 8cdc0b808b551d3a # Review: required -# Source-Hash: cb59562ba7eb1d25 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left side" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a copy count from 1 to 20 and spacing from 0 to 2 m" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.leftSide" -msgstr "Côté gauche" +msgid "node.cabinet.runPanel.arrayInvalidOptions" +msgstr "Choisissez un nombre de copies de 1 à 20 et un espacement de 0 à 2 m" +# Source-Hash: cb89fe4161e87d68 # Review: required -# Source-Hash: 766354d53f17d78c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{name}: moves {distance}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "There is not enough room in this run for the requested array" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.moved" -msgstr "{name} : se déplace de {distance}" +msgid "node.cabinet.runPanel.arrayNoRoom" +msgstr "Ce linéaire n'a pas assez de place pour la série demandée" +# Source-Hash: 075d027345689724 # Review: required -# Source-Hash: df1083d9ffc2c59d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{name}: {width}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a standard or appliance module as the source" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.previewItem" -msgstr "{name} : {width}" +msgid "node.cabinet.runPanel.arrayNoSource" +msgstr "Choisissez un module standard ou un appareil comme source" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: ada7fbece9ca9e3c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace selected item" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.replaceSelectedItem" -msgstr "Remplacer l'élément sélectionné" +msgid "node.cabinet.runPanel.auto" +msgstr "Auto" +# Source-Hash: 7ceade8f25b58fe9 # Review: required -# Source-Hash: ab8b52d2704537d2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replaces only the selected item." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.replacesOnlyTheSelectedItem" -msgstr "Remplace uniquement l'élément sélectionné." +msgid "node.cabinet.runPanel.back" +msgstr "Retour" +# Source-Hash: b2c3a03bf67a97a7 # Review: required -# Source-Hash: 03cb6dea6e4a4c5e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace with…" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Balances standard base cabinets while keeping appliance and corner-filler widths fixed." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.replaceWith" -msgstr "Remplacer par…" +msgid "node.cabinet.runPanel.balancesStandardBaseCabinetsWhileKeeping" +msgstr "Équilibre les meubles bas standard en gardant fixes les largeurs des appareils et des fileuses d'angle." +# Source-Hash: 9cf3754f15467c50 # Review: required -# Source-Hash: 948fe657641f298c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace with {label}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.replaceWithLabel" -msgstr "Remplacer par {label}" +msgid "node.cabinet.runPanel.bar" +msgstr "Barre" +# Source-Hash: ccec5da17ca39eee # Review: required -# Source-Hash: 154f9fa86b7670ba -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{name}: {before} → {after}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar counter" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.resized" -msgstr "{name} : {before} → {after}" +msgid "node.cabinet.runPanel.barCounter" +msgstr "Comptoir de bar" +# Source-Hash: 97c1605fff221752 # Review: required -# Source-Hash: 4ecc493400fb6aa2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right side" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar depth" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.rightSide" -msgstr "Côté droit" +msgid "node.cabinet.runPanel.barDepth" +msgstr "Profondeur du bar" +# Source-Hash: 9514a6ddebdca34e # Review: required -# Source-Hash: f2c30e7e21cf27e6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unable to update this kitchen." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar height" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.unableToUpdateThisKitchen" -msgstr "Impossible de mettre à jour cette cuisine." +msgid "node.cabinet.runPanel.barHeight" +msgstr "Hauteur du bar" -# Source-Hash: 2e6d8cda361c648d +# Source-Hash: 7af3b69b4b5aeb19 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Modular Cabinet" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Carcass height" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.label" -msgstr "Meuble modulaire" +msgid "node.cabinet.runPanel.carcassHeight" +msgstr "Hauteur du caisson" -# Review: required -# Source-Hash: 740e0a4e4afa78ea -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finished height extends {overflow} mm above the ceiling." -#: packages/nodes/src/cabinet/panel.tsx +# Source-Hash: 5211341ed18f33f6 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.aboveCeiling" -msgstr "La hauteur finie dépasse le plafond de {overflow} mm." +msgid "node.cabinet.runPanel.center" +msgstr "Centre" +# Source-Hash: b1ab1ba948bb77b0 # Review: required -# Source-Hash: e3b4d2ed4f6f5efb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add chimney" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Common wall-cabinet heights. Use the slider below for a custom height." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.addChimney" -msgstr "Ajouter une hotte" +msgid "node.cabinet.runPanel.commonWallCabinetHeightsUseThe" +msgstr "Hauteurs courantes de meubles hauts. Utilisez le curseur ci-dessous pour une hauteur personnalisée." +# Source-Hash: 88ccc87b9b45a464 # Review: required -# Source-Hash: 90bdc92c0a91d060 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add compartment" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Copies" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.addCompartment" -msgstr "Ajouter un compartiment" +msgid "node.cabinet.runPanel.copies" +msgstr "Copies" +# Source-Hash: d215c489b8385d9f # Review: required -# Source-Hash: ece05d9b6f4b616d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add wall cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Copies include the source cabinet structure and any attached wall cabinet. Existing modules stay fixed; the requested array must fit in the available run space." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.addWallCabinet" -msgstr "Ajouter un meuble haut" +msgid "node.cabinet.runPanel.copiesIncludeTheSourceCabinetStructure" +msgstr "Les copies reprennent la structure du meuble source et tout meuble haut fixé. Les modules existants restent en place ; la série demandée doit tenir dans la place disponible." +# Source-Hash: 221d1b64649b08f8 # Review: required -# Source-Hash: f571cb2d06ae01ae -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Advanced" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner fillers cannot be used as array sources" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.advanced" -msgstr "Avancé" +msgid "node.cabinet.runPanel.cornerFillersCannotBeUsedAs" +msgstr "Les fileuses d'angle ne peuvent pas servir de source" +# Source-Hash: d8d1bc5a0f9fa0cd # Review: required -# Source-Hash: 7f4dcb90defe1ac2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Appliance" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Countertop depth" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.appliance" -msgstr "Électroménager" +msgid "node.cabinet.runPanel.countertopDepth" +msgstr "Profondeur du plan de travail" +# Source-Hash: 10bba4a11996c84b # Review: required -# Source-Hash: bd5e3f533412ff6a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Appliance front" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Countertop height" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.applianceFront" -msgstr "Façade d'appareil" +msgid "node.cabinet.runPanel.countertopHeight" +msgstr "Hauteur du plan de travail" +# Source-Hash: 8abdfbc1798d9eaa # Review: required -# Source-Hash: 05b65242d8c48791 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Create array" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.auto" -msgstr "Auto" +msgid "node.cabinet.runPanel.createArray" +msgstr "Créer la série" +# Source-Hash: 7984b1c42abd9c02 # Review: required -# Source-Hash: 9cf3754f15467c50 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cutout" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.bar" -msgstr "Barre" +msgid "node.cabinet.runPanel.cutout" +msgstr "Découpe" +# Source-Hash: 555240ffcca44233 # Review: required -# Source-Hash: 133893b177bd05d6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base Cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete {name}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.baseCabinet" -msgstr "Meuble bas" +msgid "node.cabinet.runPanel.deleteModule" +msgstr "Supprimer {name}" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: d63f16df2c754126 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet construction, compartments, and opening preview." -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.cabinetConstructionCompartmentsAndOpeningPreview" -msgstr "Construction du meuble, compartiments et aperçu d'ouverture." +msgid "node.cabinet.runPanel.depth" +msgstr "Profondeur" +# Source-Hash: 76cd03300faa9b2b # Review: required -# Source-Hash: d62dc35dac835228 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet panel" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Direction" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.cabinetPanel" -msgstr "Panneau du meuble" +msgid "node.cabinet.runPanel.direction" +msgstr "Direction" +# Source-Hash: 5ca5884d3ff7edf4 # Review: required -# Source-Hash: 81caf4809d58b5f5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet Type" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate along run" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.cabinetType" -msgstr "Type de meuble" +msgid "node.cabinet.runPanel.duplicateAlongRun" +msgstr "Dupliquer le long du linéaire" +# Source-Hash: a834f687290afc10 # Review: required -# Source-Hash: 5211341ed18f33f6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equalize all resizeable standard base cabinets in this run" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.center" -msgstr "Centre" +msgid "node.cabinet.runPanel.equalizeAll" +msgstr "Égaliser tous les meubles bas standard redimensionnables de ce linéaire" +# Source-Hash: 24da8a2de2c6e345 # Review: required -# Source-Hash: d7cf5045c01b2eb9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The resizeable cabinet widths are already equal" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.close" -msgstr "Fermer" +msgid "node.cabinet.runPanel.equalizeAlreadyEqual" +msgstr "Les largeurs des meubles redimensionnables sont déjà égales" +# Source-Hash: c38a4faef2097b73 # Review: required -# Source-Hash: cf29134333e47184 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "At least two standard base cabinets are required" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.closeCabinet" -msgstr "Fermer le meuble" +msgid "node.cabinet.runPanel.equalizeNeedsTwo" +msgstr "Il faut au moins deux meubles bas standard" +# Source-Hash: 61f15ae24419430c # Review: required -# Source-Hash: b1ab1ba948bb77b0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Common wall-cabinet heights. Use the slider below for a custom height." -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The available run width cannot satisfy the cabinet width limits" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.commonWallCabinetHeightsUseThe" -msgstr "Hauteurs courantes de meubles hauts. Utilisez le curseur ci-dessous pour une hauteur personnalisée." +msgid "node.cabinet.runPanel.equalizeNoFit" +msgstr "La largeur disponible du linéaire ne respecte pas les limites de largeur des meubles" +# Source-Hash: 7617bb3b455dcdda # Review: required -# Source-Hash: fe9e63d5c5087386 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Compartments" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equalize widths" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.compartments" -msgstr "Compartiments" +msgid "node.cabinet.runPanel.equalizeWidths" +msgstr "Égaliser les largeurs" +# Source-Hash: ad8c948d883a0c9d # Review: required -# Source-Hash: 7984b1c42abd9c02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cutout" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{side, select, left {Left: {width} mm} other {Right: {width} mm}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.cutout" -msgstr "Découpe" +msgid "node.cabinet.runPanel.fillerPlanSide" +msgstr "{side, select, left {Gauche : {width} mm} other {Droite : {width} mm}}" +# Source-Hash: 47ccd8c8b04475cd # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish & align" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.depth" -msgstr "Profondeur" +msgid "node.cabinet.runPanel.finishAlign" +msgstr "Finitions et alignement" +# Source-Hash: 855892e18c74153a # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finished back" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.dimensions" -msgstr "Dimensions" +msgid "node.cabinet.runPanel.finishedBack" +msgstr "Dos fini" +# Source-Hash: 7ab47aea30c73663 # Review: required -# Source-Hash: 82c9ea6f403fc934 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit kitchen run" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finished exposed ends" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.editKitchenRun" -msgstr "Modifier le linéaire de cuisine" +msgid "node.cabinet.runPanel.finishedExposedEnds" +msgstr "Côtés apparents finis" +# Source-Hash: c9356f25caf33eec # Review: required -# Source-Hash: 7e9bbeb035fc73e2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fill to ceiling" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fits 50–150 mm gaps at run ends beside perpendicular walls." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.fillToCeiling" -msgstr "Jusqu'au plafond" +msgid "node.cabinet.runPanel.fits50150MmGapsAt" +msgstr "Comble les écarts de 50 à 150 mm en bout de linéaire contre les murs perpendiculaires." +# Source-Hash: b6f541bc28e38d2f # Review: required -# Source-Hash: b3907da0ad234f10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit wall fillers" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.finish" -msgstr "Terminer" +msgid "node.cabinet.runPanel.fitWallFillers" +msgstr "Ajuster les fileuses murales" +# Source-Hash: 2af738f010ce28f0 # Review: required -# Source-Hash: c1796152935221ef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front construction" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fronts" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.frontConstruction" -msgstr "Construction de la façade" +msgid "node.cabinet.runPanel.fronts" +msgstr "Façades" -# Review: required # Source-Hash: 58884f99d64e6d00 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Handles" -#: packages/nodes/src/cabinet/panel.tsx +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.handles" +msgid "node.cabinet.runPanel.handles" msgstr "Poignées" -# Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/cabinet/panel.tsx -#, fuzzy -msgid "node.cabinet.panel.height" -msgstr "Hauteur" - -# Review: required # Source-Hash: d73589d7c04b1121 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Height preset" -#: packages/nodes/src/cabinet/panel.tsx +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.heightPreset" +msgid "node.cabinet.runPanel.heightPreset" msgstr "Hauteur prédéfinie" -# Review: required # Source-Hash: 590bfdd02dcdb857 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hole" -#: packages/nodes/src/cabinet/panel.tsx +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.hole" +msgid "node.cabinet.runPanel.hole" msgstr "Trou" -# Review: required # Source-Hash: 3db1dea825785a30 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Inset" -#: packages/nodes/src/cabinet/panel.tsx +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.inset" +msgid "node.cabinet.runPanel.inset" msgstr "Encastré" +# Source-Hash: 2997c230c529590d # Review: required -# Source-Hash: 1176d2568d093bf1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchen" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Island & Bar" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.kitchen" -msgstr "Cuisine" +msgid "node.cabinet.runPanel.islandBar" +msgstr "Îlot et bar" -# Review: required # Source-Hash: a74f10dadc92c8bb -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen run" -#: packages/nodes/src/cabinet/panel.tsx +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.kitchenRun" +msgid "node.cabinet.runPanel.kitchenRun" msgstr "Linéaire de cuisine" -# Review: required # Source-Hash: 103e15b39c909210 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Knob" -#: packages/nodes/src/cabinet/panel.tsx +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.knob" +msgid "node.cabinet.runPanel.knob" msgstr "Bouton" +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# Source-Hash: 81d365ccef73068c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting" -#: packages/nodes/src/cabinet/panel.tsx -#, fuzzy -msgid "node.cabinet.panel.mounting" -msgstr "Montage" - -# Review: required -# Source-Hash: f2953d2931e36d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/nodes/src/cabinet/panel.tsx -#, fuzzy -msgid "node.cabinet.panel.none" -msgstr "Aucun" - -# Review: required -# Source-Hash: 3e52f04f92e08070 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/cabinet/panel.tsx -#, fuzzy -msgid "node.cabinet.panel.open" -msgstr "Ouvrir" - -# Review: required -# Source-Hash: b8ecc16c07d66f42 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open Animation" -#: packages/nodes/src/cabinet/panel.tsx -#, fuzzy -msgid "node.cabinet.panel.openAnimation" -msgstr "Animation d'ouverture" - -# Review: required -# Source-Hash: 2d4adbbd70c3ae6a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open cabinet" -#: packages/nodes/src/cabinet/panel.tsx -#, fuzzy -msgid "node.cabinet.panel.openCabinet" -msgstr "Ouvrir le meuble" - -# Review: required -# Source-Hash: 9c215dc512e57fa4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overlay" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.overlay" -msgstr "Recouvrement" +msgid "node.cabinet.runPanel.left" +msgstr "Gauche" +# Source-Hash: 3c88a1840043e15a # Review: required -# Source-Hash: a35b7357943a5cae -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel-ready" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match base heights, backs, reveals and handles. Align upper cabinets; preserve tall appliances and custom compartments." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.panelReady" -msgstr "Prêt à habiller" +msgid "node.cabinet.runPanel.matchBaseHeightsBacksRevealsAnd" +msgstr "Harmonise les hauteurs des meubles bas, les dos, les jeux et les poignées. Aligne les meubles hauts ; conserve les grands appareils et les compartiments personnalisés." +# Source-Hash: b112e31fe44cc94b # Review: required -# Source-Hash: 3d0d4eee59177824 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Planning checks" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Metric · 600 mm" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.planningChecks" -msgstr "Vérifications de conception" +msgid "node.cabinet.runPanel.metricProfile" +msgstr "Métrique · 600 mm" +# Source-Hash: 4739f6315c5e8680 # Review: required -# Source-Hash: c7b10382e01914ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Play" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Module {number}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.play" -msgstr "Lancer" +msgid "node.cabinet.runPanel.moduleNumber" +msgstr "Module {number}" +# Source-Hash: b8801184e07e4815 # Review: required -# Source-Hash: c530f8af9dfd846f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Play animation" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modules" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.playAnimation" -msgstr "Lancer l'animation" +msgid "node.cabinet.runPanel.modules" +msgstr "Modules" +# Source-Hash: 81d365ccef73068c # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.position" -msgstr "Position" +msgid "node.cabinet.runPanel.mounting" +msgstr "Montage" +# Source-Hash: a3914bd96488175c # Review: required -# Source-Hash: efca749fc4463623 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised Arch" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No eligible module" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.raisedArch" -msgstr "Arche en relief" +msgid "node.cabinet.runPanel.noEligibleModule" +msgstr "Aucun module admissible" +# Source-Hash: f2953d2931e36d0c # Review: required -# Source-Hash: a8639a97ab07cd59 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove wall cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.removeWallCabinet" -msgstr "Supprimer le meuble haut" +msgid "node.cabinet.runPanel.none" +msgstr "Aucun" +# Source-Hash: 9c215dc512e57fa4 # Review: required -# Source-Hash: 03cb6dea6e4a4c5e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace with…" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overlay" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.replaceWith" -msgstr "Remplacer par…" +msgid "node.cabinet.runPanel.overlay" +msgstr "Recouvrement" +# Source-Hash: 49fb05dfafd6001d # Review: required -# Source-Hash: 5d6956c21fde6418 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reveal gap" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plinth height" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.revealGap" -msgstr "Jeu entre façades" +msgid "node.cabinet.runPanel.plinthHeight" +msgstr "Hauteur du socle" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: 5b68e435b7210876 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaker" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.shaker" -msgstr "Shaker" +msgid "node.cabinet.runPanel.position" +msgstr "Position" +# Source-Hash: efca749fc4463623 # Review: required -# Source-Hash: c378ed346bf83375 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shared countertop, plinth, and finishes" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised Arch" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.sharedCountertopPlinthAndFinishes" -msgstr "Plan de travail, socle et finitions communs" +msgid "node.cabinet.runPanel.raisedArch" +msgstr "Arche en relief" +# Source-Hash: 5d6956c21fde6418 # Review: required -# Source-Hash: 8775bc8dc9593964 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reveal gap" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.slab" -msgstr "Dalle" +msgid "node.cabinet.runPanel.revealGap" +msgstr "Jeu entre façades" +# Source-Hash: b34d5ee0f218221d # Review: required -# Source-Hash: 8606fe2c60764a95 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid matching front between the cabinet and wall. Countertop and toe-kick continue across this filler." -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.solidMatchingFrontBetweenTheCabinet" -msgstr "Façade pleine assortie entre le meuble et le mur. Le plan de travail et la plinthe continuent sur cette fileuse." +msgid "node.cabinet.runPanel.right" +msgstr "Droite" +# Source-Hash: e022da49ae8b4aef # Review: required -# Source-Hash: 5a4d5353cc496a63 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard width" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Seating overhang" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.standardWidth" -msgstr "Largeur standard" +msgid "node.cabinet.runPanel.seatingOverhang" +msgstr "Débord pour assise" +# Source-Hash: 5b68e435b7210876 # Review: required -# Source-Hash: 4a784e3e95a08715 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stop" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaker" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.stop" -msgstr "Arrêter" +msgid "node.cabinet.runPanel.shaker" +msgstr "Shaker" +# Source-Hash: cba29b18ce666b0a # Review: required -# Source-Hash: 72c9fcd7a0eb5380 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stop animation" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shared Plinth & Countertop" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.stopAnimation" -msgstr "Arrêter l'animation" +msgid "node.cabinet.runPanel.sharedPlinthCountertop" +msgstr "Socle et plan de travail communs" +# Source-Hash: f7d577c4064c16ff # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show countertop" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.style" -msgstr "Style" +msgid "node.cabinet.runPanel.showCountertop" +msgstr "Afficher le plan de travail" +# Source-Hash: 5d98e04dfd2e0a83 # Review: required -# Source-Hash: bfd618690e0c2f24 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tall Cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show plinth" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.tallCabinet" -msgstr "Colonne" +msgid "node.cabinet.runPanel.showPlinth" +msgstr "Afficher le socle" +# Source-Hash: 8775bc8dc9593964 # Review: required -# Source-Hash: 27644f0497fd9849 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.top" -msgstr "Haut" +msgid "node.cabinet.runPanel.slab" +msgstr "Dalle" +# Source-Hash: 5bdc0a959203c52e # Review: required -# Source-Hash: d09654ebd12a538a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Source module" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.topCabinet" -msgstr "Meuble haut" +msgid "node.cabinet.runPanel.sourceModule" +msgstr "Module source" +# Source-Hash: e4698e83d02beb6c # Review: required -# Source-Hash: bc19e7805b3e3703 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top / Ceiling" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spacing" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.topCeiling" -msgstr "Haut / Plafond" +msgid "node.cabinet.runPanel.spacing" +msgstr "Espacement" +# Source-Hash: 40e3105cbe68d163 # Review: required -# Source-Hash: 29ea8a68eed99925 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top depth" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard dimensions" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.topDepth" -msgstr "Profondeur du haut" +msgid "node.cabinet.runPanel.standardDimensions" +msgstr "Dimensions standard" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: 2d40f591e7dcbf5a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top height" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.topHeight" -msgstr "Hauteur du haut" +msgid "node.cabinet.runPanel.style" +msgstr "Style" +# Source-Hash: e9d7ad9851d476d9 # Review: required -# Source-Hash: 3b878d6015c03945 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trim / Soffit" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{type, select, shelf {Shelf} drawer {Drawer} door {Door} oven {Oven} microwave {Microwave} dishwasher {Dishwasher} sink {Sink} cooktop_gas {Gas cooktop} cooktop_induction {Induction cooktop} pull_out_pantry {Pull-out pantry} fridge_single {Fridge} fridge_double {Double fridge} fridge_top_freezer {Top-freezer fridge} fridge_bottom_freezer {Bottom-freezer fridge} hood_pyramid {Pyramid hood} hood_curved_glass {Curved glass hood} other {{raw}}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.trimSoffit" -msgstr "Bandeau / Soffite" +msgid "node.cabinet.runPanel.summaryCompartment" +msgstr "{type, select, shelf {Étagère} drawer {Tiroir} door {Porte} oven {Four} microwave {Micro-ondes} dishwasher {Lave-vaisselle} sink {Évier} cooktop_gas {Plaque gaz} cooktop_induction {Plaque à induction} pull_out_pantry {Coulissant garde-manger} fridge_single {Réfrigérateur} fridge_double {Réfrigérateur double} fridge_top_freezer {Réfrigérateur congélateur en haut} fridge_bottom_freezer {Réfrigérateur congélateur en bas} hood_pyramid {Hotte pyramide} hood_curved_glass {Hotte verre incurvé} other {{raw}}}" +# Source-Hash: 98582c257f149d44 # Review: required -# Source-Hash: a6e5be20001e8d26 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Uses the cabinet front style, reveal, handle, and front material settings below." -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {{number} compartment} other {{number} compartments}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.usesTheCabinetFrontStyleReveal" -msgstr "Utilise le style de façade, le jeu, la poignée et le matériau de façade définis ci-dessous." +msgid "node.cabinet.runPanel.summaryCompartments" +msgstr "{count, plural, one {{number} compartiment} many {{number} compartiments} other {{number} compartiments}}" +# Source-Hash: 65b1cbba3b92c5b2 # Review: required -# Source-Hash: cd55643590c64a42 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall filler" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Empty" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.wallFiller" -msgstr "Fileuse murale" +msgid "node.cabinet.runPanel.summaryEmpty" +msgstr "Vide" +# Source-Hash: 5db8b868684cf9f3 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tall cabinet" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.width" -msgstr "Largeur" +msgid "node.cabinet.runPanel.summaryTall" +msgstr "Colonne" +# Source-Hash: 27644f0497fd9849 # Review: required -# Source-Hash: 4ef03cfd6782316b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base cabinet" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.preset.baseCabinet" -msgstr "Meuble bas" +msgid "node.cabinet.runPanel.top" +msgstr "Haut" +# Source-Hash: 88c85283afe0c0bc # Review: required -# Source-Hash: d353fff221a78228 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dishwasher" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unable to finish this kitchen run." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.preset.dishwasher" -msgstr "Lave-vaisselle" +msgid "node.cabinet.runPanel.unableToFinish" +msgstr "Impossible de terminer ce linéaire de cuisine." +# Source-Hash: 8f668fb3e1a1696a # Review: required -# Source-Hash: ecb596567b8b7179 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawer cabinet" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use {name} as array source" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.preset.drawerCabinet" -msgstr "Meuble à tiroirs" +msgid "node.cabinet.runPanel.useAsArraySource" +msgstr "Utiliser {name} comme source de la série" +# Source-Hash: 9308a109d017dcd6 # Review: required -# Source-Hash: 85724031c91952a3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fridge" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use this module as the array source" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.preset.fridge" -msgstr "Réfrigérateur" +msgid "node.cabinet.runPanel.useThisModuleAsTheArray" +msgstr "Utiliser ce module comme source de la série" +# Source-Hash: 1ce253a4d11bfa68 # Review: required -# Source-Hash: 72d587d58b645a81 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gas cooktop" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "US · 24 in" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.preset.gasCooktop" -msgstr "Plaque gaz" +msgid "node.cabinet.runPanel.usProfile" +msgstr "US · 24 po" +# Source-Hash: a2d852b2c5629796 # Review: required -# Source-Hash: 6b02c36e6aac2cd6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Induction cooktop" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waterfall ends" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.preset.inductionCooktop" -msgstr "Plaque à induction" +msgid "node.cabinet.runPanel.waterfallEnds" +msgstr "Retombées en cascade" +# Source-Hash: ffc8d80e438f40b7 # Review: required -# Source-Hash: d5fcb790aef707bf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Oven Tower" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An editable module inside a modular cabinet run." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.preset.ovenTower" -msgstr "Colonne four" +msgid "node.cabinetModule.description" +msgstr "Module modifiable dans une rangée de meubles modulaires." +# Source-Hash: d5c19ec529e26a98 # Review: required -# Source-Hash: edd4d1ab7525dcaa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sink cabinet" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet Module" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.preset.sinkCabinet" -msgstr "Meuble sous-évier" +msgid "node.cabinetModule.label" +msgstr "Module de meuble" +# Source-Hash: 25be6d614ec09df9 # Review: required -# Source-Hash: 9b7427a8954f618b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tall Pantry" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom chord" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.preset.tallPantry" -msgstr "Colonne garde-manger" +msgid "node.ceiling.buildUpSection.bottomChord" +msgstr "Entrait" +# Source-Hash: a0c71abc0f146a2b # Review: required -# Source-Hash: 3bd9629eb17cc572 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall cabinet" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling joists" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.preset.wallCabinet" -msgstr "Meuble haut" +msgid "node.ceiling.buildUpSection.ceilingJoists" +msgstr "Solives de plafond" +# Source-Hash: 7d286c87375d417e # Review: required -# Source-Hash: 7c40d26770eede82 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add left" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Decking" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.runPanel.addLeft" -msgstr "Ajouter à gauche" +msgid "node.ceiling.buildUpSection.decking" +msgstr "Platelage" +# Source-Hash: b3907da0ad234f10 # Review: required -# Source-Hash: 25082cdf77e219c3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add right" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.runPanel.addRight" -msgstr "Ajouter à droite" +msgid "node.ceiling.buildUpSection.finish" +msgstr "Finition" +# Source-Hash: c7e72beff9fe4b37 # Review: required -# Source-Hash: 4b1204c1b706f618 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Align cabinets & handles" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framing" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.runPanel.alignCabinetsHandles" -msgstr "Aligner meubles et poignées" +msgid "node.ceiling.buildUpSection.framing" +msgstr "Ossature" +# Source-Hash: c7aa596536ceeecb # Review: required -# Source-Hash: 8c73c7a9406db5ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Applies depth, carcass, plinth, and countertop thickness to this run." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Joists" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.runPanel.appliesDepthCarcassPlinthAndCountertop" -msgstr "Applique à ce linéaire la profondeur, le caisson, le socle et l'épaisseur du plan de travail." +msgid "node.ceiling.buildUpSection.joists" +msgstr "Solives" +# Source-Hash: 4ccd2fc1a471fca5 # Review: required -# Source-Hash: ef576e6c8f9ebe5f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {Create {number} module copy} other {Create {number} module copies}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layers" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.runPanel.arrayCreate" -msgstr "{count, plural, one {Créer {number} copie de module} many {Créer {number} copies de module} other {Créer {number} copies de module}}" +msgid "node.ceiling.buildUpSection.layers" +msgstr "Couches" +# Source-Hash: f2953d2931e36d0c # Review: required -# Source-Hash: 0eec3888096306a1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {Create {number} {name} copy} other {Create {number} {name} copies}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.runPanel.arrayCreateNamed" -msgstr "{count, plural, one {Créer {number} copie de {name}} many {Créer {number} copies de {name}} other {Créer {number} copies de {name}}}" +msgid "node.ceiling.buildUpSection.none" +msgstr "Aucune" +# Source-Hash: 441f7f652ea6a0d8 # Review: required -# Source-Hash: 8cdc0b808b551d3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a copy count from 1 to 20 and spacing from 0 to 2 m" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preset" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.runPanel.arrayInvalidOptions" -msgstr "Choisissez un nombre de copies de 1 à 20 et un espacement de 0 à 2 m" +msgid "node.ceiling.buildUpSection.preset" +msgstr "Préréglage" +# Source-Hash: 2bc7b44c217cb8fb # Review: required -# Source-Hash: cb89fe4161e87d68 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "There is not enough room in this run for the requested array" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The height is the finished underside; the layers rise from it." +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.runPanel.arrayNoRoom" -msgstr "Ce linéaire n'a pas assez de place pour la série demandée" +msgid "node.ceiling.buildUpSection.theHeightIsTheFinishedUnderside" +msgstr "La hauteur correspond à la sous-face finie ; les couches montent à partir de là." +# Source-Hash: fdbb503f0941bd56 # Review: required -# Source-Hash: 075d027345689724 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a standard or appliance module as the source" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.runPanel.arrayNoSource" -msgstr "Choisissez un module standard ou un appareil comme source" +msgid "node.ceiling.buildUpSection.thickness" +msgstr "Épaisseur" +# Source-Hash: 2cf52770d658d006 # Review: required -# Source-Hash: 05b65242d8c48791 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Truss bottom chords" +#: packages/nodes/src/ceiling/build-up-section.tsx +#, fuzzy +msgid "node.ceiling.buildUpSection.trussBottomChords" +msgstr "Entraits de fermettes" + +# Source-Hash: 4d6d5e9439f40e9b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A polygon-bounded ceiling surface that hosts ceiling-mounted items." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.runPanel.auto" -msgstr "Auto" +msgid "node.ceiling.description" +msgstr "Surface de plafond délimitée par un polygone, qui accueille les éléments fixés au plafond." +# Source-Hash: 4275c05172abd7fb # Review: required -# Source-Hash: 7ceade8f25b58fe9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.runPanel.back" -msgstr "Retour" +msgid "node.ceiling.label" +msgstr "Plafond" +# Source-Hash: 659e6b799ad7c27d # Review: required -# Source-Hash: b2c3a03bf67a97a7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Balances standard base cabinets while keeping appliance and corner-filler widths fixed." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Hole" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.balancesStandardBaseCabinetsWhileKeeping" -msgstr "Équilibre les meubles bas standard en gardant fixes les largeurs des appareils et des fileuses d'angle." +msgid "node.ceiling.panel.addHole" +msgstr "Ajouter une trémie" +# Source-Hash: 8332ab41e22958f1 # Review: required -# Source-Hash: 9cf3754f15467c50 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Area" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.bar" -msgstr "Barre" +msgid "node.ceiling.panel.area" +msgstr "Surface" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: ccec5da17ca39eee -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar counter" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.barCounter" -msgstr "Comptoir de bar" +msgid "node.ceiling.panel.auto" +msgstr "Auto" +# Source-Hash: 4275c05172abd7fb # Review: required -# Source-Hash: 97c1605fff221752 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar depth" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.barDepth" -msgstr "Profondeur du bar" +msgid "node.ceiling.panel.ceiling" +msgstr "Plafond" +# Source-Hash: b2a1b3bc9676fe05 # Review: required -# Source-Hash: 9514a6ddebdca34e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar height" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom height" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.barHeight" -msgstr "Hauteur du bar" +msgid "node.ceiling.panel.customHeight" +msgstr "Hauteur personnalisée" +# Source-Hash: 4e4f1a24e4a9d61e # Review: required -# Source-Hash: 7af3b69b4b5aeb19 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Carcass height" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut opening" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.carcassHeight" -msgstr "Hauteur du caisson" +msgid "node.ceiling.panel.cutOpening" +msgstr "Découper une ouverture" +# Source-Hash: 16552c2580bbe8b8 # Review: required -# Source-Hash: 5211341ed18f33f6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.center" -msgstr "Centre" +msgid "node.ceiling.panel.done" +msgstr "Terminé" +# Source-Hash: a5c2353769b603d5 # Review: required -# Source-Hash: b1ab1ba948bb77b0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Common wall-cabinet heights. Use the slider below for a custom height." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows level" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.commonWallCabinetHeightsUseThe" -msgstr "Hauteurs courantes de meubles hauts. Utilisez le curseur ci-dessous pour une hauteur personnalisée." +msgid "node.ceiling.panel.followsLevel" +msgstr "Suit le niveau" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 88ccc87b9b45a464 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Copies" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.copies" -msgstr "Copies" +msgid "node.ceiling.panel.height" +msgstr "Hauteur" +# Source-Hash: 703f56131ac45e60 # Review: required -# Source-Hash: d215c489b8385d9f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Copies include the source cabinet structure and any attached wall cabinet. Existing modules stay fixed; the requested array must fit in the available run space." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High (3.0m)" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.copiesIncludeTheSourceCabinetStructure" -msgstr "Les copies reprennent la structure du meuble source et tout meuble haut fixé. Les modules existants restent en place ; la série demandée doit tenir dans la place disponible." +msgid "node.ceiling.panel.high30m" +msgstr "Haut (3,0 m)" +# Source-Hash: 4ed40bdab397fe22 # Review: required -# Source-Hash: 221d1b64649b08f8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner fillers cannot be used as array sources" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High (9'0\")" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.cornerFillersCannotBeUsedAs" -msgstr "Les fileuses d'angle ne peuvent pas servir de source" +msgid "node.ceiling.panel.high90" +msgstr "Haut (9'0\")" +# Source-Hash: 34504c6ca6445e76 # Review: required -# Source-Hash: d8d1bc5a0f9fa0cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Countertop depth" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Holes" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.countertopDepth" -msgstr "Profondeur du plan de travail" +msgid "node.ceiling.panel.holes" +msgstr "Trémies" +# Source-Hash: 6e68b62d2aa611a4 # Review: required -# Source-Hash: 10bba4a11996c84b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Countertop height" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Info" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.countertopHeight" -msgstr "Hauteur du plan de travail" +msgid "node.ceiling.panel.info" +msgstr "Info" +# Source-Hash: 6925a008b1924062 # Review: required -# Source-Hash: 8abdfbc1798d9eaa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Create array" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Limited by the level to {height} — raise the level height for a taller ceiling." +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.createArray" -msgstr "Créer la série" +msgid "node.ceiling.panel.limitedByLevel" +msgstr "Limité par le niveau à {height} — augmentez la hauteur du niveau pour un plafond plus haut." +# Source-Hash: c7410ff087be3a61 # Review: required -# Source-Hash: 7984b1c42abd9c02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cutout" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low (2.4m)" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.cutout" -msgstr "Découpe" +msgid "node.ceiling.panel.low24m" +msgstr "Bas (2,4 m)" +# Source-Hash: a59425761b7c9084 # Review: required -# Source-Hash: 555240ffcca44233 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete {name}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low (8'0\")" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.deleteModule" -msgstr "Supprimer {name}" +msgid "node.ceiling.panel.low80" +msgstr "Bas (8'0\")" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.depth" -msgstr "Profondeur" +msgid "node.ceiling.panel.move" +msgstr "Déplacer" +# Source-Hash: 1d2dafb0d8f26ed5 # Review: required -# Source-Hash: 76cd03300faa9b2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Direction" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No holes" +#: packages/nodes/src/ceiling/panel.tsx +#, fuzzy +msgid "node.ceiling.panel.noHoles" +msgstr "Aucune trémie" + +# Source-Hash: 24f5fbd158798197 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard (2.5m)" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.direction" -msgstr "Direction" +msgid "node.ceiling.panel.standard25m" +msgstr "Standard (2,5 m)" +# Source-Hash: 73cf00cf1900c22b # Review: required -# Source-Hash: 5ca5884d3ff7edf4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate along run" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard (8'6\")" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.duplicateAlongRun" -msgstr "Dupliquer le long du linéaire" +msgid "node.ceiling.panel.standard86" +msgstr "Standard (8'6\")" +# Source-Hash: 065626498678bc5d # Review: required -# Source-Hash: a834f687290afc10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equalize all resizeable standard base cabinets in this run" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Taller than this level ({available} available). Raise the level height first." +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.equalizeAll" -msgstr "Égaliser tous les meubles bas standard redimensionnables de ce linéaire" +msgid "node.ceiling.panel.tallerThanLevel" +msgstr "Plus haut que ce niveau ({available} disponibles). Augmentez d’abord la hauteur du niveau." +# Source-Hash: ea12ce3c2b3588e7 # Review: required -# Source-Hash: 24da8a2de2c6e345 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The resizeable cabinet widths are already equal" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical masonry stack on a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.runPanel.equalizeAlreadyEqual" -msgstr "Les largeurs des meubles redimensionnables sont déjà égales" +msgid "node.chimney.description" +msgstr "Souche maçonnée verticale sur un pan de toit." +# Source-Hash: 95169058fec6db14 # Review: required -# Source-Hash: c38a4faef2097b73 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "At least two standard base cabinets are required" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Chimney" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.runPanel.equalizeNeedsTwo" -msgstr "Il faut au moins deux meubles bas standard" +msgid "node.chimney.label" +msgstr "Cheminée" +# Source-Hash: dc393661f0038c2d # Review: required -# Source-Hash: 61f15ae24419430c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The available run width cannot satisfy the cabinet width limits" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Above Ridge" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.equalizeNoFit" -msgstr "La largeur disponible du linéaire ne respecte pas les limites de largeur des meubles" +msgid "node.chimney.panel.aboveRidge" +msgstr "Au-dessus du faîtage" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 7617bb3b455dcdda -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equalize widths" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.equalizeWidths" -msgstr "Égaliser les largeurs" +msgid "node.chimney.panel.actions" +msgstr "Actions" +# Source-Hash: 7ceade8f25b58fe9 # Review: required -# Source-Hash: ad8c948d883a0c9d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{side, select, left {Left: {width} mm} other {Right: {width} mm}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.fillerPlanSide" -msgstr "{side, select, left {Gauche : {width} mm} other {Droite : {width} mm}}" +msgid "node.chimney.panel.back" +msgstr "Retour" +# Source-Hash: 0d42509b34b05dec # Review: required -# Source-Hash: 47ccd8c8b04475cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish & align" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bands" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.finishAlign" -msgstr "Finitions et alignement" +msgid "node.chimney.panel.bands" +msgstr "Bandeaux" +# Source-Hash: d52b53241789ee63 # Review: required -# Source-Hash: 855892e18c74153a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finished back" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.finishedBack" -msgstr "Dos fini" +msgid "node.chimney.panel.cap" +msgstr "Chapeau" +# Source-Hash: 95169058fec6db14 # Review: required -# Source-Hash: 7ab47aea30c73663 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finished exposed ends" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Chimney" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.finishedExposedEnds" -msgstr "Côtés apparents finis" +msgid "node.chimney.panel.chimney" +msgstr "Cheminée" +# Source-Hash: b619f366d2a1dfda # Review: required -# Source-Hash: c9356f25caf33eec -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fits 50–150 mm gaps at run ends beside perpendicular walls." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Chimney Type" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.fits50150MmGapsAt" -msgstr "Comble les écarts de 50 à 150 mm en bout de linéaire contre les murs perpendiculaires." +msgid "node.chimney.panel.chimneyType" +msgstr "Type de cheminée" +# Source-Hash: 6786ac75cbe9af57 # Review: required -# Source-Hash: b6f541bc28e38d2f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fit wall fillers" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corbeled" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.fitWallFillers" -msgstr "Ajuster les fileuses murales" +msgid "node.chimney.panel.corbeled" +msgstr "En encorbellement" +# Source-Hash: 89eba9f077fba348 # Review: required -# Source-Hash: 2af738f010ce28f0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fronts" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner Bevel" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.fronts" -msgstr "Façades" +msgid "node.chimney.panel.cornerBevel" +msgstr "Chanfrein d'angle" +# Source-Hash: 8a4beb9a57edc26e # Review: required -# Source-Hash: 58884f99d64e6d00 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handles" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Count" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.handles" -msgstr "Poignées" +msgid "node.chimney.panel.count" +msgstr "Nombre" +# Source-Hash: f8ba7d73d3006d57 # Review: required -# Source-Hash: d73589d7c04b1121 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height preset" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.heightPreset" -msgstr "Hauteur prédéfinie" +msgid "node.chimney.panel.cricket" +msgstr "Costière" +# Source-Hash: 14144df9e1364eea # Review: required -# Source-Hash: 590bfdd02dcdb857 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hole" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cutout Offset" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.hole" -msgstr "Trou" +msgid "node.chimney.panel.cutoutOffset" +msgstr "Décalage de la découpe" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: 3db1dea825785a30 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inset" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.inset" -msgstr "Encastré" +msgid "node.chimney.panel.delete" +msgstr "Supprimer" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: 2997c230c529590d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Island & Bar" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.islandBar" -msgstr "Îlot et bar" +msgid "node.chimney.panel.depth" +msgstr "Profondeur" +# Source-Hash: 016d8e70618916d4 # Review: required -# Source-Hash: a74f10dadc92c8bb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchen run" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diameter" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.kitchenRun" -msgstr "Linéaire de cuisine" +msgid "node.chimney.panel.diameter" +msgstr "Diamètre" +# Source-Hash: 3cd71355956a1821 # Review: required -# Source-Hash: 103e15b39c909210 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Knob" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.knob" -msgstr "Bouton" +msgid "node.chimney.panel.double" +msgstr "Double" +# Source-Hash: 150340cd05f4a6dd # Review: required -# Source-Hash: f365c6b6dd9ebab9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Extent" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.left" -msgstr "Gauche" +msgid "node.chimney.panel.extent" +msgstr "Étendue" +# Source-Hash: 9cab4d4c95f63cdd # Review: required -# Source-Hash: 3c88a1840043e15a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match base heights, backs, reveals and handles. Align upper cabinets; preserve tall appliances and custom compartments." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.matchBaseHeightsBacksRevealsAnd" -msgstr "Harmonise les hauteurs des meubles bas, les dos, les jeux et les poignées. Aligne les meubles hauts ; conserve les grands appareils et les compartiments personnalisés." +msgid "node.chimney.panel.flat" +msgstr "Plat" +# Source-Hash: f817c09ef0bb6d69 # Review: required -# Source-Hash: b112e31fe44cc94b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Metric · 600 mm" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flues" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.metricProfile" -msgstr "Métrique · 600 mm" +msgid "node.chimney.panel.flues" +msgstr "Conduits" +# Source-Hash: a3c10560fa3c1612 # Review: required -# Source-Hash: 4739f6315c5e8680 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Module {number}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Footprint" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.moduleNumber" -msgstr "Module {number}" +msgid "node.chimney.panel.footprint" +msgstr "Emprise" +# Source-Hash: e360f89d3c0ec456 # Review: required -# Source-Hash: b8801184e07e4815 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Modules" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.modules" -msgstr "Modules" +msgid "node.chimney.panel.front" +msgstr "Avant" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 81d365ccef73068c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.mounting" -msgstr "Montage" +msgid "node.chimney.panel.height" +msgstr "Hauteur" +# Source-Hash: 5b490bc19dddf201 # Review: required -# Source-Hash: a3914bd96488175c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No eligible module" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hollow Depth" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.noEligibleModule" -msgstr "Aucun module admissible" +msgid "node.chimney.panel.hollowDepth" +msgstr "Profondeur du creux" +# Source-Hash: 643687bc3adaac76 # Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" +#: packages/nodes/src/chimney/panel.tsx +#, fuzzy +msgid "node.chimney.panel.length" +msgstr "Longueur" + # Source-Hash: f2953d2931e36d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "None" -#: packages/nodes/src/cabinet/run-panel.tsx +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.none" +msgid "node.chimney.panel.none" msgstr "Aucun" +# Source-Hash: 0f0e13abf9b2bb67 # Review: required -# Source-Hash: 9c215dc512e57fa4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overlay" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Offset" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.overlay" -msgstr "Recouvrement" +msgid "node.chimney.panel.offset" +msgstr "Décalage" +# Source-Hash: 88540def2ce16ac5 # Review: required -# Source-Hash: 49fb05dfafd6001d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Plinth height" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overhang" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.plinthHeight" -msgstr "Hauteur du socle" +msgid "node.chimney.panel.overhang" +msgstr "Débord" +# Source-Hash: 6ce059aee1386f72 # Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panels" +#: packages/nodes/src/chimney/panel.tsx +#, fuzzy +msgid "node.chimney.panel.panels" +msgstr "Panneaux" + # Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Position" -#: packages/nodes/src/cabinet/run-panel.tsx +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.position" +msgid "node.chimney.panel.position" msgstr "Position" +# Source-Hash: f29fef1beeb25f22 # Review: required -# Source-Hash: efca749fc4463623 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised Arch" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangular" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.raisedArch" -msgstr "Arche en relief" +msgid "node.chimney.panel.rectangular" +msgstr "Rectangulaire" +# Source-Hash: 01989595ee7c1dc0 # Review: required -# Source-Hash: 5d6956c21fde6418 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reveal gap" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.revealGap" -msgstr "Jeu entre façades" +msgid "node.chimney.panel.rotation" +msgstr "Rotation" +# Source-Hash: ad0457800a1f0eb4 # Review: required -# Source-Hash: b34d5ee0f218221d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.right" -msgstr "Droite" +msgid "node.chimney.panel.round" +msgstr "Rond" +# Source-Hash: 8c6e3985459dacf9 # Review: required -# Source-Hash: e022da49ae8b4aef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Seating overhang" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.seatingOverhang" -msgstr "Débord pour assise" +msgid "node.chimney.panel.shoulder" +msgstr "Épaulement" +# Source-Hash: 84b9195c73dd7a67 # Review: required -# Source-Hash: 5b68e435b7210876 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaker" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Side Margin" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.shaker" -msgstr "Shaker" +msgid "node.chimney.panel.sideMargin" +msgstr "Marge latérale" +# Source-Hash: a05a390ae205fdd8 # Review: required -# Source-Hash: cba29b18ce666b0a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shared Plinth & Countertop" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Simple" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.sharedPlinthCountertop" -msgstr "Socle et plan de travail communs" +msgid "node.chimney.panel.simple" +msgstr "Simple" + +# Source-Hash: 62ab2eb3c775da95 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single" +#: packages/nodes/src/chimney/panel.tsx +#, fuzzy +msgid "node.chimney.panel.single" +msgstr "Simple" + +# Source-Hash: f6998707123fe72d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sloped" +#: packages/nodes/src/chimney/panel.tsx +#, fuzzy +msgid "node.chimney.panel.sloped" +msgstr "En pente" +# Source-Hash: e4698e83d02beb6c # Review: required -# Source-Hash: f7d577c4064c16ff -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show countertop" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spacing" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.showCountertop" -msgstr "Afficher le plan de travail" +msgid "node.chimney.panel.spacing" +msgstr "Espacement" +# Source-Hash: 39287346366fc206 # Review: required -# Source-Hash: 5d98e04dfd2e0a83 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show plinth" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.showPlinth" -msgstr "Afficher le socle" +msgid "node.chimney.panel.square" +msgstr "Carré" +# Source-Hash: 2c6b1cf17a973d67 # Review: required -# Source-Hash: 8775bc8dc9593964 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stepped" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.slab" -msgstr "Dalle" +msgid "node.chimney.panel.stepped" +msgstr "En gradins" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: 5bdc0a959203c52e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Source module" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.sourceModule" -msgstr "Module source" +msgid "node.chimney.panel.style" +msgstr "Style" +# Source-Hash: f86f1f22230596b7 # Review: required -# Source-Hash: e4698e83d02beb6c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spacing" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tapered" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.spacing" -msgstr "Espacement" +msgid "node.chimney.panel.tapered" +msgstr "Effilé" +# Source-Hash: fdbb503f0941bd56 # Review: required -# Source-Hash: 40e3105cbe68d163 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard dimensions" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.standardDimensions" -msgstr "Dimensions standard" +msgid "node.chimney.panel.thickness" +msgstr "Épaisseur" +# Source-Hash: 14b162761ce18fe9 # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Offset" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.style" -msgstr "Style" +msgid "node.chimney.panel.topOffset" +msgstr "Décalage du haut" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: e9d7ad9851d476d9 +# Source-Hash: 1a5ccd607c400d76 # Review: required -# English: "{type, select, shelf {Shelf} drawer {Drawer} door {Door} oven {Oven} microwave {Microwave} dishwasher {Dishwasher} sink {Sink} cooktop_gas {Gas cooktop} cooktop_induction {Induction cooktop} pull_out_pantry {Pull-out pantry} fridge_single {Fridge} fridge_double {Double fridge} fridge_top_freezer {Top-freezer fridge} fridge_bottom_freezer {Bottom-freezer fridge} hood_pyramid {Pyramid hood} hood_curved_glass {Curved glass hood} other {{raw}}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall Thickness" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.summaryCompartment" -msgstr "{type, select, shelf {Étagère} drawer {Tiroir} door {Porte} oven {Four} microwave {Micro-ondes} dishwasher {Lave-vaisselle} sink {Évier} cooktop_gas {Plaque gaz} cooktop_induction {Plaque à induction} pull_out_pantry {Coulissant garde-manger} fridge_single {Réfrigérateur} fridge_double {Réfrigérateur double} fridge_top_freezer {Réfrigérateur congélateur en haut} fridge_bottom_freezer {Réfrigérateur congélateur en bas} hood_pyramid {Hotte pyramide} hood_curved_glass {Hotte verre incurvé} other {{raw}}}" +msgid "node.chimney.panel.wallThickness" +msgstr "Épaisseur de paroi" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: 98582c257f149d44 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {{number} compartment} other {{number} compartments}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.summaryCompartments" -msgstr "{count, plural, one {{number} compartiment} many {{number} compartiments} other {{number} compartiments}}" +msgid "node.chimney.panel.width" +msgstr "Largeur" +# Source-Hash: abff67400a76e5eb # Review: required -# Source-Hash: 65b1cbba3b92c5b2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Empty" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brick" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.summaryEmpty" -msgstr "Vide" +msgid "node.chimney.preset.brick" +msgstr "Brique" +# Source-Hash: f6cbdaa17e989b91 # Review: required -# Source-Hash: 5db8b868684cf9f3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tall cabinet" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modern" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.summaryTall" -msgstr "Colonne" +msgid "node.chimney.preset.modern" +msgstr "Moderne" +# Source-Hash: ad0457800a1f0eb4 # Review: required -# Source-Hash: 27644f0497fd9849 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.top" -msgstr "Haut" +msgid "node.chimney.preset.round" +msgstr "Rond" +# Source-Hash: 6a06e628257f3393 # Review: required -# Source-Hash: 88c85283afe0c0bc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unable to finish this kitchen run." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A parametric column with configurable cross-section, base, and capital." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.runPanel.unableToFinish" -msgstr "Impossible de terminer ce linéaire de cuisine." +msgid "node.column.description" +msgstr "Poteau paramétrique avec section, base et chapiteau configurables." +# Source-Hash: 3530ac1f4046cd22 # Review: required -# Source-Hash: 8f668fb3e1a1696a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use {name} as array source" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Column" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.runPanel.useAsArraySource" -msgstr "Utiliser {name} comme source de la série" +msgid "node.column.label" +msgstr "Poteau" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 9308a109d017dcd6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use this module as the array source" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.useThisModuleAsTheArray" -msgstr "Utiliser ce module comme source de la série" +msgid "node.column.panel.actions" +msgstr "Actions" +# Source-Hash: 14b21685d375581a # Review: required -# Source-Hash: 1ce253a4d11bfa68 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "US · 24 in" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A-Frame" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.usProfile" -msgstr "US · 24 po" +msgid "node.column.panel.aFrame" +msgstr "Cadre en A" +# Source-Hash: 4007d88108e25c2b # Review: required -# Source-Hash: a2d852b2c5629796 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waterfall ends" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Apply preset..." +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.waterfallEnds" -msgstr "Retombées en cascade" +msgid "node.column.panel.applyPreset" +msgstr "Appliquer un préréglage…" -# Source-Hash: ffc8d80e438f40b7 +# Source-Hash: dbfe7c561383c964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "An editable module inside a modular cabinet run." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Apply proportion..." +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.cabinetModule.description" -msgstr "Module modifiable dans une rangée de meubles modulaires." +msgid "node.column.panel.applyProportion" +msgstr "Appliquer une proportion…" -# Source-Hash: d5c19ec529e26a98 +# Source-Hash: 1f3fd938f0b26c9f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet Module" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Depth" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.cabinetModule.label" -msgstr "Module de meuble" +msgid "node.column.panel.bottomDepth" +msgstr "Profondeur du bas" + +# Source-Hash: 85576e19cd3da914 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Height" +#: packages/nodes/src/column/panel.tsx +#, fuzzy +msgid "node.column.panel.bottomHeight" +msgstr "Hauteur du bas" -# Source-Hash: 4d6d5e9439f40e9b +# Source-Hash: 4df0bbb04744a810 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A polygon-bounded ceiling surface that hosts ceiling-mounted items." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.description" -msgstr "Surface de plafond délimitée par un polygone, qui accueille les éléments fixés au plafond." +msgid "node.column.panel.bottomSpread" +msgstr "Écartement en bas" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: 67479fecb980a441 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Step Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.label" -msgstr "Plafond" +msgid "node.column.panel.bottomStepSpread" +msgstr "Écart des gradins du bas" -# Source-Hash: 659e6b799ad7c27d +# Source-Hash: 6ea977c42202ca24 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Hole" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Tiers" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.addHole" -msgstr "Ajouter une trémie" +msgid "node.column.panel.bottomTiers" +msgstr "Gradins du bas" -# Source-Hash: 8332ab41e22958f1 +# Source-Hash: 709ca788827f8a94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Area" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.area" -msgstr "Surface" +msgid "node.column.panel.bottomWidth" +msgstr "Largeur du bas" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: 39d33008c81fc075 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box Frame" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.auto" -msgstr "Auto" +msgid "node.column.panel.boxFrame" +msgstr "Cadre caisson" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: 381b1f481f747677 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brace Depth" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.ceiling" -msgstr "Plafond" +msgid "node.column.panel.braceDepth" +msgstr "Profondeur du contreventement" -# Source-Hash: b2a1b3bc9676fe05 +# Source-Hash: 8509b09b4ecdd6b6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom height" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brace Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.customHeight" -msgstr "Hauteur personnalisée" +msgid "node.column.panel.braceWidth" +msgstr "Largeur du contreventement" -# Source-Hash: 4e4f1a24e4a9d61e +# Source-Hash: 08558dd786f45281 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut opening" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bulge" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.cutOpening" -msgstr "Découper une ouverture" +msgid "node.column.panel.bulge" +msgstr "Renflement" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: 663b9a9e6a469b02 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bulged" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.done" -msgstr "Terminé" +msgid "node.column.panel.bulged" +msgstr "Renflée" -# Source-Hash: a5c2353769b603d5 +# Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows level" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Column" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.followsLevel" -msgstr "Suit le niveau" +msgid "node.column.panel.column" +msgstr "Poteau" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: ca0a856f04460bd5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connector Plates" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.height" -msgstr "Hauteur" +msgid "node.column.panel.connectorPlates" +msgstr "Plaques d'assemblage" -# Source-Hash: 703f56131ac45e60 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High (3.0m)" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.high30m" -msgstr "Haut (3,0 m)" +msgid "node.column.panel.delete" +msgstr "Supprimer" -# Source-Hash: 4ed40bdab397fe22 +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High (9'0\")" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.high90" -msgstr "Haut (9'0\")" +msgid "node.column.panel.depth" +msgstr "Profondeur" -# Source-Hash: 34504c6ca6445e76 +# Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Holes" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.holes" -msgstr "Trémies" +msgid "node.column.panel.dimensions" +msgstr "Dimensions" -# Source-Hash: 6e68b62d2aa611a4 +# Source-Hash: b963a08f0d540014 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Info" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edge Softness" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.info" -msgstr "Info" +msgid "node.column.panel.edgeSoftness" +msgstr "Adoucissement des arêtes" -# Source-Hash: 6925a008b1924062 +# Source-Hash: 82b3db356639ef92 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Limited by the level to {height} — raise the level height for a taller ceiling." -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ends" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.limitedByLevel" -msgstr "Limité par le niveau à {height} — augmentez la hauteur du niveau pour un plafond plus haut." +msgid "node.column.panel.ends" +msgstr "Extrémités" -# Source-Hash: c7410ff087be3a61 +# Source-Hash: 646c3cd99df3e285 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low (2.4m)" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.low24m" -msgstr "Bas (2,4 m)" +msgid "node.column.panel.endWidth" +msgstr "Largeur d'extrémité" -# Source-Hash: a59425761b7c9084 +# Source-Hash: 02e229bca2a2b5f1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low (8'0\")" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fork Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.low80" -msgstr "Bas (8'0\")" +msgid "node.column.panel.forkSpread" +msgstr "Écartement de la fourche" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: fdebfac05413abcf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Heavy" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.move" -msgstr "Déplacer" +msgid "node.column.panel.heavy" +msgstr "Massive" + +# Source-Hash: 646ef0fbcbc58edf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/column/panel.tsx +#, fuzzy +msgid "node.column.panel.height" +msgstr "Hauteur" -# Source-Hash: 1d2dafb0d8f26ed5 +# Source-Hash: 957fae84ed52a2e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No holes" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height and footprint are controlled by the lean-to extension. Rotate or change the support style here; resize from the parent lean-to." +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.noHoles" -msgstr "Aucune trémie" +msgid "node.column.panel.heightAndFootprintAreControlledBy" +msgstr "La hauteur et l'emprise sont pilotées par l'appentis. Faites pivoter ou changez le style de support ici ; redimensionnez depuis l'appentis parent." -# Source-Hash: 24f5fbd158798197 +# Source-Hash: bb851e93088b73a2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard (2.5m)" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hourglass" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.standard25m" -msgstr "Standard (2,5 m)" +msgid "node.column.panel.hourglass" +msgstr "Sablier" -# Source-Hash: 73cf00cf1900c22b +# Source-Hash: 9cc75129edee59ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard (8'6\")" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "K Brace" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.standard86" -msgstr "Standard (8'6\")" +msgid "node.column.panel.kBrace" +msgstr "Contreventement en K" -# Source-Hash: 065626498678bc5d +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Taller than this level ({available} available). Raise the level height first." -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.tallerThanLevel" -msgstr "Plus haut que ce niveau ({available} disponibles). Augmentez d’abord la hauteur du niveau." +msgid "node.column.panel.move" +msgstr "Déplacer" -# Source-Hash: ea12ce3c2b3588e7 +# Source-Hash: 6dc190abd3f22787 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical masonry stack on a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Neck Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.description" -msgstr "Souche maçonnée verticale sur un pan de toit." +msgid "node.column.panel.neckWidth" +msgstr "Largeur du col" -# Source-Hash: 95169058fec6db14 +# Source-Hash: 7dba7ed55eeba18f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Chimney" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.label" -msgstr "Cheminée" +msgid "node.column.panel.noBottom" +msgstr "Sans base" +# Source-Hash: 682d71815bb20e94 # Review: required -# Source-Hash: dc393661f0038c2d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Above Ridge" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No Top" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.aboveRidge" -msgstr "Au-dessus du faîtage" +msgid "node.column.panel.noTop" +msgstr "Sans chapiteau" +# Source-Hash: 4da8688437f64db8 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plinth Thickness" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.actions" -msgstr "Actions" +msgid "node.column.panel.plinthThickness" +msgstr "Épaisseur de la plinthe" +# Source-Hash: 0bf453b4882c663c # Review: required -# Source-Hash: 7ceade8f25b58fe9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Portal Frame" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.back" -msgstr "Retour" +msgid "node.column.panel.portalFrame" +msgstr "Portique" +# Source-Hash: 441f7f652ea6a0d8 # Review: required -# Source-Hash: 0d42509b34b05dec -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bands" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preset" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.bands" -msgstr "Bandeaux" +msgid "node.column.panel.preset" +msgstr "Préréglage" +# Source-Hash: f29fef1beeb25f22 # Review: required -# Source-Hash: d52b53241789ee63 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangular" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.cap" -msgstr "Chapeau" +msgid "node.column.panel.rectangular" +msgstr "Rectangulaire" +# Source-Hash: 23b9d290b165cd49 # Review: required -# Source-Hash: 95169058fec6db14 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Chimney" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ring Pairs" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.chimney" -msgstr "Cheminée" +msgid "node.column.panel.ringPairs" +msgstr "Paires d'anneaux" +# Source-Hash: 8db82d731a19651e # Review: required -# Source-Hash: b619f366d2a1dfda -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Chimney Type" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ring Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.chimneyType" -msgstr "Type de cheminée" +msgid "node.column.panel.ringSpread" +msgstr "Écart des anneaux" +# Source-Hash: bdb524a15d9e1509 # Review: required -# Source-Hash: 6786ac75cbe9af57 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corbeled" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ring Thickness" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.corbeled" -msgstr "En encorbellement" +msgid "node.column.panel.ringThickness" +msgstr "Épaisseur des anneaux" +# Source-Hash: ad0457800a1f0eb4 # Review: required -# Source-Hash: 89eba9f077fba348 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner Bevel" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.cornerBevel" -msgstr "Chanfrein d'angle" +msgid "node.column.panel.round" +msgstr "Rond" +# Source-Hash: baa84a2d17095dcf # Review: required -# Source-Hash: 8a4beb9a57edc26e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Count" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round Band Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.count" -msgstr "Nombre" +msgid "node.column.panel.roundBandWidth" +msgstr "Largeur de la bague ronde" +# Source-Hash: 5f1f67fb0ca59a6d # Review: required -# Source-Hash: f8ba7d73d3006d57 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rounded Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.cricket" -msgstr "Costière" +msgid "node.column.panel.roundedBottom" +msgstr "Base arrondie" +# Source-Hash: 446816980ed0da27 # Review: required -# Source-Hash: 14144df9e1364eea -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cutout Offset" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rounded Top" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.cutoutOffset" -msgstr "Décalage de la découpe" +msgid "node.column.panel.roundedTop" +msgstr "Chapiteau arrondi" +# Source-Hash: 9e554c26be80f0d0 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segment Twist" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.delete" -msgstr "Supprimer" +msgid "node.column.panel.segmentTwist" +msgstr "Torsion des segments" + +# Source-Hash: 4fc63ad21de30103 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft" +#: packages/nodes/src/column/panel.tsx +#, fuzzy +msgid "node.column.panel.shaft" +msgstr "Gaine" +# Source-Hash: 9bc3a704a9a96b3a # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Corner Radius" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.depth" -msgstr "Profondeur" +msgid "node.column.panel.shaftCornerRadius" +msgstr "Rayon d'angle du fût" +# Source-Hash: 3dab61aeb47e504d # Review: required -# Source-Hash: 016d8e70618916d4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diameter" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.diameter" -msgstr "Diamètre" +msgid "node.column.panel.shaftWidth" +msgstr "Largeur du fût" +# Source-Hash: 85ea1d3c8b749680 # Review: required -# Source-Hash: 3cd71355956a1821 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.double" -msgstr "Double" +msgid "node.column.panel.shape" +msgstr "Forme" +# Source-Hash: 49a2ce13016d4073 # Review: required -# Source-Hash: 150340cd05f4a6dd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Extent" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Short / Stout" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.extent" -msgstr "Étendue" +msgid "node.column.panel.shortStout" +msgstr "Courte / Trapue" +# Source-Hash: 4637a9a61638cc66 # Review: required -# Source-Hash: 9cab4d4c95f63cdd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Simple Block Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.flat" -msgstr "Plat" +msgid "node.column.panel.simpleBlockBottom" +msgstr "Base en bloc simple" +# Source-Hash: 9278f9b4a48208b0 # Review: required -# Source-Hash: f817c09ef0bb6d69 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flues" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Simple Top" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.flues" -msgstr "Conduits" +msgid "node.column.panel.simpleTop" +msgstr "Chapiteau simple" +# Source-Hash: 9099890734ae1238 # Review: required -# Source-Hash: a3c10560fa3c1612 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Footprint" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single Strut" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.footprint" -msgstr "Emprise" +msgid "node.column.panel.singleStrut" +msgstr "Jambe de force unique" +# Source-Hash: d87ce271009ce063 # Review: required -# Source-Hash: e360f89d3c0ec456 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slender" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.front" -msgstr "Avant" +msgid "node.column.panel.slender" +msgstr "Élancée" +# Source-Hash: 39287346366fc206 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.height" -msgstr "Hauteur" +msgid "node.column.panel.square" +msgstr "Carré" +# Source-Hash: 2dc84759d8df709d # Review: required -# Source-Hash: 5b490bc19dddf201 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hollow Depth" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square Plinth Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.hollowDepth" -msgstr "Profondeur du creux" +msgid "node.column.panel.squarePlinthBottom" +msgstr "Base à plinthe carrée" +# Source-Hash: d998c212030bc7c2 # Review: required -# Source-Hash: 643687bc3adaac76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.length" -msgstr "Longueur" +msgid "node.column.panel.standard" +msgstr "Standard" +# Source-Hash: 01a6393135e0fb10 # Review: required -# Source-Hash: f2953d2931e36d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stepped Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.none" -msgstr "Aucun" +msgid "node.column.panel.steppedBottom" +msgstr "Base à gradins" +# Source-Hash: 3d7e443797d4146e # Review: required -# Source-Hash: 0f0e13abf9b2bb67 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Offset" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stepped Top" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.offset" -msgstr "Décalage" +msgid "node.column.panel.steppedTop" +msgstr "Chapiteau à gradins" +# Source-Hash: 4ee35f740730ae87 # Review: required -# Source-Hash: 88540def2ce16ac5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overhang" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.overhang" -msgstr "Débord" +msgid "node.column.panel.straight" +msgstr "Droit" +# Source-Hash: 6063ae2877faa35d # Review: required -# Source-Hash: 6ce059aee1386f72 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panels" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Taper" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.panels" -msgstr "Panneaux" +msgid "node.column.panel.taper" +msgstr "Fuselage" +# Source-Hash: f86f1f22230596b7 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tapered" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.position" -msgstr "Position" +msgid "node.column.panel.tapered" +msgstr "Effilé" +# Source-Hash: 3e7ec47626ee3f22 # Review: required -# Source-Hash: f29fef1beeb25f22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangular" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Depth" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.rectangular" -msgstr "Rectangulaire" +msgid "node.column.panel.topDepth" +msgstr "Profondeur du haut" +# Source-Hash: 0ca9047731784f56 # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Height" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.rotation" -msgstr "Rotation" +msgid "node.column.panel.topHeight" +msgstr "Hauteur du haut" +# Source-Hash: 3d8a2be83b5b536a # Review: required -# Source-Hash: ad0457800a1f0eb4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.round" -msgstr "Rond" +msgid "node.column.panel.topSpread" +msgstr "Écartement en haut" + +# Source-Hash: f4ae0dc639dbc220 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Step Spread" +#: packages/nodes/src/column/panel.tsx +#, fuzzy +msgid "node.column.panel.topStepSpread" +msgstr "Écart des gradins du haut" +# Source-Hash: 8acc4e843934b086 # Review: required -# Source-Hash: 8c6e3985459dacf9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Tiers" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.shoulder" -msgstr "Épaulement" +msgid "node.column.panel.topTiers" +msgstr "Gradins du haut" +# Source-Hash: a50eb6400611a57c # Review: required -# Source-Hash: 84b9195c73dd7a67 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Side Margin" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.sideMargin" -msgstr "Marge latérale" +msgid "node.column.panel.topWidth" +msgstr "Largeur du haut" +# Source-Hash: f425799b82e085ed # Review: required -# Source-Hash: a05a390ae205fdd8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Simple" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transform" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.simple" -msgstr "Simple" +msgid "node.column.panel.transform" +msgstr "Transformation" +# Source-Hash: 952fd1ef187c6646 # Review: required -# Source-Hash: 62ab2eb3c775da95 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trestle" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.single" -msgstr "Simple" +msgid "node.column.panel.trestle" +msgstr "Tréteau" +# Source-Hash: 7430dad59aaf98f4 # Review: required -# Source-Hash: f6998707123fe72d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sloped" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tripod" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.sloped" -msgstr "En pente" +msgid "node.column.panel.tripod" +msgstr "Trépied" +# Source-Hash: 0db559f22647ec73 # Review: required -# Source-Hash: e4698e83d02beb6c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spacing" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Twist Segments" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.spacing" -msgstr "Espacement" +msgid "node.column.panel.twistSegments" +msgstr "Segments de torsion" +# Source-Hash: 8038a34ffebf4932 # Review: required -# Source-Hash: 39287346366fc206 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.square" -msgstr "Carré" +msgid "node.column.panel.vertical" +msgstr "Vertical" +# Source-Hash: f24cc343d79acc10 # Review: required -# Source-Hash: 2c6b1cf17a973d67 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stepped" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "V Support" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.stepped" -msgstr "En gradins" +msgid "node.column.panel.vSupport" +msgstr "Support en V" +# Source-Hash: 44dda7136b93c8ee # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.style" -msgstr "Style" +msgid "node.column.panel.waist" +msgstr "Paillasse" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: f86f1f22230596b7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tapered" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.tapered" -msgstr "Effilé" +msgid "node.column.panel.width" +msgstr "Largeur" +# Source-Hash: 4e6640dfff42cea4 # Review: required -# Source-Hash: fdbb503f0941bd56 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "X Brace" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.thickness" -msgstr "Épaisseur" +msgid "node.column.panel.xBrace" +msgstr "Croisillon en X" +# Source-Hash: fefc9b1cfb26b5a8 # Review: required -# Source-Hash: 14b162761ce18fe9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Offset" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Yaw" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.topOffset" -msgstr "Décalage du haut" +msgid "node.column.panel.yaw" +msgstr "Lacet" +# Source-Hash: 86259690e332b66d # Review: required -# Source-Hash: 1a5ccd607c400d76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Thickness" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Y Support" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.wallThickness" -msgstr "Épaisseur de paroi" +msgid "node.column.panel.ySupport" +msgstr "Support en Y" +# Source-Hash: 4d3a89de7073d38d # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A {size} deck post stands no taller than {limit} (IRC Table R507.4, by species and the area it carries): check it, or use the next size up." +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.chimney.panel.width" -msgstr "Largeur" +msgid "node.column.postSection.aSizeDeckPostStandsNo" +msgstr "Un poteau de terrasse {size} ne doit pas dépasser {limit} de haut (IRC Table R507.4, selon l’essence et la surface portée) : vérifiez-le, ou passez à la taille supérieure." +# Source-Hash: 9e9715d52410c86f # Review: required -# Source-Hash: abff67400a76e5eb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Brick" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.chimney.preset.brick" -msgstr "Brique" +msgid "node.column.postSection.custom" +msgstr "Personnalisé" +# Source-Hash: 31f74f6b8e7f077e # Review: required -# Source-Hash: f6cbdaa17e989b91 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Modern" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit to the beam over it ({height})" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.chimney.preset.modern" -msgstr "Moderne" +msgid "node.column.postSection.fitToTheBeamOverIt" +msgstr "Ajuster à la poutre au-dessus ({height})" +# Source-Hash: f09c0bf0ea50fc47 # Review: required -# Source-Hash: ad0457800a1f0eb4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit to the ceiling plane ({height})" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.chimney.preset.round" -msgstr "Rond" +msgid "node.column.postSection.fitToTheCeilingPlane" +msgstr "Ajuster au plan du plafond ({height})" -# Source-Hash: 6a06e628257f3393 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A parametric column with configurable cross-section, base, and capital." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.column.description" -msgstr "Poteau paramétrique avec section, base et chapiteau configurables." +msgid "node.column.postSection.height" +msgstr "Hauteur" -# Source-Hash: 3530ac1f4046cd22 +# Source-Hash: b1778491849d76d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Column" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keep its shape and style it as a column" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.column.label" -msgstr "Poteau" +msgid "node.column.postSection.keepItsShapeAndStyleIt" +msgstr "Garder sa forme et le styliser comme une colonne" +# Source-Hash: 151f47e85cf7cc8b # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Make it a column" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.column.panel.actions" -msgstr "Actions" +msgid "node.column.postSection.makeItAColumn" +msgstr "En faire une colonne" +# Source-Hash: 5cc981e79d737694 # Review: required -# Source-Hash: 14b21685d375581a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A-Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.column.panel.aFrame" -msgstr "Cadre en A" +msgid "node.column.postSection.post" +msgstr "Poteau bois" +# Source-Hash: 64ed304f3773f93d # Review: required -# Source-Hash: 4007d88108e25c2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Apply preset..." -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Treated" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.column.panel.applyPreset" -msgstr "Appliquer un préréglage…" +msgid "node.column.postSection.treated" +msgstr "Traité" +# Source-Hash: 5c362de43a2cbac1 # Review: required -# Source-Hash: dbfe7c561383c964 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Apply proportion..." -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Untreated" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.column.panel.applyProportion" -msgstr "Appliquer une proportion…" +msgid "node.column.postSection.untreated" +msgstr "Non traité" +# Source-Hash: bf2baf3d7b55f0df # Review: required -# Source-Hash: 1f3fd938f0b26c9f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A-Frame Support" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.bottomDepth" -msgstr "Profondeur du bas" +msgid "node.column.preset.aFrameSupport" +msgstr "Support en A" +# Source-Hash: 51cf77bb359cee43 # Review: required -# Source-Hash: 85576e19cd3da914 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight Round" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.bottomHeight" -msgstr "Hauteur du bas" +msgid "node.column.preset.basicPillar" +msgstr "Ronde droite" +# Source-Hash: 39d33008c81fc075 # Review: required -# Source-Hash: 4df0bbb04744a810 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Spread" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box Frame" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.bottomSpread" -msgstr "Écartement en bas" +msgid "node.column.preset.boxFrameSupport" +msgstr "Cadre caisson" +# Source-Hash: 4f22058e862d1f81 # Review: required -# Source-Hash: 67479fecb980a441 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Step Spread" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Soft Bulged" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.bottomStepSpread" -msgstr "Écart des gradins du bas" +msgid "node.column.preset.bulgedPillar" +msgstr "Légèrement renflée" +# Source-Hash: bb851e93088b73a2 # Review: required -# Source-Hash: 6ea977c42202ca24 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Tiers" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hourglass" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.bottomTiers" -msgstr "Gradins du bas" +msgid "node.column.preset.hourglassPillar" +msgstr "Sablier" +# Source-Hash: 9cc75129edee59ad # Review: required -# Source-Hash: 709ca788827f8a94 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "K Brace" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.bottomWidth" -msgstr "Largeur du bas" +msgid "node.column.preset.kBraceSupport" +msgstr "Contreventement en K" +# Source-Hash: 0bf453b4882c663c # Review: required -# Source-Hash: 39d33008c81fc075 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box Frame" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Portal Frame" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.boxFrame" -msgstr "Cadre caisson" +msgid "node.column.preset.portalFrameSupport" +msgstr "Portique" +# Source-Hash: 9099890734ae1238 # Review: required -# Source-Hash: 381b1f481f747677 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Brace Depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single Strut" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.braceDepth" -msgstr "Profondeur du contreventement" +msgid "node.column.preset.singleStrutSupport" +msgstr "Jambe de force unique" +# Source-Hash: 0c13af329b9b57cd # Review: required -# Source-Hash: 8509b09b4ecdd6b6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Brace Width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square Block" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.braceWidth" -msgstr "Largeur du contreventement" +msgid "node.column.preset.squarePillar" +msgstr "Bloc carré" +# Source-Hash: 4c294bad84924665 # Review: required -# Source-Hash: 08558dd786f45281 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bulge" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tapered Round" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.bulge" -msgstr "Renflement" +msgid "node.column.preset.taperedPillar" +msgstr "Ronde fuselée" +# Source-Hash: 360e405bfd74a379 # Review: required -# Source-Hash: 663b9a9e6a469b02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bulged" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trestle Frame" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.bulged" -msgstr "Renflée" +msgid "node.column.preset.trestleSupport" +msgstr "Cadre à tréteau" +# Source-Hash: 4589103259b4fc4d # Review: required -# Source-Hash: 3530ac1f4046cd22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Column" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tripod Support" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.column" -msgstr "Poteau" +msgid "node.column.preset.tripodSupport" +msgstr "Support trépied" +# Source-Hash: f24cc343d79acc10 # Review: required -# Source-Hash: ca0a856f04460bd5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connector Plates" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "V Support" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.connectorPlates" -msgstr "Plaques d'assemblage" +msgid "node.column.preset.vFrameSupport" +msgstr "Support en V" +# Source-Hash: 4e6640dfff42cea4 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "X Brace" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.delete" -msgstr "Supprimer" +msgid "node.column.preset.xBraceSupport" +msgstr "Croisillon en X" +# Source-Hash: 86259690e332b66d # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Y Support" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.depth" -msgstr "Profondeur" +msgid "node.column.preset.yFrameSupport" +msgstr "Support en Y" +# Source-Hash: 895766ad1b766c2e # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Associative linear, curved, circular, angular, or coordinate plan dimension." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.panel.dimensions" -msgstr "Dimensions" +msgid "node.constructionDimension.description" +msgstr "Cote de plan associative : linéaire, courbe, circulaire, angulaire ou en coordonnées." +# Source-Hash: 6875b60ee8a7cc3b # Review: required -# Source-Hash: b963a08f0d540014 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edge Softness" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Construction Dimension" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.panel.edgeSoftness" -msgstr "Adoucissement des arêtes" +msgid "node.constructionDimension.label" +msgstr "Cote de construction" +# Source-Hash: 61a6c6b9bc29c4f8 # Review: required -# Source-Hash: 82b3db356639ef92 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ends" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Left" +#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.column.panel.ends" -msgstr "Extrémités" +msgid "node.cornerRadius.bottomLeft" +msgstr "Bas gauche" +# Source-Hash: c5368accab136fa6 # Review: required -# Source-Hash: 646c3cd99df3e285 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Right" +#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.column.panel.endWidth" -msgstr "Largeur d'extrémité" +msgid "node.cornerRadius.bottomRight" +msgstr "Bas droite" +# Source-Hash: c8f86af3f03af6c7 # Review: required -# Source-Hash: 02e229bca2a2b5f1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fork Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Left" +#: packages/nodes/src/door/panel.tsx +#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.column.panel.forkSpread" -msgstr "Écartement de la fourche" +msgid "node.cornerRadius.topLeft" +msgstr "Haut gauche" +# Source-Hash: 0ead7f1ffdbbd892 # Review: required -# Source-Hash: fdebfac05413abcf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Heavy" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Right" +#: packages/nodes/src/door/panel.tsx +#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.column.panel.heavy" -msgstr "Massive" +msgid "node.cornerRadius.topRight" +msgstr "Haut droite" + +# Source-Hash: a276c9693f01dec7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Louvered roof lantern with a dome or pyramid cap and optional finial." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.cupola.description" +msgstr "Lanterneau à persiennes avec coiffe en dôme ou pyramide et épi facultatif." +# Source-Hash: e679dd19f96eba0a # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cupola" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.panel.height" -msgstr "Hauteur" +msgid "node.cupola.label" +msgstr "Lanterneau" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 957fae84ed52a2e3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height and footprint are controlled by the lean-to extension. Rotate or change the support style here; resize from the parent lean-to." -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.heightAndFootprintAreControlledBy" -msgstr "La hauteur et l'emprise sont pilotées par l'appentis. Faites pivoter ou changez le style de support ici ; redimensionnez depuis l'appentis parent." +msgid "node.cupola.panel.actions" +msgstr "Actions" +# Source-Hash: e679dd19f96eba0a # Review: required -# Source-Hash: bb851e93088b73a2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hourglass" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cupola" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.hourglass" -msgstr "Sablier" +msgid "node.cupola.panel.cupola" +msgstr "Lanterneau" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: 9cc75129edee59ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "K Brace" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.kBrace" -msgstr "Contreventement en K" +msgid "node.cupola.panel.delete" +msgstr "Supprimer" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.move" -msgstr "Déplacer" +msgid "node.cupola.panel.depth" +msgstr "Profondeur" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: 6dc190abd3f22787 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Neck Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.neckWidth" -msgstr "Largeur du col" +msgid "node.cupola.panel.dimensions" +msgstr "Dimensions" +# Source-Hash: de47e23eb81efe02 # Review: required -# Source-Hash: 7dba7ed55eeba18f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dome" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.noBottom" -msgstr "Sans base" +msgid "node.cupola.panel.dome" +msgstr "Dôme" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: 682d71815bb20e94 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No Top" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.noTop" -msgstr "Sans chapiteau" +msgid "node.cupola.panel.duplicate" +msgstr "Dupliquer" +# Source-Hash: 1cfe33235b30b1d8 # Review: required -# Source-Hash: 4da8688437f64db8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Plinth Thickness" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finial" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.plinthThickness" -msgstr "Épaisseur de la plinthe" +msgid "node.cupola.panel.finial" +msgstr "Épi de faîtage" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 0bf453b4882c663c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Portal Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.portalFrame" -msgstr "Portique" +msgid "node.cupola.panel.height" +msgstr "Hauteur" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: 441f7f652ea6a0d8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preset" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.preset" -msgstr "Préréglage" +msgid "node.cupola.panel.move" +msgstr "Déplacer" +# Source-Hash: b5e0cb318d484d0c # Review: required -# Source-Hash: f29fef1beeb25f22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangular" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No Finial" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.rectangular" -msgstr "Rectangulaire" +msgid "node.cupola.panel.noFinial" +msgstr "Sans épi de faîtage" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: 23b9d290b165cd49 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ring Pairs" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.ringPairs" -msgstr "Paires d'anneaux" +msgid "node.cupola.panel.position" +msgstr "Position" +# Source-Hash: 47587b825e9a696b # Review: required -# Source-Hash: 8db82d731a19651e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ring Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pyramid" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.ringSpread" -msgstr "Écart des anneaux" +msgid "node.cupola.panel.pyramid" +msgstr "Pyramide" +# Source-Hash: 01989595ee7c1dc0 # Review: required -# Source-Hash: bdb524a15d9e1509 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ring Thickness" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.ringThickness" -msgstr "Épaisseur des anneaux" +msgid "node.cupola.panel.rotation" +msgstr "Rotation" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: ad0457800a1f0eb4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.round" -msgstr "Rond" +msgid "node.cupola.panel.style" +msgstr "Style" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: baa84a2d17095dcf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round Band Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.roundBandWidth" -msgstr "Largeur de la bague ronde" +msgid "node.cupola.panel.width" +msgstr "Largeur" +# Source-Hash: 5d4ccdf13668fab4 # Review: required -# Source-Hash: 5f1f67fb0ca59a6d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rounded Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto elevator cutout" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.column.panel.roundedBottom" -msgstr "Base arrondie" +msgid "node.cutout.autoElevator" +msgstr "Découpe auto d’ascenseur" +# Source-Hash: 78aa03576e02dda7 # Review: required -# Source-Hash: 446816980ed0da27 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rounded Top" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto stair cutout" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.column.panel.roundedTop" -msgstr "Chapiteau arrondi" +msgid "node.cutout.autoStair" +msgstr "Découpe auto d’escalier" -# Review: required -# Source-Hash: 9e554c26be80f0d0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segment Twist" -#: packages/nodes/src/column/panel.tsx +# Source-Hash: e04298381837252f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.column.panel.segmentTwist" -msgstr "Torsion des segments" +msgid "node.cutout.opening" +msgstr "Ouverture" +# Source-Hash: ce37dbd7a309940b # Review: required -# Source-Hash: 4fc63ad21de30103 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room cutout" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.column.panel.shaft" -msgstr "Gaine" +msgid "node.cutout.room" +msgstr "Découpe de pièce" +# Source-Hash: b1757d76048706b7 # Review: required -# Source-Hash: 9bc3a704a9a96b3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Corner Radius" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap hinge side" +#: packages/nodes/src/door/actions.tsx #, fuzzy -msgid "node.column.panel.shaftCornerRadius" -msgstr "Rayon d'angle du fût" +msgid "node.door.actions.swapHingeSide" +msgstr "Inverser le côté des charnières" +# Source-Hash: d8bbb9fdf69726ca # Review: required -# Source-Hash: 3dab61aeb47e504d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap swing side" +#: packages/nodes/src/door/actions.tsx #, fuzzy -msgid "node.column.panel.shaftWidth" -msgstr "Largeur du fût" +msgid "node.door.actions.swapSwingSide" +msgstr "Inverser le sens d’ouverture" +# Source-Hash: 6123b20edb9569de # Review: required -# Source-Hash: 85ea1d3c8b749680 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A door cut into a wall. Animated open/close state." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.panel.shape" -msgstr "Forme" +msgid "node.door.description" +msgstr "Porte découpée dans un mur, avec ouverture et fermeture animées." +# Source-Hash: 787e10f5db16904e # Review: required -# Source-Hash: 49a2ce13016d4073 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Short / Stout" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.panel.shortStout" -msgstr "Courte / Trapue" +msgid "node.door.label" +msgstr "Porte" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 4637a9a61638cc66 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Simple Block Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.simpleBlockBottom" -msgstr "Base en bloc simple" +msgid "node.door.panel.actions" +msgstr "Actions" +# Source-Hash: 8337b3213849faca # Review: required -# Source-Hash: 9278f9b4a48208b0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Simple Top" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "+ Add Segment" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.simpleTop" -msgstr "Chapiteau simple" +msgid "node.door.panel.addSegment" +msgstr "+ Ajouter un segment" +# Source-Hash: 663175a9c461a96d # Review: required -# Source-Hash: 9099890734ae1238 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single Strut" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.singleStrut" -msgstr "Jambe de force unique" +msgid "node.door.panel.all" +msgstr "Tout" +# Source-Hash: 710261f5ffb32617 # Review: required -# Source-Hash: d87ce271009ce063 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slender" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arch" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.slender" -msgstr "Élancée" +msgid "node.door.panel.arch" +msgstr "Arc" +# Source-Hash: 3715cd54e4775087 # Review: required -# Source-Hash: 39287346366fc206 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arch Height" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.square" -msgstr "Carré" +msgid "node.door.panel.archHeight" +msgstr "Hauteur de l’arc" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: 2dc84759d8df709d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square Plinth Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.squarePlinthBottom" -msgstr "Base à plinthe carrée" +msgid "node.door.panel.auto" +msgstr "Auto" +# Source-Hash: 8a04486ba122ea7d # Review: required -# Source-Hash: d998c212030bc7c2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto follows the wall" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.standard" -msgstr "Standard" +msgid "node.door.panel.autoFollowsTheWall" +msgstr "Auto suit le mur" +# Source-Hash: 387773c8aa2820a4 # Review: required -# Source-Hash: 01a6393135e0fb10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stepped Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar Height" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.steppedBottom" -msgstr "Base à gradins" +msgid "node.door.panel.barHeight" +msgstr "Hauteur de la barre" +# Source-Hash: 30edd1c180aac9b4 # Review: required -# Source-Hash: 3d7e443797d4146e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stepped Top" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Columns" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.steppedTop" -msgstr "Chapiteau à gradins" +msgid "node.door.panel.columns" +msgstr "Colonnes" +# Source-Hash: f533584833a4a7bb # Review: required -# Source-Hash: 4ee35f740730ae87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Content Padding" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.straight" -msgstr "Droit" +msgid "node.door.panel.contentPadding" +msgstr "Marge intérieure" +# Source-Hash: 7a90a42b578f2435 # Review: required -# Source-Hash: 6063ae2877faa35d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Taper" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner Radius" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.taper" -msgstr "Fuselage" +msgid "node.door.panel.cornerRadius" +msgstr "Rayon d’angle" +# Source-Hash: aa0e8e02212091e4 # Review: required -# Source-Hash: f86f1f22230596b7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tapered" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom: the segments match no style." +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.tapered" -msgstr "Effilé" +msgid "node.door.panel.customTheSegmentsMatchNoStyle" +msgstr "Personnalisé : les segments ne correspondent à aucun style." +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: 3e7ec47626ee3f22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Depth" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.topDepth" -msgstr "Profondeur du haut" +msgid "node.door.panel.delete" +msgstr "Supprimer" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: 0ca9047731784f56 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Height" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.topHeight" -msgstr "Hauteur du haut" +msgid "node.door.panel.depth" +msgstr "Profondeur" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: 3d8a2be83b5b536a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.dimensions" +msgstr "Dimensions" + +# Source-Hash: 76cd03300faa9b2b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Direction" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.topSpread" -msgstr "Écartement en haut" +msgid "node.door.panel.direction" +msgstr "Direction" +# Source-Hash: c53c3307e2a2a32a # Review: required -# Source-Hash: f4ae0dc639dbc220 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Step Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divider" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.topStepSpread" -msgstr "Écart des gradins du haut" +msgid "node.door.panel.divider" +msgstr "Séparateur" +# Source-Hash: 787e10f5db16904e # Review: required -# Source-Hash: 8acc4e843934b086 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Tiers" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.topTiers" -msgstr "Gradins du haut" +msgid "node.door.panel.door" +msgstr "Porte" +# Source-Hash: 4a0aa7f647e6461b # Review: required -# Source-Hash: a50eb6400611a57c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Closer" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.topWidth" -msgstr "Largeur du haut" +msgid "node.door.panel.doorCloser" +msgstr "Ferme-porte" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: f425799b82e085ed -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transform" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.transform" -msgstr "Transformation" +msgid "node.door.panel.duplicate" +msgstr "Dupliquer" +# Source-Hash: 65b1cbba3b92c5b2 # Review: required -# Source-Hash: 952fd1ef187c6646 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trestle" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Empty" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.trestle" -msgstr "Tréteau" +msgid "node.door.panel.empty" +msgstr "Vide" +# Source-Hash: 6982301da2dbe186 # Review: required -# Source-Hash: 7430dad59aaf98f4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tripod" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Enable Handle" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.tripod" -msgstr "Trépied" +msgid "node.door.panel.enableHandle" +msgstr "Activer la poignée" +# Source-Hash: 2e96ebf9c6e7fe49 # Review: required -# Source-Hash: 0db559f22647ec73 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Twist Segments" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Enable Threshold" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.twistSegments" -msgstr "Segments de torsion" +msgid "node.door.panel.enableThreshold" +msgstr "Activer le seuil" +# Source-Hash: 61f9413d3bbabde7 # Review: required -# Source-Hash: 8038a34ffebf4932 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip Side" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.vertical" -msgstr "Vertical" +msgid "node.door.panel.flipSide" +msgstr "Inverser le côté" +# Source-Hash: 7e8fdd28f9d54d1f # Review: required -# Source-Hash: f24cc343d79acc10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "V Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fold" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.vSupport" -msgstr "Support en V" +msgid "node.door.panel.fold" +msgstr "Pli" +# Source-Hash: ce3a6c03765dbbd8 # Review: required -# Source-Hash: 44dda7136b93c8ee -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.waist" -msgstr "Paillasse" +msgid "node.door.panel.frame" +msgstr "Cadre" +# Source-Hash: 0cce8ae784f78478 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth (auto)" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.width" -msgstr "Largeur" +msgid "node.door.panel.frameDepthAuto" +msgstr "Profondeur (auto)" +# Source-Hash: 53aa825a4737190a # Review: required -# Source-Hash: 4e6640dfff42cea4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "X Brace" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Garage" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.xBrace" -msgstr "Croisillon en X" +msgid "node.door.panel.garage" +msgstr "Garage" +# Source-Hash: 8ab91094cf650204 # Review: required -# Source-Hash: fefc9b1cfb26b5a8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Yaw" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.yaw" -msgstr "Lacet" +msgid "node.door.panel.glass" +msgstr "Vitrage" +# Source-Hash: 41483b645efc0c65 # Review: required -# Source-Hash: 86259690e332b66d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Y Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handle" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.ySupport" -msgstr "Support en Y" +msgid "node.door.panel.handle" +msgstr "Poignée" +# Source-Hash: b4a496a904640583 # Review: required -# Source-Hash: bf2baf3d7b55f0df -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A-Frame Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handle Side" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.aFrameSupport" -msgstr "Support en A" +msgid "node.door.panel.handleSide" +msgstr "Côté de la poignée" +# Source-Hash: 8c1bc3a078056ff7 # Review: required -# Source-Hash: 51cf77bb359cee43 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight Round" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hardware" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.basicPillar" -msgstr "Ronde droite" +msgid "node.door.panel.hardware" +msgstr "Quincaillerie" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 39d33008c81fc075 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.boxFrameSupport" -msgstr "Cadre caisson" +msgid "node.door.panel.height" +msgstr "Hauteur" +# Source-Hash: 7c8f079bbefe86c9 # Review: required -# Source-Hash: 4f22058e862d1f81 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Soft Bulged" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hinges Side" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.bulgedPillar" -msgstr "Légèrement renflée" +msgid "node.door.panel.hingesSide" +msgstr "Côté des charnières" +# Source-Hash: ac9c79f08ef130a1 # Review: required -# Source-Hash: bb851e93088b73a2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hourglass" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Horizontal" +#: packages/nodes/src/door/panel.tsx +#, fuzzy +msgid "node.door.panel.horizontal" +msgstr "Horizontal" + +# Source-Hash: 42824e50de26bc14 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Individual" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.hourglassPillar" -msgstr "Sablier" +msgid "node.door.panel.individual" +msgstr "Individuel" +# Source-Hash: 3db1dea825785a30 # Review: required -# Source-Hash: 9cc75129edee59ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "K Brace" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inset" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.kBraceSupport" -msgstr "Contreventement en K" +msgid "node.door.panel.inset" +msgstr "Encastré" +# Source-Hash: 1f4ad5ad3e1be222 # Review: required -# Source-Hash: 0bf453b4882c663c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Portal Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inward" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.portalFrameSupport" -msgstr "Portique" +msgid "node.door.panel.inward" +msgstr "Vers l’intérieur" +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# Source-Hash: 9099890734ae1238 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single Strut" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.singleStrutSupport" -msgstr "Jambe de force unique" +msgid "node.door.panel.left" +msgstr "Gauche" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: 0c13af329b9b57cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square Block" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.squarePillar" -msgstr "Bloc carré" +msgid "node.door.panel.move" +msgstr "Déplacer" +# Source-Hash: 3e52f04f92e08070 # Review: required -# Source-Hash: 4c294bad84924665 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tapered Round" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.taperedPillar" -msgstr "Ronde fuselée" +msgid "node.door.panel.open" +msgstr "Ouvrir" +# Source-Hash: e04298381837252f # Review: required -# Source-Hash: 360e405bfd74a379 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trestle Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.trestleSupport" -msgstr "Cadre à tréteau" +msgid "node.door.panel.opening" +msgstr "Ouverture" +# Source-Hash: ecb81bd3eefa6a47 # Review: required -# Source-Hash: 4589103259b4fc4d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tripod Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening Shape" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.tripodSupport" -msgstr "Support trépied" +msgid "node.door.panel.openingShape" +msgstr "Forme de l’ouverture" +# Source-Hash: ccd8f06b8f8d27c9 # Review: required -# Source-Hash: f24cc343d79acc10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "V Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outward" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.vFrameSupport" -msgstr "Support en V" +msgid "node.door.panel.outward" +msgstr "Vers l’extérieur" +# Source-Hash: 482469f5a0873f73 # Review: required -# Source-Hash: 4e6640dfff42cea4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "X Brace" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.xBraceSupport" -msgstr "Croisillon en X" +msgid "node.door.panel.panel" +msgstr "Panneau" +# Source-Hash: 6ce059aee1386f72 # Review: required -# Source-Hash: 86259690e332b66d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Y Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panels" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.yFrameSupport" -msgstr "Support en Y" +msgid "node.door.panel.panels" +msgstr "Panneaux" -# Source-Hash: 895766ad1b766c2e +# Source-Hash: ad56a8ab82ff1a77 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Associative linear, curved, circular, angular, or coordinate plan dimension." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panic Bar" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.constructionDimension.description" -msgstr "Cote de plan associative : linéaire, courbe, circulaire, angulaire ou en coordonnées." +msgid "node.door.panel.panicBar" +msgstr "Barre antipanique" -# Source-Hash: 6875b60ee8a7cc3b +# Source-Hash: ade6246634d93054 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Construction Dimension" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pocket" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.constructionDimension.label" -msgstr "Cote de construction" +msgid "node.door.panel.pocket" +msgstr "À galandage" -# Source-Hash: 61a6c6b9bc29c4f8 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Left" -#: packages/nodes/src/window/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cornerRadius.bottomLeft" -msgstr "Bas gauche" +msgid "node.door.panel.position" +msgstr "Position" -# Source-Hash: c5368accab136fa6 +# Source-Hash: 947eacd2689daced # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Right" -#: packages/nodes/src/window/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rail" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cornerRadius.bottomRight" -msgstr "Bas droite" +msgid "node.door.panel.rail" +msgstr "Lisse" -# Source-Hash: c8f86af3f03af6c7 +# Source-Hash: 3b6f225112035fde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Left" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rect" #: packages/nodes/src/door/panel.tsx -#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.cornerRadius.topLeft" -msgstr "Haut gauche" +msgid "node.door.panel.rect" +msgstr "Rect." -# Source-Hash: 0ead7f1ffdbbd892 +# Source-Hash: c05172113af5a2b8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Right" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "- Remove" #: packages/nodes/src/door/panel.tsx -#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.cornerRadius.topRight" -msgstr "Haut droite" +msgid "node.door.panel.remove" +msgstr "- Retirer" -# Source-Hash: a276c9693f01dec7 +# Source-Hash: 59236bd016c6b904 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Louvered roof lantern with a dome or pyramid cap and optional finial." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reveal Radius" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.description" -msgstr "Lanterneau à persiennes avec coiffe en dôme ou pyramide et épi facultatif." +msgid "node.door.panel.revealRadius" +msgstr "Rayon de l’ébrasement" -# Source-Hash: e679dd19f96eba0a +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cupola" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.label" -msgstr "Lanterneau" +msgid "node.door.panel.right" +msgstr "Droite" +# Source-Hash: fc826da6c99303e6 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rounded" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.actions" -msgstr "Actions" +msgid "node.door.panel.rounded" +msgstr "Arrondi" +# Source-Hash: 505d8419cf4cc5e1 # Review: required -# Source-Hash: e679dd19f96eba0a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cupola" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segments" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.cupola" -msgstr "Lanterneau" +msgid "node.door.panel.segments" +msgstr "Segments" +# Source-Hash: a8096eb4beaadeef # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Size is limited to the wall, including clearance for the opening frame." +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.delete" -msgstr "Supprimer" +msgid "node.door.panel.sizeIsLimitedToTheWall" +msgstr "La taille est limitée au mur, dégagement du cadre d’ouverture compris." +# Source-Hash: c00de0e2c9b0ddcb # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slide" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.depth" -msgstr "Profondeur" +msgid "node.door.panel.slide" +msgstr "Coulisser" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.dimensions" -msgstr "Dimensions" +msgid "node.door.panel.style" +msgstr "Style" +# Source-Hash: e48604b5f7b2a5f4 # Review: required -# Source-Hash: de47e23eb81efe02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dome" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swing" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.dome" -msgstr "Dôme" +msgid "node.door.panel.swing" +msgstr "Battant" +# Source-Hash: fdbb503f0941bd56 # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.duplicate" -msgstr "Dupliquer" +msgid "node.door.panel.thickness" +msgstr "Épaisseur" +# Source-Hash: f165d6c05be2b651 # Review: required -# Source-Hash: 1cfe33235b30b1d8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finial" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Threshold" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.finial" -msgstr "Épi de faîtage" +msgid "node.door.panel.threshold" +msgstr "Seuil" +# Source-Hash: 7e2505dd1d5e3513 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Shape" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.height" -msgstr "Hauteur" +msgid "node.door.panel.topShape" +msgstr "Forme du haut" +# Source-Hash: c44f7ab8bbd24858 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.move" -msgstr "Déplacer" +msgid "node.door.panel.type" +msgstr "Type" +# Source-Hash: 8038a34ffebf4932 # Review: required -# Source-Hash: b5e0cb318d484d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No Finial" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.noFinial" -msgstr "Sans épi de faîtage" +msgid "node.door.panel.vertical" +msgstr "Vertical" +# Source-Hash: 63d6b766151965f9 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "wall" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.position" -msgstr "Position" +msgid "node.door.panel.wall" +msgstr "mur" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: 47587b825e9a696b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pyramid" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.pyramid" -msgstr "Pyramide" +msgid "node.door.panel.width" +msgstr "Largeur" +# Source-Hash: 8421deea35cb5afc # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Barn" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.cupola.panel.rotation" -msgstr "Rotation" +msgid "node.door.style.barn" +msgstr "Coulissante de grange" +# Source-Hash: f747fbe71717772e # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Craftsman" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.cupola.panel.style" -msgstr "Style" +msgid "node.door.style.craftsman" +msgstr "Craftsman" +# Source-Hash: 092033938ca2debb # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "French" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.cupola.panel.width" -msgstr "Largeur" +msgid "node.door.style.french" +msgstr "Porte-fenêtre" -# Source-Hash: 5d4ccdf13668fab4 +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto elevator cutout" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.cutout.autoElevator" -msgstr "Découpe auto d’ascenseur" +msgid "node.door.style.glass" +msgstr "Vitrage" -# Source-Hash: 78aa03576e02dda7 +# Source-Hash: 6ab8b98b38eb2e65 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto stair cutout" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Half-louvered" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.cutout.autoStair" -msgstr "Découpe auto d’escalier" +msgid "node.door.style.halfLouvered" +msgstr "Mi-persiennée" -# Source-Hash: e04298381837252f +# Source-Hash: f6cbdaa17e989b91 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modern" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.cutout.opening" -msgstr "Ouverture" +msgid "node.door.style.modern" +msgstr "Moderne" -# Source-Hash: ce37dbd7a309940b +# Source-Hash: 482469f5a0873f73 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room cutout" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.cutout.room" -msgstr "Découpe de pièce" +msgid "node.door.style.panel" +msgstr "Panneau" -# Source-Hash: 6123b20edb9569de -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A door cut into a wall. Animated open/close state." -#: packages/nodes/src/i18n/definition-messages.ts +# Source-Hash: ac42c328610a0edd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paneled glass" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.door.description" -msgstr "Porte découpée dans un mur, avec ouverture et fermeture animées." +msgid "node.door.style.paneledGlass" +msgstr "Vitrée à panneaux" -# Source-Hash: 787e10f5db16904e +# Source-Hash: 5b68e435b7210876 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaker" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.door.label" -msgstr "Porte" +msgid "node.door.style.shaker" +msgstr "Shaker" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 9ad6ac42b4152b64 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Six-panel" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.door.panel.actions" -msgstr "Actions" +msgid "node.door.style.sixPanel" +msgstr "Six panneaux" -# Source-Hash: 8337b3213849faca +# Source-Hash: 8421deea35cb5afc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "+ Add Segment" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Barn" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.addSegment" -msgstr "+ Ajouter un segment" +msgid "node.door.type.barn" +msgstr "Coulissante de grange" -# Source-Hash: 663175a9c461a96d +# Source-Hash: 3cd71355956a1821 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.all" -msgstr "Tout" +msgid "node.door.type.double" +msgstr "Double" -# Source-Hash: 710261f5ffb32617 +# Source-Hash: 29ff60e662b789fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arch" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Folding" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.arch" -msgstr "Arc" +msgid "node.door.type.folding" +msgstr "Pliante" -# Source-Hash: 3715cd54e4775087 +# Source-Hash: 092033938ca2debb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arch Height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "French" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.archHeight" -msgstr "Hauteur de l’arc" +msgid "node.door.type.french" +msgstr "Porte-fenêtre" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: c86309fefe89699b # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 -# English: "Auto" +# AI-Model: claude-opus-5-5 +# English: "Roll-up" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.auto" -msgstr "Auto" +msgid "node.door.type.garageRollup" +msgstr "Enroulable" -# Source-Hash: 8a04486ba122ea7d +# Source-Hash: fb6a868430547544 # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 -# English: "Auto follows the wall" +# AI-Model: claude-opus-5-5 +# English: "Sectional" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.autoFollowsTheWall" -msgstr "Auto suit le mur" +msgid "node.door.type.garageSectional" +msgstr "Sectionnelle" -# Source-Hash: 387773c8aa2820a4 +# Source-Hash: 0b5eb64b569db837 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar Height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilt-up" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.barHeight" -msgstr "Hauteur de la barre" +msgid "node.door.type.garageTiltup" +msgstr "Basculante" -# Source-Hash: 30edd1c180aac9b4 +# Source-Hash: e744be60baad6abc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Columns" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hinged" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.columns" -msgstr "Colonnes" +msgid "node.door.type.hinged" +msgstr "Battante" -# Source-Hash: f533584833a4a7bb +# Source-Hash: ade6246634d93054 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Content Padding" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pocket" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.contentPadding" -msgstr "Marge intérieure" +msgid "node.door.type.pocket" +msgstr "À galandage" -# Source-Hash: 7a90a42b578f2435 +# Source-Hash: 18cbc73c5e1590aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner Radius" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sliding" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.cornerRadius" -msgstr "Rayon d’angle" +msgid "node.door.type.sliding" +msgstr "Coulissante" -# Source-Hash: aa0e8e02212091e4 +# Source-Hash: 387e57242c8d110a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom: the segments match no style." -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "House-shaped protrusion on a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.customTheSegmentsMatchNoStyle" -msgstr "Personnalisé : les segments ne correspondent à aucun style." +msgid "node.dormer.description" +msgstr "Saillie en forme de maison sur un pan de toit." -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 6b6f8068bbc4c902 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dormer" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.delete" -msgstr "Supprimer" +msgid "node.dormer.label" +msgstr "Lucarne" # Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Depth" -#: packages/nodes/src/door/panel.tsx +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.depth" +msgid "node.dormer.panel.depth" msgstr "Profondeur" # Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dimensions" -#: packages/nodes/src/door/panel.tsx +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.dimensions" +msgid "node.dormer.panel.dimensions" msgstr "Dimensions" -# Source-Hash: 76cd03300faa9b2b +# Source-Hash: 6b6f8068bbc4c902 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Direction" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dormer" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.direction" -msgstr "Direction" +msgid "node.dormer.panel.dormer" +msgstr "Lucarne" -# Source-Hash: c53c3307e2a2a32a +# Source-Hash: 6949d667043bee0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Divider" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.divider" -msgstr "Séparateur" +msgid "node.dormer.panel.dutch" +msgstr "Demi-croupe" -# Source-Hash: 787e10f5db16904e +# Source-Hash: 9cab4d4c95f63cdd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.door" -msgstr "Porte" +msgid "node.dormer.panel.flat" +msgstr "Plat" -# Source-Hash: 4a0aa7f647e6461b +# Source-Hash: deaffa095d126dfe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Closer" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.gable" +msgstr "Deux pans" + +# Source-Hash: 7f53d9ffca39984a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.gambrel" +msgstr "Brisé" + +# Source-Hash: 9eda0ea8d447066d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hip" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.hip" +msgstr "Croupe" + +# Source-Hash: 7f7bb0e875af3260 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard" +#: packages/nodes/src/dormer/panel.tsx +#, fuzzy +msgid "node.dormer.panel.mansard" +msgstr "Mansarde" + +# Source-Hash: 53af9efc7eca6594 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pitch Direction" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.doorCloser" -msgstr "Ferme-porte" +msgid "node.dormer.panel.pitchDirection" +msgstr "Sens de la pente" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 6c39ef7125494c4a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pitch Rise" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.duplicate" -msgstr "Dupliquer" +msgid "node.dormer.panel.pitchRise" +msgstr "Hauteur de pente" -# Source-Hash: 65b1cbba3b92c5b2 +# Source-Hash: 96336d4b0820b977 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Empty" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rise Back" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.empty" -msgstr "Vide" +msgid "node.dormer.panel.riseBack" +msgstr "Montée vers l'arrière" -# Source-Hash: 6982301da2dbe186 +# Source-Hash: ee3d45f8b756d029 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Enable Handle" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rise Front" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.enableHandle" -msgstr "Activer la poignée" +msgid "node.dormer.panel.riseFront" +msgstr "Montée vers l'avant" -# Source-Hash: 2e96ebf9c6e7fe49 +# Source-Hash: 5e0622f3b09c9326 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Enable Threshold" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Height" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.enableThreshold" -msgstr "Activer le seuil" +msgid "node.dormer.panel.roofHeight" +msgstr "Hauteur de toiture" -# Source-Hash: 61f9413d3bbabde7 +# Source-Hash: 19ab9527ae7889f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip Side" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Type" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.flipSide" -msgstr "Inverser le côté" +msgid "node.dormer.panel.roofType" +msgstr "Type de toit" -# Source-Hash: 7e8fdd28f9d54d1f +# Source-Hash: dba6a7b56cf7083f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fold" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Section" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.fold" -msgstr "Pli" +msgid "node.dormer.panel.section" +msgstr "Section" -# Source-Hash: ce3a6c03765dbbd8 +# Source-Hash: c8d0df27faa3feaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.frame" -msgstr "Cadre" +msgid "node.dormer.panel.shed" +msgstr "Appentis" -# Source-Hash: 0cce8ae784f78478 +# Source-Hash: e0f973edce3e4ca8 # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 -# English: "Depth (auto)" -#: packages/nodes/src/door/panel.tsx +# AI-Model: claude-opus-5-5 +# English: "Wall Height" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.frameDepthAuto" -msgstr "Profondeur (auto)" +msgid "node.dormer.panel.wallHeight" +msgstr "Hauteur du mur" -# Source-Hash: 53aa825a4737190a +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Garage" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.garage" -msgstr "Garage" +msgid "node.dormer.panel.width" +msgstr "Largeur" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: 0b1d1e9a36456a50 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Windows" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.glass" -msgstr "Vitrage" +msgid "node.dormer.panel.windows" +msgstr "Fenêtres" -# Source-Hash: 41483b645efc0c65 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handle" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/dormer/panel-actions-section.tsx #, fuzzy -msgid "node.door.panel.handle" -msgstr "Poignée" +msgid "node.dormer.panelActionsSection.actions" +msgstr "Actions" -# Source-Hash: b4a496a904640583 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handle Side" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/dormer/panel-actions-section.tsx #, fuzzy -msgid "node.door.panel.handleSide" -msgstr "Côté de la poignée" +msgid "node.dormer.panelActionsSection.delete" +msgstr "Supprimer" -# Source-Hash: 8c1bc3a078056ff7 +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hardware" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/dormer/panel-actions-section.tsx #, fuzzy -msgid "node.door.panel.hardware" -msgstr "Quincaillerie" +msgid "node.dormer.panelActionsSection.duplicate" +msgstr "Dupliquer" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/dormer/panel-actions-section.tsx #, fuzzy -msgid "node.door.panel.height" -msgstr "Hauteur" +msgid "node.dormer.panelActionsSection.move" +msgstr "Déplacer" -# Source-Hash: 7c8f079bbefe86c9 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hinges Side" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/dormer/panel-position-section.tsx #, fuzzy -msgid "node.door.panel.hingesSide" -msgstr "Côté des charnières" +msgid "node.dormer.panelPositionSection.position" +msgstr "Position" -# Source-Hash: ac9c79f08ef130a1 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Horizontal" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/dormer/panel-position-section.tsx #, fuzzy -msgid "node.door.panel.horizontal" -msgstr "Horizontal" +msgid "node.dormer.panelPositionSection.rotation" +msgstr "Rotation" -# Source-Hash: 42824e50de26bc14 +# Source-Hash: 7b19d21b9ad868c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Individual" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Window" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.individual" -msgstr "Individuel" +msgid "node.dormer.panelWindowsSection.addWindow" +msgstr "Ajouter une fenêtre" -# Source-Hash: 3db1dea825785a30 +# Source-Hash: 70d7cc5a6422feaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inset" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit {name}" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.inset" -msgstr "Encastré" +msgid "node.dormer.panelWindowsSection.editNamed" +msgstr "Modifier {name}" -# Source-Hash: 1f4ad5ad3e1be222 +# Source-Hash: b6648f023e6c83dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inward" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit window" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.inward" -msgstr "Vers l’intérieur" +msgid "node.dormer.panelWindowsSection.editWindow" +msgstr "Modifier la fenêtre" -# Source-Hash: f365c6b6dd9ebab9 +# Source-Hash: 4649baf9753aeb74 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Increase the dormer width to add another window." +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.left" -msgstr "Gauche" +msgid "node.dormer.panelWindowsSection.increaseTheDormerWidthToAdd" +msgstr "Élargissez la lucarne pour ajouter une autre fenêtre." # Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Move" -#: packages/nodes/src/door/panel.tsx +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.move" +msgid "node.dormer.panelWindowsSection.move" msgstr "Déplacer" -# Source-Hash: 3e52f04f92e08070 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/door/panel.tsx -#, fuzzy -msgid "node.door.panel.open" -msgstr "Ouvrir" - -# Source-Hash: e04298381837252f +# Source-Hash: c24226954309d83e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move {name}" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.opening" -msgstr "Ouverture" +msgid "node.dormer.panelWindowsSection.moveNamed" +msgstr "Déplacer {name}" -# Source-Hash: ecb81bd3eefa6a47 +# Source-Hash: f07faaf0d5e43eef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening Shape" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move window" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.openingShape" -msgstr "Forme de l’ouverture" +msgid "node.dormer.panelWindowsSection.moveWindow" +msgstr "Déplacer la fenêtre" -# Source-Hash: ccd8f06b8f8d27c9 +# Source-Hash: d2816490ea93d363 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Outward" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No windows" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.outward" -msgstr "Vers l’extérieur" +msgid "node.dormer.panelWindowsSection.noWindows" +msgstr "Aucune fenêtre" -# Source-Hash: 482469f5a0873f73 +# Source-Hash: 5cbb24f8b1ce7fb7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Window {number}" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.panel" -msgstr "Panneau" +msgid "node.dormer.panelWindowsSection.windowNumber" +msgstr "Fenêtre {number}" -# Source-Hash: 6ce059aee1386f72 +# Source-Hash: 9ca7d951240907cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panels" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Windows ({length})" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.panels" -msgstr "Panneaux" +msgid "node.dormer.panelWindowsSection.windowsLength" +msgstr "Fenêtres ({length})" -# Source-Hash: ad56a8ab82ff1a77 +# Source-Hash: f975c4759607806a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panic Bar" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{face, select, back {Back} left {Left} right {Right} other {Front}} · {width} × {height} m" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.panicBar" -msgstr "Barre antipanique" +msgid "node.dormer.panelWindowsSection.windowSummary" +msgstr "{face, select, back {Arrière} left {Gauche} right {Droite} other {Avant}} · {width} × {height} m" -# Source-Hash: ade6246634d93054 +# Source-Hash: b46392d2ea865760 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pocket" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical drop pipe from a gutter outlet to the ground." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.pocket" -msgstr "À galandage" +msgid "node.downspout.description" +msgstr "Tuyau vertical de la sortie de gouttière jusqu’au sol." # Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Position" -#: packages/nodes/src/door/panel.tsx +#: packages/nodes/src/downspout/inspector-editors.tsx #, fuzzy -msgid "node.door.panel.position" +msgid "node.downspout.inspectorEditors.position" msgstr "Position" -# Source-Hash: 947eacd2689daced +# Source-Hash: 1a1ec08a311f1b35 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rail" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspout" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.rail" -msgstr "Lisse" +msgid "node.downspout.label" +msgstr "Descente pluviale" -# Source-Hash: 3b6f225112035fde +# Source-Hash: 29eadb8c84ae9632 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rect" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elbow, tee, reducer, or square-to-round transition connecting duct runs." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.rect" -msgstr "Rect." +msgid "node.ductFitting.description" +msgstr "Coude, té, réduction ou transition carré-rond reliant des gaines." -# Source-Hash: c05172113af5a2b8 +# Source-Hash: 7323a0fc9efb077f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "- Remove" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap W/H" +#: packages/nodes/src/duct-fitting/inspector-editors.tsx #, fuzzy -msgid "node.door.panel.remove" -msgstr "- Retirer" +msgid "node.ductFitting.inspectorEditors.swapWH" +msgstr "Inverser L/H" -# Source-Hash: 59236bd016c6b904 +# Source-Hash: 064b36c4fc5deb87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reveal Radius" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap width and height" +#: packages/nodes/src/duct-fitting/inspector-editors.tsx #, fuzzy -msgid "node.door.panel.revealRadius" -msgstr "Rayon de l’ébrasement" +msgid "node.ductFitting.inspectorEditors.swapWidthAndHeight" +msgstr "Inverser largeur et hauteur" -# Source-Hash: b34d5ee0f218221d +# Source-Hash: 6d0c3833d87535e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct Fitting" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.right" -msgstr "Droite" +msgid "node.ductFitting.label" +msgstr "Raccord de gaine" -# Source-Hash: fc826da6c99303e6 +# Source-Hash: dd86efcab72fc5c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rounded" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Axis" +#: packages/nodes/src/duct-fitting/tool.tsx #, fuzzy -msgid "node.door.panel.rounded" -msgstr "Arrondi" +msgid "node.ductFitting.tool.axis" +msgstr "Axe" -# Source-Hash: 505d8419cf4cc5e1 +# Source-Hash: 5232a826549f915e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segments" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "⌥ axis" +#: packages/nodes/src/duct-fitting/tool.tsx #, fuzzy -msgid "node.door.panel.segments" -msgstr "Segments" +msgid "node.ductFitting.tool.axis2" +msgstr "⌥ axe" -# Source-Hash: a8096eb4beaadeef +# Source-Hash: 880b34f6fc0ae854 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Size is limited to the wall, including clearance for the opening frame." -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a duct face that fits the door" +#: packages/nodes/src/duct-fitting/tool.tsx #, fuzzy -msgid "node.door.panel.sizeIsLimitedToTheWall" -msgstr "La taille est limitée au mur, dégagement du cadre d’ouverture compris." +msgid "node.ductFitting.tool.hoverADuctFaceThatFits" +msgstr "Survolez une face de gaine adaptée à la trappe" -# Source-Hash: c00de0e2c9b0ddcb +# Source-Hash: 706f5b43a1d4a84a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slide" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place access door" +#: packages/nodes/src/duct-fitting/tool.tsx #, fuzzy -msgid "node.door.panel.slide" -msgstr "Coulisser" +msgid "node.ductFitting.tool.placeAccessDoor" +msgstr "Placer une trappe de visite" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: 8fb180251a321cef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/duct-fitting/tool.tsx +#, fuzzy +msgid "node.ductFitting.tool.rTRotate" +msgstr "R/T pivoter" + +# Source-Hash: 09eb45a9b35d1a9f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "HVAC duct run — polyline of round, rect, or flat-oval sections." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.style" -msgstr "Style" +msgid "node.ductSegment.description" +msgstr "Réseau de gaines CVC — polyligne de sections rondes, rectangulaires ou oblongues." -# Source-Hash: e48604b5f7b2a5f4 +# Source-Hash: e971d82044e2f48e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swing" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.swing" -msgstr "Battant" +msgid "node.ductSegment.label" +msgstr "Gaine" -# Source-Hash: fdbb503f0941bd56 +# Source-Hash: 33181d0f42421013 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct terminal — supply register, ceiling diffuser, or return grille. Duct runs end at its collar." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.thickness" -msgstr "Épaisseur" +msgid "node.ductTerminal.description" +msgstr "Terminal aéraulique — bouche de soufflage, diffuseur plafonnier ou grille de reprise. Les gaines se terminent sur son collet." -# Source-Hash: f165d6c05be2b651 +# Source-Hash: 161e5386b939e1bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Threshold" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Register" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.threshold" -msgstr "Seuil" +msgid "node.ductTerminal.label" +msgstr "Bouche" -# Source-Hash: 7e2505dd1d5e3513 +# Source-Hash: 83c665eafcf43a68 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Shape" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{mount, select, floor {Mount Floor} ceiling {Mount Ceiling} wall {Mount Wall} other {Mount {label}}}" +#: packages/nodes/src/duct-terminal/tool.tsx #, fuzzy -msgid "node.door.panel.topShape" -msgstr "Forme du haut" +msgid "node.ductTerminal.tool.mount" +msgstr "{mount, select, floor {Pose au sol} ceiling {Pose au plafond} wall {Pose murale} other {Pose {label}}}" -# Source-Hash: c44f7ab8bbd24858 +# Source-Hash: f067dd52ea051385 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "M surface" +#. Key hint: pressing M switches the mounting surface. +#: packages/nodes/src/duct-terminal/tool.tsx #, fuzzy -msgid "node.door.panel.type" -msgstr "Type" +msgid "node.ductTerminal.tool.mSurface" +msgstr "M surface" -# Source-Hash: 8038a34ffebf4932 +# Source-Hash: 8fb180251a321cef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/duct-terminal/tool.tsx #, fuzzy -msgid "node.door.panel.vertical" -msgstr "Vertical" +msgid "node.ductTerminal.tool.rTRotate" +msgstr "R/T pivoter" -# Source-Hash: 63d6b766151965f9 +# Source-Hash: 98446855908ee71d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "wall" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapped to duct" +#: packages/nodes/src/duct-terminal/tool.tsx #, fuzzy -msgid "node.door.panel.wall" -msgstr "mur" +msgid "node.ductTerminal.tool.snappedToDuct" +msgstr "Accroché à la gaine" -# Source-Hash: 3a0ccd6c46877a87 +# Source-Hash: d0afa386e65cd3a4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A multi-level elevator shaft with configurable openings per level." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.width" -msgstr "Largeur" +msgid "node.elevator.description" +msgstr "Gaine d’ascenseur sur plusieurs niveaux, ouvertures configurables par niveau." -# Source-Hash: 8421deea35cb5afc +# Source-Hash: ab5cbab7be160a1c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Barn" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevator" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.style.barn" -msgstr "Coulissante de grange" +msgid "node.elevator.label" +msgstr "Ascenseur" -# Source-Hash: f747fbe71717772e +# Source-Hash: 7e6d5f138e315bdb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Craftsman" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Access" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.style.craftsman" -msgstr "Craftsman" +msgid "node.elevator.panel.access" +msgstr "Accès" -# Source-Hash: 092033938ca2debb +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "French" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.style.french" -msgstr "Porte-fenêtre" +msgid "node.elevator.panel.actions" +msgstr "Actions" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: fdf7108a011bd94b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cab" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.style.glass" -msgstr "Vitrage" +msgid "node.elevator.panel.cab" +msgstr "Cabine" -# Source-Hash: 6ab8b98b38eb2e65 +# Source-Hash: 2d0ab44f3820f22c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Half-louvered" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cab Height" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.style.halfLouvered" -msgstr "Mi-persiennée" +msgid "node.elevator.panel.cabHeight" +msgstr "Hauteur de cabine" -# Source-Hash: f6cbdaa17e989b91 +# Source-Hash: 65f410261609060b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Modern" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center opening" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.style.modern" -msgstr "Moderne" +msgid "node.elevator.panel.centerOpening" +msgstr "Ouverture centrale" -# Source-Hash: 482469f5a0873f73 +# Source-Hash: c5433f4d3ea8a8a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default Floor" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.style.panel" -msgstr "Panneau" +msgid "node.elevator.panel.defaultFloor" +msgstr "Niveau par défaut" -# Source-Hash: ac42c328610a0edd +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paneled glass" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.style.paneledGlass" -msgstr "Vitrée à panneaux" +msgid "node.elevator.panel.delete" +msgstr "Supprimer" -# Source-Hash: 5b68e435b7210876 +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaker" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.style.shaker" -msgstr "Shaker" +msgid "node.elevator.panel.depth" +msgstr "Profondeur" -# Source-Hash: 9ad6ac42b4152b64 +# Source-Hash: 748877ae309c313c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Six-panel" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Destination" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.style.sixPanel" -msgstr "Six panneaux" +msgid "node.elevator.panel.destination" +msgstr "Destination" -# Source-Hash: 8421deea35cb5afc +# Source-Hash: 3bff69bd74544339 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Barn" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Disabled" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.barn" -msgstr "Coulissante de grange" +msgid "node.elevator.panel.disabled" +msgstr "Désactivé" -# Source-Hash: 3cd71355956a1821 +# Source-Hash: d8baf402fa9c52f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Height" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.double" -msgstr "Double" +msgid "node.elevator.panel.doorHeight" +msgstr "Hauteur de porte" -# Source-Hash: 29ff60e662b789fb +# Source-Hash: 20f60b98de67849b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Folding" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Doors" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.folding" -msgstr "Pliante" +msgid "node.elevator.panel.doors" +msgstr "Portes" -# Source-Hash: 092033938ca2debb +# Source-Hash: eb0d4023a513b16c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "French" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Time" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.french" -msgstr "Porte-fenêtre" +msgid "node.elevator.panel.doorTime" +msgstr "Durée de porte" -# Source-Hash: c86309fefe89699b +# Source-Hash: b3e001acdb1f869d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roll-up" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Type" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.garageRollup" -msgstr "Enroulable" +msgid "node.elevator.panel.doorType" +msgstr "Type de porte" -# Source-Hash: fb6a868430547544 +# Source-Hash: c6203a69fdf44065 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sectional" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Width" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.garageSectional" -msgstr "Sectionnelle" +msgid "node.elevator.panel.doorWidth" +msgstr "Largeur de porte" -# Source-Hash: 0b5eb64b569db837 +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilt-up" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.garageTiltup" -msgstr "Basculante" +msgid "node.elevator.panel.duplicate" +msgstr "Dupliquer" -# Source-Hash: e744be60baad6abc +# Source-Hash: eb3abe5340b26138 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hinged" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dwell" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.hinged" -msgstr "Battante" +msgid "node.elevator.panel.dwell" +msgstr "Temps d'arrêt" -# Source-Hash: ade6246634d93054 +# Source-Hash: ab5cbab7be160a1c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pocket" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevator" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.pocket" -msgstr "À galandage" +msgid "node.elevator.panel.elevator" +msgstr "Ascenseur" -# Source-Hash: 18cbc73c5e1590aa +# Source-Hash: 702140636ff3977a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sliding" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "From" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.sliding" -msgstr "Coulissante" +msgid "node.elevator.panel.from" +msgstr "Depuis" -# Source-Hash: 387e57242c8d110a +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "House-shaped protrusion on a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.description" -msgstr "Saillie en forme de maison sur un pan de toit." +msgid "node.elevator.panel.glass" +msgstr "Vitrage" -# Source-Hash: 6b6f8068bbc4c902 +# Source-Hash: 88810658a2b97bc6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dormer" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass frame" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.label" -msgstr "Lucarne" +msgid "node.elevator.panel.glassFrame" +msgstr "Cadre vitré" +# Source-Hash: c0ff16d77ebc9593 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Motion" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.depth" -msgstr "Profondeur" +msgid "node.elevator.panel.motion" +msgstr "Mouvement" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.dimensions" -msgstr "Dimensions" +msgid "node.elevator.panel.move" +msgstr "Déplacer" +# Source-Hash: 825ac8855353a4e1 # Review: required -# Source-Hash: 6b6f8068bbc4c902 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dormer" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening Style" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.dormer" -msgstr "Lucarne" +msgid "node.elevator.panel.openingStyle" +msgstr "Type d'ouverture" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: 6949d667043bee0b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.dutch" -msgstr "Demi-croupe" +msgid "node.elevator.panel.position" +msgstr "Position" +# Source-Hash: 01989595ee7c1dc0 # Review: required -# Source-Hash: 9cab4d4c95f63cdd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.flat" -msgstr "Plat" +msgid "node.elevator.panel.rotation" +msgstr "Rotation" +# Source-Hash: f9a95d8407fafda4 # Review: required -# Source-Hash: deaffa095d126dfe -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segmented panel" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.gable" -msgstr "Deux pans" +msgid "node.elevator.panel.segmentedPanel" +msgstr "Panneau segmenté" +# Source-Hash: aa7b49b13f96057f # Review: required -# Source-Hash: 7f53d9ffca39984a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Service" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.gambrel" -msgstr "Brisé" +msgid "node.elevator.panel.service" +msgstr "Desserte" +# Source-Hash: 4fc63ad21de30103 # Review: required -# Source-Hash: 9eda0ea8d447066d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hip" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.hip" -msgstr "Croupe" +msgid "node.elevator.panel.shaft" +msgstr "Gaine" +# Source-Hash: 6605ade39317cd42 # Review: required -# Source-Hash: 7f7bb0e875af3260 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Depth" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.mansard" -msgstr "Mansarde" +msgid "node.elevator.panel.shaftDepth" +msgstr "Profondeur de gaine" +# Source-Hash: b28db5a3a48fe52e # Review: required -# Source-Hash: 53af9efc7eca6594 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pitch Direction" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Style" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.pitchDirection" -msgstr "Sens de la pente" +msgid "node.elevator.panel.shaftStyle" +msgstr "Style de gaine" +# Source-Hash: 3dab61aeb47e504d # Review: required -# Source-Hash: 6c39ef7125494c4a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pitch Rise" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Width" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.pitchRise" -msgstr "Hauteur de pente" +msgid "node.elevator.panel.shaftWidth" +msgstr "Largeur de gaine" +# Source-Hash: aee3b2bd78c87d0b # Review: required -# Source-Hash: 96336d4b0820b977 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rise Back" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single left" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.riseBack" -msgstr "Montée vers l'arrière" +msgid "node.elevator.panel.singleLeft" +msgstr "Simple gauche" +# Source-Hash: cc43ffbef4ac7ae0 # Review: required -# Source-Hash: ee3d45f8b756d029 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rise Front" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single right" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.riseFront" -msgstr "Montée vers l'avant" +msgid "node.elevator.panel.singleRight" +msgstr "Simple droite" +# Source-Hash: ef3e765e692faf4c # Review: required -# Source-Hash: 5e0622f3b09c9326 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Height" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.roofHeight" -msgstr "Hauteur de toiture" +msgid "node.elevator.panel.solid" +msgstr "Plein" +# Source-Hash: 8008b6f17089beaf # Review: required -# Source-Hash: 19ab9527ae7889f4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Type" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid panel" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.roofType" -msgstr "Type de toit" +msgid "node.elevator.panel.solidPanel" +msgstr "Panneau plein" +# Source-Hash: 3b006be0b1f0493f # Review: required -# Source-Hash: dba6a7b56cf7083f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Section" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Speed" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.section" -msgstr "Section" +msgid "node.elevator.panel.speed" +msgstr "Vitesse" +# Source-Hash: 6d37a1679fa3708e # Review: required -# Source-Hash: c8d0df27faa3feaa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stop {stopOrder}" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.shed" -msgstr "Appentis" +msgid "node.elevator.panel.stopStoporder" +msgstr "Arrêt {stopOrder}" +# Source-Hash: b3214a20e45a7aed # Review: required -# Source-Hash: e0f973edce3e4ca8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Height" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "To" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.wallHeight" -msgstr "Hauteur du mur" +msgid "node.elevator.panel.to" +msgstr "Vers" +# Source-Hash: 1a5ccd607c400d76 # Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall Thickness" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.wallThickness" +msgstr "Épaisseur de paroi" + # Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Width" -#: packages/nodes/src/dormer/panel.tsx +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.width" +msgid "node.elevator.panel.width" msgstr "Largeur" +# Source-Hash: fefc9b1cfb26b5a8 # Review: required -# Source-Hash: 0b1d1e9a36456a50 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Windows" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Yaw" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.windows" -msgstr "Fenêtres" +msgid "node.elevator.panel.yaw" +msgstr "Lacet" +# Source-Hash: 7b22c91cf520e161 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/dormer/panel-actions-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low curved lens-shaped roof vent with a louvered front." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.dormer.panelActionsSection.actions" -msgstr "Actions" +msgid "node.eyebrowVent.description" +msgstr "Aérateur de toit bas, courbe et lenticulaire avec façade à persiennes." +# Source-Hash: 654b29319185ac66 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/dormer/panel-actions-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eyebrow Vent" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.dormer.panelActionsSection.delete" -msgstr "Supprimer" +msgid "node.eyebrowVent.label" +msgstr "Chien-assis de ventilation" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/dormer/panel-actions-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelActionsSection.duplicate" -msgstr "Dupliquer" +msgid "node.eyebrowVent.panel.actions" +msgstr "Actions" +# Source-Hash: abc97377800a8333 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/dormer/panel-actions-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back height" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelActionsSection.move" -msgstr "Déplacer" +msgid "node.eyebrowVent.panel.backHeight" +msgstr "Hauteur arrière" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/dormer/panel-position-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelPositionSection.position" -msgstr "Position" +msgid "node.eyebrowVent.panel.delete" +msgstr "Supprimer" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/dormer/panel-position-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelPositionSection.rotation" -msgstr "Rotation" +msgid "node.eyebrowVent.panel.depth" +msgstr "Profondeur" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: 7b19d21b9ad868c7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Window" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.addWindow" -msgstr "Ajouter une fenêtre" +msgid "node.eyebrowVent.panel.dimensions" +msgstr "Dimensions" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: 70d7cc5a6422feaa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit {name}" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.editNamed" -msgstr "Modifier {name}" +msgid "node.eyebrowVent.panel.duplicate" +msgstr "Dupliquer" +# Source-Hash: 654b29319185ac66 # Review: required -# Source-Hash: b6648f023e6c83dc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit window" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eyebrow Vent" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.editWindow" -msgstr "Modifier la fenêtre" +msgid "node.eyebrowVent.panel.eyebrowVent" +msgstr "Chien-assis de ventilation" +# Source-Hash: a2d107a5deaa01f4 # Review: required -# Source-Hash: 4649baf9753aeb74 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Increase the dormer width to add another window." -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Half-round" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.increaseTheDormerWidthToAdd" -msgstr "Élargissez la lucarne pour ajouter une autre fenêtre." +msgid "node.eyebrowVent.panel.halfRound" +msgstr "Demi-rond" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.move" -msgstr "Déplacer" +msgid "node.eyebrowVent.panel.height" +msgstr "Hauteur" +# Source-Hash: 318192f27a774fb7 # Review: required -# Source-Hash: c24226954309d83e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move {name}" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Louvers" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.moveNamed" -msgstr "Déplacer {name}" +msgid "node.eyebrowVent.panel.louvers" +msgstr "Persiennes" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: f07faaf0d5e43eef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move window" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.moveWindow" -msgstr "Déplacer la fenêtre" +msgid "node.eyebrowVent.panel.move" +msgstr "Déplacer" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: d2816490ea93d363 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No windows" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.noWindows" -msgstr "Aucune fenêtre" +msgid "node.eyebrowVent.panel.position" +msgstr "Position" +# Source-Hash: 01989595ee7c1dc0 # Review: required -# Source-Hash: 5cbb24f8b1ce7fb7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Window {number}" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.windowNumber" -msgstr "Fenêtre {number}" +msgid "node.eyebrowVent.panel.rotation" +msgstr "Rotation" +# Source-Hash: e16f85e4bebfefb1 # Review: required -# Source-Hash: 9ca7d951240907cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Windows ({length})" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scoop" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.windowsLength" -msgstr "Fenêtres ({length})" +msgid "node.eyebrowVent.panel.scoop" +msgstr "Écope" +# Source-Hash: ec53d40877e11b62 # Review: required -# Source-Hash: f975c4759607806a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{face, select, back {Back} left {Left} right {Right} other {Front}} · {width} × {height} m" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slant-box" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.windowSummary" -msgstr "{face, select, back {Arrière} left {Gauche} right {Droite} other {Avant}} · {width} × {height} m" +msgid "node.eyebrowVent.panel.slantBox" +msgstr "Boîte inclinée" -# Source-Hash: b46392d2ea865760 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical drop pipe from a gutter outlet to the ground." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.downspout.description" -msgstr "Tuyau vertical de la sortie de gouttière jusqu’au sol." +msgid "node.eyebrowVent.panel.style" +msgstr "Style" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/downspout/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.downspout.inspectorEditors.position" -msgstr "Position" +msgid "node.eyebrowVent.panel.width" +msgstr "Largeur" -# Source-Hash: 1a1ec08a311f1b35 +# Source-Hash: 20032fe9430f610d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A straight or curved fence segment with configurable posts and infill." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.downspout.label" -msgstr "Descente pluviale" +msgid "node.fence.description" +msgstr "Tronçon de clôture droit ou courbe, poteaux et remplissage configurables." -# Source-Hash: 29eadb8c84ae9632 +# Source-Hash: 6f84b85097bc1ffc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elbow, tee, reducer, or square-to-round transition connecting duct runs." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add point after" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductFitting.description" -msgstr "Coude, té, réduction ou transition carré-rond reliant des gaines." +msgid "node.fence.inspectorEditors.addPointAfter" +msgstr "Ajouter un point après" +# Source-Hash: 1a15ab3101e2d166 # Review: required -# Source-Hash: 7323a0fc9efb077f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swap W/H" -#: packages/nodes/src/duct-fitting/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a slab or shaped surface on this level." +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductFitting.inspectorEditors.swapWH" -msgstr "Inverser L/H" +msgid "node.fence.inspectorEditors.chooseASlabOrShapedSurface" +msgstr "Choisissez une dalle ou une surface modelée sur ce niveau." +# Source-Hash: 78a5625401384000 # Review: required -# Source-Hash: 064b36c4fc5deb87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swap width and height" -#: packages/nodes/src/duct-fitting/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a surface" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductFitting.inspectorEditors.swapWidthAndHeight" -msgstr "Inverser largeur et hauteur" +msgid "node.fence.inspectorEditors.chooseASurface" +msgstr "Choisir une surface" -# Source-Hash: 6d0c3833d87535e4 +# Source-Hash: 2ee121dca87bb64a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct Fitting" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductFitting.label" -msgstr "Raccord de gaine" +msgid "node.fence.inspectorEditors.corner" +msgstr "Angle" +# Source-Hash: f08fbb462e9afc0e # Review: required -# Source-Hash: dd86efcab72fc5c7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Axis" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curve" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductFitting.tool.axis" -msgstr "Axe" +msgid "node.fence.inspectorEditors.curve" +msgstr "Courbe" +# Source-Hash: a028e08962c388e0 # Review: required -# Source-Hash: 5232a826549f915e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "⌥ axis" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curved" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductFitting.tool.axis2" -msgstr "⌥ axe" +msgid "node.fence.inspectorEditors.curved" +msgstr "Courbe" +# Source-Hash: 81b75058b7843a0c # Review: required -# Source-Hash: 880b34f6fc0ae854 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a duct face that fits the door" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{style, select, picket {Distribution controls pickets in each bay between posts.} horizontal {Distribution controls posts along the full fence.} other {Distribution controls infill pieces between the two end posts.}} Spacing is measured between centers. The available width limits the count so pieces do not overlap." +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductFitting.tool.hoverADuctFaceThatFits" -msgstr "Survolez une face de gaine adaptée à la trappe" +msgid "node.fence.inspectorEditors.distributionInfo" +msgstr "{style, select, picket {La répartition règle les lattes de chaque travée entre poteaux.} horizontal {La répartition règle les poteaux sur toute la clôture.} other {La répartition règle les éléments de remplissage entre les deux poteaux d'extrémité.}} L'espacement se mesure entre centres. La largeur disponible limite le nombre pour éviter les chevauchements." +# Source-Hash: fbc8f54b0e3fdeb1 # Review: required -# Source-Hash: 706f5b43a1d4a84a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place access door" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit path" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.editPath" +msgstr "Modifier le tracé" + +# Source-Hash: 55686db44529c013 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Extend path" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductFitting.tool.placeAccessDoor" -msgstr "Placer une trappe de visite" +msgid "node.fence.inspectorEditors.extendPath" +msgstr "Prolonger le tracé" +# Source-Hash: 0bf0f27e631aa98d # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow highest surface" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductFitting.tool.rTRotate" -msgstr "R/T pivoter" +msgid "node.fence.inspectorEditors.followHighestSurface" +msgstr "Suivre la surface la plus haute" -# Source-Hash: 09eb45a9b35d1a9f +# Source-Hash: e0b381fcb05a65c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "HVAC duct run — polyline of round, rect, or flat-oval sections." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow selected surface" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductSegment.description" -msgstr "Réseau de gaines CVC — polyligne de sections rondes, rectangulaires ou oblongues." +msgid "node.fence.inspectorEditors.followSelectedSurface" +msgstr "Suivre la surface sélectionnée" -# Source-Hash: e971d82044e2f48e +# Source-Hash: c418d97f803af8dd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hold starting height" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductSegment.label" -msgstr "Gaine" +msgid "node.fence.inspectorEditors.holdStartingHeight" +msgstr "Garder la hauteur de départ" -# Source-Hash: 33181d0f42421013 +# Source-Hash: 295ca9336dc1935b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct terminal — supply register, ceiling diffuser, or return grille. Duct runs end at its collar." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Join" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductTerminal.description" -msgstr "Terminal aéraulique — bouche de soufflage, diffuseur plafonnier ou grille de reprise. Les gaines se terminent sur son collet." +msgid "node.fence.inspectorEditors.join" +msgstr "Joindre" -# Source-Hash: 161e5386b939e1bc +# Source-Hash: 643687bc3adaac76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Register" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductTerminal.label" -msgstr "Bouche" +msgid "node.fence.inspectorEditors.length" +msgstr "Longueur" +# Source-Hash: 1fedc8a2f2ea6887 # Review: required -# Source-Hash: 83c665eafcf43a68 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{mount, select, floor {Mount Floor} ceiling {Mount Ceiling} wall {Mount Wall} other {Mount {label}}}" -#: packages/nodes/src/duct-terminal/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {{number} point} other {{number} points}} · {length} m" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductTerminal.tool.mount" -msgstr "{mount, select, floor {Pose au sol} ceiling {Pose au plafond} wall {Pose murale} other {Pose {label}}}" +msgid "node.fence.inspectorEditors.pathSummary" +msgstr "{count, plural, one {{number} point} many {{number} points} other {{number} points}} · {length} m" +# Source-Hash: c96d499e11181429 # Review: required -# Source-Hash: f067dd52ea051385 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "M surface" -#. Key hint: pressing M switches the mounting surface. -#: packages/nodes/src/duct-terminal/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket rail projection" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductTerminal.tool.mSurface" -msgstr "M surface" +msgid "node.fence.inspectorEditors.picketRailProjection" +msgstr "Saillie des lattes sur la lisse" +# Source-Hash: a1880fca8372d06f # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/duct-terminal/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Point" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductTerminal.tool.rTRotate" -msgstr "R/T pivoter" +msgid "node.fence.inspectorEditors.point" +msgstr "Point" +# Source-Hash: 39bc6254b5307f53 # Review: required -# Source-Hash: 98446855908ee71d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapped to duct" -#: packages/nodes/src/duct-terminal/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove point" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductTerminal.tool.snappedToDuct" -msgstr "Accroché à la gaine" +msgid "node.fence.inspectorEditors.removePoint" +msgstr "Supprimer le point" -# Source-Hash: d0afa386e65cd3a4 +# Source-Hash: ea56af3a0d7a65e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A multi-level elevator shaft with configurable openings per level." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set each span to straight or curved, then drag its points and curve handles in either view." +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.elevator.description" -msgstr "Gaine d’ascenseur sur plusieurs niveaux, ouvertures configurables par niveau." +msgid "node.fence.inspectorEditors.setEachSpanToStraightOr" +msgstr "Rendez chaque travée droite ou courbe, puis faites glisser ses points et poignées de courbure dans l’une ou l’autre vue." -# Source-Hash: ab5cbab7be160a1c +# Source-Hash: 354c8bc5c8da5a6e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevator" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Smooth" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.elevator.label" -msgstr "Ascenseur" +msgid "node.fence.inspectorEditors.smooth" +msgstr "Lisser" +# Source-Hash: 3c700cc1299a150f # Review: required -# Source-Hash: 7e6d5f138e315bdb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Access" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Span to point {number}" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.elevator.panel.access" -msgstr "Accès" +msgid "node.fence.inspectorEditors.spanToPointNumber" +msgstr "Travée jusqu'au point {number}" +# Source-Hash: 4ee35f740730ae87 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.elevator.panel.actions" -msgstr "Actions" +msgid "node.fence.inspectorEditors.straight" +msgstr "Droit" +# Source-Hash: 78a454b7ac7a3cd9 # Review: required -# Source-Hash: fdf7108a011bd94b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cab" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.elevator.panel.cab" -msgstr "Cabine" +msgid "node.fence.inspectorEditors.surface" +msgstr "Surface" +# Source-Hash: ab2de0428c093018 # Review: required -# Source-Hash: 2d0ab44f3820f22c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cab Height" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface behavior" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.elevator.panel.cabHeight" -msgstr "Hauteur de cabine" +msgid "node.fence.inspectorEditors.surfaceBehavior" +msgstr "Comportement sur la surface" +# Source-Hash: 02042fde61b5aa11 # Review: required -# Source-Hash: 65f410261609060b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center opening" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fence" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.elevator.panel.centerOpening" -msgstr "Ouverture centrale" +msgid "node.fence.label" +msgstr "Clôture" +# Source-Hash: 3e07a9889c1bd7f9 # Review: required -# Source-Hash: c5433f4d3ea8a8a7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default Floor" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Detach endpoint" +#: packages/nodes/src/fence/move-endpoint-tool.tsx #, fuzzy -msgid "node.elevator.panel.defaultFloor" -msgstr "Niveau par défaut" +msgid "node.fence.moveEndpointTool.detachEndpoint" +msgstr "Détacher l'extrémité" +# Source-Hash: 7a3ce9fec6370e3e # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag endpoint" +#: packages/nodes/src/fence/move-endpoint-tool.tsx #, fuzzy -msgid "node.elevator.panel.delete" -msgstr "Supprimer" +msgid "node.fence.moveEndpointTool.dragEndpoint" +msgstr "Faire glisser l'extrémité" +# Source-Hash: d7cf5045c01b2eb9 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close" +#: packages/nodes/src/fence-feature/actions.tsx +#, fuzzy +msgid "node.fenceFeature.actions.close" +msgstr "Fermer" + +# Source-Hash: 3e52f04f92e08070 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/fence-feature/actions.tsx #, fuzzy -msgid "node.elevator.panel.depth" -msgstr "Profondeur" +msgid "node.fenceFeature.actions.open" +msgstr "Ouvrir" +# Source-Hash: fc4cf2bc034fc547 # Review: required -# Source-Hash: 748877ae309c313c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Destination" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Board width" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.destination" -msgstr "Destination" +msgid "node.fenceFeature.inspector.boardWidth" +msgstr "Largeur des planches" +# Source-Hash: f3b11e5b2dd3b25f # Review: required -# Source-Hash: 3bff69bd74544339 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Disabled" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bracing" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.disabled" -msgstr "Désactivé" +msgid "node.fenceFeature.inspector.bracing" +msgstr "Contreventement" +# Source-Hash: d09ec3d9565734c3 # Review: required -# Source-Hash: d8baf402fa9c52f0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Height" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Distance from start" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.doorHeight" -msgstr "Hauteur de porte" +msgid "node.fenceFeature.inspector.distanceFromStart" +msgstr "Distance depuis le début" +# Source-Hash: dcd803eaf3796298 # Review: required -# Source-Hash: 20f60b98de67849b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Doors" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fence unavailable." +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.doors" -msgstr "Portes" +msgid "node.fenceFeature.inspector.fenceUnavailable" +msgstr "Clôture indisponible." +# Source-Hash: 3519d91b7bda18a5 # Review: required -# Source-Hash: eb0d4023a513b16c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Time" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame width" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.doorTime" -msgstr "Durée de porte" +msgid "node.fenceFeature.inspector.frameWidth" +msgstr "Largeur du cadre" +# Source-Hash: cb18554b2420e700 # Review: required -# Source-Hash: b3e001acdb1f869d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Type" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gate height" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.doorType" -msgstr "Type de porte" +msgid "node.fenceFeature.inspector.gateHeight" +msgstr "Hauteur du portail" +# Source-Hash: 54098b5ee574737a # Review: required -# Source-Hash: c6203a69fdf44065 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Width" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gate style" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.doorWidth" -msgstr "Largeur de porte" +msgid "node.fenceFeature.inspector.gateStyle" +msgstr "Style de portail" +# Source-Hash: 4fc3e60be28f60d5 # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground clearance" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.duplicate" -msgstr "Dupliquer" +msgid "node.fenceFeature.inspector.groundClearance" +msgstr "Garde au sol" +# Source-Hash: 916f2e07bf082795 # Review: required -# Source-Hash: eb3abe5340b26138 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dwell" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hinges and latch" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.dwell" -msgstr "Temps d'arrêt" +msgid "node.fenceFeature.inspector.hingesAndLatch" +msgstr "Charnières et loquet" +# Source-Hash: 5bd2e597fbb2a2c9 # Review: required -# Source-Hash: ab5cbab7be160a1c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevator" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hinge side" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.elevator" -msgstr "Ascenseur" +msgid "node.fenceFeature.inspector.hingeSide" +msgstr "Côté des charnières" +# Source-Hash: 8fec7e969045a8e7 # Review: required -# Source-Hash: 702140636ff3977a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "From" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Horizontal boards" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.from" -msgstr "Depuis" +msgid "node.fenceFeature.inspector.horizontalBoards" +msgstr "Lames horizontales" +# Source-Hash: f4addad87cc4223e # Review: required -# Source-Hash: 8ab91094cf650204 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Infill spacing" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.glass" -msgstr "Vitrage" +msgid "node.fenceFeature.inspector.infillSpacing" +msgstr "Espacement du remplissage" +# Source-Hash: cdec08b292742b20 # Review: required -# Source-Hash: 88810658a2b97bc6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass frame" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Jamb posts" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.glassFrame" -msgstr "Cadre vitré" +msgid "node.fenceFeature.inspector.jambPosts" +msgstr "Poteaux de jambage" +# Source-Hash: ef88410453ee7414 # Review: required -# Source-Hash: c0ff16d77ebc9593 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Motion" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keep the opening inside the fence and clear of other gates or passages." +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.motion" -msgstr "Mouvement" +msgid "node.fenceFeature.inspector.keepTheOpeningInsideTheFence" +msgstr "Gardez l'ouverture dans la clôture et à l'écart des autres portails ou passages." +# Source-Hash: 67cd0171b226fedb # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Leaf thickness" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.move" -msgstr "Déplacer" +msgid "node.fenceFeature.inspector.leafThickness" +msgstr "Épaisseur du vantail" +# Source-Hash: c390ba248e629b9e # Review: required -# Source-Hash: 825ac8855353a4e1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening Style" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Leaves" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.openingStyle" -msgstr "Type d'ouverture" +msgid "node.fenceFeature.inspector.leaves" +msgstr "Vantaux" +# Source-Hash: d7bb934589475512 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left leaf proportion" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.position" -msgstr "Position" +msgid "node.fenceFeature.inspector.leftLeafProportion" +msgstr "Proportion du vantail gauche" +# Source-Hash: aa9fe0ebace8957d # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match fence height" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.rotation" -msgstr "Rotation" +msgid "node.fenceFeature.inspector.matchFenceHeight" +msgstr "Hauteur de la clôture" +# Source-Hash: c15c1af69ec5c1eb # Review: required -# Source-Hash: f9a95d8407fafda4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segmented panel" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match fence style" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.matchFenceStyle" +msgstr "Assortir au style de clôture" + +# Source-Hash: 51b7ab6a0a78d90a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening angle" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.segmentedPanel" -msgstr "Panneau segmenté" +msgid "node.fenceFeature.inspector.openingAngle" +msgstr "Angle d’ouverture" +# Source-Hash: d2e20300c07aa722 # Review: required -# Source-Hash: aa7b49b13f96057f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Service" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening width" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.service" -msgstr "Desserte" +msgid "node.fenceFeature.inspector.openingWidth" +msgstr "Largeur d'ouverture" +# Source-Hash: 6b108fb1d0eb8f9d # Review: required -# Source-Hash: 4fc63ad21de30103 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open rails" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.shaft" -msgstr "Gaine" +msgid "node.fenceFeature.inspector.openRails" +msgstr "Lisses ajourées" +# Source-Hash: d500c4b7827d3390 # Review: required -# Source-Hash: 6605ade39317cd42 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Depth" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cross" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.shaftDepth" -msgstr "Profondeur de gaine" +msgid "node.fenceFeature.inspector.option.cross" +msgstr "Croix" +# Source-Hash: 7420c0d2caee1c22 # Review: required -# Source-Hash: b28db5a3a48fe52e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Style" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diagonal" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.shaftStyle" -msgstr "Style de gaine" +msgid "node.fenceFeature.inspector.option.diagonal" +msgstr "Diagonale" +# Source-Hash: 7308869944020839 # Review: required -# Source-Hash: 3dab61aeb47e504d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Width" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double gate" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.shaftWidth" -msgstr "Largeur de gaine" +msgid "node.fenceFeature.inspector.option.doubleGate" +msgstr "Portail double" +# Source-Hash: 1f4ad5ad3e1be222 # Review: required -# Source-Hash: aee3b2bd78c87d0b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single left" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inward" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.singleLeft" -msgstr "Simple gauche" +msgid "node.fenceFeature.inspector.option.inward" +msgstr "Vers l’intérieur" +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# Source-Hash: cc43ffbef4ac7ae0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single right" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.singleRight" -msgstr "Simple droite" +msgid "node.fenceFeature.inspector.option.left" +msgstr "Gauche" +# Source-Hash: f2953d2931e36d0c # Review: required -# Source-Hash: ef3e765e692faf4c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.solid" -msgstr "Plein" +msgid "node.fenceFeature.inspector.option.none" +msgstr "Aucun" +# Source-Hash: ccd8f06b8f8d27c9 # Review: required -# Source-Hash: 8008b6f17089beaf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid panel" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outward" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.solidPanel" -msgstr "Panneau plein" +msgid "node.fenceFeature.inspector.option.outward" +msgstr "Vers l’extérieur" +# Source-Hash: b34d5ee0f218221d # Review: required -# Source-Hash: 3b006be0b1f0493f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Speed" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.speed" -msgstr "Vitesse" +msgid "node.fenceFeature.inspector.option.right" +msgstr "Droite" +# Source-Hash: d327097d9ac1099f # Review: required -# Source-Hash: 6d37a1679fa3708e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stop {stopOrder}" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single gate" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.stopStoporder" -msgstr "Arrêt {stopOrder}" +msgid "node.fenceFeature.inspector.option.singleGate" +msgstr "Portail simple" +# Source-Hash: 9295ddc2805b21e2 # Review: required -# Source-Hash: b3214a20e45a7aed -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "To" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.to" -msgstr "Vers" +msgid "node.fenceFeature.inspector.picket" +msgstr "Piquets" +# Source-Hash: 8dd5999b235f60ab # Review: required -# Source-Hash: 1a5ccd607c400d76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Thickness" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post height" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.wallThickness" -msgstr "Épaisseur de paroi" +msgid "node.fenceFeature.inspector.postHeight" +msgstr "Hauteur des poteaux" +# Source-Hash: 90bcd7a8123ec343 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove gate" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.width" -msgstr "Largeur" +msgid "node.fenceFeature.inspector.removeGate" +msgstr "Supprimer le portail" +# Source-Hash: 7e3505710613543f # Review: required -# Source-Hash: fefc9b1cfb26b5a8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Yaw" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove opening" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.yaw" -msgstr "Lacet" +msgid "node.fenceFeature.inspector.removeOpening" +msgstr "Supprimer l'ouverture" -# Source-Hash: 7b22c91cf520e161 +# Source-Hash: af6f8885fe0fa4e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low curved lens-shaped roof vent with a louvered front." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid privacy" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.eyebrowVent.description" -msgstr "Aérateur de toit bas, courbe et lenticulaire avec façade à persiennes." +msgid "node.fenceFeature.inspector.solidPrivacy" +msgstr "Occultant plein" -# Source-Hash: 654b29319185ac66 +# Source-Hash: 1a7048255c3bdfcb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Eyebrow Vent" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swing direction" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.eyebrowVent.label" -msgstr "Chien-assis de ventilation" +msgid "node.fenceFeature.inspector.swingDirection" +msgstr "Sens d'ouverture" +# Source-Hash: eba3df14a2de0812 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical slats" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.eyebrowVent.panel.actions" -msgstr "Actions" +msgid "node.fenceFeature.inspector.verticalSlats" +msgstr "Lames verticales" +# Source-Hash: df61821ed00852d8 # Review: required -# Source-Hash: abc97377800a8333 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back height" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A gate hosted by a fence." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.backHeight" -msgstr "Hauteur arrière" +msgid "node.fenceGate.description" +msgstr "Portail porté par une clôture." +# Source-Hash: 4a479aa23542d766 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gate" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.delete" -msgstr "Supprimer" +msgid "node.fenceGate.label" +msgstr "Portail" +# Source-Hash: 8f9c927d79796c26 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An intentional opening in a fence." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.depth" -msgstr "Profondeur" +msgid "node.fenceOpening.description" +msgstr "Ouverture volontaire dans une clôture." +# Source-Hash: ab67bb47e647d594 # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open Passage" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.dimensions" -msgstr "Dimensions" +msgid "node.fenceOpening.label" +msgstr "Passage" +# Source-Hash: dc3adf0c2d50dba6 # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor opening" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.duplicate" -msgstr "Dupliquer" +msgid "node.floorOpening.label" +msgstr "Trémie" +# Source-Hash: 2f4fac2b1d39fdb1 # Review: required -# Source-Hash: 654b29319185ac66 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Eyebrow Vent" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A measurement / reference annotation (linear, area, or arc)." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.eyebrowVent" -msgstr "Chien-assis de ventilation" +msgid "node.guide.description" +msgstr "Annotation de mesure ou de référence (linéaire, surface ou arc)." +# Source-Hash: 1344ea2602e3aa9e # Review: required -# Source-Hash: a2d107a5deaa01f4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Half-round" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guide" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.halfRound" -msgstr "Demi-rond" +msgid "node.guide.label" +msgstr "Guide" +# Source-Hash: 5402d634f40b2f97 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rain-water channel running along the eave of a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.height" -msgstr "Hauteur" +msgid "node.gutter.description" +msgstr "Chéneau d’eau pluviale le long de l’égout d’un pan de toit." +# Source-Hash: fc7d4ecf973db135 # Review: required -# Source-Hash: 318192f27a774fb7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Louvers" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Downspout" +#: packages/nodes/src/gutter/downspouts-panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.louvers" -msgstr "Persiennes" +msgid "node.gutter.downspoutsPanel.addDownspout" +msgstr "Ajouter une descente" +# Source-Hash: 9b9929bac2c39bca # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspout {number}" +#: packages/nodes/src/gutter/downspouts-panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.move" -msgstr "Déplacer" +msgid "node.gutter.downspoutsPanel.downspoutNumber" +msgstr "Descente {number}" +# Source-Hash: fc34d45725838141 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspouts" +#: packages/nodes/src/gutter/downspouts-panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.position" -msgstr "Position" +msgid "node.gutter.downspoutsPanel.downspouts" +msgstr "Descentes d'eau" +# Source-Hash: ac329c74056f0616 # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove downspout" +#: packages/nodes/src/gutter/downspouts-panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.rotation" -msgstr "Rotation" +msgid "node.gutter.downspoutsPanel.removeDownspout" +msgstr "Supprimer la descente" +# Source-Hash: 14ba981da3627ae2 # Review: required -# Source-Hash: e16f85e4bebfefb1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scoop" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gutter" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.scoop" -msgstr "Écope" +msgid "node.gutter.label" +msgstr "Gouttière" +# Source-Hash: 387082cd5f118bed # Review: required -# Source-Hash: ec53d40877e11b62 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slant-box" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Manual" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.slantBox" -msgstr "Boîte inclinée" +msgid "node.hole.manual" +msgstr "Manuel" +# Source-Hash: fffde6fa82e65ffc # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hole {number} (Editing)" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.style" -msgstr "Style" +msgid "node.holeEditing" +msgstr "Trémie {number} (en cours de modification)" +# Source-Hash: 0fe446c72451e4a5 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hole {number}" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.width" -msgstr "Largeur" +msgid "node.holeNumber" +msgstr "Trémie {number}" -# Source-Hash: 20032fe9430f610d +# Source-Hash: 8eeeb79ff4221939 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A straight or curved fence segment with configurable posts and infill." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} {unit} · {count, plural, one {{points} pt} other {{points} pts}} · {source}" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.fence.description" -msgstr "Tronçon de clôture droit ou courbe, poteaux et remplissage configurables." +msgid "node.holeSummary" +msgstr "{area} {unit} · {count, plural, one {{points} pt} many {{points} pts} other {{points} pts}} · {source}" +# Source-Hash: 50e9252d30f3fb4d # Review: required -# Source-Hash: 6f84b85097bc1ffc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add point after" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Furnace, air handler, or condenser — duct runs connect to its supply/return collars." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fence.inspectorEditors.addPointAfter" -msgstr "Ajouter un point après" +msgid "node.hvacEquipment.description" +msgstr "Chaudière, centrale de traitement d’air ou condenseur — les gaines se raccordent à ses collets de soufflage et de reprise." +# Source-Hash: 3bf1c1a8dbb93743 # Review: required -# Source-Hash: 1a15ab3101e2d166 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a slab or shaped surface on this level." -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "HVAC Unit" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fence.inspectorEditors.chooseASlabOrShapedSurface" -msgstr "Choisissez une dalle ou une surface modelée sur ce niveau." +msgid "node.hvacEquipment.label" +msgstr "Unité CVC" +# Source-Hash: 8fb180251a321cef # Review: required -# Source-Hash: 78a5625401384000 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a surface" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/hvac-equipment/tool.tsx #, fuzzy -msgid "node.fence.inspectorEditors.chooseASurface" -msgstr "Choisir une surface" +msgid "node.hvacEquipment.tool.rTRotate" +msgstr "R/T pivoter" -# Review: required -# Source-Hash: 2ee121dca87bb64a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner" -#: packages/nodes/src/fence/inspector-editors.tsx +# Source-Hash: f24a1089d9256460 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Geometry preserved from an imported model when no native Pascal shape exists." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fence.inspectorEditors.corner" -msgstr "Angle" +msgid "node.importedMesh.description" +msgstr "Géométrie conservée d’un modèle importé lorsqu’aucune forme Pascal native n’existe." +# Source-Hash: 9f9d11f287f722d7 # Review: required -# Source-Hash: f08fbb462e9afc0e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curve" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Imported Mesh" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fence.inspectorEditors.curve" -msgstr "Courbe" +msgid "node.importedMesh.label" +msgstr "Maillage importé" +# Source-Hash: 9cce89f94c673821 # Review: required -# Source-Hash: a028e08962c388e0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curved" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Couldn't rebuild with these values." +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.curved" -msgstr "Courbe" +msgid "node.item.authoredParams.couldnTRebuildWithTheseValues" +msgstr "Impossible de reconstruire avec ces valeurs." +# Source-Hash: 373b929318436fe3 # Review: required -# Source-Hash: 81b75058b7843a0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{style, select, picket {Distribution controls pickets in each bay between posts.} horizontal {Distribution controls posts along the full fence.} other {Distribution controls infill pieces between the two end posts.}} Spacing is measured between centers. The available width limits the count so pieces do not overlap." -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Parameters" +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.distributionInfo" -msgstr "{style, select, picket {La répartition règle les lattes de chaque travée entre poteaux.} horizontal {La répartition règle les poteaux sur toute la clôture.} other {La répartition règle les éléments de remplissage entre les deux poteaux d'extrémité.}} L'espacement se mesure entre centres. La largeur disponible limite le nombre pour éviter les chevauchements." +msgid "node.item.authoredParams.parameters" +msgstr "Paramètres" +# Source-Hash: 558cb886dbe0babe # Review: required -# Source-Hash: fbc8f54b0e3fdeb1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit path" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rebuilding…" +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.editPath" -msgstr "Modifier le tracé" +msgid "node.item.authoredParams.rebuilding" +msgstr "Reconstruction…" +# Source-Hash: a094c99dc8ad29a3 # Review: required -# Source-Hash: 55686db44529c013 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Extend path" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rebuilding in Blender…" +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.extendPath" -msgstr "Prolonger le tracé" +msgid "node.item.authoredParams.rebuildingInBlender" +msgstr "Reconstruction dans Blender…" +# Source-Hash: 1778f93ee143cd95 # Review: required -# Source-Hash: 0bf0f27e631aa98d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follow highest surface" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset {param}" +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.followHighestSurface" -msgstr "Suivre la surface la plus haute" +msgid "node.item.authoredParams.resetParam" +msgstr "Réinitialiser {param}" +# Source-Hash: 5a28cf5f2402dd7a # Review: required -# Source-Hash: e0b381fcb05a65c4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follow selected surface" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset parameters" +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.followSelectedSurface" -msgstr "Suivre la surface sélectionnée" +msgid "node.item.authoredParams.resetParameters" +msgstr "Réinitialiser les paramètres" +# Source-Hash: 6eb8025c60d6d3ca # Review: required -# Source-Hash: c418d97f803af8dd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hold starting height" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset to default" +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.holdStartingHeight" -msgstr "Garder la hauteur de départ" +msgid "node.item.authoredParams.resetToDefault" +msgstr "Rétablir la valeur par défaut" +# Source-Hash: 63f79b3c467177b3 # Review: required -# Source-Hash: 295ca9336dc1935b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Join" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A catalog-backed item (furniture, fixtures, decorations)." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fence.inspectorEditors.join" -msgstr "Joindre" +msgid "node.item.description" +msgstr "Élément issu du catalogue (mobilier, équipements, décoration)." +# Source-Hash: 2743a0e9d2743807 # Review: required -# Source-Hash: 643687bc3adaac76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Item" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fence.inspectorEditors.length" -msgstr "Longueur" +msgid "node.item.label" +msgstr "Élément" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 1fedc8a2f2ea6887 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {{number} point} other {{number} points}} · {length} m" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.pathSummary" -msgstr "{count, plural, one {{number} point} many {{number} points} other {{number} points}} · {length} m" +msgid "node.item.panel.actions" +msgstr "Actions" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: c96d499e11181429 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket rail projection" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.picketRailProjection" -msgstr "Saillie des lattes sur la lisse" +msgid "node.item.panel.delete" +msgstr "Supprimer" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: a1880fca8372d06f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Point" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.point" -msgstr "Point" +msgid "node.item.panel.dimensions" +msgstr "Dimensions" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: 39bc6254b5307f53 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove point" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.removePoint" -msgstr "Supprimer le point" +msgid "node.item.panel.duplicate" +msgstr "Dupliquer" +# Source-Hash: 6e68b62d2aa611a4 # Review: required -# Source-Hash: ea56af3a0d7a65e4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set each span to straight or curved, then drag its points and curve handles in either view." -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Info" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.setEachSpanToStraightOr" -msgstr "Rendez chaque travée droite ou courbe, puis faites glisser ses points et poignées de courbure dans l’une ou l’autre vue." +msgid "node.item.panel.info" +msgstr "Info" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: 354c8bc5c8da5a6e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Smooth" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.smooth" -msgstr "Lisser" +msgid "node.item.panel.move" +msgstr "Déplacer" +# Source-Hash: 28fe6e9deddde6e8 # Review: required -# Source-Hash: 3c700cc1299a150f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Span to point {number}" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "pos" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.spanToPointNumber" -msgstr "Travée jusqu'au point {number}" +msgid "node.item.panel.pos" +msgstr "pos" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: 4ee35f740730ae87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.straight" -msgstr "Droit" +msgid "node.item.panel.position" +msgstr "Position" +# Source-Hash: 5f433581c8f404fa # Review: required -# Source-Hash: 78a454b7ac7a3cd9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "rot" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.surface" -msgstr "Surface" +msgid "node.item.panel.rot" +msgstr "rot" +# Source-Hash: 01989595ee7c1dc0 # Review: required -# Source-Hash: ab2de0428c093018 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface behavior" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.surfaceBehavior" -msgstr "Comportement sur la surface" +msgid "node.item.panel.rotation" +msgstr "Rotation" -# Source-Hash: 02042fde61b5aa11 +# Source-Hash: 8210f376c0d29acc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fence" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scale" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.label" -msgstr "Clôture" +msgid "node.item.panel.scale" +msgstr "Échelle" +# Source-Hash: 58fee802997c811c # Review: required -# Source-Hash: 3e07a9889c1bd7f9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Detach endpoint" -#: packages/nodes/src/fence/move-endpoint-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "scale" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.moveEndpointTool.detachEndpoint" -msgstr "Détacher l'extrémité" +msgid "node.item.panel.scale2" +msgstr "échelle" +# Source-Hash: b0d264950558d50e # Review: required -# Source-Hash: 7a3ce9fec6370e3e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag endpoint" -#: packages/nodes/src/fence/move-endpoint-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Uniform Scale" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.moveEndpointTool.dragEndpoint" -msgstr "Faire glisser l'extrémité" +msgid "node.item.panel.uniformScale" +msgstr "Échelle uniforme" +# Source-Hash: 4b8d7e52013d1691 # Review: required -# Source-Hash: d7cf5045c01b2eb9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close" -#: packages/nodes/src/fence-feature/actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "XYZ" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fenceFeature.actions.close" -msgstr "Fermer" +msgid "node.item.panel.xyz" +msgstr "XYZ" +# Source-Hash: a9e2d7b215696e2a # Review: required -# Source-Hash: 3e52f04f92e08070 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/fence-feature/actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An attached mono-pitch or freestanding mono, gable, or butterfly canopy with managed structure and drainage." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.actions.open" -msgstr "Ouvrir" +msgid "node.leanToExtension.description" +msgstr "Auvent adossé à un pan ou autoportant (un pan, deux pans ou papillon) avec structure et évacuation gérées." +# Source-Hash: 8503bedfbafde9a3 # Review: required -# Source-Hash: fc4cf2bc034fc547 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Board width" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Canopy" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.boardWidth" -msgstr "Largeur des planches" +msgid "node.leanToExtension.label" +msgstr "Auvent" +# Source-Hash: 45673462f914d3df # Review: required -# Source-Hash: f3b11e5b2dd3b25f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bracing" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A single floor of a building, holding walls / slabs / ceilings / items." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.bracing" -msgstr "Contreventement" +msgid "node.level.description" +msgstr "Un étage d’un bâtiment, avec murs, dalles, plafonds et éléments." +# Source-Hash: 0608743fc1736d86 # Review: required -# Source-Hash: d09ec3d9565734c3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Distance from start" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.distanceFromStart" -msgstr "Distance depuis le début" +msgid "node.level.label" +msgstr "Niveau" +# Source-Hash: 156bdee8fee5bec6 # Review: required -# Source-Hash: dcd803eaf3796298 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fence unavailable." -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Refrigerant lineset — copper suction + liquid pair joining a condenser to the indoor coil." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.fenceUnavailable" -msgstr "Clôture indisponible." +msgid "node.lineset.description" +msgstr "Liaison frigorifique — paire cuivre aspiration + liquide reliant le condenseur à la batterie intérieure." +# Source-Hash: 362b03eba9d8234c # Review: required -# Source-Hash: 3519d91b7bda18a5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame width" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lineset" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.frameWidth" -msgstr "Largeur du cadre" +msgid "node.lineset.label" +msgstr "Liaison frigorifique" +# Source-Hash: 2bd4a85bed158269 # Review: required -# Source-Hash: cb18554b2420e700 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gate height" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standalone refrigerant liquid line — a thin bare-copper run; Follow mode traces an existing lineset." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.gateHeight" -msgstr "Hauteur du portail" +msgid "node.liquidLine.description" +msgstr "Ligne liquide frigorifique autonome — fin tube cuivre nu ; le mode Suivre longe une liaison existante." +# Source-Hash: c34c9b36492c6e21 # Review: required -# Source-Hash: 54098b5ee574737a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gate style" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Liquid Line" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.gateStyle" -msgstr "Style de portail" +msgid "node.liquidLine.label" +msgstr "Ligne liquide" +# Source-Hash: 601aaf23ce5a9279 # Review: required -# Source-Hash: 4fc3e60be28f60d5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground clearance" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click to trace this lineset run" +#: packages/nodes/src/liquid-line/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.groundClearance" -msgstr "Garde au sol" +msgid "node.liquidLine.tool.clickToTraceThisLinesetRun" +msgstr "Cliquez pour suivre ce tronçon de liaison frigorifique" +# Source-Hash: 77df017af9260468 # Review: required -# Source-Hash: 916f2e07bf082795 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hinges and latch" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow: hover a lineset" +#: packages/nodes/src/liquid-line/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.hingesAndLatch" -msgstr "Charnières et loquet" +msgid "node.liquidLine.tool.followHoverALineset" +msgstr "Suivre : survolez une liaison frigorifique" +# Source-Hash: ff4e3bb72267859e # Review: required -# Source-Hash: 5bd2e597fbb2a2c9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hinge side" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A persistent distance, angle, area, perimeter, or volume annotation." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.hingeSide" -msgstr "Côté des charnières" +msgid "node.measurement.description" +msgstr "Annotation persistante de distance, d’angle, de surface, de périmètre ou de volume." +# Source-Hash: ec3567fd058bab7c # Review: required -# Source-Hash: 8fec7e969045a8e7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Horizontal boards" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Measurement" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.horizontalBoards" -msgstr "Lames horizontales" +msgid "node.measurement.label" +msgstr "Mesure" +# Source-Hash: d71b38e990539364 # Review: required -# Source-Hash: f4addad87cc4223e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Infill spacing" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{kind} {number}" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.infillSpacing" -msgstr "Espacement du remplissage" +msgid "node.numberedName" +msgstr "{kind} {number}" +# Source-Hash: 09865d8781ef8699 # Review: required -# Source-Hash: cdec08b292742b20 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Jamb posts" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Currently {value}" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/roof/panel.tsx +#: packages/nodes/src/stair/panel.tsx +#: packages/nodes/src/wall/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.jambPosts" -msgstr "Poteaux de jambage" +msgid "node.panel.currently" +msgstr "Actuellement {value}" + +# Source-Hash: 7764b50334e9f71d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV joint — elbow bend, 45° wye, or sanitary tee." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.pipeFitting.description" +msgstr "Raccord d’évacuation — coude, culotte à 45° ou té sanitaire." +# Source-Hash: c040baa6ed4c7aa5 # Review: required -# Source-Hash: ef88410453ee7414 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Keep the opening inside the fence and clear of other gates or passages." -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pipe Fitting" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.keepTheOpeningInsideTheFence" -msgstr "Gardez l'ouverture dans la clôture et à l'écart des autres portails ou passages." +msgid "node.pipeFitting.label" +msgstr "Raccord de tuyau" +# Source-Hash: dd86efcab72fc5c7 # Review: required -# Source-Hash: 67cd0171b226fedb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Leaf thickness" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Axis" +#: packages/nodes/src/pipe-fitting/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.leafThickness" -msgstr "Épaisseur du vantail" +msgid "node.pipeFitting.tool.axis" +msgstr "Axe" +# Source-Hash: 5232a826549f915e # Review: required -# Source-Hash: c390ba248e629b9e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Leaves" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "⌥ axis" +#: packages/nodes/src/pipe-fitting/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.leaves" -msgstr "Vantaux" +msgid "node.pipeFitting.tool.axis2" +msgstr "⌥ axe" +# Source-Hash: 8fb180251a321cef # Review: required -# Source-Hash: d7bb934589475512 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left leaf proportion" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/pipe-fitting/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.leftLeafProportion" -msgstr "Proportion du vantail gauche" +msgid "node.pipeFitting.tool.rTRotate" +msgstr "R/T pivoter" +# Source-Hash: a0bb4762aa66fa3e # Review: required -# Source-Hash: aa9fe0ebace8957d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match fence height" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drain / waste / vent pipe run — draw level or toggle a ¼″ per foot fall with S." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.matchFenceHeight" -msgstr "Hauteur de la clôture" +msgid "node.pipeSegment.description" +msgstr "Canalisation d’évacuation et de ventilation — tracez à plat ou basculez une pente de ¼″ par pied avec S." +# Source-Hash: 457155657704f7cc # Review: required -# Source-Hash: c15c1af69ec5c1eb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match fence style" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV Pipe" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.matchFenceStyle" -msgstr "Assortir au style de clôture" +msgid "node.pipeSegment.label" +msgstr "Tuyau d’évacuation" +# Source-Hash: 6d0cdd14d0675e05 # Review: required -# Source-Hash: 51b7ab6a0a78d90a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening angle" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV P-trap — water seal on the waste line. The trap arm runs to the vent." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.openingAngle" -msgstr "Angle d’ouverture" +msgid "node.pipeTrap.description" +msgstr "Siphon en P — garde d’eau sur l’évacuation. Le bras du siphon rejoint la ventilation." +# Source-Hash: b778a315e82065a0 # Review: required -# Source-Hash: d2e20300c07aa722 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening width" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trap" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.openingWidth" -msgstr "Largeur d'ouverture" +msgid "node.pipeTrap.label" +msgstr "Siphon" +# Source-Hash: 73078bc0f5d686fa # Review: required -# Source-Hash: 6b108fb1d0eb8f9d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open rails" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{diameter}\" Trap" +#: packages/nodes/src/pipe-trap/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.openRails" -msgstr "Lisses ajourées" +msgid "node.pipeTrap.tool.diameterTrap" +msgstr "Siphon {diameter}\"" +# Source-Hash: 8fb180251a321cef # Review: required -# Source-Hash: d500c4b7827d3390 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cross" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/pipe-trap/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.cross" -msgstr "Croix" +msgid "node.pipeTrap.tool.rTRotate" +msgstr "R/T pivoter" +# Source-Hash: 0efe82436b915f6d # Review: required -# Source-Hash: 7420c0d2caee1c22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diagonal" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Experimental editable recipe" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.option.diagonal" -msgstr "Diagonale" +msgid "node.proceduralItem.description" +msgstr "Recette modifiable expérimentale" +# Source-Hash: c8bbcc888cce7b8a # Review: required -# Source-Hash: 7308869944020839 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double gate" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Procedural item" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.option.doubleGate" -msgstr "Portail double" +msgid "node.proceduralItem.label" +msgstr "Élément procédural" +# Source-Hash: 356aa0ed69cb8ec5 # Review: required -# Source-Hash: 1f4ad5ad3e1be222 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inward" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ventilation strip running along the ridge of a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.option.inward" -msgstr "Vers l’intérieur" +msgid "node.ridgeVent.description" +msgstr "Bande de ventilation le long du faîtage d’un pan de toit." +# Source-Hash: 54b74080f33c8c4e # Review: required -# Source-Hash: f365c6b6dd9ebab9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge Vent" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.option.left" -msgstr "Gauche" +msgid "node.ridgeVent.label" +msgstr "Ventilation de faîtage" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: f2953d2931e36d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.none" -msgstr "Aucun" +msgid "node.ridgeVent.panel.actions" +msgstr "Actions" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: ccd8f06b8f8d27c9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Outward" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.outward" -msgstr "Vers l’extérieur" +msgid "node.ridgeVent.panel.delete" +msgstr "Supprimer" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: b34d5ee0f218221d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.right" -msgstr "Droite" +msgid "node.ridgeVent.panel.dimensions" +msgstr "Dimensions" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: d327097d9ac1099f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single gate" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.singleGate" -msgstr "Portail simple" +msgid "node.ridgeVent.panel.duplicate" +msgstr "Dupliquer" +# Source-Hash: 18bf817325c1c537 # Review: required -# Source-Hash: 9295ddc2805b21e2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End Caps" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.picket" -msgstr "Piquets" +msgid "node.ridgeVent.panel.endCaps" +msgstr "Embouts d'extrémité" -# Review: required -# Source-Hash: 8dd5999b235f60ab -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post height" -#: packages/nodes/src/fence-feature/inspector.tsx +# Source-Hash: 466f817a0102d4a5 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flanged" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.postHeight" -msgstr "Hauteur des poteaux" +msgid "node.ridgeVent.panel.flanged" +msgstr "À bride" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 90bcd7a8123ec343 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove gate" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.removeGate" -msgstr "Supprimer le portail" +msgid "node.ridgeVent.panel.height" +msgstr "Hauteur" +# Source-Hash: 643687bc3adaac76 # Review: required -# Source-Hash: 7e3505710613543f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove opening" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.removeOpening" -msgstr "Supprimer l'ouverture" +msgid "node.ridgeVent.panel.length" +msgstr "Longueur" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: af6f8885fe0fa4e9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid privacy" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.solidPrivacy" -msgstr "Occultant plein" +msgid "node.ridgeVent.panel.move" +msgstr "Déplacer" +# Source-Hash: 3e52f04f92e08070 # Review: required -# Source-Hash: 1a7048255c3bdfcb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swing direction" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.swingDirection" -msgstr "Sens d'ouverture" +msgid "node.ridgeVent.panel.open" +msgstr "Ouvrir" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: eba3df14a2de0812 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical slats" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.verticalSlats" -msgstr "Lames verticales" +msgid "node.ridgeVent.panel.position" +msgstr "Position" -# Source-Hash: df61821ed00852d8 +# Source-Hash: 54b74080f33c8c4e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A gate hosted by a fence." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge Vent" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceGate.description" -msgstr "Portail porté par une clôture." +msgid "node.ridgeVent.panel.ridgeVent" +msgstr "Ventilation de faîtage" -# Source-Hash: 4a479aa23542d766 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gate" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceGate.label" -msgstr "Portail" +msgid "node.ridgeVent.panel.rotation" +msgstr "Rotation" -# Source-Hash: 8f9c927d79796c26 +# Source-Hash: e9046e9823b400a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "An intentional opening in a fence." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingled" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceOpening.description" -msgstr "Ouverture volontaire dans une clôture." +msgid "node.ridgeVent.panel.shingled" +msgstr "En bardeaux" -# Source-Hash: ab67bb47e647d594 +# Source-Hash: d998c212030bc7c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open Passage" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceOpening.label" -msgstr "Passage" +msgid "node.ridgeVent.panel.standard" +msgstr "Standard" -# Source-Hash: dc3adf0c2d50dba6 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor opening" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.floorOpening.label" -msgstr "Trémie" +msgid "node.ridgeVent.panel.style" +msgstr "Style" -# Source-Hash: 2f4fac2b1d39fdb1 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A measurement / reference annotation (linear, area, or arc)." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.guide.description" -msgstr "Annotation de mesure ou de référence (linéaire, surface ou arc)." +msgid "node.ridgeVent.panel.width" +msgstr "Largeur" -# Source-Hash: 1344ea2602e3aa9e +# Source-Hash: c6d3976b4eb80586 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guide" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arch bays" +#: packages/nodes/src/roof/barrel-panel.tsx #, fuzzy -msgid "node.guide.label" -msgstr "Guide" +msgid "node.roof.barrelPanel.archBays" +msgstr "Travées en arc" -# Source-Hash: 5402d634f40b2f97 +# Source-Hash: 1cfdd5affedf153c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rain-water channel running along the eave of a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Barrel arch" +#: packages/nodes/src/roof/barrel-panel.tsx #, fuzzy -msgid "node.gutter.description" -msgstr "Chéneau d’eau pluviale le long de l’égout d’un pan de toit." +msgid "node.roof.barrelPanel.barrelArch" +msgstr "Voûte en berceau" +# Source-Hash: b3e8929750d18f7b # Review: required -# Source-Hash: fc7d4ecf973db135 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Downspout" -#: packages/nodes/src/gutter/downspouts-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat panes follow a circular arch. Rise is measured from the eaves." +#: packages/nodes/src/roof/barrel-panel.tsx #, fuzzy -msgid "node.gutter.downspoutsPanel.addDownspout" -msgstr "Ajouter une descente" +msgid "node.roof.barrelPanel.flatPanesFollowACircularArch" +msgstr "Les vitrages plats suivent un arc circulaire. La flèche se mesure depuis l’égout." +# Source-Hash: fe8c5b735495eb00 # Review: required -# Source-Hash: 9b9929bac2c39bca -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspout {number}" -#: packages/nodes/src/gutter/downspouts-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rise" +#: packages/nodes/src/roof/barrel-panel.tsx #, fuzzy -msgid "node.gutter.downspoutsPanel.downspoutNumber" -msgstr "Descente {number}" +msgid "node.roof.barrelPanel.rise" +msgstr "Hauteur" +# Source-Hash: 6afeec8de7ed618d # Review: required -# Source-Hash: fc34d45725838141 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspouts" -#: packages/nodes/src/gutter/downspouts-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A pitched / hip / gable roof composed of one or more segments." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.gutter.downspoutsPanel.downspouts" -msgstr "Descentes d'eau" +msgid "node.roof.description" +msgstr "Toit en pente, en croupe ou à deux pans composé d’un ou plusieurs pans." +# Source-Hash: b5be04471fd3fb7a # Review: required -# Source-Hash: ac329c74056f0616 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove downspout" -#: packages/nodes/src/gutter/downspouts-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arch bay {number}" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.gutter.downspoutsPanel.removeDownspout" -msgstr "Supprimer la descente" +msgid "node.roof.glazing.face.archBay" +msgstr "Travée en arc {number}" -# Source-Hash: 14ba981da3627ae2 +# Source-Hash: 93381b9024a75a99 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gutter" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back slope" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.gutter.label" -msgstr "Gouttière" +msgid "node.roof.glazing.face.back" +msgstr "Versant arrière" -# Source-Hash: 387082cd5f118bed +# Source-Hash: 08b00107b635e11d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Manual" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left end" +#: packages/nodes/src/roof/glazing-panel-editor.tsx +#, fuzzy +msgid "node.roof.glazing.face.endLeft" +msgstr "Extrémité gauche" + +# Source-Hash: 821734ea5d17a693 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right end" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.hole.manual" -msgstr "Manuel" +msgid "node.roof.glazing.face.endRight" +msgstr "Extrémité droite" -# Source-Hash: fffde6fa82e65ffc +# Source-Hash: 40c9ef62055067e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hole {number} (Editing)" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front slope" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.holeEditing" -msgstr "Trémie {number} (en cours de modification)" +msgid "node.roof.glazing.face.front" +msgstr "Versant avant" -# Source-Hash: 0fe446c72451e4a5 +# Source-Hash: 1a88da71d5e5f0d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hole {number}" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed slope" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.holeNumber" -msgstr "Trémie {number}" +msgid "node.roof.glazing.face.slope" +msgstr "Versant du monopente" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: fd26f8df9d087c6b +# Source-Hash: 3bcc542295b4c61e # Review: required -# English: "{area} m² · {count, plural, one {{points} pt} other {{points} pts}} · {source}" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Alignment" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.holeSummary" -msgstr "{area} m² · {count, plural, one {{points} pt} many {{points} pts} other {{points} pts}} · {source}" +msgid "node.roof.glazingControls.alignment" +msgstr "Alignement" -# Source-Hash: 50e9252d30f3fb4d +# Source-Hash: 5211341ed18f33f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Furnace, air handler, or condenser — duct runs connect to its supply/return collars." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.hvacEquipment.description" -msgstr "Chaudière, centrale de traitement d’air ou condenseur — les gaines se raccordent à ses collets de soufflage et de reprise." +msgid "node.roof.glazingControls.center" +msgstr "Centre" -# Source-Hash: 3bf1c1a8dbb93743 +# Source-Hash: 512e47607a37af46 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "HVAC Unit" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a layout to edit the grid." +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.hvacEquipment.label" -msgstr "Unité CVC" +msgid "node.roof.glazingControls.chooseALayoutToEditThe" +msgstr "Choisissez une disposition pour modifier la trame." +# Source-Hash: 65b1cbba3b92c5b2 # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/hvac-equipment/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Empty" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.hvacEquipment.tool.rTRotate" -msgstr "R/T pivoter" +msgid "node.roof.glazingControls.empty" +msgstr "Vide" -# Source-Hash: f24a1089d9256460 +# Source-Hash: 135874d189176d13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Geometry preserved from an imported model when no native Pascal shape exists." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.importedMesh.description" -msgstr "Géométrie conservée d’un modèle importé lorsqu’aucune forme Pascal native n’existe." +msgid "node.roof.glazingControls.end" +msgstr "Fin" -# Source-Hash: 9f9d11f287f722d7 +# Source-Hash: 4fb65101d0b1a222 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Imported Mesh" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fixed spacing" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.importedMesh.label" -msgstr "Maillage importé" +msgid "node.roof.glazingControls.fixedSpacing" +msgstr "Espacement fixe" -# Source-Hash: 9cce89f94c673821 +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Couldn't rebuild with these values." -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.couldnTRebuildWithTheseValues" -msgstr "Impossible de reconstruire avec ces valeurs." +msgid "node.roof.glazingControls.glass" +msgstr "Vitrage" -# Source-Hash: 373b929318436fe3 +# Source-Hash: 54800340a0eeab23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Parameters" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layout" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.parameters" -msgstr "Paramètres" +msgid "node.roof.glazingControls.layout" +msgstr "Disposition" -# Source-Hash: 558cb886dbe0babe +# Source-Hash: 321ca5101ab61db7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rebuilding…" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Maximum spacing" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.rebuilding" -msgstr "Reconstruction…" +msgid "node.roof.glazingControls.maximumSpacing" +msgstr "Espacement maximal" -# Source-Hash: a094c99dc8ad29a3 +# Source-Hash: d10743fce478d9f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rebuilding in Blender…" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Max spacing" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.rebuildingInBlender" -msgstr "Reconstruction dans Blender…" +msgid "node.roof.glazingControls.maxSpacing" +msgstr "Espacement max." -# Source-Hash: 1778f93ee143cd95 +# Source-Hash: 37d9f63758abdb67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset {param}" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mixed" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.resetParam" -msgstr "Réinitialiser {param}" +msgid "node.roof.glazingControls.mixed" +msgstr "Mixte" -# Source-Hash: 5a28cf5f2402dd7a +# Source-Hash: b91302bf741c9fd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset parameters" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel count" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.resetParameters" -msgstr "Réinitialiser les paramètres" +msgid "node.roof.glazingControls.panelCount" +msgstr "Nombre de panneaux" -# Source-Hash: 6eb8025c60d6d3ca +# Source-Hash: 6ce059aee1386f72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset to default" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panels" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.resetToDefault" -msgstr "Rétablir la valeur par défaut" +msgid "node.roof.glazingControls.panels" +msgstr "Panneaux" -# Source-Hash: 63f79b3c467177b3 +# Source-Hash: ef3e765e692faf4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A catalog-backed item (furniture, fixtures, decorations)." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.description" -msgstr "Élément issu du catalogue (mobilier, équipements, décoration)." +msgid "node.roof.glazingControls.solid" +msgstr "Plein" -# Source-Hash: 2743a0e9d2743807 +# Source-Hash: e4698e83d02beb6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Item" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spacing" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.label" -msgstr "Élément" +msgid "node.roof.glazingControls.spacing" +msgstr "Espacement" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 0a26a1e61c825660 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.actions" -msgstr "Actions" +msgid "node.roof.glazingControls.start" +msgstr "Début" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 095237e9e2df4d9c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{title} alignment" +#: packages/nodes/src/roof/glazing-controls.tsx +#, fuzzy +msgid "node.roof.glazingControls.titleAlignment" +msgstr "Alignement {title}" + +# Source-Hash: c98a4e6b28f05e0f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Changes apply to all {length} roof segments." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.delete" -msgstr "Supprimer" +msgid "node.roof.glazingPanel.changesApplyToAllLengthRoof" +msgstr "Les modifications s’appliquent aux {length} segments de toit." -# Source-Hash: 12df69f42beb0643 +# Source-Hash: c5d2ff7fda4787cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose one roof system to edit settings for all selected segments." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.dimensions" -msgstr "Dimensions" +msgid "node.roof.glazingPanel.chooseOneRoofSystemToEdit" +msgstr "Choisissez un système de toiture pour modifier les réglages de tous les segments sélectionnés." -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 80e07a119b63187c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close the roof ends" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.duplicate" -msgstr "Dupliquer" +msgid "node.roof.glazingPanel.closeTheRoofEnds" +msgstr "Fermer les extrémités du toit" -# Source-Hash: 6e68b62d2aa611a4 +# Source-Hash: e28dd27d54aaa7ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Info" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default panel infill" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.info" -msgstr "Info" +msgid "node.roof.glazingPanel.defaultPanelInfill" +msgstr "Remplissage par défaut des panneaux" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 134d33e2465937e7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divides each roof face into columns." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.move" -msgstr "Déplacer" +msgid "node.roof.glazingPanel.dividesEachRoofFaceIntoColumns" +msgstr "Divise chaque versant en colonnes." -# Source-Hash: 28fe6e9deddde6e8 +# Source-Hash: 896a6e4da3357c39 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "pos" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divides the length of each arch bay into columns." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.pos" -msgstr "pos" +msgid "node.roof.glazingPanel.dividesTheLengthOfEachArch" +msgstr "Divise la longueur de chaque travée en arc en colonnes." -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: be9c810d28d1feb9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End infill fills the space above the walls. Edit room walls and ceilings separately." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.position" -msgstr "Position" +msgid "node.roof.glazingPanel.endInfillFillsTheSpaceAbove" +msgstr "Le remplissage d’about comble l’espace au-dessus des murs. Modifiez séparément les murs et plafonds des pièces." -# Source-Hash: 5f433581c8f404fa +# Source-Hash: 0b8b27dbc57cca44 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "rot" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame color" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.rot" -msgstr "rot" +msgid "node.roof.glazingPanel.frameColor" +msgstr "Couleur du cadre" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: fd413477f1a9e5ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame depth" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.rotation" -msgstr "Rotation" +msgid "node.roof.glazingPanel.frameDepth" +msgstr "Profondeur du cadre" -# Source-Hash: 8210f376c0d29acc +# Source-Hash: 3519d91b7bda18a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scale" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame width" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.scale" -msgstr "Échelle" +msgid "node.roof.glazingPanel.frameWidth" +msgstr "Largeur du cadre" -# Source-Hash: 58fee802997c811c +# Source-Hash: c7e72beff9fe4b37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "scale" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framing" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.scale2" -msgstr "échelle" +msgid "node.roof.glazingPanel.framing" +msgstr "Ossature" -# Source-Hash: b0d264950558d50e +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Uniform Scale" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.uniformScale" -msgstr "Échelle uniforme" +msgid "node.roof.glazingPanel.glass" +msgstr "Vitrage" -# Source-Hash: 4b8d7e52013d1691 +# Source-Hash: 9c38875c310547ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "XYZ" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass tint" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.xyz" -msgstr "XYZ" +msgid "node.roof.glazingPanel.glassTint" +msgstr "Teinte du vitrage" -# Source-Hash: a9e2d7b215696e2a +# Source-Hash: dd330a94b3f7a65a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "An attached mono-pitch or freestanding mono, gable, or butterfly canopy with managed structure and drainage." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glazed" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.leanToExtension.description" -msgstr "Auvent adossé à un pan ou autoportant (un pan, deux pans ou papillon) avec structure et évacuation gérées." +msgid "node.roof.glazingPanel.glazed" +msgstr "Vitré" -# Source-Hash: 8503bedfbafde9a3 +# Source-Hash: e6be52df9197243a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Canopy" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glazing is available for gable, straight shed, and barrel roofs." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.leanToExtension.label" -msgstr "Auvent" +msgid "node.roof.glazingPanel.glazingIsAvailableForGableStraight" +msgstr "Le vitrage est disponible pour les toits à pignon, monopentes droits et voûtés." -# Source-Hash: 45673462f914d3df +# Source-Hash: a4e7ef2e31d7220b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A single floor of a building, holding walls / slabs / ceilings / items." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid across the roof" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.level.description" -msgstr "Un étage d’un bâtiment, avec murs, dalles, plafonds et éléments." +msgid "node.roof.glazingPanel.gridAcrossTheRoof" +msgstr "Trame en travers du toit" -# Source-Hash: 0608743fc1736d86 +# Source-Hash: 2f28a3b33fccf56b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid along the length" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.level.label" -msgstr "Niveau" +msgid "node.roof.glazingPanel.gridAlongTheLength" +msgstr "Trame dans la longueur" -# Source-Hash: 156bdee8fee5bec6 +# Source-Hash: 1f701893dbf9d72b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Refrigerant lineset — copper suction + liquid pair joining a condenser to the indoor coil." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid along the slope" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.lineset.description" -msgstr "Liaison frigorifique — paire cuivre aspiration + liquide reliant le condenseur à la batterie intérieure." +msgid "node.roof.glazingPanel.gridAlongTheSlope" +msgstr "Trame dans la pente" -# Source-Hash: 362b03eba9d8234c +# Source-Hash: 20c8dfbadda20e3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lineset" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid within each arch bay" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.lineset.label" -msgstr "Liaison frigorifique" +msgid "node.roof.glazingPanel.gridWithinEachArchBay" +msgstr "Trame dans chaque travée en arc" -# Source-Hash: 2bd4a85bed158269 +# Source-Hash: 7c339a5fae55681d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standalone refrigerant liquid line — a thin bare-copper run; Follow mode traces an existing lineset." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Infill" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.liquidLine.description" -msgstr "Ligne liquide frigorifique autonome — fin tube cuivre nu ; le mode Suivre longe une liaison existante." +msgid "node.roof.glazingPanel.infill" +msgstr "Remplissage" -# Source-Hash: c34c9b36492c6e21 +# Source-Hash: 1c0b8a5503c5daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Liquid Line" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opacity" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.liquidLine.label" -msgstr "Ligne liquide" +msgid "node.roof.glazingPanel.opacity" +msgstr "Opacité" +# Source-Hash: 4d412746658f2faf # Review: required -# Source-Hash: 601aaf23ce5a9279 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click to trace this lineset run" -#: packages/nodes/src/liquid-line/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pane thickness" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.liquidLine.tool.clickToTraceThisLinesetRun" -msgstr "Cliquez pour suivre ce tronçon de liaison frigorifique" +msgid "node.roof.glazingPanel.paneThickness" +msgstr "Épaisseur du carreau" +# Source-Hash: 570136e723cb7d99 # Review: required -# Source-Hash: 77df017af9260468 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follow: hover a lineset" -#: packages/nodes/src/liquid-line/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof system" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.liquidLine.tool.followHoverALineset" -msgstr "Suivre : survolez une liaison frigorifique" +msgid "node.roof.glazingPanel.roofSystem" +msgstr "Système de toiture" -# Source-Hash: ff4e3bb72267859e +# Source-Hash: a6a7a36d982b4911 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A persistent distance, angle, area, perimeter, or volume annotation." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roughness" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.measurement.description" -msgstr "Annotation persistante de distance, d’angle, de surface, de périmètre ou de volume." +msgid "node.roof.glazingPanel.roughness" +msgstr "Rugosité" -# Source-Hash: ec3567fd058bab7c +# Source-Hash: 2fa6fbeda5d45949 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Measurement" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spacing is measured on the slope, not its horizontal projection." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.measurement.label" -msgstr "Mesure" +msgid "node.roof.glazingPanel.spacingIsMeasuredOnTheSlope" +msgstr "L’espacement se mesure sur la pente, pas sur sa projection horizontale." -# Source-Hash: d71b38e990539364 +# Source-Hash: d998c212030bc7c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{kind} {number}" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.numberedName" -msgstr "{kind} {number}" +msgid "node.roof.glazingPanel.standard" +msgstr "Standard" -# Source-Hash: 09865d8781ef8699 +# Source-Hash: efbe1c4facf561f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Currently {value}" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/roof/panel.tsx -#: packages/nodes/src/stair/panel.tsx -#: packages/nodes/src/wall/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Subdivides each flat arch bay. Arch bays controls the divisions around the curve." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.panel.currently" -msgstr "Actuellement {value}" +msgid "node.roof.glazingPanel.subdividesEachFlatArchBayArch" +msgstr "Subdivise chaque travée plane en arc. Le nombre de travées règle les divisions le long de la courbe." -# Source-Hash: 7764b50334e9f71d +# Source-Hash: 1497eac9e4f63016 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV joint — elbow bend, 45° wye, or sanitary tee." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a panel to override its default infill." +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeFitting.description" -msgstr "Raccord d’évacuation — coude, culotte à 45° ou té sanitaire." +msgid "node.roof.glazingPanelEditor.chooseAPanelToOverrideIts" +msgstr "Choisissez un panneau pour remplacer son remplissage par défaut." -# Source-Hash: c040baa6ed4c7aa5 +# Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pipe Fitting" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Column" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeFitting.label" -msgstr "Raccord de tuyau" +msgid "node.roof.glazingPanelEditor.column2" +msgstr "Poteau" +# Source-Hash: 9e9715d52410c86f # Review: required -# Source-Hash: dd86efcab72fc5c7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Axis" -#: packages/nodes/src/pipe-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeFitting.tool.axis" -msgstr "Axe" +msgid "node.roof.glazingPanelEditor.custom" +msgstr "Personnalisé" +# Source-Hash: 4ca0e0e73229540c # Review: required -# Source-Hash: 5232a826549f915e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "⌥ axis" -#: packages/nodes/src/pipe-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeFitting.tool.axis2" -msgstr "⌥ axe" +msgid "node.roof.glazingPanelEditor.default" +msgstr "Par défaut" +# Source-Hash: 9ef92ad8ae49ed72 # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/pipe-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{columns, plural, one {{columnCount} column} other {{columnCount} columns}} · {rows, plural, one {{rowCount} row} other {{rowCount} rows}}" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeFitting.tool.rTRotate" -msgstr "R/T pivoter" +msgid "node.roof.glazingPanelEditor.grid" +msgstr "{columns, plural, one {{columnCount} colonne} many {{columnCount} colonnes} other {{columnCount} colonnes}} · {rows, plural, one {{rowCount} rangée} many {{rowCount} rangées} other {{rowCount} rangées}}" -# Source-Hash: a0bb4762aa66fa3e +# Source-Hash: 11624abbcfdd5506 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drain / waste / vent pipe run — draw level or toggle a ¼″ per foot fall with S." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Individual panels" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeSegment.description" -msgstr "Canalisation d’évacuation et de ventilation — tracez à plat ou basculez une pente de ¼″ par pied avec S." +msgid "node.roof.glazingPanelEditor.individualPanels" +msgstr "Panneaux individuels" -# Source-Hash: 457155657704f7cc +# Source-Hash: 3a019ce58d021431 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV Pipe" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel infill" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeSegment.label" -msgstr "Tuyau d’évacuation" +msgid "node.roof.glazingPanelEditor.panelInfill" +msgstr "Remplissage du panneau" -# Source-Hash: 6d0cdd14d0675e05 +# Source-Hash: 6eb8025c60d6d3ca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV P-trap — water seal on the waste line. The trap arm runs to the vent." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset to default" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeTrap.description" -msgstr "Siphon en P — garde d’eau sur l’évacuation. Le bras du siphon rejoint la ventilation." +msgid "node.roof.glazingPanelEditor.resetToDefault" +msgstr "Rétablir la valeur par défaut" -# Source-Hash: b778a315e82065a0 +# Source-Hash: 6fba44f2bfd8af8e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trap" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof face" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeTrap.label" -msgstr "Siphon" +msgid "node.roof.glazingPanelEditor.roofFace" +msgstr "Versant" +# Source-Hash: 03a22f6df69c47d3 # Review: required -# Source-Hash: 73078bc0f5d686fa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{diameter}\" Trap" -#: packages/nodes/src/pipe-trap/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Row" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeTrap.tool.diameterTrap" -msgstr "Siphon {diameter}\"" +msgid "node.roof.glazingPanelEditor.row2" +msgstr "Rangée" +# Source-Hash: 6c2cc2d9cd778998 # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/pipe-trap/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selected panel infill" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeTrap.tool.rTRotate" -msgstr "R/T pivoter" +msgid "node.roof.glazingPanelEditor.selectedPanelInfill" +msgstr "Remplissage du panneau sélectionné" -# Source-Hash: 0efe82436b915f6d +# Source-Hash: f5f730969df63d1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Experimental editable recipe" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.proceduralItem.description" -msgstr "Recette modifiable expérimentale" +msgid "node.roof.label" +msgstr "Toit" -# Source-Hash: c8bbcc888cce7b8a -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Procedural item" -#: packages/nodes/src/i18n/definition-messages.ts +# Source-Hash: aa6d82bdb3cc1d9a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.proceduralItem.label" -msgstr "Élément procédural" +msgid "node.roof.panel.actions" +msgstr "Actions" -# Source-Hash: 356aa0ed69cb8ec5 +# Source-Hash: d60471ce3cd45348 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ventilation strip running along the ridge of a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Chimney" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.description" -msgstr "Bande de ventilation le long du faîtage d’un pan de toit." +msgid "node.roof.panel.addChimney" +msgstr "Ajouter une cheminée" -# Source-Hash: 54b74080f33c8c4e +# Source-Hash: 1ca6a1cf9cc6e3ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ridge Vent" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Cupola" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.label" -msgstr "Ventilation de faîtage" +msgid "node.roof.panel.addCupola" +msgstr "Ajouter une coupole" +# Source-Hash: 94dea147eeaac52b # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Dormer" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.actions" -msgstr "Actions" +msgid "node.roof.panel.addDormer" +msgstr "Ajouter une lucarne" +# Source-Hash: 5679acdd64484726 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Eyebrow Vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.delete" -msgstr "Supprimer" +msgid "node.roof.panel.addEyebrowVent" +msgstr "Ajouter une chatière en œil-de-bœuf" +# Source-Hash: 25a141dc0d7c4b44 # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Gutter" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.dimensions" -msgstr "Dimensions" +msgid "node.roof.panel.addGutter" +msgstr "Ajouter une gouttière" +# Source-Hash: 7230bdc8a2252626 # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Skylight" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.duplicate" -msgstr "Dupliquer" +msgid "node.roof.panel.addSkylight" +msgstr "Ajouter un puits de lumière" +# Source-Hash: 0f220e2602b7ff24 # Review: required -# Source-Hash: 18bf817325c1c537 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End Caps" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Solar Panel" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.endCaps" -msgstr "Embouts d'extrémité" +msgid "node.roof.panel.addSolarPanel" +msgstr "Ajouter un panneau solaire" +# Source-Hash: 4d83a2e5a4d9e6b4 # Review: required -# Source-Hash: 466f817a0102d4a5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flanged" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.flanged" -msgstr "À bride" +msgid "node.roof.panel.addVent" +msgstr "Ajouter une ventilation" +# Source-Hash: e9a89a5e4ac8cd61 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.height" -msgstr "Hauteur" +msgid "node.roof.panel.box" +msgstr "Boîte" +# Source-Hash: 3bf078fe2560daca # Review: required -# Source-Hash: 643687bc3adaac76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "box vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.length" -msgstr "Longueur" +msgid "node.roof.panel.boxVent" +msgstr "ventilation caisson" +# Source-Hash: 4986740251121471 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "chimney" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.move" -msgstr "Déplacer" +msgid "node.roof.panel.chimney" +msgstr "cheminée" +# Source-Hash: 9e9715d52410c86f # Review: required -# Source-Hash: 3e52f04f92e08070 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.open" -msgstr "Ouvrir" +msgid "node.roof.panel.custom" +msgstr "Personnalisé" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.position" -msgstr "Position" +msgid "node.roof.panel.delete" +msgstr "Supprimer" +# Source-Hash: 5169968a4b0c1840 # Review: required -# Source-Hash: 54b74080f33c8c4e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ridge Vent" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "dormer" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.ridgeVent" -msgstr "Ventilation de faîtage" +msgid "node.roof.panel.dormer" +msgstr "lucarne" +# Source-Hash: 72e51c6e5e9c6c26 # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw Segment" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.rotation" -msgstr "Rotation" +msgid "node.roof.panel.drawSegment" +msgstr "Dessiner un segment" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: e9046e9823b400a0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingled" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.shingled" -msgstr "En bardeaux" +msgid "node.roof.panel.duplicate" +msgstr "Dupliquer" +# Source-Hash: 5c99a67253bfc02a # Review: required -# Source-Hash: d998c212030bc7c2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eave overhang" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.standard" -msgstr "Standard" +msgid "node.roof.panel.eaveOverhang" +msgstr "Débord d’égout" +# Source-Hash: 34756c5ea718ccb5 # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eaves" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.style" -msgstr "Style" +msgid "node.roof.panel.eaves" +msgstr "Avant-toits" +# Source-Hash: 7c4196b9e791c195 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elements" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.width" -msgstr "Largeur" +msgid "node.roof.panel.elements" +msgstr "Éléments" -# Source-Hash: c6d3976b4eb80586 +# Source-Hash: 6b8ba49aa355fe87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arch bays" -#: packages/nodes/src/roof/barrel-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows walls" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.barrelPanel.archBays" -msgstr "Travées en arc" +msgid "node.roof.panel.followsWalls" +msgstr "Suit les murs" -# Source-Hash: 1cfdd5affedf153c +# Source-Hash: dbd062efc7f4fd7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Barrel arch" -#: packages/nodes/src/roof/barrel-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable overhang" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.barrelPanel.barrelArch" -msgstr "Voûte en berceau" +msgid "node.roof.panel.gableOverhang" +msgstr "Débord de rive" -# Source-Hash: b3e8929750d18f7b +# Source-Hash: 23b434461c990711 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat panes follow a circular arch. Rise is measured from the eaves." -#: packages/nodes/src/roof/barrel-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "gutter" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.barrelPanel.flatPanesFollowACircularArch" -msgstr "Les vitrages plats suivent un arc circulaire. La flèche se mesure depuis l’égout." +msgid "node.roof.panel.gutter" +msgstr "gouttière" -# Source-Hash: fe8c5b735495eb00 +# Source-Hash: 0608743fc1736d86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rise" -#: packages/nodes/src/roof/barrel-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.barrelPanel.rise" -msgstr "Hauteur" +msgid "node.roof.panel.level" +msgstr "Niveau" -# Source-Hash: 6afeec8de7ed618d +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A pitched / hip / gable roof composed of one or more segments." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.description" -msgstr "Toit en pente, en croupe ou à deux pans composé d’un ou plusieurs pans." +msgid "node.roof.panel.move" +msgstr "Déplacer" -# Source-Hash: b5be04471fd3fb7a +# Source-Hash: 39661f4827b0f435 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arch bay {number}" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move to {level}" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.archBay" -msgstr "Travée en arc {number}" +msgid "node.roof.panel.moveToLevel" +msgstr "Déplacer vers {level}" -# Source-Hash: 93381b9024a75a99 +# Source-Hash: c534093ff560a9f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back slope" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move to the roof level" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.back" -msgstr "Versant arrière" +msgid "node.roof.panel.moveToTheRoofLevel" +msgstr "Déplacer vers le niveau de toiture" -# Source-Hash: 08b00107b635e11d +# Source-Hash: 0939fad1cb1831f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left end" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On {storey} with its walls, so it hides that floor's plan in solo and exploded views.{roofs, plural, =0 {} =1 {} other { The floor's {roofCount} roofs move together.}}" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.endLeft" -msgstr "Extrémité gauche" +msgid "node.roof.panel.onStoreyWalls" +msgstr "Sur {storey} avec ses murs : il masque donc le plan de cet étage dans les vues isolée et éclatée.{roofs, plural, =0 {} =1 {} one {} many { Les {roofCount} toits de l’étage se déplacent ensemble.} other { Les {roofCount} toits de l’étage se déplacent ensemble.}}" -# Source-Hash: 821734ea5d17a693 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right end" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.endRight" -msgstr "Extrémité droite" +msgid "node.roof.panel.position" +msgstr "Position" -# Source-Hash: 40c9ef62055067e1 +# Source-Hash: e6ddc8a624465793 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front slope" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.front" -msgstr "Versant avant" +msgid "node.roof.panel.ridge" +msgstr "Faîtage" -# Source-Hash: 1a88da71d5e5f0d6 +# Source-Hash: 83112cbc205e9972 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed slope" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "ridge vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.slope" -msgstr "Versant du monopente" +msgid "node.roof.panel.ridgeVent" +msgstr "faîtière ventilée" -# Source-Hash: 3bcc542295b4c61e +# Source-Hash: f5f730969df63d1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Alignment" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.alignment" -msgstr "Alignement" +msgid "node.roof.panel.roof" +msgstr "Toit" -# Source-Hash: 5211341ed18f33f6 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.center" -msgstr "Centre" +msgid "node.roof.panel.rotation" +msgstr "Rotation" -# Source-Hash: 512e47607a37af46 +# Source-Hash: 505d8419cf4cc5e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a layout to edit the grid." -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segments" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.chooseALayoutToEditThe" -msgstr "Choisissez une disposition pour modifier la trame." +msgid "node.roof.panel.segments" +msgstr "Segments" -# Source-Hash: 65b1cbba3b92c5b2 +# Source-Hash: 0c084c517dbc153b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Empty" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{roofType, select, hip {Hip} gable {Gable} shed {Shed} gambrel {Gambrel} dutch {Dutch} mansard {Mansard} flat {Flat} conical {Conical} barrel {Barrel} other {Roof}}" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.empty" -msgstr "Vide" +msgid "node.roof.panel.segmentType" +msgstr "{roofType, select, hip {Croupe} gable {Pignon} shed {Monopente} gambrel {Gambrel} dutch {Demi-croupe} mansard {Mansarde} flat {Plat} conical {Conique} barrel {Voûte} other {Toit}}" -# Source-Hash: 135874d189176d13 +# Source-Hash: 0c4c82caccb4775c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "skylight" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.end" -msgstr "Fin" +msgid "node.roof.panel.skylight" +msgstr "puits de lumière" -# Source-Hash: 4fb65101d0b1a222 +# Source-Hash: b9f931508dd6ec70 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fixed spacing" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "solar panel" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.fixedSpacing" -msgstr "Espacement fixe" +msgid "node.roof.panel.solarPanel" +msgstr "panneau solaire" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: d2428b22f1757a4e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turbine" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.glass" -msgstr "Vitrage" +msgid "node.roof.panel.turbine" +msgstr "Turbine" -# Source-Hash: 54800340a0eeab23 +# Source-Hash: 86d02a3d3a3a7fa2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Layout" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "turbine vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.layout" -msgstr "Disposition" +msgid "node.roof.panel.turbineVent" +msgstr "aérateur à turbine" -# Source-Hash: 321ca5101ab61db7 +# Source-Hash: 6df330bcfcaac604 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Maximum spacing" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Apply to all planes of this roof" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.maximumSpacing" -msgstr "Espacement maximal" +msgid "node.roofSegment.buildUpSection.applyToAllPlanesOfThis" +msgstr "Appliquer à tous les pans de ce toit" -# Source-Hash: d10743fce478d9f4 +# Source-Hash: 7254a3eb47471b8a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Max spacing" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Architectural shingle" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.maxSpacing" -msgstr "Espacement max." +msgid "node.roofSegment.buildUpSection.architecturalShingle" +msgstr "Bardeau architectural" -# Source-Hash: 37d9f63758abdb67 +# Source-Hash: afd23a6d653689c6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mixed" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Asphalt 3-tab" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.mixed" -msgstr "Mixte" +msgid "node.roofSegment.buildUpSection.asphalt3Tab" +msgstr "Bardeau d’asphalte 3 pattes" -# Source-Hash: b91302bf741c9fd6 +# Source-Hash: 2650e7c436297ef2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel count" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clay tile" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.panelCount" -msgstr "Nombre de panneaux" +msgid "node.roofSegment.buildUpSection.clayTile" +msgstr "Tuile terre cuite" -# Source-Hash: 6ce059aee1386f72 +# Source-Hash: 92af091c56892f25 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panels" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Concrete tile" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.panels" -msgstr "Panneaux" +msgid "node.roofSegment.buildUpSection.concreteTile" +msgstr "Tuile béton" -# Source-Hash: ef3e765e692faf4c +# Source-Hash: 75168c15633cbad3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Covering" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.solid" -msgstr "Plein" +msgid "node.roofSegment.buildUpSection.covering" +msgstr "Revêtement" -# Source-Hash: e4698e83d02beb6c +# Source-Hash: f3aa561772702108 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spacing" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.spacing" -msgstr "Espacement" +msgid "node.roofSegment.buildUpSection.deck" +msgstr "Support" -# Source-Hash: 0a26a1e61c825660 +# Source-Hash: 14187d972ce9e1de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit layers" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.start" -msgstr "Début" +msgid "node.roofSegment.buildUpSection.editLayers" +msgstr "Modifier les couches" -# Source-Hash: 095237e9e2df4d9c +# Source-Hash: 5aff5f630e4b18c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{title} alignment" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.titleAlignment" -msgstr "Alignement {title}" +msgid "node.roofSegment.buildUpSection.finishName" +msgstr "Nom de la finition" -# Source-Hash: c98a4e6b28f05e0f +# Source-Hash: b9ed3f21665672eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Changes apply to all {length} roof segments." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ice and water shield" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.changesApplyToAllLengthRoof" -msgstr "Les modifications s’appliquent aux {length} segments de toit." +msgid "node.roofSegment.buildUpSection.iceAndWaterShield" +msgstr "Membrane autoadhésive" -# Source-Hash: c5d2ff7fda4787cd +# Source-Hash: 6d79431c0092abac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose one roof system to edit settings for all selected segments." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.chooseOneRoofSystemToEdit" -msgstr "Choisissez un système de toiture pour modifier les réglages de tous les segments sélectionnés." +msgid "node.roofSegment.buildUpSection.insulationName" +msgstr "Nom de l’isolant" -# Source-Hash: 80e07a119b63187c +# Source-Hash: e4e9305964238fda # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close the roof ends" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Interior finish" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.closeTheRoofEnds" -msgstr "Fermer les extrémités du toit" +msgid "node.roofSegment.buildUpSection.interiorFinish" +msgstr "Finition intérieure" -# Source-Hash: e28dd27d54aaa7ae +# Source-Hash: 4ccd2fc1a471fca5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default panel infill" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layers" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.defaultPanelInfill" -msgstr "Remplissage par défaut des panneaux" +msgid "node.roofSegment.buildUpSection.layers" +msgstr "Couches" -# Source-Hash: 134d33e2465937e7 +# Source-Hash: 8f343a87f121347e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Divides each roof face into columns." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "#15 felt" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.dividesEachRoofFaceIntoColumns" -msgstr "Divise chaque versant en colonnes." +msgid "node.roofSegment.buildUpSection.n15Felt" +msgstr "Feutre n° 15" -# Source-Hash: 896a6e4da3357c39 +# Source-Hash: faa54521399dc5b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Divides the length of each arch bay into columns." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "#30 felt" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.dividesTheLengthOfEachArch" -msgstr "Divise la longueur de chaque travée en arc en colonnes." +msgid "node.roofSegment.buildUpSection.n30Felt" +msgstr "Feutre n° 30" -# Source-Hash: be9c810d28d1feb9 +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End infill fills the space above the walls. Edit room walls and ceilings separately." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.endInfillFillsTheSpaceAbove" -msgstr "Le remplissage d’about comble l’espace au-dessus des murs. Modifiez séparément les murs et plafonds des pièces." +msgid "node.roofSegment.buildUpSection.none" +msgstr "Aucune" -# Source-Hash: 0b8b27dbc57cca44 +# Source-Hash: 441f7f652ea6a0d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame color" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preset" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.frameColor" -msgstr "Couleur du cadre" +msgid "node.roofSegment.buildUpSection.preset" +msgstr "Préréglage" -# Source-Hash: fd413477f1a9e5ed +# Source-Hash: a9cb232546779779 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame depth" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafters" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.frameDepth" -msgstr "Profondeur du cadre" +msgid "node.roofSegment.buildUpSection.rafters" +msgstr "Chevrons" -# Source-Hash: 3519d91b7bda18a5 +# Source-Hash: 5c0d95afa820e706 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame width" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roofing" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.frameWidth" -msgstr "Largeur du cadre" +msgid "node.roofSegment.buildUpSection.roofing" +msgstr "Couverture" -# Source-Hash: c7e72beff9fe4b37 +# Source-Hash: 75a1bff32810894e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Framing" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roofing name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.framing" -msgstr "Ossature" +msgid "node.roofSegment.buildUpSection.roofingName" +msgstr "Nom de la couverture" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: 36a588e44085108c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sheathing" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.glass" -msgstr "Vitrage" +msgid "node.roofSegment.buildUpSection.sheathing" +msgstr "Voligeage" -# Source-Hash: 9c38875c310547ae +# Source-Hash: abdad84e524e56e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass tint" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sheathing name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.glassTint" -msgstr "Teinte du vitrage" +msgid "node.roofSegment.buildUpSection.sheathingName" +msgstr "Nom du voligeage" -# Source-Hash: dd330a94b3f7a65a +# Source-Hash: a7b5921026935493 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glazed" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slate" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.glazed" -msgstr "Vitré" +msgid "node.roofSegment.buildUpSection.slate" +msgstr "Ardoise" -# Source-Hash: e6be52df9197243a +# Source-Hash: c156b8bd7920b129 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glazing is available for gable, straight shed, and barrel roofs." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standing-seam metal" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.glazingIsAvailableForGableStraight" -msgstr "Le vitrage est disponible pour les toits à pignon, monopentes droits et voûtés." +msgid "node.roofSegment.buildUpSection.standingSeamMetal" +msgstr "Métal à joint debout" -# Source-Hash: a4e7ef2e31d7220b +# Source-Hash: f5defb7d8a17154e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid across the roof" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Synthetic" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.gridAcrossTheRoof" -msgstr "Trame en travers du toit" +msgid "node.roofSegment.buildUpSection.synthetic" +msgstr "Synthétique" -# Source-Hash: 2f28a3b33fccf56b +# Source-Hash: 472f395a8b6319a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid along the length" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top chord" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.gridAlongTheLength" -msgstr "Trame dans la longueur" +msgid "node.roofSegment.buildUpSection.topChord" +msgstr "Arbalétrier" -# Source-Hash: 1f701893dbf9d72b +# Source-Hash: 4dd558e7eeec7acf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid along the slope" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trusses" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.gridAlongTheSlope" -msgstr "Trame dans la pente" +msgid "node.roofSegment.buildUpSection.trusses" +msgstr "Fermettes" -# Source-Hash: 20c8dfbadda20e3b +# Source-Hash: 3909955f8a920be1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid within each arch bay" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Underlayment" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.gridWithinEachArchBay" -msgstr "Trame dans chaque travée en arc" +msgid "node.roofSegment.buildUpSection.underlayment" +msgstr "Sous-couche" -# Source-Hash: 7c339a5fae55681d +# Source-Hash: 0167cfd2ec25cf5d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Infill" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Underlayment name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.infill" -msgstr "Remplissage" +msgid "node.roofSegment.buildUpSection.underlaymentName" +msgstr "Nom de la sous-couche" -# Source-Hash: 1c0b8a5503c5daeb +# Source-Hash: 7095fa6e1c927c5e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opacity" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wood shake" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.opacity" -msgstr "Opacité" +msgid "node.roofSegment.buildUpSection.woodShake" +msgstr "Bardeau de fente" -# Source-Hash: 4d412746658f2faf +# Source-Hash: 99afd827dbe5d647 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pane thickness" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A single pitched plane of a parent roof." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.roof.glazingPanel.paneThickness" -msgstr "Épaisseur du carreau" +msgid "node.roofSegment.description" +msgstr "Un pan incliné d’un toit parent." -# Source-Hash: 570136e723cb7d99 +# Source-Hash: e72a64b3e00aad98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof system" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Segment" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.roof.glazingPanel.roofSystem" -msgstr "Système de toiture" +msgid "node.roofSegment.label" +msgstr "Pan de toit" -# Source-Hash: a6a7a36d982b4911 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roughness" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanel.roughness" -msgstr "Rugosité" +msgid "node.roofSegment.panel.actions" +msgstr "Actions" -# Source-Hash: 2fa6fbeda5d45949 +# Source-Hash: c69865ec5d9d1ac9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spacing is measured on the slope, not its horizontal projection." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Angle" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanel.spacingIsMeasuredOnTheSlope" -msgstr "L’espacement se mesure sur la pente, pas sur sa projection horizontale." +msgid "node.roofSegment.panel.angle" +msgstr "Angle" -# Source-Hash: d998c212030bc7c2 +# Source-Hash: eb8f344a3c137280 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arc" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanel.standard" -msgstr "Standard" +msgid "node.roofSegment.panel.arc" +msgstr "Arc" -# Source-Hash: efbe1c4facf561f7 +# Source-Hash: 1eb45f83eeaabfad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Subdivides each flat arch bay. Arch bays controls the divisions around the curve." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto gutters" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanel.subdividesEachFlatArchBayArch" -msgstr "Subdivise chaque travée plane en arc. Le nombre de travées règle les divisions le long de la courbe." +msgid "node.roofSegment.panel.autoGutters" +msgstr "Gouttières auto" -# Source-Hash: 1497eac9e4f63016 +# Source-Hash: 0986c4933d2b5808 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a panel to override its default infill." -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto ridge vent" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.chooseAPanelToOverrideIts" -msgstr "Choisissez un panneau pour remplacer son remplissage par défaut." +msgid "node.roofSegment.panel.autoRidgeVent" +msgstr "Faîtière ventilée auto" -# Source-Hash: 3530ac1f4046cd22 +# Source-Hash: 344fe9d407a233a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Column" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Barrel" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.column2" -msgstr "Poteau" +msgid "node.roofSegment.panel.barrel" +msgstr "Voûte" -# Source-Hash: 9e9715d52410c86f +# Source-Hash: 6ca418a2ecab5984 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clipped version" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.custom" -msgstr "Personnalisé" +msgid "node.roofSegment.panel.clippedVersion" +msgstr "Version tronquée" -# Source-Hash: 4ca0e0e73229540c +# Source-Hash: 3241ecabee8221a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Conical" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.default" -msgstr "Par défaut" +msgid "node.roofSegment.panel.conical" +msgstr "Conique" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 9ef92ad8ae49ed72 +# Source-Hash: a37cfbc4db93cfd3 # Review: required -# English: "{columns, plural, one {{columnCount} column} other {{columnCount} columns}} · {rows, plural, one {{rowCount} row} other {{rowCount} rows}}" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Conical Shape" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.grid" -msgstr "{columns, plural, one {{columnCount} colonne} many {{columnCount} colonnes} other {{columnCount} colonnes}} · {rows, plural, one {{rowCount} rangée} many {{rowCount} rangées} other {{rowCount} rangées}}" +msgid "node.roofSegment.panel.conicalShape" +msgstr "Forme conique" -# Source-Hash: 11624abbcfdd5506 +# Source-Hash: a10f29fcde60eea9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Individual panels" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck Thick." +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.individualPanels" -msgstr "Panneaux individuels" +msgid "node.roofSegment.panel.deckThick" +msgstr "Ép. terrasse" -# Source-Hash: 3a019ce58d021431 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel infill" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.panelInfill" -msgstr "Remplissage du panneau" +msgid "node.roofSegment.panel.delete" +msgstr "Supprimer" -# Source-Hash: 6eb8025c60d6d3ca +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset to default" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.resetToDefault" -msgstr "Rétablir la valeur par défaut" +msgid "node.roofSegment.panel.depth" +msgstr "Profondeur" -# Source-Hash: 6fba44f2bfd8af8e +# Source-Hash: 016d8e70618916d4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof face" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diameter" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.roofFace" -msgstr "Versant" +msgid "node.roofSegment.panel.diameter" +msgstr "Diamètre" -# Source-Hash: 03a22f6df69c47d3 +# Source-Hash: e132bf88b9e4d75e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Row" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done editing" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.row2" -msgstr "Rangée" +msgid "node.roofSegment.panel.doneEditing" +msgstr "Terminer la modification" -# Source-Hash: 6c2cc2d9cd778998 +# Source-Hash: 00a4416e0a33d856 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Selected panel infill" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drainage" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.selectedPanelInfill" -msgstr "Remplissage du panneau sélectionné" +msgid "node.roofSegment.panel.drainage" +msgstr "Évacuation" -# Source-Hash: f5f730969df63d1d +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.label" -msgstr "Toit" +msgid "node.roofSegment.panel.duplicate" +msgstr "Dupliquer" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 6949d667043bee0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.actions" -msgstr "Actions" +msgid "node.roofSegment.panel.dutch" +msgstr "Demi-croupe" -# Source-Hash: d60471ce3cd45348 +# Source-Hash: 4c539865731d5d66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Chimney" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eave cut" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addChimney" -msgstr "Ajouter une cheminée" +msgid "node.roofSegment.panel.eaveCut" +msgstr "Coupe d’about" -# Source-Hash: 1ca6a1cf9cc6e3ed +# Source-Hash: 5c99a67253bfc02a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Cupola" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eave overhang" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addCupola" -msgstr "Ajouter une coupole" +msgid "node.roofSegment.panel.eaveOverhang" +msgstr "Débord d’égout" -# Source-Hash: 94dea147eeaac52b -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Dormer" -#: packages/nodes/src/roof/panel.tsx +# Source-Hash: dc90862aafc9d287 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit footprint" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addDormer" -msgstr "Ajouter une lucarne" +msgid "node.roofSegment.panel.editFootprint" +msgstr "Modifier l’emprise" -# Source-Hash: 5679acdd64484726 +# Source-Hash: 9532d5e73585ea62 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Eyebrow Vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End overhang" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addEyebrowVent" -msgstr "Ajouter une chatière en œil-de-bœuf" +msgid "node.roofSegment.panel.endOverhang" +msgstr "Débord d’about" -# Source-Hash: 25a141dc0d7c4b44 +# Source-Hash: 74f4143cd02de4a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Gutter" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fascia" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addGutter" -msgstr "Ajouter une gouttière" +msgid "node.roofSegment.panel.fascia" +msgstr "Bandeau de rive" -# Source-Hash: 7230bdc8a2252626 +# Source-Hash: 45baed9dc8b8047a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Skylight" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fascia height" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addSkylight" -msgstr "Ajouter un puits de lumière" +msgid "node.roofSegment.panel.fasciaHeight" +msgstr "Hauteur du bandeau" -# Source-Hash: 0f220e2602b7ff24 +# Source-Hash: 9cab4d4c95f63cdd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Solar Panel" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addSolarPanel" -msgstr "Ajouter un panneau solaire" +msgid "node.roofSegment.panel.flat" +msgstr "Plat" -# Source-Hash: 4d83a2e5a4d9e6b4 +# Source-Hash: a3c10560fa3c1612 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Footprint" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addVent" -msgstr "Ajouter une ventilation" +msgid "node.roofSegment.panel.footprint" +msgstr "Emprise" -# Source-Hash: e9a89a5e4ac8cd61 +# Source-Hash: deaffa095d126dfe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.box" -msgstr "Boîte" +msgid "node.roofSegment.panel.gable" +msgstr "Deux pans" -# Source-Hash: 3bf078fe2560daca +# Source-Hash: dbd062efc7f4fd7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "box vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable overhang" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.boxVent" -msgstr "ventilation caisson" +msgid "node.roofSegment.panel.gableOverhang" +msgstr "Débord de rive" -# Source-Hash: 4986740251121471 +# Source-Hash: 7f53d9ffca39984a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "chimney" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.chimney" -msgstr "cheminée" +msgid "node.roofSegment.panel.gambrel" +msgstr "Brisé" -# Source-Hash: 9e9715d52410c86f +# Source-Hash: 9eda0ea8d447066d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hip" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.custom" -msgstr "Personnalisé" +msgid "node.roofSegment.panel.hip" +msgstr "Croupe" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 7ae4179d0abd80f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kink Depth" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.delete" -msgstr "Supprimer" +msgid "node.roofSegment.panel.kinkDepth" +msgstr "Profondeur du coude" -# Source-Hash: 5169968a4b0c1840 +# Source-Hash: e19b2bca70030855 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "dormer" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kink Height" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.dormer" -msgstr "lucarne" +msgid "node.roofSegment.panel.kinkHeight" +msgstr "Hauteur du coude" -# Source-Hash: 72e51c6e5e9c6c26 +# Source-Hash: 643687bc3adaac76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw Segment" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.drawSegment" -msgstr "Dessiner un segment" +msgid "node.roofSegment.panel.length" +msgstr "Longueur" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 7f7bb0e875af3260 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.duplicate" -msgstr "Dupliquer" +msgid "node.roofSegment.panel.mansard" +msgstr "Mansarde" -# Source-Hash: 7c4196b9e791c195 +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elements" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.elements" -msgstr "Éléments" +msgid "node.roofSegment.panel.move" +msgstr "Déplacer" -# Source-Hash: 6b8ba49aa355fe87 +# Source-Hash: 75e3449fc1776d09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows walls" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pitch" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.followsWalls" -msgstr "Suit les murs" +msgid "node.roofSegment.panel.pitch" +msgstr "Pente" -# Source-Hash: 23b434461c990711 +# Source-Hash: 6ae4075a23bb4ec4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "gutter" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plumb" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.gutter" -msgstr "gouttière" +msgid "node.roofSegment.panel.plumb" +msgstr "Aplomb" -# Source-Hash: 0608743fc1736d86 +# Source-Hash: 16d8ab5937d74bdb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plumb + level" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.level" -msgstr "Niveau" +msgid "node.roofSegment.panel.plumbLevel" +msgstr "Aplomb + niveau" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.move" -msgstr "Déplacer" +msgid "node.roofSegment.panel.position" +msgstr "Position" -# Source-Hash: 39661f4827b0f435 +# Source-Hash: bf91b71a9aa76e94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move to {level}" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.moveToLevel" -msgstr "Déplacer vers {level}" +msgid "node.roofSegment.panel.reset" +msgstr "Réinitialiser" -# Source-Hash: c534093ff560a9f0 +# Source-Hash: e72a64b3e00aad98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move to the roof level" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Segment" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.moveToTheRoofLevel" -msgstr "Déplacer vers le niveau de toiture" +msgid "node.roofSegment.panel.roofSegment" +msgstr "Pan de toit" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 0939fad1cb1831f0 +# Source-Hash: 19ab9527ae7889f4 # Review: required -# English: "On {storey} with its walls, so it hides that floor's plan in solo and exploded views.{roofs, plural, =0 {} =1 {} other { The floor's {roofCount} roofs move together.}}" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Type" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.onStoreyWalls" -msgstr "Sur {storey} avec ses murs : il masque donc le plan de cet étage dans les vues isolée et éclatée.{roofs, plural, =0 {} =1 {} one {} many { Les {roofCount} toits de l’étage se déplacent ensemble.} other { Les {roofCount} toits de l’étage se déplacent ensemble.}}" +msgid "node.roofSegment.panel.roofType" +msgstr "Type de toit" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.position" -msgstr "Position" +msgid "node.roofSegment.panel.rotation" +msgstr "Rotation" -# Source-Hash: e6ddc8a624465793 +# Source-Hash: 85ea1d3c8b749680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ridge" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.ridge" -msgstr "Faîtage" +msgid "node.roofSegment.panel.shape" +msgstr "Forme" -# Source-Hash: 83112cbc205e9972 +# Source-Hash: c8d0df27faa3feaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "ridge vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.ridgeVent" -msgstr "faîtière ventilée" +msgid "node.roofSegment.panel.shed" +msgstr "Appentis" -# Source-Hash: f5f730969df63d1d +# Source-Hash: 4d944a2393bbddb2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingle Thick." +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.roof" -msgstr "Toit" +msgid "node.roofSegment.panel.shingleThick" +msgstr "Ép. bardeau" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: 93b34a5b546664c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Span" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.rotation" -msgstr "Rotation" +msgid "node.roofSegment.panel.span" +msgstr "Portée" -# Source-Hash: 505d8419cf4cc5e1 +# Source-Hash: 39287346366fc206 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segments" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.segments" -msgstr "Segments" +msgid "node.roofSegment.panel.square" +msgstr "Équerre" -# Source-Hash: 0c084c517dbc153b +# Source-Hash: e90aceedf4a6b183 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{roofType, select, hip {Hip} gable {Gable} shed {Shed} gambrel {Gambrel} dutch {Dutch} mansard {Mansard} flat {Flat} conical {Conical} barrel {Barrel} other {Roof}}" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start Angle" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.segmentType" -msgstr "{roofType, select, hip {Croupe} gable {Pignon} shed {Monopente} gambrel {Gambrel} dutch {Demi-croupe} mansard {Mansarde} flat {Plat} conical {Conique} barrel {Voûte} other {Toit}}" +msgid "node.roofSegment.panel.startAngle" +msgstr "Angle de départ" -# Source-Hash: 0c4c82caccb4775c +# Source-Hash: a20c89205a4448d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "skylight" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.skylight" -msgstr "puits de lumière" +msgid "node.roofSegment.panel.structure" +msgstr "Structure" -# Source-Hash: b9f931508dd6ec70 +# Source-Hash: a2db62c74fe2bcee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "solar panel" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Rake Length" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.solarPanel" -msgstr "panneau solaire" +msgid "node.roofSegment.panel.topRakeLength" +msgstr "Longueur de rive haute" -# Source-Hash: d2428b22f1757a4e +# Source-Hash: 913d9552030ac86a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Turbine" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Rake Thick." +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.turbine" -msgstr "Turbine" +msgid "node.roofSegment.panel.topRakeThick" +msgstr "Ép. rive haute" -# Source-Hash: 86d02a3d3a3a7fa2 +# Source-Hash: 3beb5eb35f0c5c17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "turbine vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trim" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.turbineVent" -msgstr "aérateur à turbine" +msgid "node.roofSegment.panel.trim" +msgstr "Moulures" -# Source-Hash: 99afd827dbe5d647 +# Source-Hash: e6c5009c0d31fca1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A single pitched plane of a parent roof." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist Height" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.description" -msgstr "Un pan incliné d’un toit parent." +msgid "node.roofSegment.panel.waistHeight" +msgstr "Hauteur de taille" -# Source-Hash: e72a64b3e00aad98 +# Source-Hash: 4a8caffd24b6ee02 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Segment" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist Length" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.label" -msgstr "Pan de toit" +msgid "node.roofSegment.panel.waistLength" +msgstr "Longueur de taille" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 71045af5c81a11e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist Width" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.actions" -msgstr "Actions" +msgid "node.roofSegment.panel.waistWidth" +msgstr "Largeur de taille" -# Source-Hash: c69865ec5d9d1ac9 +# Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.angle" -msgstr "Angle" +msgid "node.roofSegment.panel.wall" +msgstr "Mur" -# Source-Hash: eb8f344a3c137280 +# Source-Hash: e0f973edce3e4ca8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arc" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall Height" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.arc" -msgstr "Arc" +msgid "node.roofSegment.panel.wallHeight" +msgstr "Hauteur du mur" -# Source-Hash: 1eb45f83eeaabfad +# Source-Hash: d0db6dee5fe2edbd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto gutters" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall Thick." #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.autoGutters" -msgstr "Gouttières auto" +msgid "node.roofSegment.panel.wallThick" +msgstr "Ép. mur" -# Source-Hash: 0986c4933d2b5808 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto ridge vent" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.autoRidgeVent" -msgstr "Faîtière ventilée auto" +msgid "node.roofSegment.panel.width" +msgstr "Largeur" -# Source-Hash: 344fe9d407a233a9 +# Source-Hash: 6600a850000b98ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Barrel" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A captured session with optional mesh, motion, media, and sensor data." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.scan.description" +msgstr "Session capturée avec maillage, mouvement, médias et données de capteurs facultatifs." + +# Source-Hash: 3a0701ebcb9f26cb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Capture" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.roofSegment.panel.barrel" -msgstr "Voûte" +msgid "node.scan.label" +msgstr "Capture" -# Source-Hash: 6ca418a2ecab5984 +# Source-Hash: 95b5307eefb187c6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clipped version" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segment {number}" +#: packages/nodes/src/door/panel.tsx +#: packages/nodes/src/roof/panel.tsx +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.clippedVersion" -msgstr "Version tronquée" +msgid "node.segmentNumber" +msgstr "Segment {number}" -# Source-Hash: 3241ecabee8221a1 +# Source-Hash: acb8cb92b3674b50 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Conical" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Separator" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.roofSegment.panel.conical" -msgstr "Conique" +msgid "node.separator.label" +msgstr "Séparateur" -# Source-Hash: a37cfbc4db93cfd3 +# Source-Hash: e34eb5b5bfbfce7c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Conical Shape" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Batt" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.conicalShape" -msgstr "Forme conique" +msgid "node.shared.buildUpControls.batt" +msgstr "Matelas" -# Source-Hash: a10f29fcde60eea9 +# Source-Hash: 430cef5fa9bd2787 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Deck Thick." -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Blown" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.deckThick" -msgstr "Ép. terrasse" +msgid "node.shared.buildUpControls.blown" +msgstr "Soufflé" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 4da800c75b9a6b23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drywall" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.delete" -msgstr "Supprimer" +msgid "node.shared.buildUpControls.drywall" +msgstr "Plaque de plâtre" -# Source-Hash: 99ac4d03c3061f3a +# Source-Hash: 4e8f119349fa2dd4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drywall thickness" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.depth" -msgstr "Profondeur" +msgid "node.shared.buildUpControls.drywallThickness" +msgstr "Épaisseur de plaque de plâtre" -# Source-Hash: 016d8e70618916d4 +# Source-Hash: 7d6ed24c02ab0c5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diameter" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.diameter" -msgstr "Diamètre" +msgid "node.shared.buildUpControls.insulation" +msgstr "Isolant" -# Source-Hash: e132bf88b9e4d75e +# Source-Hash: 4251fc1e9051a7db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done editing" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation thickness" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.doneEditing" -msgstr "Terminer la modification" +msgid "node.shared.buildUpControls.insulationThickness" +msgstr "Épaisseur d’isolant" -# Source-Hash: 00a4416e0a33d856 +# Source-Hash: f567133879529366 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drainage" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label} thickness" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.drainage" -msgstr "Évacuation" +msgid "node.shared.buildUpControls.labelThickness" +msgstr "Épaisseur ({label})" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.duplicate" -msgstr "Dupliquer" +msgid "node.shared.buildUpControls.none" +msgstr "Aucun" -# Source-Hash: 6949d667043bee0b +# Source-Hash: 4f7f8af75bf8e914 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "OSB" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.dutch" -msgstr "Demi-croupe" +msgid "node.shared.buildUpControls.osb" +msgstr "OSB" -# Source-Hash: 5c99a67253bfc02a +# Source-Hash: a6fd2cbf5c2154e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Eave overhang" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plaster" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.eaveOverhang" -msgstr "Débord d’égout" +msgid "node.shared.buildUpControls.plaster" +msgstr "Plâtre" -# Source-Hash: dc90862aafc9d287 +# Source-Hash: e669c2c08bd80e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit footprint" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plywood" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.editFootprint" -msgstr "Modifier l’emprise" +msgid "node.shared.buildUpControls.plywood" +msgstr "Contreplaqué" -# Source-Hash: 9532d5e73585ea62 +# Source-Hash: 3d153fa2037159f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End overhang" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rigid board" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.endOverhang" -msgstr "Débord d’about" +msgid "node.shared.buildUpControls.rigidBoard" +msgstr "Panneau rigide" -# Source-Hash: 74f4143cd02de4a6 +# Source-Hash: e4698e83d02beb6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fascia" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spacing" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.fascia" -msgstr "Bandeau de rive" +msgid "node.shared.buildUpControls.spacing" +msgstr "Espacement" -# Source-Hash: 45baed9dc8b8047a +# Source-Hash: bb2a1cccfd0bd194 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fascia height" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{spacing} o.c." +#. A framing spacing on centre (centre of one member to the next), e.g. 16" o.c. +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.fasciaHeight" -msgstr "Hauteur du bandeau" +msgid "node.shared.buildUpControls.spacingOC" +msgstr "{spacing} d’entraxe" -# Source-Hash: 9cab4d4c95f63cdd +# Source-Hash: ab62afff8ba3f37f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wood plank" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.flat" -msgstr "Plat" +msgid "node.shared.buildUpControls.woodPlank" +msgstr "Lambris" -# Source-Hash: a3c10560fa3c1612 +# Source-Hash: e7512c891d8da7d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Footprint" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turn light off" +#: packages/nodes/src/shared/item-interaction-actions.tsx #, fuzzy -msgid "node.roofSegment.panel.footprint" -msgstr "Emprise" +msgid "node.shared.itemInteractionActions.turnLightOff" +msgstr "Éteindre la lumière" -# Source-Hash: deaffa095d126dfe +# Source-Hash: d47ec95e14909fe5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turn light on" +#: packages/nodes/src/shared/item-interaction-actions.tsx #, fuzzy -msgid "node.roofSegment.panel.gable" -msgstr "Deux pans" +msgid "node.shared.itemInteractionActions.turnLightOn" +msgstr "Allumer la lumière" -# Source-Hash: dbd062efc7f4fd7f +# Source-Hash: 18bf48fbbe121ef0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable overhang" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Casing" +#: packages/nodes/src/shared/opening-casing-section.tsx #, fuzzy -msgid "node.roofSegment.panel.gableOverhang" -msgstr "Débord de rive" +msgid "node.shared.openingCasingSection.casing" +msgstr "Chambranle" -# Source-Hash: 7f53d9ffca39984a +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/shared/opening-casing-section.tsx #, fuzzy -msgid "node.roofSegment.panel.gambrel" -msgstr "Brisé" +msgid "node.shared.openingCasingSection.width" +msgstr "Largeur" -# Source-Hash: 9eda0ea8d447066d +# Source-Hash: ee1c8bc3e27fb550 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hip" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Automatic support" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.hip" -msgstr "Croupe" +msgid "node.shared.runHangerInspector.automaticSupport" +msgstr "Support automatique" -# Source-Hash: 7ae4179d0abd80f5 +# Source-Hash: 1353e40320c72a99 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kink Depth" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger {number} · segment {segment}" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.kinkDepth" -msgstr "Profondeur du coude" +msgid "node.shared.runHangerInspector.hangerOnSegment" +msgstr "Suspente {number} · segment {segment}" -# Source-Hash: e19b2bca70030855 +# Source-Hash: 737ced90d0454197 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kink Height" -#: packages/nodes/src/roof-segment/panel.tsx -#, fuzzy -msgid "node.roofSegment.panel.kinkHeight" -msgstr "Hauteur du coude" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Individual hangers" +#: packages/nodes/src/shared/run-hanger-inspector.tsx +#, fuzzy +msgid "node.shared.runHangerInspector.individualHangers" +msgstr "Suspentes individuelles" -# Source-Hash: 643687bc3adaac76 +# Source-Hash: e6b17b09ed91c8c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Missing support" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.length" -msgstr "Longueur" +msgid "node.shared.runHangerInspector.missingSupport" +msgstr "Support manquant" -# Source-Hash: 7f7bb0e875af3260 +# Source-Hash: c895c3c603382ec9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No support within reach. Move the hanger or choose another host." +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.mansard" -msgstr "Mansarde" +msgid "node.shared.runHangerInspector.noSupportWithinReachMoveThe" +msgstr "Aucun support à portée. Déplacez la suspente ou choisissez un autre support." -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 6ce526cb7444be36 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger {number} position in metres" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.move" -msgstr "Déplacer" +msgid "node.shared.runHangerInspector.positionLabel" +msgstr "Position de la suspente {number} en mètres" -# Source-Hash: 75e3449fc1776d09 +# Source-Hash: cbd36c4b82a55539 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pitch" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position (m)" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.pitch" -msgstr "Pente" +msgid "node.shared.runHangerInspector.positionM" +msgstr "Position (m)" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: b629c4f8388fd36f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Positions are measured along each path segment. Changing spacing regenerates the numbered slots." +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.position" -msgstr "Position" +msgid "node.shared.runHangerInspector.positionsAreMeasuredAlongEachPath" +msgstr "Les positions se mesurent le long de chaque segment du tracé. Modifier l'espacement régénère les emplacements numérotés." -# Source-Hash: bf91b71a9aa76e94 +# Source-Hash: c21cfbdb64e53388 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reveal support" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.reset" -msgstr "Réinitialiser" +msgid "node.shared.runHangerInspector.revealSupport" +msgstr "Afficher le support" -# Source-Hash: e72a64b3e00aad98 +# Source-Hash: 9d5e4440db18e477 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Segment" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Skip" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.roofSegment" -msgstr "Pan de toit" +msgid "node.shared.runHangerInspector.skip" +msgstr "Ignorer" -# Source-Hash: 19ab9527ae7889f4 +# Source-Hash: 1b184f78bf989931 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Type" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger {number} support" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.roofType" -msgstr "Type de toit" +msgid "node.shared.runHangerInspector.supportLabel" +msgstr "Support de la suspente {number}" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: b2d703d283baf64a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "About these checks" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.rotation" -msgstr "Rotation" +msgid "node.shared.systemCheckPanel.aboutTheseChecks" +msgstr "À propos de ces vérifications" -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: 461cc26706956993 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All findings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.shape" -msgstr "Forme" +msgid "node.shared.systemCheckPanel.allFindings" +msgstr "Tous les constats" -# Source-Hash: c8d0df27faa3feaa +# Source-Hash: 7beeb4c4997f5edb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All systems" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.shed" -msgstr "Appentis" +msgid "node.shared.systemCheckPanel.allSystems" +msgstr "Tous les réseaux" -# Source-Hash: 4d944a2393bbddb2 +# Source-Hash: d613df280aa13b42 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingle Thick." -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connections" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.shingleThick" -msgstr "Ép. bardeau" +msgid "node.shared.systemCheckPanel.connections" +msgstr "Raccordements" -# Source-Hash: 93b34a5b546664c4 +# Source-Hash: 00a4416e0a33d856 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Span" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drainage" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.span" -msgstr "Portée" +msgid "node.shared.systemCheckPanel.drainage" +msgstr "Évacuation" -# Source-Hash: e90aceedf4a6b183 +# Source-Hash: fc4ac19649f0ee8f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start Angle" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Error" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.startAngle" -msgstr "Angle de départ" +msgid "node.shared.systemCheckPanel.error" +msgstr "Erreur" -# Source-Hash: a20c89205a4448d2 +# Source-Hash: b92720ff88a1bcfd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Errors" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.structure" -msgstr "Structure" +msgid "node.shared.systemCheckPanel.errors" +msgstr "Erreurs" -# Source-Hash: a2db62c74fe2bcee +# Source-Hash: d0e23bdbe1b380ff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Rake Length" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Filter system checks" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.topRakeLength" -msgstr "Longueur de rive haute" +msgid "node.shared.systemCheckPanel.filterSystemChecks" +msgstr "Filtrer les vérifications" -# Source-Hash: 913d9552030ac86a +# Source-Hash: 30d8dba84c42040e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Rake Thick." -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hangers" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.topRakeThick" -msgstr "Ép. rive haute" +msgid "node.shared.systemCheckPanel.hangers" +msgstr "Supports" -# Source-Hash: 3beb5eb35f0c5c17 +# Source-Hash: 8cd416ca57d969f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trim" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Intersections" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.trim" -msgstr "Moulures" +msgid "node.shared.systemCheckPanel.intersections" +msgstr "Croisements" -# Source-Hash: e6c5009c0d31fca1 +# Source-Hash: 18d652275a9a525c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist Height" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Locate {name} ({id})" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.waistHeight" -msgstr "Hauteur de taille" +msgid "node.shared.systemCheckPanel.locate" +msgstr "Localiser {name} ({id})" -# Source-Hash: 4a8caffd24b6ee02 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist Length" -#: packages/nodes/src/roof-segment/panel.tsx +# Source-Hash: 88546aa3a5987966 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Missing item" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.waistLength" -msgstr "Longueur de taille" +msgid "node.shared.systemCheckPanel.missingItem" +msgstr "Élément manquant" -# Source-Hash: 71045af5c81a11e4 +# Source-Hash: 2452d2922a7ecf4a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist Width" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No findings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.waistWidth" -msgstr "Largeur de taille" +msgid "node.shared.systemCheckPanel.noFindings" +msgstr "Aucun constat" -# Source-Hash: 2210e5ee50b74dc9 +# Source-Hash: 995442fbfc786768 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No findings in this category" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.wall" -msgstr "Mur" +msgid "node.shared.systemCheckPanel.noFindingsInThisCategory" +msgstr "Aucun constat dans cette catégorie" -# Source-Hash: e0f973edce3e4ca8 +# Source-Hash: b5c58159b3eef89c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Height" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open ends" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.wallHeight" -msgstr "Hauteur du mur" +msgid "node.shared.systemCheckPanel.openEnds" +msgstr "Extrémités ouvertes" -# Source-Hash: d0db6dee5fe2edbd +# Source-Hash: 3003dacc858d36ff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Thick." -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open ends and separate branches may be intentional. Intersection checks use bounding boxes; inspect openings and clearances." +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.wallThick" -msgstr "Ép. mur" +msgid "node.shared.systemCheckPanel.openEndsAndSeparateBranchesMay" +msgstr "Les extrémités ouvertes et les branches séparées peuvent être voulues. Les croisements sont testés par boîtes englobantes ; vérifiez ouvertures et dégagements." -# Source-Hash: 3a0ccd6c46877a87 +# Source-Hash: c40c64562b6a1a91 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selected connected system" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.width" -msgstr "Largeur" +msgid "node.shared.systemCheckPanel.selectedConnectedSystem" +msgstr "Réseau connecté sélectionné" -# Source-Hash: 6600a850000b98ad +# Source-Hash: 68355a98439229e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A captured session with optional mesh, motion, media, and sensor data." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selected: {count, plural, one {{number} run} other {{number} runs}} · {length} m" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.scan.description" -msgstr "Session capturée avec maillage, mouvement, médias et données de capteurs facultatifs." +msgid "node.shared.systemCheckPanel.selectedRuns" +msgstr "Sélection : {count, plural, one {{number} tronçon} many {{number} tronçons} other {{number} tronçons}} · {length} m" -# Source-Hash: 3a0701ebcb9f26cb +# Source-Hash: e7a352627f8fcd45 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Capture" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Separate branches" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.scan.label" -msgstr "Capture" +msgid "node.shared.systemCheckPanel.separateBranches" +msgstr "Branches séparées" -# Source-Hash: 95b5307eefb187c6 +# Source-Hash: 910a5ee73f2ef8a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segment {number}" -#: packages/nodes/src/door/panel.tsx -#: packages/nodes/src/roof/panel.tsx -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show all findings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.segmentNumber" -msgstr "Segment {number}" +msgid "node.shared.systemCheckPanel.showAllFindings" +msgstr "Afficher tous les constats" -# Source-Hash: acb8cb92b3674b50 +# Source-Hash: dda8887833d07390 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Separator" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System checks" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.separator.label" -msgstr "Séparateur" +msgid "node.shared.systemCheckPanel.systemChecks" +msgstr "Vérifications du réseau" -# Source-Hash: e7512c891d8da7d8 +# Source-Hash: 4dad0ed68e63d124 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Turn light off" -#: packages/nodes/src/shared/item-interaction-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System finding" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.itemInteractionActions.turnLightOff" -msgstr "Éteindre la lumière" +msgid "node.shared.systemCheckPanel.systemFinding" +msgstr "Constat du réseau" -# Source-Hash: d47ec95e14909fe5 +# Source-Hash: e37307a519466b38 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Turn light on" -#: packages/nodes/src/shared/item-interaction-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System findings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.itemInteractionActions.turnLightOn" -msgstr "Allumer la lumière" +msgid "node.shared.systemCheckPanel.systemFindings" +msgstr "Constats du réseau" +# Source-Hash: 5128de8b5a618339 # Review: required -# Source-Hash: ee1c8bc3e27fb550 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Automatic support" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Warning" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.automaticSupport" -msgstr "Support automatique" +msgid "node.shared.systemCheckPanel.warning" +msgstr "Avertissement" +# Source-Hash: 7e1647f9ce51509e # Review: required -# Source-Hash: 1353e40320c72a99 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger {number} · segment {segment}" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Warnings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.hangerOnSegment" -msgstr "Suspente {number} · segment {segment}" +msgid "node.shared.systemCheckPanel.warnings" +msgstr "Avertissements" +# Source-Hash: 26aff27b7284fc84 # Review: required -# Source-Hash: 737ced90d0454197 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Individual hangers" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A configurable shelving unit. Items host on each row." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.shared.runHangerInspector.individualHangers" -msgstr "Suspentes individuelles" +msgid "node.shelf.description" +msgstr "Étagère configurable. Les éléments se posent sur chaque rangée." +# Source-Hash: d7145f84f8e0e3fe # Review: required -# Source-Hash: e6b17b09ed91c8c2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Missing support" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shelf" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.shared.runHangerInspector.missingSupport" -msgstr "Support manquant" +msgid "node.shelf.label" +msgstr "Étagère" +# Source-Hash: c52492c73312a922 # Review: required -# Source-Hash: c895c3c603382ec9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No support within reach. Move the hanger or choose another host." -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The top-level container holding buildings, zones, and the property boundary." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.shared.runHangerInspector.noSupportWithinReachMoveThe" -msgstr "Aucun support à portée. Déplacez la suspente ou choisissez un autre support." +msgid "node.site.description" +msgstr "Conteneur de premier niveau avec les bâtiments, les zones et la limite de propriété." +# Source-Hash: 91f90818d42a984e # Review: required -# Source-Hash: 6ce526cb7444be36 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger {number} position in metres" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Site" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.shared.runHangerInspector.positionLabel" -msgstr "Position de la suspente {number} en mètres" +msgid "node.site.label" +msgstr "Terrain" +# Source-Hash: 3b5a53b6d058a02a # Review: required -# Source-Hash: cbd36c4b82a55539 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position (m)" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Address" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.positionM" -msgstr "Position (m)" +msgid "node.site.panel.address" +msgstr "Adresse" +# Source-Hash: ea03c49930137a0f # Review: required -# Source-Hash: b629c4f8388fd36f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Positions are measured along each path segment. Changing spacing regenerates the numbered slots." -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "APN" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.positionsAreMeasuredAlongEachPath" -msgstr "Les positions se mesurent le long de chaque segment du tracé. Modifier l'espacement régénère les emplacements numérotés." +msgid "node.site.panel.apn" +msgstr "N° de parcelle" +# Source-Hash: 8519c9ddf5e6b371 # Review: required -# Source-Hash: c21cfbdb64e53388 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reveal support" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto — most north-facing edge" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.revealSupport" -msgstr "Afficher le support" +msgid "node.site.panel.autoMostNorthFacingEdge" +msgstr "Auto — bord le plus au nord" +# Source-Hash: bc493d7655b3e3ad # Review: required -# Source-Hash: 9d5e4440db18e477 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Skip" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Contour interval (site plan and 3D)" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.skip" -msgstr "Ignorer" +msgid "node.site.panel.contourIntervalSitePlanAnd3d" +msgstr "Équidistance des courbes (plan de masse et 3D)" +# Source-Hash: 99208d226da1315f # Review: required -# Source-Hash: 1b184f78bf989931 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger {number} support" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "County" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.supportLabel" -msgstr "Support de la suspente {number}" +msgid "node.site.panel.county" +msgstr "Comté" -# Source-Hash: b2d703d283baf64a +# Source-Hash: 0830cf0f95ad429d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "About these checks" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "e.g. RS-60" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.aboutTheseChecks" -msgstr "À propos de ces vérifications" +msgid "node.site.panel.eGRs60" +msgstr "p. ex. RS-60" -# Source-Hash: 461cc26706956993 +# Source-Hash: b3e7e118266b5074 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All findings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "e.g. Tampa LDC §27-156" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.allFindings" -msgstr "Tous les constats" +msgid "node.site.panel.eGTampaLdc27156" +msgstr "p. ex. Tampa LDC §27-156" -# Source-Hash: 7beeb4c4997f5edb +# Source-Hash: 187e11889d08a2dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All systems" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "every 12 in" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.allSystems" -msgstr "Tous les réseaux" +msgid "node.site.panel.every12In" +msgstr "tous les 12 in" -# Source-Hash: d613df280aa13b42 +# Source-Hash: 17ee041f655085f8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connections" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "every 24 in" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.connections" -msgstr "Raccordements" +msgid "node.site.panel.every24In" +msgstr "tous les 24 in" -# Source-Hash: 00a4416e0a33d856 +# Source-Hash: 40d7f9ddf5efcb7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drainage" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "every 6 in" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.drainage" -msgstr "Évacuation" +msgid "node.site.panel.every6In" +msgstr "tous les 6 in" -# Source-Hash: fc4ac19649f0ee8f +# Source-Hash: 442a3ce78ae6b462 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Error" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finding…" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.error" -msgstr "Erreur" +msgid "node.site.panel.finding" +msgstr "Recherche…" -# Source-Hash: b92720ff88a1bcfd +# Source-Hash: 734c1eac014adc69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Errors" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Find parcel" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.errors" -msgstr "Erreurs" +msgid "node.site.panel.findParcel" +msgstr "Trouver la parcelle" -# Source-Hash: d0e23bdbe1b380ff +# Source-Hash: ccb70faaf91dbcb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Filter system checks" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front (street) edge" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.filterSystemChecks" -msgstr "Filtrer les vérifications" +msgid "node.site.panel.frontStreetEdge" +msgstr "Bord avant (rue)" -# Source-Hash: 30d8dba84c42040e +# Source-Hash: 4232218226616327 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hangers" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Looking up the parcel and the streets around it…" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.hangers" -msgstr "Supports" +msgid "node.site.panel.lookingUpTheParcel" +msgstr "Recherche de la parcelle et des rues alentour…" -# Source-Hash: 8cd416ca57d969f5 +# Source-Hash: c39eb5933468a637 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Intersections" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lot area" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.intersections" -msgstr "Croisements" +msgid "node.site.panel.lotArea" +msgstr "Surface du terrain" -# Source-Hash: 18d652275a9a525c +# Source-Hash: c8a874b339ff9696 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Locate {name} ({id})" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "1200 W Cass St, Tampa, FL" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.locate" -msgstr "Localiser {name} ({id})" +msgid "node.site.panel.n1200WCassStTampaFl" +msgstr "1200 W Cass St, Tampa, FL" -# Source-Hash: 88546aa3a5987966 +# Source-Hash: 30a0924a3360be68 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Missing item" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "none" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.missingItem" -msgstr "Élément manquant" +msgid "node.site.panel.none" +msgstr "aucun" -# Source-Hash: 2452d2922a7ecf4a +# Source-Hash: dd4e835cb90c5736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No findings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "North rotation" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.noFindings" -msgstr "Aucun constat" +msgid "node.site.panel.northRotation" +msgstr "Rotation du nord" -# Source-Hash: 995442fbfc786768 +# Source-Hash: a4bfb2891c820e2e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No findings in this category" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No surveyed lines — contours are drawn from the sculpted ground." +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.noFindingsInThisCategory" -msgstr "Aucun constat dans cette catégorie" +msgid "node.site.panel.noSurveyedLinesContoursAreDrawn" +msgstr "Aucune ligne relevée — les courbes sont tracées depuis le terrain modelé." -# Source-Hash: b5c58159b3eef89c +# Source-Hash: 1f0d024c0adbf0e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open ends" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Orientation" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.openEnds" -msgstr "Extrémités ouvertes" +msgid "node.site.panel.orientation" +msgstr "Orientation" -# Source-Hash: 3003dacc858d36ff +# Source-Hash: 9a3961409e34bf66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open ends and separate branches may be intentional. Intersection checks use bounding boxes; inspect openings and clearances." -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Parcel" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.openEndsAndSeparateBranchesMay" -msgstr "Les extrémités ouvertes et les branches séparées peuvent être voulues. Les croisements sont testés par boîtes englobantes ; vérifiez ouvertures et dégagements." +msgid "node.site.panel.parcel" +msgstr "Parcelle" -# Source-Hash: c40c64562b6a1a91 +# Source-Hash: 3aecc563cb9a2c68 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Selected connected system" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Parcel lookup failed." +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.selectedConnectedSystem" -msgstr "Réseau connecté sélectionné" +msgid "node.site.panel.parcelLookupFailed" +msgstr "La recherche de parcelle a échoué." -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 68355a98439229e2 +# Source-Hash: 36696c4a8bede421 # Review: required -# English: "Selected: {count, plural, one {{number} run} other {{number} runs}} · {length} m" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Project look" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.selectedRuns" -msgstr "Sélection : {count, plural, one {{number} tronçon} many {{number} tronçons} other {{number} tronçons}} · {length} m" +msgid "node.site.panel.projectLook" +msgstr "Apparence du projet" -# Source-Hash: e7a352627f8fcd45 +# Source-Hash: 5b50fc78ccdaf7aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Separate branches" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Save current look" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.separateBranches" -msgstr "Branches séparées" +msgid "node.site.panel.saveCurrentLook" +msgstr "Enregistrer l’apparence actuelle" -# Source-Hash: 910a5ee73f2ef8a6 +# Source-Hash: f06b316f421963d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show all findings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Save the current lighting and display as this project's default. Personal display changes stay in this browser." +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.showAllFindings" -msgstr "Afficher tous les constats" +msgid "node.site.panel.saveTheCurrentLightingAndDisplay" +msgstr "Enregistrer l’éclairage et l’affichage actuels comme valeurs par défaut du projet. Les réglages d’affichage personnels restent dans ce navigateur." -# Source-Hash: dda8887833d07390 +# Source-Hash: e87df48b61eda8ce # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System checks" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Setbacks" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.systemChecks" -msgstr "Vérifications du réseau" +msgid "node.site.panel.setbacks" +msgstr "Reculs" -# Source-Hash: 4dad0ed68e63d124 +# Source-Hash: 9ede31abea7ad545 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System finding" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show ground" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.systemFinding" -msgstr "Constat du réseau" +msgid "node.site.panel.showGround" +msgstr "Afficher le sol" -# Source-Hash: e37307a519466b38 +# Source-Hash: 1e16a47e5e10c83e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System findings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show the contour lines in 3D" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.systemFindings" -msgstr "Constats du réseau" +msgid "node.site.panel.showTheContourLinesIn3d" +msgstr "Afficher les courbes de niveau en 3D" -# Source-Hash: 5128de8b5a618339 +# Source-Hash: 464241679edcbdb4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Warning" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "side" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.warning" -msgstr "Avertissement" +msgid "node.site.panel.side" +msgstr "côté" -# Source-Hash: 7e1647f9ce51509e +# Source-Hash: 91f90818d42a984e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Warnings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Site" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.warnings" -msgstr "Avertissements" +msgid "node.site.panel.site" +msgstr "Terrain" -# Source-Hash: 26aff27b7284fc84 +# Source-Hash: 6165ee130f0082e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A configurable shelving unit. Items host on each row." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Source" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shelf.description" -msgstr "Étagère configurable. Les éléments se posent sur chaque rangée." +msgid "node.site.panel.source" +msgstr "Source" -# Source-Hash: d7145f84f8e0e3fe +# Source-Hash: 5f3110d075c6a1a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shelf" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Source / citation" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shelf.label" -msgstr "Étagère" +msgid "node.site.panel.sourceCitation" +msgstr "Source / référence" -# Source-Hash: c52492c73312a922 +# Source-Hash: 041cfc610fef830b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The top-level container holding buildings, zones, and the property boundary." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Street address" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.description" -msgstr "Conteneur de premier niveau avec les bâtiments, les zones et la limite de propriété." +msgid "node.site.panel.streetAddress" +msgstr "Adresse postale" -# Source-Hash: 91f90818d42a984e +# Source-Hash: bdca51c5e6437075 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Site" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "survey" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.label" -msgstr "Terrain" +msgid "node.site.panel.survey" +msgstr "relevé" -# Source-Hash: 3b5a53b6d058a02a +# Source-Hash: 2177f21713b01a24 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Address" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {{lineCount} surveyed line} other {{lineCount} surveyed lines}} at {interval} ft ({datum}) — {source}" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.address" -msgstr "Adresse" +msgid "node.site.panel.surveyedContours" +msgstr "{count, plural, one {{lineCount} ligne relevée} many {{lineCount} lignes relevées} other {{lineCount} lignes relevées}} tous les {interval} ft ({datum}) — {source}" -# Source-Hash: ea03c49930137a0f +# Source-Hash: d457508edd5bb8cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "APN" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terrain" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.apn" -msgstr "N° de parcelle" +msgid "node.site.panel.terrain" +msgstr "Terrain" -# Source-Hash: 8519c9ddf5e6b371 +# Source-Hash: 4c8601a0b7aeed3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto — most north-facing edge" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type an address first." #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.autoMostNorthFacingEdge" -msgstr "Auto — bord le plus au nord" +msgid "node.site.panel.typeAnAddressFirst" +msgstr "Saisissez d’abord une adresse." -# Source-Hash: bc493d7655b3e3ad +# Source-Hash: dfe4cd35b3e0d5f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Contour interval (site plan and 3D)" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use project look" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.contourIntervalSitePlanAnd3d" -msgstr "Équidistance des courbes (plan de masse et 3D)" +msgid "node.site.panel.useProjectLook" +msgstr "Utiliser l’apparence du projet" -# Source-Hash: 99208d226da1315f +# Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "County" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.county" -msgstr "Comté" +msgid "node.site.panel.zone" +msgstr "Zone" -# Source-Hash: 0830cf0f95ad429d +# Source-Hash: e360f89d3c0ec456 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "e.g. RS-60" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.eGRs60" -msgstr "p. ex. RS-60" +msgid "node.site.setback.front" +msgstr "Avant" -# Source-Hash: b3e7e118266b5074 +# Source-Hash: ab1354f1aa520a54 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "e.g. Tampa LDC §27-156" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left (override)" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.eGTampaLdc27156" -msgstr "p. ex. Tampa LDC §27-156" +msgid "node.site.setback.leftOverride" +msgstr "Gauche (remplacement)" -# Source-Hash: 187e11889d08a2dc +# Source-Hash: 1a7e8e8f8e9232d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "every 12 in" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rear" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.every12In" -msgstr "tous les 12 in" +msgid "node.site.setback.rear" +msgstr "Arrière" -# Source-Hash: 17ee041f655085f8 +# Source-Hash: 8370146b38c30102 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "every 24 in" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right (override)" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.every24In" -msgstr "tous les 24 in" +msgid "node.site.setback.rightOverride" +msgstr "Droite (remplacement)" -# Source-Hash: 40d7f9ddf5efcb7f +# Source-Hash: feefe9c7cb273e79 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "every 6 in" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Side" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.every6In" -msgstr "tous les 6 in" +msgid "node.site.setback.side" +msgstr "Côté" -# Source-Hash: 442a3ce78ae6b462 +# Source-Hash: 67d903d7fe0c69c1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finding…" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framed glass opening on a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.site.panel.finding" -msgstr "Recherche…" +msgid "node.skylight.description" +msgstr "Ouverture vitrée encadrée sur un pan de toit." -# Source-Hash: 734c1eac014adc69 +# Source-Hash: 358826fbdeaf72b9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Find parcel" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Skylight" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.site.panel.findParcel" -msgstr "Trouver la parcelle" +msgid "node.skylight.label" +msgstr "Fenêtre de toit" -# Source-Hash: ccb70faaf91dbcb1 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front (street) edge" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.frontStreetEdge" -msgstr "Bord avant (rue)" +msgid "node.skylight.panel.actions" +msgstr "Actions" -# Source-Hash: 4232218226616327 +# Source-Hash: f1113261ad2797de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Looking up the parcel and the streets around it…" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Along X" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.lookingUpTheParcel" -msgstr "Recherche de la parcelle et des rues alentour…" +msgid "node.skylight.panel.alongX" +msgstr "Selon X" -# Source-Hash: c39eb5933468a637 +# Source-Hash: 5b84b1c644493370 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lot area" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Along Z" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.lotArea" -msgstr "Surface du terrain" +msgid "node.skylight.panel.alongZ" +msgstr "Selon Z" -# Source-Hash: c8a874b339ff9696 +# Source-Hash: b3a163b453896bef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "1200 W Cass St, Tampa, FL" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.n1200WCassStTampaFl" -msgstr "1200 W Cass St, Tampa, FL" +msgid "node.skylight.panel.bottom" +msgstr "Bas" -# Source-Hash: 30a0924a3360be68 +# Source-Hash: b8ff053666ee326b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "none" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curb" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.none" -msgstr "aucun" +msgid "node.skylight.panel.curb" +msgstr "Costière" -# Source-Hash: dd4e835cb90c5736 +# Source-Hash: 14144df9e1364eea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "North rotation" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cutout Offset" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.northRotation" -msgstr "Rotation du nord" +msgid "node.skylight.panel.cutoutOffset" +msgstr "Décalage de la découpe" -# Source-Hash: a4bfb2891c820e2e +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No surveyed lines — contours are drawn from the sculpted ground." -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.noSurveyedLinesContoursAreDrawn" -msgstr "Aucune ligne relevée — les courbes sont tracées depuis le terrain modelé." +msgid "node.skylight.panel.delete" +msgstr "Supprimer" -# Source-Hash: 1f0d024c0adbf0e8 +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Orientation" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.orientation" -msgstr "Orientation" +msgid "node.skylight.panel.depth" +msgstr "Profondeur" -# Source-Hash: 9a3961409e34bf66 +# Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Parcel" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.parcel" -msgstr "Parcelle" +msgid "node.skylight.panel.dimensions" +msgstr "Dimensions" -# Source-Hash: 3aecc563cb9a2c68 +# Source-Hash: ce3a6c03765dbbd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Parcel lookup failed." -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.parcelLookupFailed" -msgstr "La recherche de parcelle a échoué." +msgid "node.skylight.panel.frame" +msgstr "Cadre" -# Source-Hash: 36696c4a8bede421 +# Source-Hash: 911ea36eb835f3a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Project look" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass Thickness" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.projectLook" -msgstr "Apparence du projet" +msgid "node.skylight.panel.glassThickness" +msgstr "Épaisseur du vitrage" -# Source-Hash: 5b50fc78ccdaf7aa +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Save current look" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.saveCurrentLook" -msgstr "Enregistrer l’apparence actuelle" +msgid "node.skylight.panel.height" +msgstr "Hauteur" -# Source-Hash: f06b316f421963d7 +# Source-Hash: d56303913961984f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Save the current lighting and display as this project's default. Personal display changes stay in this browser." -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern Height" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.saveTheCurrentLightingAndDisplay" -msgstr "Enregistrer l’éclairage et l’affichage actuels comme valeurs par défaut du projet. Les réglages d’affichage personnels restent dans ce navigateur." +msgid "node.skylight.panel.lanternHeight" +msgstr "Hauteur du lanterneau" -# Source-Hash: e87df48b61eda8ce +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Setbacks" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.setbacks" -msgstr "Reculs" +msgid "node.skylight.panel.left" +msgstr "Gauche" -# Source-Hash: 9ede31abea7ad545 +# Source-Hash: f3e9604e3b85510f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show ground" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Motor" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.showGround" -msgstr "Afficher le sol" +msgid "node.skylight.panel.motor" +msgstr "Moteur" -# Source-Hash: 1e16a47e5e10c83e +# Source-Hash: a025444e0f500725 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show the contour lines in 3D" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Motor Housing" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.showTheContourLinesIn3d" -msgstr "Afficher les courbes de niveau en 3D" +msgid "node.skylight.panel.motorHousing" +msgstr "Boîtier moteur" -# Source-Hash: 464241679edcbdb4 +# Source-Hash: b2cbc4e2e5545a6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "side" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.side" -msgstr "côté" +msgid "node.skylight.panel.no" +msgstr "Non" -# Source-Hash: 91f90818d42a984e +# Source-Hash: a8e0b9fe5cfb4e3e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Site" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No Motor" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.site" -msgstr "Terrain" +msgid "node.skylight.panel.noMotor" +msgstr "Sans moteur" -# Source-Hash: 6165ee130f0082e8 +# Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Source" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.source" -msgstr "Source" +msgid "node.skylight.panel.open" +msgstr "Ouvrir" -# Source-Hash: 5f3110d075c6a1a7 +# Source-Hash: 9bfc55f879926fe6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Source / citation" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening Angle" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.sourceCitation" -msgstr "Source / référence" +msgid "node.skylight.panel.openingAngle" +msgstr "Angle d'ouverture" -# Source-Hash: 041cfc610fef830b +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Street address" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.streetAddress" -msgstr "Adresse postale" +msgid "node.skylight.panel.position" +msgstr "Position" -# Source-Hash: bdca51c5e6437075 +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "survey" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.survey" -msgstr "relevé" +msgid "node.skylight.panel.right" +msgstr "Droite" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 2177f21713b01a24 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# English: "{count, plural, one {{lineCount} surveyed line} other {{lineCount} surveyed lines}} at {interval} ft ({datum}) — {source}" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.surveyedContours" -msgstr "{count, plural, one {{lineCount} ligne relevée} many {{lineCount} lignes relevées} other {{lineCount} lignes relevées}} tous les {interval} ft ({datum}) — {source}" +msgid "node.skylight.panel.rotation" +msgstr "Rotation" -# Source-Hash: d457508edd5bb8cf +# Source-Hash: 358826fbdeaf72b9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terrain" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Skylight" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.terrain" -msgstr "Terrain" +msgid "node.skylight.panel.skylight" +msgstr "Fenêtre de toit" -# Source-Hash: 4c8601a0b7aeed3a +# Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type an address first." -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.typeAnAddressFirst" -msgstr "Saisissez d’abord une adresse." +msgid "node.skylight.panel.thickness" +msgstr "Épaisseur" -# Source-Hash: dfe4cd35b3e0d5f5 +# Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use project look" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.useProjectLook" -msgstr "Utiliser l’apparence du projet" +msgid "node.skylight.panel.top" +msgstr "Haut" -# Source-Hash: a107b4d76d6972e3 +# Source-Hash: 75991d106eb93dae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Scale" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.zone" -msgstr "Zone" +msgid "node.skylight.panel.topScale" +msgstr "Échelle du haut" -# Source-Hash: e360f89d3c0ec456 +# Source-Hash: 3272a61417949895 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Track Width" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.front" -msgstr "Avant" +msgid "node.skylight.panel.trackWidth" +msgstr "Largeur du rail" -# Source-Hash: ab1354f1aa520a54 +# Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left (override)" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.leftOverride" -msgstr "Gauche (remplacement)" +msgid "node.skylight.panel.type" +msgstr "Type" -# Source-Hash: 1a7e8e8f8e9232d7 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rear" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.rear" -msgstr "Arrière" +msgid "node.skylight.panel.width" +msgstr "Largeur" -# Source-Hash: 8370146b38c30102 +# Source-Hash: 184fda5c980b9d9c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right (override)" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Yes" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.rightOverride" -msgstr "Droite (remplacement)" +msgid "node.skylight.panel.yes" +msgstr "Oui" -# Source-Hash: feefe9c7cb273e79 +# Source-Hash: 445aacf307de133d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Side" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat roof skylight" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.side" -msgstr "Côté" +msgid "node.skylight.type.flat" +msgstr "Puits de lumière pour toit plat" -# Source-Hash: 67d903d7fe0c69c1 +# Source-Hash: 446176b7c5d8b284 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Framed glass opening on a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof lantern" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.skylight.description" -msgstr "Ouverture vitrée encadrée sur un pan de toit." +msgid "node.skylight.type.lantern" +msgstr "Lanterneau" -# Source-Hash: 358826fbdeaf72b9 +# Source-Hash: a6559387f108518f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Skylight" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening skylight" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.skylight.label" -msgstr "Fenêtre de toit" +msgid "node.skylight.type.opening" +msgstr "Puits de lumière ouvrant" +# Source-Hash: 379436bb5a74867a # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sliding skylight" #: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.skylight.panel.actions" -msgstr "Actions" +msgid "node.skylight.type.sliding" +msgstr "Puits de lumière coulissant" +# Source-Hash: d26ac61f593fe1bf # Review: required -# Source-Hash: f1113261ad2797de -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Along X" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walk-on rooflight" #: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.skylight.panel.alongX" -msgstr "Selon X" +msgid "node.skylight.type.walkOn" +msgstr "Verrière praticable" + +# Source-Hash: ad8f8036d34f6cea +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A polygon-bounded floor surface that hosts items on top." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.slab.description" +msgstr "Surface de sol délimitée par un polygone, sur laquelle se posent les éléments." +# Source-Hash: 8775bc8dc9593964 # Review: required -# Source-Hash: 5b84b1c644493370 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Along Z" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.skylight.panel.alongZ" -msgstr "Selon Z" +msgid "node.slab.label" +msgstr "Dalle" +# Source-Hash: 659e6b799ad7c27d # Review: required -# Source-Hash: b3a163b453896bef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Hole" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.bottom" -msgstr "Bas" +msgid "node.slab.panel.addHole" +msgstr "Ajouter une trémie" +# Source-Hash: 8332ab41e22958f1 # Review: required -# Source-Hash: b8ff053666ee326b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curb" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Area" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.curb" -msgstr "Costière" +msgid "node.slab.panel.area" +msgstr "Surface" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: 14144df9e1364eea -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cutout Offset" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.cutoutOffset" -msgstr "Décalage de la découpe" +msgid "node.slab.panel.auto" +msgstr "Auto" +# Source-Hash: fadada809e27477c # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.delete" -msgstr "Supprimer" +msgid "node.slab.panel.base" +msgstr "Base" +# Source-Hash: 12195951bba19804 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut hatch" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.depth" -msgstr "Profondeur" +msgid "node.slab.panel.cutHatch" +msgstr "Découper une trappe" +# Source-Hash: 4e4f1a24e4a9d61e # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut opening" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.dimensions" -msgstr "Dimensions" +msgid "node.slab.panel.cutOpening" +msgstr "Découper une ouverture" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: ce3a6c03765dbbd8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.frame" -msgstr "Cadre" +msgid "node.slab.panel.depth" +msgstr "Profondeur" +# Source-Hash: 16552c2580bbe8b8 # Review: required -# Source-Hash: 911ea36eb835f3a6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass Thickness" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.glassThickness" -msgstr "Épaisseur du vitrage" +msgid "node.slab.panel.done" +msgstr "Terminé" +# Source-Hash: 8a3bc5111b9e97f4 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevation" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.height" -msgstr "Hauteur" +msgid "node.slab.panel.elevation" +msgstr "Altitude" +# Source-Hash: 201b720b76d79762 # Review: required -# Source-Hash: d56303913961984f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern Height" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Extends the perimeter down to terrain. The flat surface, base, and thickness stay unchanged." +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.lanternHeight" -msgstr "Hauteur du lanterneau" +msgid "node.slab.panel.extendsThePerimeterDownToTerrain" +msgstr "Prolonge le pourtour jusqu’au terrain. La surface plane, la base et l’épaisseur restent inchangées." +# Source-Hash: 387ce45ca2eb045f # Review: required -# Source-Hash: f365c6b6dd9ebab9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fixed" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.left" -msgstr "Gauche" +msgid "node.slab.panel.fixed" +msgstr "Fixe" +# Source-Hash: d7148fa065bc709b # Review: required -# Source-Hash: f3e9604e3b85510f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Motor" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.motor" -msgstr "Moteur" +msgid "node.slab.panel.floor" +msgstr "Niveau" +# Source-Hash: 89b2cfd72a0a7e23 # Review: required -# Source-Hash: a025444e0f500725 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Motor Housing" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows terrain" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.motorHousing" -msgstr "Boîtier moteur" +msgid "node.slab.panel.followsTerrain" +msgstr "Suit le terrain" +# Source-Hash: 48c832c1fc389290 # Review: required -# Source-Hash: b2cbc4e2e5545a6c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.no" -msgstr "Non" +msgid "node.slab.panel.foundation" +msgstr "Fondation" +# Source-Hash: 34504c6ca6445e76 # Review: required -# Source-Hash: a8e0b9fe5cfb4e3e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No Motor" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Holes" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.noMotor" -msgstr "Sans moteur" +msgid "node.slab.panel.holes" +msgstr "Trémies" +# Source-Hash: 6e68b62d2aa611a4 # Review: required -# Source-Hash: 3e52f04f92e08070 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Info" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.open" -msgstr "Ouvrir" +msgid "node.slab.panel.info" +msgstr "Info" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: 9bfc55f879926fe6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening Angle" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.openingAngle" -msgstr "Angle d'ouverture" +msgid "node.slab.panel.move" +msgstr "Déplacer" +# Source-Hash: 1d2dafb0d8f26ed5 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No holes" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.position" -msgstr "Position" +msgid "node.slab.panel.noHoles" +msgstr "Aucune trémie" +# Source-Hash: c6a29e75bf215488 # Review: required -# Source-Hash: b34d5ee0f218221d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rim" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.right" -msgstr "Droite" +msgid "node.slab.panel.rim" +msgstr "Rebord" +# Source-Hash: 8775bc8dc9593964 # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.rotation" -msgstr "Rotation" +msgid "node.slab.panel.slab" +msgstr "Dalle" +# Source-Hash: fb23c960abf5de23 # Review: required -# Source-Hash: 358826fbdeaf72b9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Skylight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard (2\")" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.skylight" -msgstr "Fenêtre de toit" +msgid "node.slab.panel.standard2" +msgstr "Standard (2\")" +# Source-Hash: 5f865b052c9b40eb # Review: required -# Source-Hash: fdbb503f0941bd56 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard (5cm)" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.thickness" -msgstr "Épaisseur" +msgid "node.slab.panel.standard5cm" +msgstr "Standard (5 cm)" +# Source-Hash: cff0e2e72cfab157 # Review: required -# Source-Hash: 27644f0497fd9849 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sunken (15cm)" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.top" -msgstr "Haut" +msgid "node.slab.panel.sunken15cm" +msgstr "Encaissé (15 cm)" +# Source-Hash: 8abc2aec4be98fe9 # Review: required -# Source-Hash: 75991d106eb93dae -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Scale" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sunken (6\")" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.topScale" -msgstr "Échelle du haut" +msgid "node.slab.panel.sunken6" +msgstr "Encaissé (6\")" +# Source-Hash: 78a454b7ac7a3cd9 # Review: required -# Source-Hash: 3272a61417949895 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Track Width" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.trackWidth" -msgstr "Largeur du rail" +msgid "node.slab.panel.surface" +msgstr "Surface" +# Source-Hash: 516636d85be919f0 # Review: required -# Source-Hash: c44f7ab8bbd24858 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thick (15cm)" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.type" -msgstr "Type" +msgid "node.slab.panel.thick15cm" +msgstr "Épais (15 cm)" +# Source-Hash: c84078f3560da233 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thick (6\")" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.width" -msgstr "Largeur" +msgid "node.slab.panel.thick6" +msgstr "Épais (6\")" +# Source-Hash: fdbb503f0941bd56 # Review: required -# Source-Hash: 184fda5c980b9d9c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Yes" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.yes" -msgstr "Oui" +msgid "node.slab.panel.thickness" +msgstr "Épaisseur" +# Source-Hash: 61c191f6df40285b # Review: required -# Source-Hash: 445aacf307de133d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat roof skylight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thin (1\")" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.type.flat" -msgstr "Puits de lumière pour toit plat" +msgid "node.slab.panel.thin1" +msgstr "Mince (1\")" +# Source-Hash: d345b1f707506fe7 # Review: required -# Source-Hash: 446176b7c5d8b284 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof lantern" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thin (2cm)" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.type.lantern" -msgstr "Lanterneau" +msgid "node.slab.panel.thin2cm" +msgstr "Mince (2 cm)" +# Source-Hash: 065ffaaf64ab479d # Review: required -# Source-Hash: a6559387f108518f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening skylight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid of photovoltaic panels mounted on a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.skylight.type.opening" -msgstr "Puits de lumière ouvrant" +msgid "node.solarPanel.description" +msgstr "Ensemble de panneaux photovoltaïques fixés sur un pan de toit." +# Source-Hash: 4d18446ff8eaa680 # Review: required -# Source-Hash: 379436bb5a74867a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sliding skylight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solar Panel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.skylight.type.sliding" -msgstr "Puits de lumière coulissant" +msgid "node.solarPanel.label" +msgstr "Panneau solaire" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: d26ac61f593fe1bf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walk-on rooflight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.skylight.type.walkOn" -msgstr "Verrière praticable" +msgid "node.solarPanel.panel.actions" +msgstr "Actions" -# Source-Hash: ad8f8036d34f6cea +# Source-Hash: 2184867946897298 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A polygon-bounded floor surface that hosts items on top." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Array" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.description" -msgstr "Surface de sol délimitée par un polygone, sur laquelle se posent les éléments." +msgid "node.solarPanel.panel.array" +msgstr "Champ" -# Source-Hash: 8775bc8dc9593964 +# Source-Hash: 6eaa0e2a78d44d59 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto-fit to roof" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.label" -msgstr "Dalle" +msgid "node.solarPanel.panel.autoFitToRoof" +msgstr "Ajuster au toit" -# Source-Hash: 659e6b799ad7c27d +# Source-Hash: 30edd1c180aac9b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Hole" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Columns" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.addHole" -msgstr "Ajouter une trémie" +msgid "node.solarPanel.panel.columns" +msgstr "Colonnes" -# Source-Hash: 8332ab41e22958f1 +# Source-Hash: d1c6dd6335337cc1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Area" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom — dimensions don't match any preset" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.area" -msgstr "Surface" +msgid "node.solarPanel.panel.customDimensionsDonTMatchAny" +msgstr "Personnalisé — les dimensions ne correspondent à aucun préréglage" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.auto" -msgstr "Auto" +msgid "node.solarPanel.panel.delete" +msgstr "Supprimer" -# Source-Hash: fadada809e27477c +# Source-Hash: fe9356b1d0e0396b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip orientation" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.base" -msgstr "Base" +msgid "node.solarPanel.panel.flipOrientation" +msgstr "Inverser l'orientation" -# Source-Hash: 12195951bba19804 +# Source-Hash: eaaa20f3b603140f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut hatch" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flush" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.cutHatch" -msgstr "Découper une trappe" +msgid "node.solarPanel.panel.flush" +msgstr "Affleurant" -# Source-Hash: 4e4f1a24e4a9d61e +# Source-Hash: fd413477f1a9e5ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut opening" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame depth" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.cutOpening" -msgstr "Découper une ouverture" +msgid "node.solarPanel.panel.frameDepth" +msgstr "Profondeur du cadre" -# Source-Hash: 99ac4d03c3061f3a +# Source-Hash: 6aa2318fa815e5f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame thickness" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.depth" -msgstr "Profondeur" +msgid "node.solarPanel.panel.frameThickness" +msgstr "Épaisseur du cadre" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: c5657f721eae3dff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap X" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.done" -msgstr "Terminé" +msgid "node.solarPanel.panel.gapX" +msgstr "Espacement X" -# Source-Hash: 8a3bc5111b9e97f4 +# Source-Hash: e6e3b393aa7c0d98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevation" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap Y" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.elevation" -msgstr "Altitude" +msgid "node.solarPanel.panel.gapY" +msgstr "Espacement Y" -# Source-Hash: 201b720b76d79762 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Extends the perimeter down to terrain. The flat surface, base, and thickness stay unchanged." -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.extendsThePerimeterDownToTerrain" -msgstr "Prolonge le pourtour jusqu’au terrain. La surface plane, la base et l’épaisseur restent inchangées." +msgid "node.solarPanel.panel.height" +msgstr "Hauteur" -# Source-Hash: 387ce45ca2eb045f +# Source-Hash: 81d365ccef73068c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fixed" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.fixed" -msgstr "Fixe" +msgid "node.solarPanel.panel.mounting" +msgstr "Montage" -# Source-Hash: d7148fa065bc709b +# Source-Hash: 482469f5a0873f73 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.floor" -msgstr "Niveau" +msgid "node.solarPanel.panel.panel" +msgstr "Panneau" -# Source-Hash: 89b2cfd72a0a7e23 +# Source-Hash: 441f7f652ea6a0d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows terrain" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preset" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.followsTerrain" -msgstr "Suit le terrain" +msgid "node.solarPanel.panel.preset" +msgstr "Préréglage" -# Source-Hash: 48c832c1fc389290 +# Source-Hash: c913b494c3901a17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rows" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.foundation" -msgstr "Fondation" +msgid "node.solarPanel.panel.rows" +msgstr "Rangées" -# Source-Hash: 34504c6ca6445e76 +# Source-Hash: a4dba2b2675dbba0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Holes" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Setbacks too large to fit a panel." +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.holes" -msgstr "Trémies" +msgid "node.solarPanel.panel.setbacksTooLarge" +msgstr "Retraits trop grands pour placer un panneau." -# Source-Hash: 6e68b62d2aa611a4 +# Source-Hash: 4d18446ff8eaa680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Info" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solar Panel" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.info" -msgstr "Info" +msgid "node.solarPanel.panel.solarPanel" +msgstr "Panneau solaire" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 0af6194a8b8d8be6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standoff" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.move" -msgstr "Déplacer" +msgid "node.solarPanel.panel.standoff" +msgstr "Entretoise" -# Source-Hash: 1d2dafb0d8f26ed5 +# Source-Hash: 58cb60c14826f1d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No holes" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilt angle" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.noHoles" -msgstr "Aucune trémie" +msgid "node.solarPanel.panel.tiltAngle" +msgstr "Angle d’inclinaison" -# Source-Hash: c6a29e75bf215488 +# Source-Hash: 787005b26aec58a3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rim" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilted" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.rim" -msgstr "Rebord" +msgid "node.solarPanel.panel.tilted" +msgstr "Incliné" -# Source-Hash: 8775bc8dc9593964 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.slab" -msgstr "Dalle" +msgid "node.solarPanel.panel.width" +msgstr "Largeur" -# Source-Hash: fb23c960abf5de23 +# Source-Hash: cd53f16290b67f7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard (2\")" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Compact" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.standard2" -msgstr "Standard (2\")" +msgid "node.solarPanel.preset.compact" +msgstr "Compact" -# Source-Hash: 5f865b052c9b40eb +# Source-Hash: 317ebe2aa996af70 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard (5cm)" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frameless" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.standard5cm" -msgstr "Standard (5 cm)" +msgid "node.solarPanel.preset.frameless" +msgstr "Sans cadre" -# Source-Hash: cff0e2e72cfab157 +# Source-Hash: 46660ad432e19312 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sunken (15cm)" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Residential" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.sunken15cm" -msgstr "Encaissé (15 cm)" +msgid "node.solarPanel.preset.residential" +msgstr "Résidentiel" -# Source-Hash: 8abc2aec4be98fe9 +# Source-Hash: b33386b8fe3725fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sunken (6\")" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Residential Large" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.sunken6" -msgstr "Encaissé (6\")" +msgid "node.solarPanel.preset.residentialLarge" +msgstr "Résidentiel grand format" -# Source-Hash: 78a454b7ac7a3cd9 +# Source-Hash: 638f17c80f424dd3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Player or camera origin within a level. One per level." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.slab.panel.surface" -msgstr "Surface" +msgid "node.spawn.description" +msgstr "Origine du joueur ou de la caméra dans un niveau. Une par niveau." -# Source-Hash: 516636d85be919f0 +# Source-Hash: 3e2f6b4274f592c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thick (15cm)" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spawn Point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.slab.panel.thick15cm" -msgstr "Épais (15 cm)" +msgid "node.spawn.label" +msgstr "Point d’apparition" -# Source-Hash: c84078f3560da233 +# Source-Hash: faaa4f6b40001667 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thick (6\")" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Body" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.slab.panel.thick6" -msgstr "Épais (6\")" +msgid "node.stair.constructionControls.body" +msgstr "Corps" -# Source-Hash: fdbb503f0941bd56 +# Source-Hash: 29b9fdb127a54435 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center stringer" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.slab.panel.thickness" -msgstr "Épaisseur" +msgid "node.stair.constructionControls.centerStringer" +msgstr "Limon central" -# Source-Hash: 61c191f6df40285b +# Source-Hash: b2b2383577835a61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thin (1\")" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Closed risers" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.slab.panel.thin1" -msgstr "Mince (1\")" +msgid "node.stair.constructionControls.closedRisers" +msgstr "Contremarches fermées" -# Source-Hash: d345b1f707506fe7 +# Source-Hash: 49a25acbaf33ee3d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thin (2cm)" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "From structure" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.slab.panel.thin2cm" -msgstr "Mince (2 cm)" +msgid "node.stair.constructionControls.fromStructure" +msgstr "Selon la structure" -# Source-Hash: 065ffaaf64ab479d +# Source-Hash: 6f6b188bff3c0223 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid of photovoltaic panels mounted on a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inherit" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.description" -msgstr "Ensemble de panneaux photovoltaïques fixés sur un pan de toit." +msgid "node.stair.constructionControls.inherit" +msgstr "Hériter" -# Source-Hash: 4d18446ff8eaa680 +# Source-Hash: ce25dc4a23f3ae10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solar Panel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Nosing" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.label" -msgstr "Panneau solaire" +msgid "node.stair.constructionControls.nosing" +msgstr "Nez de marche" +# Source-Hash: 3e52f04f92e08070 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.actions" -msgstr "Actions" +msgid "node.stair.constructionControls.open" +msgstr "Ouvrir" +# Source-Hash: 7717e0464ad1e7df # Review: required -# Source-Hash: 2184867946897298 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Array" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Original" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.array" -msgstr "Champ" +msgid "node.stair.constructionControls.original" +msgstr "Original" +# Source-Hash: 8a6f6c6b0cca7460 # Review: required -# Source-Hash: 6eaa0e2a78d44d59 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto-fit to roof" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Riser thickness" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.autoFitToRoof" -msgstr "Ajuster au toit" +msgid "node.stair.constructionControls.riserThickness" +msgstr "Épaisseur de contremarche" +# Source-Hash: 2fe058966023b542 # Review: required -# Source-Hash: 30edd1c180aac9b4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Columns" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Side stringers" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.columns" -msgstr "Colonnes" +msgid "node.stair.constructionControls.sideStringers" +msgstr "Limons latéraux" +# Source-Hash: ef3e765e692faf4c # Review: required -# Source-Hash: d1c6dd6335337cc1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom — dimensions don't match any preset" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.customDimensionsDonTMatchAny" -msgstr "Personnalisé — les dimensions ne correspondent à aucun préréglage" +msgid "node.stair.constructionControls.solid" +msgstr "Plein" +# Source-Hash: 4c1489839e306865 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringer depth" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.delete" -msgstr "Supprimer" +msgid "node.stair.constructionControls.stringerDepth" +msgstr "Hauteur du limon" +# Source-Hash: 17e1a09c422d3660 # Review: required -# Source-Hash: fe9356b1d0e0396b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip orientation" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringer width" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.flipOrientation" -msgstr "Inverser l'orientation" +msgid "node.stair.constructionControls.stringerWidth" +msgstr "Largeur du limon" +# Source-Hash: 146f8e61ff310dc5 # Review: required -# Source-Hash: eaaa20f3b603140f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flush" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tread finish" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.flush" -msgstr "Affleurant" +msgid "node.stair.constructionControls.treadFinish" +msgstr "Finition des marches" +# Source-Hash: 9089f91f3fbbf4cd # Review: required -# Source-Hash: fd413477f1a9e5ed -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame depth" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tread thickness" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.frameDepth" -msgstr "Profondeur du cadre" +msgid "node.stair.constructionControls.treadThickness" +msgstr "Épaisseur des marches" +# Source-Hash: 44dda7136b93c8ee # Review: required -# Source-Hash: 6aa2318fa815e5f2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame thickness" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.frameThickness" -msgstr "Épaisseur du cadre" +msgid "node.stair.constructionControls.waist" +msgstr "Paillasse" +# Source-Hash: dfd6d2ff7a94f22e # Review: required -# Source-Hash: c5657f721eae3dff -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap X" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist thickness" +#: packages/nodes/src/stair/construction-controls.tsx +#, fuzzy +msgid "node.stair.constructionControls.waistThickness" +msgstr "Épaisseur de paillasse" + +# Source-Hash: 8535b75637105412 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A stair composed of one or more flights with configurable treads, risers, railings." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.solarPanel.panel.gapX" -msgstr "Espacement X" +msgid "node.stair.description" +msgstr "Escalier composé d’une ou plusieurs volées, avec marches, contremarches et garde-corps configurables." +# Source-Hash: c24b098693e1006d # Review: required -# Source-Hash: e6e3b393aa7c0d98 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap Y" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The flight chain does not reach the declared destination." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.gapY" -msgstr "Espacement Y" +msgid "node.stair.diagnostic.arrivalMismatch" +msgstr "La suite de volées n’atteint pas la destination déclarée." +# Source-Hash: 124ad1cd6bb00013 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Two risers plus going is outside the 0.60–0.65 m design range." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.height" -msgstr "Hauteur" +msgid "node.stair.diagnostic.comfortTarget" +msgstr "Deux hauteurs plus un giron sortent de la plage de conception 0,60–0,65 m." +# Source-Hash: 7452fcd8370bef34 # Review: required -# Source-Hash: 81d365ccef73068c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Going is below the design target." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.mounting" -msgstr "Montage" +msgid "node.stair.diagnostic.goingTarget" +msgstr "Le giron est inférieur à l’objectif de conception." +# Source-Hash: 449683eb727091d5 # Review: required -# Source-Hash: 482469f5a0873f73 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overhead surfaces leave less than the target headroom." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.panel" -msgstr "Panneau" +msgid "node.stair.diagnostic.headroomTarget" +msgstr "Les surfaces au-dessus laissent moins que l’échappée cible." +# Source-Hash: 9e9357408f6a0d08 # Review: required -# Source-Hash: 441f7f652ea6a0d8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preset" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Detailed headroom could not be evaluated: check riser counts and the surface query budget." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.preset" -msgstr "Préréglage" +msgid "node.stair.diagnostic.headroomUnresolved" +msgstr "L’échappée détaillée n’a pas pu être évaluée : vérifiez le nombre de contremarches et le budget de requêtes de surface." +# Source-Hash: 40fd019d72ff3835 # Review: required -# Source-Hash: c913b494c3901a17 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rows" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight dimensions and integer riser count must be positive." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.rows" -msgstr "Rangées" +msgid "node.stair.diagnostic.invalidFlight" +msgstr "Les dimensions de volée et le nombre entier de contremarches doivent être positifs." +# Source-Hash: 3d4b6f859bd8de50 # Review: required -# Source-Hash: a4dba2b2675dbba0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Setbacks too large to fit a panel." -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The destination must be above the stair base." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.setbacksTooLarge" -msgstr "Retraits trop grands pour placer un panneau." +msgid "node.stair.diagnostic.invalidRise" +msgstr "La destination doit être au-dessus de la base de l’escalier." +# Source-Hash: 5f196b22e2c8296a # Review: required -# Source-Hash: 4d18446ff8eaa680 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solar Panel" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing depth exceeds a full circle at the walking line; the visible landing is limited to one circle." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.solarPanel" -msgstr "Panneau solaire" +msgid "node.stair.diagnostic.landingOverlap" +msgstr "La profondeur du palier dépasse un cercle complet sur la ligne de foulée ; le palier visible est limité à un cercle." +# Source-Hash: 0122ec92b951a114 # Review: required -# Source-Hash: 0af6194a8b8d8be6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standoff" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The narrow end of a winder tread is below 0.10 m; check the intended stair use." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.standoff" -msgstr "Entretoise" +msgid "node.stair.diagnostic.narrowWinderEnd" +msgstr "L’extrémité étroite d’une marche balancée est inférieure à 0,10 m ; vérifiez l’usage prévu de l’escalier." +# Source-Hash: a664dc7f3b014af8 # Review: required -# Source-Hash: 58cb60c14826f1d0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilt angle" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight riser heights differ. Use uniform-riser repair only if this is a proposed design." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.tiltAngle" -msgstr "Angle d’inclinaison" +msgid "node.stair.diagnostic.nonuniformRisers" +msgstr "Les hauteurs de contremarche de la volée diffèrent. N’utilisez la correction de contremarches régulières que pour un projet." +# Source-Hash: cd140b519d37b01e # Review: required -# Source-Hash: 787005b26aec58a3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilted" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A landing has a stored rise; inspect its transition before repair." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.tilted" -msgstr "Incliné" +msgid "node.stair.diagnostic.raisedLanding" +msgstr "Un palier a une hauteur enregistrée ; vérifiez sa transition avant de corriger." +# Source-Hash: a94cfa7b2a21cf14 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Riser height exceeds the design target." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.width" -msgstr "Largeur" +msgid "node.stair.diagnostic.riserTarget" +msgstr "La hauteur de contremarche dépasse l’objectif de conception." +# Source-Hash: 53d7084bc41c1ad6 # Review: required -# Source-Hash: cd53f16290b67f7f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Compact" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.solarPanel.preset.compact" -msgstr "Compact" +msgid "node.stair.label" +msgstr "Escalier" +# Source-Hash: 4ee35f740730ae87 # Review: required -# Source-Hash: 317ebe2aa996af70 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frameless" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.preset.frameless" -msgstr "Sans cadre" +msgid "node.stair.layout.straight" +msgstr "Droit" +# Source-Hash: 1cda16cb49e6fb93 # Review: required -# Source-Hash: 46660ad432e19312 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Residential" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{layout} turn" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.preset.residential" -msgstr "Résidentiel" +msgid "node.stair.layout.turn" +msgstr "Retour {layout}" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: b33386b8fe3725fa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Residential Large" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.preset.residentialLarge" -msgstr "Résidentiel grand format" +msgid "node.stair.panel.actions" +msgstr "Actions" -# Source-Hash: 638f17c80f424dd3 +# Source-Hash: 15eaf25f306541f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Player or camera origin within a level. One per level." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add flight" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.spawn.description" -msgstr "Origine du joueur ou de la caméra dans un niveau. Une par niveau." +msgid "node.stair.panel.addFlight" +msgstr "Ajouter une volée" -# Source-Hash: 3e2f6b4274f592c0 +# Source-Hash: 1fa37c346bffb8e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spawn Point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add landing" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.spawn.label" -msgstr "Point d’apparition" +msgid "node.stair.panel.addLanding" +msgstr "Ajouter un palier" -# Source-Hash: faaa4f6b40001667 +# Source-Hash: 9ccbd6c1785f1e73 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Body" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Apply {label} layout" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.body" -msgstr "Corps" +msgid "node.stair.panel.applyLabelLayout" +msgstr "Appliquer la disposition {label}" -# Source-Hash: 29b9fdb127a54435 +# Source-Hash: 7eb42ea0fc442b8d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center stringer" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto Cutout" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.centerStringer" -msgstr "Limon central" +msgid "node.stair.panel.autoCutout" +msgstr "Découpe auto" -# Source-Hash: b2b2383577835a61 +# Source-Hash: 3eda29328f91485d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Closed risers" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Balusters" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.closedRisers" -msgstr "Contremarches fermées" +msgid "node.stair.panel.balusters" +msgstr "Balustres" -# Source-Hash: 6f6b188bff3c0223 +# Source-Hash: 19ae2360207ecf5a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inherit" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Boards" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.inherit" -msgstr "Hériter" +msgid "node.stair.panel.boards" +msgstr "Planches" -# Source-Hash: ce25dc4a23f3ae10 +# Source-Hash: 69578b7dd7723fa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Nosing" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Both" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.nosing" -msgstr "Nez de marche" +msgid "node.stair.panel.both" +msgstr "Les deux" -# Source-Hash: 3e52f04f92e08070 +# Source-Hash: 5e2429ced8144ab4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cable" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.open" -msgstr "Ouvrir" +msgid "node.stair.panel.cable" +msgstr "Câble" -# Source-Hash: 7717e0464ad1e7df +# Source-Hash: 11d6eec5d485488d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Original" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center Column" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.original" -msgstr "Original" +msgid "node.stair.panel.centerColumn" +msgstr "Colonne centrale" -# Source-Hash: 8a6f6c6b0cca7460 +# Source-Hash: 5fbbf4ad24befa7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Riser thickness" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clockwise" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.riserThickness" -msgstr "Épaisseur de contremarche" +msgid "node.stair.panel.clockwise" +msgstr "Sens horaire" -# Source-Hash: 2fe058966023b542 +# Source-Hash: 31028ca51b49018b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Side stringers" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connected to {surface}. Move the stair to connect to another edge." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.sideStringers" -msgstr "Limons latéraux" +msgid "node.stair.panel.connectedTo" +msgstr "Raccordé à {surface}. Déplacez l’escalier pour le raccorder à un autre bord." -# Source-Hash: ef3e765e692faf4c +# Source-Hash: 33133921e270509f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connected to a surface. Move the stair to connect to another edge." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.solid" -msgstr "Plein" +msgid "node.stair.panel.connectedToSurface" +msgstr "Raccordé à une surface. Déplacez l’escalier pour le raccorder à un autre bord." -# Source-Hash: 4c1489839e306865 +# Source-Hash: ce1429556f57d7ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stringer depth" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Construction" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.stringerDepth" -msgstr "Hauteur du limon" +msgid "node.stair.panel.construction" +msgstr "Construction" -# Source-Hash: 17e1a09c422d3660 +# Source-Hash: 5e3e3ab7d91c2c4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stringer width" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Counterclockwise" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.stringerWidth" -msgstr "Largeur du limon" +msgid "node.stair.panel.counterclockwise" +msgstr "Sens antihoraire" -# Source-Hash: 146f8e61ff310dc5 +# Source-Hash: a028e08962c388e0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tread finish" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curved" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.treadFinish" -msgstr "Finition des marches" +msgid "node.stair.panel.curved" +msgstr "Courbe" -# Source-Hash: 9089f91f3fbbf4cd +# Source-Hash: 0bd4232a56d25366 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tread thickness" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom rise" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.treadThickness" -msgstr "Épaisseur des marches" +msgid "node.stair.panel.customRise" +msgstr "Hauteur de marche personnalisée" -# Source-Hash: 44dda7136b93c8ee +# Source-Hash: f3aa561772702108 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.waist" -msgstr "Paillasse" +msgid "node.stair.panel.deck" +msgstr "Terrasse" -# Source-Hash: dfd6d2ff7a94f22e +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist thickness" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.waistThickness" -msgstr "Épaisseur de paillasse" +msgid "node.stair.panel.delete" +msgstr "Supprimer" -# Source-Hash: 8535b75637105412 +# Source-Hash: 1c34e5cc37add163 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A stair composed of one or more flights with configurable treads, risers, railings." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Design targets" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.description" -msgstr "Escalier composé d’une ou plusieurs volées, avec marches, contremarches et garde-corps configurables." +msgid "node.stair.panel.designTargets" +msgstr "Objectifs de conception" -# Source-Hash: c24b098693e1006d +# Source-Hash: 748877ae309c313c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The flight chain does not reach the declared destination." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Destination" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.arrivalMismatch" -msgstr "La suite de volées n’atteint pas la destination déclarée." +msgid "node.stair.panel.destination" +msgstr "Destination" -# Source-Hash: 124ad1cd6bb00013 +# Source-Hash: 1fa48e82752d1505 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Two risers plus going is outside the 0.60–0.65 m design range." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag near a deck, patio, concrete slab, or landing edge to fit the stair." #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.comfortTarget" -msgstr "Deux hauteurs plus un giron sortent de la plage de conception 0,60–0,65 m." +msgid "node.stair.panel.dragNearADeckPatioConcrete" +msgstr "Faites glisser près d’une terrasse, d’un patio, d’une dalle ou d’un bord de palier pour ajuster l’escalier." -# Source-Hash: 7452fcd8370bef34 +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Going is below the design target." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.goingTarget" -msgstr "Le giron est inférieur à l’objectif de conception." +msgid "node.stair.panel.duplicate" +msgstr "Dupliquer" -# Source-Hash: 449683eb727091d5 +# Source-Hash: 776903eb3756eea9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overhead surfaces leave less than the target headroom." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equal angle" +#: packages/nodes/src/stair/panel.tsx +#, fuzzy +msgid "node.stair.panel.equalAngle" +msgstr "Angle égal" + +# Source-Hash: 8956a359d7cec0a6 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equal going" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.headroomTarget" -msgstr "Les surfaces au-dessus laissent moins que l’échappée cible." +msgid "node.stair.panel.equalGoing" +msgstr "Giron égal" -# Source-Hash: 9e9357408f6a0d08 +# Source-Hash: 6ff728d5058c7e31 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Detailed headroom could not be evaluated: check riser counts and the surface query budget." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit risers and going" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.headroomUnresolved" -msgstr "L’échappée détaillée n’a pas pu être évaluée : vérifiez le nombre de contremarches et le budget de requêtes de surface." +msgid "node.stair.panel.fitRisersAndGoing" +msgstr "Ajuster contremarches et giron" -# Source-Hash: 40fd019d72ff3835 +# Source-Hash: d60a4c7995bd2184 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flight dimensions and integer riser count must be positive." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit To Floor" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.invalidFlight" -msgstr "Les dimensions de volée et le nombre entier de contremarches doivent être positifs." +msgid "node.stair.panel.fitToFloor" +msgstr "Ajuster au plancher" -# Source-Hash: 3d4b6f859bd8de50 +# Source-Hash: 0638614580661eb0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The destination must be above the stair base." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit uniform risers" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.invalidRise" -msgstr "La destination doit être au-dessus de la base de l’escalier." +msgid "node.stair.panel.fitUniformRisers" +msgstr "Ajuster des contremarches régulières" -# Source-Hash: 5f196b22e2c8296a +# Source-Hash: 4d365dbc1fb92b90 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing depth exceeds a full circle at the walking line; the visible landing is limited to one circle." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight {number}: {count, plural, one {{riserCount} riser} other {{riserCount} risers}} · R {riser} · T {going} · {slope}" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.landingOverlap" -msgstr "La profondeur du palier dépasse un cercle complet sur la ligne de foulée ; le palier visible est limité à un cercle." +msgid "node.stair.panel.flightMeasurements" +msgstr "Volée {number} : {count, plural, one {{riserCount} contremarche} many {{riserCount} contremarches} other {{riserCount} contremarches}} · H {riser} · G {going} · {slope}" -# Source-Hash: 0122ec92b951a114 +# Source-Hash: 6e946bd1acd94637 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The narrow end of a winder tread is below 0.10 m; check the intended stair use." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floors, ceilings and stairs only." #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.narrowWinderEnd" -msgstr "L’extrémité étroite d’une marche balancée est inférieure à 0,10 m ; vérifiez l’usage prévu de l’escalier." +msgid "node.stair.panel.floorsCeilingsAndStairsOnly" +msgstr "Planchers, plafonds et escaliers uniquement." -# Source-Hash: a664dc7f3b014af8 +# Source-Hash: fa10ea42944107a8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flight riser heights differ. Use uniform-riser repair only if this is a proposed design." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows deck" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.nonuniformRisers" -msgstr "Les hauteurs de contremarche de la volée diffèrent. N’utilisez la correction de contremarches régulières que pour un projet." +msgid "node.stair.panel.followsDeck" +msgstr "Suit la terrasse" -# Source-Hash: cd140b519d37b01e +# Source-Hash: a5c2353769b603d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A landing has a stored rise; inspect its transition before repair." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows level" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.raisedLanding" -msgstr "Un palier a une hauteur enregistrée ; vérifiez sa transition avant de corriger." +msgid "node.stair.panel.followsLevel" +msgstr "Suit le niveau" -# Source-Hash: a94cfa7b2a21cf14 +# Source-Hash: b7fc627a965bc016 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Riser height exceeds the design target." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "From Level" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.riserTarget" -msgstr "La hauteur de contremarche dépasse l’objectif de conception." +msgid "node.stair.panel.fromLevel" +msgstr "Depuis le niveau" -# Source-Hash: 53d7084bc41c1ad6 +# Source-Hash: 523b9912e283b644 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Geometry" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.label" -msgstr "Escalier" +msgid "node.stair.panel.geometry" +msgstr "Géométrie" -# Source-Hash: 4ee35f740730ae87 +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.layout.straight" -msgstr "Droit" +msgid "node.stair.panel.glass" +msgstr "Vitrage" -# Source-Hash: 1cda16cb49e6fb93 +# Source-Hash: 55adba80c39500f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{layout} turn" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Headroom:" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.layout.turn" -msgstr "Retour {layout}" +msgid "node.stair.panel.headroom" +msgstr "Échappée :" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.actions" -msgstr "Actions" +msgid "node.stair.panel.height" +msgstr "Hauteur" -# Source-Hash: 15eaf25f306541f9 +# Source-Hash: 9bcdccd29e64c4d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add flight" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inner gap" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.addFlight" -msgstr "Ajouter une volée" +msgid "node.stair.panel.innerGap" +msgstr "Écart intérieur" -# Source-Hash: 1fa37c346bffb8e4 +# Source-Hash: 8b54356df7ae40bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add landing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inner Radius" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.addLanding" -msgstr "Ajouter un palier" +msgid "node.stair.panel.innerRadius" +msgstr "Rayon intérieur" -# Source-Hash: 9ccbd6c1785f1e73 +# Source-Hash: 88d5b9ecb242c650 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Apply {label} layout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Integrated" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.applyLabelLayout" -msgstr "Appliquer la disposition {label}" +msgid "node.stair.panel.integrated" +msgstr "Intégré" -# Source-Hash: 7eb42ea0fc442b8d +# Source-Hash: de9566487b17a73b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto Cutout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.autoCutout" -msgstr "Découpe auto" +msgid "node.stair.panel.landing" +msgstr "Palier" -# Source-Hash: 3eda29328f91485d +# Source-Hash: 54800340a0eeab23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Balusters" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layout" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.balusters" -msgstr "Balustres" +msgid "node.stair.panel.layout" +msgstr "Disposition" -# Source-Hash: 19ae2360207ecf5a +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Boards" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.boards" -msgstr "Planches" +msgid "node.stair.panel.left" +msgstr "Gauche" -# Source-Hash: 69578b7dd7723fa1 +# Source-Hash: 7d4f8532c0d115e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Both" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left turn" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.both" -msgstr "Les deux" +msgid "node.stair.panel.leftTurn" +msgstr "Retour à gauche" -# Source-Hash: 5e2429ced8144ab4 +# Source-Hash: c6aa74075f37313a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cable" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Measurements" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.cable" -msgstr "Câble" +msgid "node.stair.panel.measurements" +msgstr "Mesures" -# Source-Hash: 11d6eec5d485488d +# Source-Hash: 8e464a8f52254f27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center Column" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Metal" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.centerColumn" -msgstr "Colonne centrale" +msgid "node.stair.panel.metal" +msgstr "Métal" -# Source-Hash: 5fbbf4ad24befa7f +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clockwise" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.clockwise" -msgstr "Sens horaire" +msgid "node.stair.panel.move" +msgstr "Déplacer" -# Source-Hash: 31028ca51b49018b -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connected to {surface}. Move the stair to connect to another edge." +# Source-Hash: a4f1cc34aae4db27 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Moving this stair keeps its current rise, steps, and run." #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.connectedTo" -msgstr "Raccordé à {surface}. Déplacez l’escalier pour le raccorder à un autre bord." +msgid "node.stair.panel.movingThisStairKeepsItsCurrent" +msgstr "Déplacer cet escalier conserve sa hauteur, ses marches et son reculement actuels." -# Source-Hash: 33133921e270509f +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connected to a surface. Move the stair to connect to another edge." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.connectedToSurface" -msgstr "Raccordé à une surface. Déplacez l’escalier pour le raccorder à un autre bord." +msgid "node.stair.panel.none" +msgstr "Aucun" -# Source-Hash: ce1429556f57d7ee +# Source-Hash: 47c858b3022b3ae5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Construction" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No overhead surface" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.construction" -msgstr "Construction" +msgid "node.stair.panel.noOverheadSurface" +msgstr "Aucune surface au-dessus" -# Source-Hash: 5e3e3ab7d91c2c4f +# Source-Hash: 17f1933d93cf655c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Counterclockwise" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not evaluated" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.counterclockwise" -msgstr "Sens antihoraire" +msgid "node.stair.panel.notEvaluated" +msgstr "Non évalué" -# Source-Hash: a028e08962c388e0 +# Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curved" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.curved" -msgstr "Courbe" +msgid "node.stair.panel.opening" +msgstr "Ouverture" -# Source-Hash: 0bd4232a56d25366 +# Source-Hash: 599220556fc4bbfb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom rise" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening Offset" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.customRise" -msgstr "Hauteur de marche personnalisée" +msgid "node.stair.panel.openingOffset" +msgstr "Décalage de l’ouverture" -# Source-Hash: f3aa561772702108 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Deck" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.deck" -msgstr "Terrasse" +msgid "node.stair.panel.position" +msgstr "Position" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: f522323372a7a59e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post & rail" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.delete" -msgstr "Supprimer" +msgid "node.stair.panel.postRail" +msgstr "Poteaux et lisses" -# Source-Hash: 1c34e5cc37add163 +# Source-Hash: 240ed9c77627b9a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Design targets" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.designTargets" -msgstr "Objectifs de conception" +msgid "node.stair.panel.railing" +msgstr "Garde-corps" -# Source-Hash: 748877ae309c313c +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Destination" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.destination" -msgstr "Destination" +msgid "node.stair.panel.right" +msgstr "Droite" -# Source-Hash: 1fa48e82752d1505 +# Source-Hash: ae876c3e9a5913eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag near a deck, patio, concrete slab, or landing edge to fit the stair." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right turn" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.dragNearADeckPatioConcrete" -msgstr "Faites glisser près d’une terrasse, d’un patio, d’une dalle ou d’un bord de palier pour ajuster l’escalier." +msgid "node.stair.panel.rightTurn" +msgstr "Retour à droite" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: fe8c5b735495eb00 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rise" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.duplicate" -msgstr "Dupliquer" +msgid "node.stair.panel.rise" +msgstr "Hauteur" -# Source-Hash: 776903eb3756eea9 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equal angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.equalAngle" -msgstr "Angle égal" +msgid "node.stair.panel.rotation" +msgstr "Rotation" -# Source-Hash: 8956a359d7cec0a6 +# Source-Hash: 505d8419cf4cc5e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equal going" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segments" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.equalGoing" -msgstr "Giron égal" +msgid "node.stair.panel.segments" +msgstr "Segments" -# Source-Hash: 6ff728d5058c7e31 +# Source-Hash: 0b9a0bef102b75bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fit risers and going" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{type, select, landing {Landing} other {Stair}}" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.fitRisersAndGoing" -msgstr "Ajuster contremarches et giron" +msgid "node.stair.panel.segmentType" +msgstr "{type, select, landing {Palier} other {Volée}}" -# Source-Hash: d60a4c7995bd2184 +# Source-Hash: 87b926bbf34a78ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fit To Floor" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sizing" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.fitToFloor" -msgstr "Ajuster au plancher" +msgid "node.stair.panel.sizing" +msgstr "Dimensionnement" -# Source-Hash: 0638614580661eb0 +# Source-Hash: 8a0f4562198c266f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fit uniform risers" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snap to nearby surfaces" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.fitUniformRisers" -msgstr "Ajuster des contremarches régulières" +msgid "node.stair.panel.snapToNearbySurfaces" +msgstr "Aimanter aux surfaces proches" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 4d365dbc1fb92b90 +# Source-Hash: f9a4a870cb3d3c41 # Review: required -# English: "Flight {number}: {count, plural, one {{riserCount} riser} other {{riserCount} risers}} · R {riser} · T {going} · {slope}" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spiral" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.flightMeasurements" -msgstr "Volée {number} : {count, plural, one {{riserCount} contremarche} many {{riserCount} contremarches} other {{riserCount} contremarches}} · H {riser} · G {going} · {slope}" +msgid "node.stair.panel.spiral" +msgstr "Hélicoïdal" -# Source-Hash: 6e946bd1acd94637 +# Source-Hash: f8d4f66145e1eba0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floors, ceilings and stairs only." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Staircase" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.floorsCeilingsAndStairsOnly" -msgstr "Planchers, plafonds et escaliers uniquement." +msgid "node.stair.panel.staircase" +msgstr "Escalier" -# Source-Hash: fa10ea42944107a8 +# Source-Hash: be8122fbf16dec33 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows deck" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Steps" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.followsDeck" -msgstr "Suit la terrasse" +msgid "node.stair.panel.steps" +msgstr "Marches" -# Source-Hash: a5c2353769b603d5 +# Source-Hash: 8846dc96332c5181 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows level" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Step Supports" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.followsLevel" -msgstr "Suit le niveau" +msgid "node.stair.panel.stepSupports" +msgstr "Supports de marche" -# Source-Hash: b7fc627a965bc016 +# Source-Hash: 4ee35f740730ae87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "From Level" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.fromLevel" -msgstr "Depuis le niveau" +msgid "node.stair.panel.straight" +msgstr "Droit" -# Source-Hash: 523b9912e283b644 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Geometry" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.geometry" -msgstr "Géométrie" +msgid "node.stair.panel.style" +msgstr "Style" -# Source-Hash: 8ab91094cf650204 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" +# Source-Hash: cde3878287069df2 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface connection" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.glass" -msgstr "Vitrage" +msgid "node.stair.panel.surfaceConnection" +msgstr "Raccordement à la surface" -# Source-Hash: 55adba80c39500f9 +# Source-Hash: 4e0f8b363503efff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Headroom:" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sweep" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.headroom" -msgstr "Échappée :" +msgid "node.stair.panel.sweep" +msgstr "Balayage" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: 4c294d88d712855a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target going" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.height" -msgstr "Hauteur" +msgid "node.stair.panel.targetGoing" +msgstr "Giron cible" -# Source-Hash: 9bcdccd29e64c4d8 +# Source-Hash: 74cfba22cf2e6eb8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inner gap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target headroom" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.innerGap" -msgstr "Écart intérieur" +msgid "node.stair.panel.targetHeadroom" +msgstr "Échappée cible" -# Source-Hash: 8b54356df7ae40bf +# Source-Hash: 9d05958a265a6726 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inner Radius" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target max riser" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.innerRadius" -msgstr "Rayon intérieur" +msgid "node.stair.panel.targetMaxRiser" +msgstr "Hauteur de marche max. cible" -# Source-Hash: 88d5b9ecb242c650 +# Source-Hash: d10322b16178ce37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Integrated" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target minimum going" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.integrated" -msgstr "Intégré" +msgid "node.stair.panel.targetMinimumGoing" +msgstr "Giron minimal cible" -# Source-Hash: de9566487b17a73b +# Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.landing" -msgstr "Palier" +msgid "node.stair.panel.thickness" +msgstr "Épaisseur" -# Source-Hash: 54800340a0eeab23 +# Source-Hash: b3214a20e45a7aed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Layout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "To" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.layout" -msgstr "Disposition" +msgid "node.stair.panel.to" +msgstr "Vers" -# Source-Hash: f365c6b6dd9ebab9 +# Source-Hash: 846fc58043454194 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Landing" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.left" -msgstr "Gauche" +msgid "node.stair.panel.topLanding" +msgstr "Palier d’arrivée" -# Source-Hash: 7d4f8532c0d115e9 +# Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left turn" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.leftTurn" -msgstr "Retour à gauche" +msgid "node.stair.panel.type" +msgstr "Type" -# Source-Hash: c6aa74075f37313a +# Source-Hash: b4c2f503b19443c6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Measurements" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unavailable" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.measurements" -msgstr "Mesures" +msgid "node.stair.panel.unavailable" +msgstr "Indisponible" -# Source-Hash: 8e464a8f52254f27 +# Source-Hash: 546fa6dd4e62e82d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Metal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walking line offset" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.metal" -msgstr "Métal" +msgid "node.stair.panel.walkingLineOffset" +msgstr "Décalage de la ligne de foulée" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.move" -msgstr "Déplacer" +msgid "node.stair.panel.width" +msgstr "Largeur" -# Source-Hash: a4f1cc34aae4db27 +# Source-Hash: 7b65cc10483fb191 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Moving this stair keeps its current rise, steps, and run." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Winder" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.movingThisStairKeepsItsCurrent" -msgstr "Déplacer cet escalier conserve sa hauteur, ses marches et son reculement actuels." +msgid "node.stair.panel.winder" +msgstr "Balancement" -# Source-Hash: f2953d2931e36d0c +# Source-Hash: 69578b7dd7723fa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Both" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.none" -msgstr "Aucun" +msgid "node.stair.railingControls.both" +msgstr "Les deux" -# Source-Hash: 47c858b3022b3ae5 +# Source-Hash: fe633d20f198d7e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No overhead surface" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom sloped extension" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.noOverheadSurface" -msgstr "Aucune surface au-dessus" +msgid "node.stair.railingControls.bottomExtension" +msgstr "Prolongement incliné en bas" -# Source-Hash: 17f1933d93cf655c +# Source-Hash: 384842ae1e1c6825 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Not evaluated" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuous" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.notEvaluated" -msgstr "Non évalué" +msgid "node.stair.railingControls.continuous" +msgstr "Continu" -# Source-Hash: e04298381837252f +# Source-Hash: d7148fa065bc709b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.opening" -msgstr "Ouverture" +msgid "node.stair.railingControls.floor" +msgstr "Niveau" -# Source-Hash: 599220556fc4bbfb +# Source-Hash: 644d2d9e9c3dd31f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening Offset" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handrail diameter" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.openingOffset" -msgstr "Décalage de l’ouverture" +msgid "node.stair.railingControls.handrailDiameter" +msgstr "Diamètre de la main courante" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: 5f3f2be1e572a066 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handrail height" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.position" -msgstr "Position" +msgid "node.stair.railingControls.handrailHeight" +msgstr "Hauteur de la main courante" -# Source-Hash: f522323372a7a59e +# Source-Hash: cb3239847f068a1b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post & rail" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handrail inset" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.postRail" -msgstr "Poteaux et lisses" +msgid "node.stair.railingControls.handrailInset" +msgstr "Retrait de la main courante" -# Source-Hash: 240ed9c77627b9a1 +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.railing" -msgstr "Garde-corps" +msgid "node.stair.railingControls.left" +msgstr "Gauche" -# Source-Hash: b34d5ee0f218221d +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.right" -msgstr "Droite" +msgid "node.stair.railingControls.none" +msgstr "Aucun" -# Source-Hash: ae876c3e9a5913eb +# Source-Hash: e6ac8d7c9639c351 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right turn" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No return" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.rightTurn" -msgstr "Retour à droite" +msgid "node.stair.railingControls.noReturn" +msgstr "Sans retour" -# Source-Hash: fe8c5b735495eb00 +# Source-Hash: 5688b2003002d03a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rise" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Original layout" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.rise" -msgstr "Hauteur" +msgid "node.stair.railingControls.originalLayout" +msgstr "Disposition d’origine" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: d0d904fbd052d7b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post-facing" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.rotation" -msgstr "Rotation" +msgid "node.stair.railingControls.postFacing" +msgstr "Vers le poteau" -# Source-Hash: 505d8419cf4cc5e1 +# Source-Hash: fc4d8c6f156b0430 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segments" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return length" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.segments" -msgstr "Segments" +msgid "node.stair.railingControls.returnLength" +msgstr "Longueur du retour" -# Source-Hash: 0b9a0bef102b75bc +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{type, select, landing {Landing} other {Stair}}" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.segmentType" -msgstr "{type, select, landing {Palier} other {Volée}}" +msgid "node.stair.railingControls.right" +msgstr "Droite" -# Source-Hash: 87b926bbf34a78ed +# Source-Hash: e1f8354a95b5060a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sizing" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Separate handrail" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.sizing" -msgstr "Dimensionnement" +msgid "node.stair.railingControls.separateHandrail" +msgstr "Main courante séparée" -# Source-Hash: 8a0f4562198c266f +# Source-Hash: 005f0197ec3bc95a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snap to nearby surfaces" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set the length to reach the wall or post." +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.snapToNearbySurfaces" -msgstr "Aimanter aux surfaces proches" +msgid "node.stair.railingControls.setTheLengthToReachThe" +msgstr "Réglez la longueur pour atteindre le mur ou le poteau." -# Source-Hash: f9a4a870cb3d3c41 +# Source-Hash: bef713f3ec96f758 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spiral" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top horizontal extension" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.spiral" -msgstr "Hélicoïdal" +msgid "node.stair.railingControls.topExtension" +msgstr "Prolongement horizontal en haut" -# Source-Hash: f8d4f66145e1eba0 +# Source-Hash: bdad79929de6b142 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Staircase" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall-facing" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.staircase" -msgstr "Escalier" +msgid "node.stair.railingControls.wallFacing" +msgstr "Vers le mur" -# Source-Hash: be8122fbf16dec33 +# Source-Hash: 1709ce71eba750ff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Steps" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A solid poured flight on a footing; risers closed, no stringers." +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.steps" -msgstr "Marches" +msgid "node.stair.structureControls.aSolidPouredFlightOnA" +msgstr "Une volée pleine coulée sur une semelle ; contremarches fermées, sans limons." -# Source-Hash: 8846dc96332c5181 +# Source-Hash: 56be143b76f65392 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Step Supports" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto ({autoCount})" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.stepSupports" -msgstr "Supports de marche" +msgid "node.stair.structureControls.autoAutocount" +msgstr "Auto ({autoCount})" -# Source-Hash: 4ee35f740730ae87 +# Source-Hash: d7820aaac08e4fcb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto (closed)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.straight" -msgstr "Droit" +msgid "node.stair.structureControls.autoClosed" +msgstr "Auto (fermées)" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: c7cbd493df719e71 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto (open)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.style" -msgstr "Style" +msgid "node.stair.structureControls.autoOpen" +msgstr "Auto (ouvertes)" -# Source-Hash: cde3878287069df2 +# Source-Hash: be21258d52930d5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface connection" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto (pressure-treated)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.surfaceConnection" -msgstr "Raccordement à la surface" +msgid "node.stair.structureControls.autoPressureTreated" +msgstr "Auto (traité autoclave)" -# Source-Hash: 4e0f8b363503efff +# Source-Hash: 1828540d95a5b5c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sweep" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto ({treads})" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.sweep" -msgstr "Balayage" +msgid "node.stair.structureControls.autoTreads" +msgstr "Auto ({treads})" -# Source-Hash: 4c294d88d712855a +# Source-Hash: 43c1949fa53685b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target going" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto (untreated)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.targetGoing" -msgstr "Giron cible" +msgid "node.stair.structureControls.autoUntreated" +msgstr "Auto (non traité)" -# Source-Hash: 74cfba22cf2e6eb8 +# Source-Hash: d0a3ca3ce29ae833 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target headroom" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Closed (1x8 boards)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.targetHeadroom" -msgstr "Échappée cible" +msgid "node.stair.structureControls.closed1x8Boards" +msgstr "Fermées (planches 1x8)" -# Source-Hash: 9d05958a265a6726 +# Source-Hash: 824471a3691b51db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target max riser" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Concrete" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.targetMaxRiser" -msgstr "Hauteur de marche max. cible" +msgid "node.stair.structureControls.concrete" +msgstr "Béton" -# Source-Hash: d10322b16178ce37 +# Source-Hash: dcb2dd54c3301068 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target minimum going" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# steel channel} other {# steel channels}}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.targetMinimumGoing" -msgstr "Giron minimal cible" +msgid "node.stair.structureControls.countSteelChannels" +msgstr "{count, plural, one {# profilé acier en U} many {# profilés acier en U} other {# profilés acier en U}}" -# Source-Hash: fdbb503f0941bd56 +# Source-Hash: fbf12088b828a103 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# steel channel at {spacing} o.c.} other {# steel channels at {spacing} o.c.}}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.thickness" -msgstr "Épaisseur" +msgid "node.stair.structureControls.countSteelChannelsAtSpacing" +msgstr "{count, plural, one {# profilé acier en U à {spacing} d’entraxe} many {# profilés acier en U à {spacing} d’entraxe} other {# profilés acier en U à {spacing} d’entraxe}}" -# Source-Hash: b3214a20e45a7aed +# Source-Hash: 6f0f06f0531c7e96 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "To" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# stringer} other {# stringers}}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.to" -msgstr "Vers" +msgid "node.stair.structureControls.countStringers" +msgstr "{count, plural, one {# limon} many {# limons} other {# limons}}" -# Source-Hash: 846fc58043454194 +# Source-Hash: cfdb3f3fc95ea940 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Landing" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# stringer at {spacing} o.c.} other {# stringers at {spacing} o.c.}}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.topLanding" -msgstr "Palier d’arrivée" +msgid "node.stair.structureControls.countStringersAtSpacing" +msgstr "{count, plural, one {# limon à {spacing} d’entraxe} many {# limons à {spacing} d’entraxe} other {# limons à {spacing} d’entraxe}}" -# Source-Hash: c44f7ab8bbd24858 +# Source-Hash: fa4b97d3aa600bcd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.type" -msgstr "Type" +msgid "node.stair.structureControls.cut" +msgstr "À crémaillère" -# Source-Hash: b4c2f503b19443c6 +# Source-Hash: ba4f3c1346b3e7af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unavailable" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight {number}: {layout}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.unavailable" -msgstr "Indisponible" +msgid "node.stair.structureControls.flightLayout" +msgstr "Volée {number} : {layout}" -# Source-Hash: 546fa6dd4e62e82d +# Source-Hash: 4cbb34fdf4c1e107 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walking line offset" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Housed sides" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.walkingLineOffset" -msgstr "Décalage de la ligne de foulée" +msgid "node.stair.structureControls.housedSides" +msgstr "À la française" -# Source-Hash: 3a0ccd6c46877a87 +# Source-Hash: e3ddff241f642295 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{inches} in o.c." +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.width" -msgstr "Largeur" +msgid "node.stair.structureControls.inchesInOC" +msgstr "{inches} in d’entraxe" -# Source-Hash: 7b65cc10483fb191 +# Source-Hash: 542ca0bee99a1533 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Winder" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{layout} (auto)" +#. The stringer count was chosen automatically, not set by hand. +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.winder" -msgstr "Balancement" +msgid "node.stair.structureControls.layoutAuto" +msgstr "{layout} (auto)" -# Source-Hash: 69578b7dd7723fa1 +# Source-Hash: 73dcfae611575500 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Both" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lumber" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.both" -msgstr "Les deux" +msgid "node.stair.structureControls.lumber" +msgstr "Bois" -# Source-Hash: fe633d20f198d7e4 +# Source-Hash: d10743fce478d9f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom sloped extension" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Max spacing" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.bottomExtension" -msgstr "Prolongement incliné en bas" +msgid "node.stair.structureControls.maxSpacing" +msgstr "Espacement max." -# Source-Hash: 384842ae1e1c6825 +# Source-Hash: ce25dc4a23f3ae10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuous" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Nosing" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.continuous" -msgstr "Continu" +msgid "node.stair.structureControls.nosing" +msgstr "Nez de marche" -# Source-Hash: d7148fa065bc709b +# Source-Hash: ba534b07476bc06d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "One {stock}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.floor" -msgstr "Niveau" +msgid "node.stair.structureControls.oneStock" +msgstr "Un {stock}" -# Source-Hash: 644d2d9e9c3dd31f +# Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handrail diameter" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.handrailDiameter" -msgstr "Diamètre de la main courante" +msgid "node.stair.structureControls.open" +msgstr "Ouvertes" -# Source-Hash: 5f3f2be1e572a066 +# Source-Hash: 20f023962f848e14 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handrail height" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Original body" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.handrailHeight" -msgstr "Hauteur de la main courante" +msgid "node.stair.structureControls.originalBody" +msgstr "Corps d’origine" -# Source-Hash: cb3239847f068a1b +# Source-Hash: ac658d76a942652f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handrail inset" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plywood + finish" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.handrailInset" -msgstr "Retrait de la main courante" +msgid "node.stair.structureControls.plywoodFinish" +msgstr "Contreplaqué + finition" -# Source-Hash: f365c6b6dd9ebab9 +# Source-Hash: 86fda85cdc89fd27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pressure-treated" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.left" -msgstr "Gauche" +msgid "node.stair.structureControls.pressureTreated" +msgstr "Traité autoclave" -# Source-Hash: f2953d2931e36d0c +# Source-Hash: d903bba423ddb755 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Risers" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.none" -msgstr "Aucun" +msgid "node.stair.structureControls.risers" +msgstr "Contremarches" -# Source-Hash: e6ac8d7c9639c351 +# Source-Hash: ff0400a550f24adf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No return" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Steel stringers" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.noReturn" -msgstr "Sans retour" +msgid "node.stair.structureControls.steelStringers" +msgstr "Limons acier" -# Source-Hash: 5688b2003002d03a +# Source-Hash: 50d4cac7f3002cd2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Original layout" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringer count" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.originalLayout" -msgstr "Disposition d’origine" +msgid "node.stair.structureControls.stringerCount" +msgstr "Nombre de limons" -# Source-Hash: d0d904fbd052d7b2 +# Source-Hash: 71733e5b479af2a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post-facing" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringers" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.postFacing" -msgstr "Vers le poteau" +msgid "node.stair.structureControls.stringers" +msgstr "Limons" -# Source-Hash: fc4d8c6f156b0430 +# Source-Hash: 191196b94d1c86f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return length" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringer type" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.returnLength" -msgstr "Longueur du retour" +msgid "node.stair.structureControls.stringerType" +msgstr "Type de limon" -# Source-Hash: b34d5ee0f218221d +# Source-Hash: a20c89205a4448d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.right" -msgstr "Droite" +msgid "node.stair.structureControls.structure" +msgstr "Structure" -# Source-Hash: e1f8354a95b5060a +# Source-Hash: 869e3785611a0858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Separate handrail" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Treads" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.separateHandrail" -msgstr "Main courante séparée" +msgid "node.stair.structureControls.treads" +msgstr "Marches" -# Source-Hash: 005f0197ec3bc95a +# Source-Hash: e1e6555b827b4620 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set the length to reach the wall or post." -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Two {stock}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.setTheLengthToReachThe" -msgstr "Réglez la longueur pour atteindre le mur ou le poteau." +msgid "node.stair.structureControls.twoStock" +msgstr "Deux {stock}" -# Source-Hash: bef713f3ec96f758 +# Source-Hash: 5c362de43a2cbac1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top horizontal extension" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Untreated" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.topExtension" -msgstr "Prolongement horizontal en haut" +msgid "node.stair.structureControls.untreated" +msgstr "Non traité" -# Source-Hash: bdad79929de6b142 +# Source-Hash: 401bae5ffee978fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall-facing" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wood stringers" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.wallFacing" -msgstr "Vers le mur" +msgid "node.stair.structureControls.woodStringers" +msgstr "Limons bois" # Source-Hash: ce0b6361eb77e93c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A single flight of a parent stair." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -29750,8 +32483,8 @@ msgstr "Une volée d’un escalier parent." # Source-Hash: 2159ec5769e1c59a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stair Segment" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -29760,8 +32493,8 @@ msgstr "Volée" # Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29770,8 +32503,8 @@ msgstr "Actions" # Source-Hash: 551b04c03b07595e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Attachment" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29780,8 +32513,8 @@ msgstr "Raccordement" # Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29790,8 +32523,8 @@ msgstr "Supprimer" # Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dimensions" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29800,8 +32533,8 @@ msgstr "Dimensions" # Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duplicate" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29810,8 +32543,8 @@ msgstr "Dupliquer" # Source-Hash: ad063fb27f370c28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Editing switches the stair to Custom rise" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29820,8 +32553,8 @@ msgstr "La modification passe l’escalier en hauteur de marche personnalisée" # Source-Hash: 776903eb3756eea9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Equal angle" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29830,8 +32563,8 @@ msgstr "Angle égal" # Source-Hash: 8956a359d7cec0a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Equal going" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29840,8 +32573,8 @@ msgstr "Giron égal" # Source-Hash: 66f1018b50c2e426 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fill to floor" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29850,8 +32583,8 @@ msgstr "Remplir jusqu’au sol" # Source-Hash: deff4254bb163b2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flight" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29860,8 +32593,8 @@ msgstr "Volée" # Source-Hash: d6da828cd0c5e8cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flight shape" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29870,8 +32603,8 @@ msgstr "Forme de la volée" # Source-Hash: e360f89d3c0ec456 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Front" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29880,8 +32613,8 @@ msgstr "Avant" # Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Height" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29890,8 +32623,8 @@ msgstr "Hauteur" # Source-Hash: 9bcdccd29e64c4d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Inner gap" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29900,8 +32633,8 @@ msgstr "Écart intérieur" # Source-Hash: de9566487b17a73b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Landing" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29910,8 +32643,8 @@ msgstr "Palier" # Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Left" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29920,8 +32653,8 @@ msgstr "Gauche" # Source-Hash: 7d4f8532c0d115e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Left turn" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29930,8 +32663,8 @@ msgstr "Retour à gauche" # Source-Hash: 643687bc3adaac76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Length" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29940,8 +32673,8 @@ msgstr "Longueur" # Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Move" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29950,8 +32683,8 @@ msgstr "Déplacer" # Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Position" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29960,8 +32693,8 @@ msgstr "Position" # Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Right" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29970,8 +32703,8 @@ msgstr "Droite" # Source-Hash: ae876c3e9a5913eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Right turn" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29980,8 +32713,8 @@ msgstr "Retour à droite" # Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rotation" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29990,8 +32723,8 @@ msgstr "Rotation" # Source-Hash: 2159ec5769e1c59a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stair Segment" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30000,8 +32733,8 @@ msgstr "Volée" # Source-Hash: be8122fbf16dec33 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Steps" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30010,8 +32743,8 @@ msgstr "Marches" # Source-Hash: 4ee35f740730ae87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Straight" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30020,8 +32753,8 @@ msgstr "Droit" # Source-Hash: a20c89205a4448d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Structure" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30030,8 +32763,8 @@ msgstr "Structure" # Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Thickness" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30040,8 +32773,8 @@ msgstr "Épaisseur" # Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Type" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30050,8 +32783,8 @@ msgstr "Type" # Source-Hash: 546fa6dd4e62e82d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Walking line offset" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30060,8 +32793,8 @@ msgstr "Décalage de la ligne de foulée" # Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Width" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30070,8 +32803,8 @@ msgstr "Largeur" # Source-Hash: 7b65cc10483fb191 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Winder" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30080,8 +32813,8 @@ msgstr "Balancement" # Source-Hash: 5434a3189441c913 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Persistent construction grid axis with identification bubbles." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30090,8 +32823,8 @@ msgstr "Axe de trame de construction persistant avec bulles d’identification." # Source-Hash: 0cfe636f7fdd9fd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Structural Grid" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30100,8 +32833,8 @@ msgstr "Trame structurelle" # Source-Hash: 36b714210f25c284 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wind-driven spinning whirlybird exhaust vent for a roof slope." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30110,198 +32843,198 @@ msgstr "Extracteur éolien rotatif pour versant de toit." # Source-Hash: 4a855abb962f5e7a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Turbine Vent" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy msgid "node.turbineVent.label" msgstr "Extracteur éolien" -# Review: required # Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.actions" msgstr "Actions" -# Review: required # Source-Hash: c65f02bcdc3231d6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Cylinder" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.cylinder" msgstr "Cylindre" -# Review: required # Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.delete" msgstr "Supprimer" -# Review: required # Source-Hash: 016d8e70618916d4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Diameter" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.diameter" msgstr "Diamètre" -# Review: required # Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dimensions" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.dimensions" msgstr "Dimensions" -# Review: required # Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duplicate" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.duplicate" msgstr "Dupliquer" -# Review: required # Source-Hash: 2d4223f80dc3945c -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Globe" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.globe" msgstr "Globe" -# Review: required # Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Height" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.height" msgstr "Hauteur" -# Review: required # Source-Hash: c0ff16d77ebc9593 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Motion" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.motion" msgstr "Mouvement" -# Review: required # Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Move" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.move" msgstr "Déplacer" -# Review: required # Source-Hash: 6faf9532dcbfe4bc -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Neck Height" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.neckHeight" msgstr "Hauteur du col" -# Review: required # Source-Hash: 1550d72740e66f77 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Pause" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.pause" msgstr "Pause" -# Review: required # Source-Hash: c7b10382e01914ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Play" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.play" msgstr "Lancer" -# Review: required # Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Position" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.position" msgstr "Position" -# Review: required # Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rotation" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.rotation" msgstr "Rotation" -# Review: required # Source-Hash: bf553d40ce68834d -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Spin Speed" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.spinSpeed" msgstr "Vitesse de rotation" -# Review: required # Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Style" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.style" msgstr "Style" -# Review: required # Source-Hash: 4a855abb962f5e7a -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Turbine Vent" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.turbineVent" msgstr "Extracteur éolien" -# Review: required # Source-Hash: 80cef0dce71e121f -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Vanes" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy @@ -30310,8 +33043,8 @@ msgstr "Ailettes" # Source-Hash: e3d2aaaf5c72bc3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A named group of zones forming one apartment, hotel room or commercial lot." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30320,8 +33053,8 @@ msgstr "Groupe nommé de zones formant un appartement, une chambre d’hôtel ou # Source-Hash: 40e5a51d0d205fcf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Apartment" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30330,8 +33063,8 @@ msgstr "Appartement" # Source-Hash: ad041d9634dd55ea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Commercial" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30340,8 +33073,8 @@ msgstr "Commercial" # Source-Hash: 862f30cb2d49f812 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Common" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30350,8 +33083,8 @@ msgstr "Commun" # Source-Hash: cd7e1bc42d47a105 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hotel room" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30360,8 +33093,8 @@ msgstr "Chambre d’hôtel" # Source-Hash: 062cc0f1afef0c52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unit" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30370,8 +33103,8 @@ msgstr "Lot" # Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Room" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30380,8 +33113,8 @@ msgstr "Pièce" # Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30390,8 +33123,8 @@ msgstr "Zone" # Source-Hash: e25d5b5630b9d8df # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Members sit on levels that are not adjacent." #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30400,8 +33133,8 @@ msgstr "Les membres sont sur des niveaux non adjacents." # Source-Hash: 5ebeb440e0e64d01 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No zones assigned yet." #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30410,8 +33143,8 @@ msgstr "Aucune zone attribuée pour l’instant." # Source-Hash: 07731fa851c75d8c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Remove {name} from unit" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30420,8 +33153,8 @@ msgstr "Retirer {name} du logement" # Source-Hash: 389839734c8350b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Remove zone from unit" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30430,8 +33163,8 @@ msgstr "Retirer la zone du logement" # Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30440,8 +33173,8 @@ msgstr "Actions" # Source-Hash: fe18958cedd627d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Color" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30450,8 +33183,8 @@ msgstr "Couleur" # Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30460,8 +33193,8 @@ msgstr "Supprimer" # Source-Hash: b80dc93401f953a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Focus" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30470,8 +33203,8 @@ msgstr "Cibler" # Source-Hash: 1218205b3bb34f1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gross area" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30480,8 +33213,8 @@ msgstr "Surface brute" # Source-Hash: aa9d6710f4cac041 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kind" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30490,8 +33223,8 @@ msgstr "Type" # Source-Hash: cc3d601d59e2e26c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Levels" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30500,8 +33233,8 @@ msgstr "Niveaux" # Source-Hash: 6bbc51529519435c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Members" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30510,8 +33243,8 @@ msgstr "Membres" # Source-Hash: 6cc5df35f0338e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Name" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30520,8 +33253,8 @@ msgstr "Nom" # Source-Hash: 54b25f70c7b63446 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No rooms yet. Pick this unit from a room's panel, or draw zones while it is focused." #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30530,8 +33263,8 @@ msgstr "Aucune pièce pour l’instant. Choisissez ce logement depuis le panneau # Source-Hash: 85d640066187108d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Report" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30540,8 +33273,8 @@ msgstr "Rapport" # Source-Hash: 062cc0f1afef0c52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unit" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30550,8 +33283,8 @@ msgstr "Lot" # Source-Hash: d53242481ff46157 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Merge walls" #: packages/nodes/src/wall/actions.tsx #, fuzzy @@ -30560,28 +33293,38 @@ msgstr "Fusionner les murs" # Source-Hash: d7ead4708d50965f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Split wall" #: packages/nodes/src/wall/actions.tsx #, fuzzy msgid "node.wall.actions.splitWall" msgstr "Scinder le mur" +# Source-Hash: 2f8c3189a0b3972b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "These walls cannot be merged." +#: packages/nodes/src/wall/actions.tsx +#, fuzzy +msgid "node.wall.actions.theseWallsCannotBeMerged" +msgstr "Ces murs ne peuvent pas être fusionnés." + # Source-Hash: 96a6f084d095ea36 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column {column}, row {row}: {type, select, glass {glass} solid {solid} other {empty}}" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy msgid "node.wall.curtain.cell" msgstr "Colonne {column}, rangée {row} : {type, select, glass {vitrage} solid {plein} other {vide}}" -# AI-Provider: cursor-agent -# AI-Model: claude-opus # Source-Hash: 904e9b269b68c670 # Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {{number} column} other {{number} columns}} · {spacing} grid spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30590,18 +33333,18 @@ msgstr "{count, plural, one {{number} colonne} many {{number} colonnes} other {{ # Source-Hash: 8b2b2f11fca9f077 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No panels" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy msgid "node.wall.curtain.noPanels" msgstr "Aucun panneau" -# AI-Provider: cursor-agent -# AI-Model: claude-opus # Source-Hash: 9f5d9775377b666e # Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {{number} row} other {{number} rows}} · {spacing} grid spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30610,8 +33353,8 @@ msgstr "{count, plural, one {{number} rangée} many {{number} rangées} other {{ # Source-Hash: 90638d5a19a4f0a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Apply tint" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30620,8 +33363,8 @@ msgstr "Appliquer la teinte" # Source-Hash: a7d624ec0f879829 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Border / opening frame" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30630,8 +33373,8 @@ msgstr "Bordure / cadre d’ouverture" # Source-Hash: b3a163b453896bef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bottom" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30640,8 +33383,8 @@ msgstr "Bas" # Source-Hash: 5503fb89c40cefeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bottom row" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30650,8 +33393,8 @@ msgstr "Rangée du bas" # Source-Hash: 1928d9e7a16360d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Cancel tint" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30660,8 +33403,8 @@ msgstr "Annuler la teinte" # Source-Hash: 5211341ed18f33f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Center" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30670,8 +33413,8 @@ msgstr "Centre" # Source-Hash: 9f4c033fa80119db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Choose a cell or enter its column and row. Use arrow keys to move between cells. Columns run from the wall start; rows count upward." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30680,8 +33423,8 @@ msgstr "Choisissez une cellule ou saisissez sa colonne et sa rangée. Utilisez l # Source-Hash: bbeadcebc59c923f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Clear hidden overrides" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30690,8 +33433,8 @@ msgstr "Effacer les remplacements masqués" # Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30700,8 +33443,8 @@ msgstr "Poteau" # Source-Hash: 711a6426e336877a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column layout" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30710,8 +33453,8 @@ msgstr "Disposition des colonnes" # Source-Hash: 59b2ab5fdf54c2e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column {column}, row {row}" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30720,8 +33463,8 @@ msgstr "Colonne {column}, rangée {row}" # Source-Hash: ce1429556f57d7ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Construction" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30730,8 +33473,8 @@ msgstr "Construction" # Source-Hash: 59d2bec8b9ae1025 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Continuous mullions and transoms assembled along the wall." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30740,8 +33483,8 @@ msgstr "Meneaux et traverses continus assemblés le long du mur." # Source-Hash: bbc5e5f3f3b99232 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Curtain wall panel selection" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30750,8 +33493,8 @@ msgstr "Sélection des panneaux du mur-rideau" # Source-Hash: 9fd79cf417eab9ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Custom infill" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30760,8 +33503,8 @@ msgstr "Remplissage personnalisé" # Source-Hash: 097ed751fa47e5fd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Default panel" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30770,8 +33513,8 @@ msgstr "Panneau par défaut" # Source-Hash: 0a0c98ae42f519ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Edit individual panels" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30780,8 +33523,8 @@ msgstr "Modifier les panneaux individuellement" # Source-Hash: 8690f82f64806e4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Effective thickness: {thickness}, limited by frame depth." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30790,8 +33533,8 @@ msgstr "Épaisseur effective : {thickness}, limitée par la profondeur du cadre. # Source-Hash: 65b1cbba3b92c5b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Empty" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30800,8 +33543,8 @@ msgstr "Vide" # Source-Hash: c6e7792839d09c69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Enable panel editing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30810,8 +33553,8 @@ msgstr "Activer la modification des panneaux" # Source-Hash: 135874d189176d13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "End" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30820,8 +33563,8 @@ msgstr "Fin" # Source-Hash: 4fb65101d0b1a222 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fixed spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30830,8 +33573,8 @@ msgstr "Espacement fixe" # Source-Hash: 1c851bde836b3b57 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Following wall defaults" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30840,8 +33583,8 @@ msgstr "Valeurs par défaut du mur" # Source-Hash: 49be990b89741501 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Frame dimensions" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30850,8 +33593,8 @@ msgstr "Dimensions du cadre" # Source-Hash: c7e72beff9fe4b37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Framing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30860,8 +33603,8 @@ msgstr "Ossature" # Source-Hash: 221f418784836f11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fully capped" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30870,8 +33613,8 @@ msgstr "Entièrement coiffé" # Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glass" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30880,8 +33623,8 @@ msgstr "Vitrage" # Source-Hash: a17c63662aa4404d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glass appearance" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30890,8 +33633,8 @@ msgstr "Aspect du vitrage" # Source-Hash: f59c4938a2116a2e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glass appearance is controlled by the paint tool." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30900,8 +33643,8 @@ msgstr "L’aspect du vitrage se règle avec l’outil Peinture." # Source-Hash: 9c38875c310547ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glass tint" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30910,8 +33653,8 @@ msgstr "Teinte du vitrage" # Source-Hash: 7660a6aa7e7cd365 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glazing gap" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30920,8 +33663,8 @@ msgstr "Jeu de vitrage" # Source-Hash: 6e739c8a698efaab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Grid limited to 32 panels per axis. Spacing expands to fit this wall." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30930,8 +33673,8 @@ msgstr "Trame limitée à 32 panneaux par axe. L’espacement s’élargit pour # Source-Hash: 1c63255b675bbcd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{length, plural, one {{number} custom panel is outside this grid. It returns if the grid expands.} other {{number} custom panels are outside this grid. They return if the grid expands.}}" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30940,8 +33683,8 @@ msgstr "{length, plural, one {{number} panneau personnalisé est hors de cette g # Source-Hash: 84af317e818c10cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Horizontal caps" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30950,8 +33693,8 @@ msgstr "Couvre-joints horizontaux" # Source-Hash: 7a71f6b25c5dc718 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Horizontal frame width" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30960,8 +33703,8 @@ msgstr "Largeur du cadre horizontal" # Source-Hash: 54800340a0eeab23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Layout" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30970,8 +33713,8 @@ msgstr "Disposition" # Source-Hash: fc37833ef19c8feb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Low roughness is smooth; high roughness gives a matte surface in rendered shading." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30980,8 +33723,8 @@ msgstr "Une rugosité faible donne une surface lisse ; une rugosité élevée do # Source-Hash: 321ca5101ab61db7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Maximum spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30990,8 +33733,8 @@ msgstr "Espacement maximal" # Source-Hash: 1452f51ec5dfc6ba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Module joint width" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31000,8 +33743,8 @@ msgstr "Largeur de joint entre modules" # Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "None" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31010,8 +33753,8 @@ msgstr "Aucun" # Source-Hash: 1c0b8a5503c5daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opacity" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31020,8 +33763,8 @@ msgstr "Opacité" # Source-Hash: 0f9ba67daa6b4625 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opaque band" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31030,8 +33773,8 @@ msgstr "Bandeau opaque" # Source-Hash: fdf533d6592eff60 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opaque bands replace a full row with solid panels. Apply their finish with the paint tool." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31040,8 +33783,8 @@ msgstr "Les bandeaux opaques remplacent une rangée entière par des panneaux pl # Source-Hash: b91302bf741c9fd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Panel count" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31050,8 +33793,8 @@ msgstr "Nombre de panneaux" # Source-Hash: 3a019ce58d021431 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Panel infill" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31060,8 +33803,8 @@ msgstr "Remplissage du panneau" # Source-Hash: 6ce059aee1386f72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Panels" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31070,8 +33813,8 @@ msgstr "Panneaux" # Source-Hash: d24fe036670f54a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Panel thickness" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31080,8 +33823,8 @@ msgstr "Épaisseur du panneau" # Source-Hash: a780f13a732bab88 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reset this panel" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31090,8 +33833,8 @@ msgstr "Réinitialiser ce panneau" # Source-Hash: 03a22f6df69c47d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Row" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31100,8 +33843,8 @@ msgstr "Rangée" # Source-Hash: 0e18ec19d0e4ea93 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Row layout" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31110,8 +33853,8 @@ msgstr "Disposition des rangées" # Source-Hash: dfb58bbd8932811d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Separate framed modules with joints between units." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31120,8 +33863,8 @@ msgstr "Modules encadrés séparés avec des joints entre unités." # Source-Hash: ef3e765e692faf4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Solid" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31130,8 +33873,8 @@ msgstr "Plein" # Source-Hash: e4698e83d02beb6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31140,8 +33883,8 @@ msgstr "Espacement" # Source-Hash: 0a26a1e61c825660 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Start" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31150,8 +33893,8 @@ msgstr "Début" # Source-Hash: d3d738ccbc7103ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stick-built" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31160,8 +33903,8 @@ msgstr "Construit sur place" # Source-Hash: fbdb9260ee302d3d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Structural glazing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31170,8 +33913,8 @@ msgstr "Vitrage structurel" # Source-Hash: 393d5c5ec4e7014c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Surface roughness" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31180,8 +33923,8 @@ msgstr "Rugosité de surface" # Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31190,8 +33933,8 @@ msgstr "Haut" # Source-Hash: 51aa1c35a1761178 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top row" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31200,8 +33943,8 @@ msgstr "Rangée du haut" # Source-Hash: 1181faa315f26c83 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Uncapped members sit behind the glazing." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31210,8 +33953,8 @@ msgstr "Les profilés sans capot sont derrière le vitrage." # Source-Hash: e68eeb4033268842 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unitized" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31220,8 +33963,8 @@ msgstr "Modulaire" # Source-Hash: 355b469b8a9c42f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Use glass settings instead" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31230,8 +33973,8 @@ msgstr "Utiliser plutôt les réglages du vitrage" # Source-Hash: 9d75fad413e547e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Use the Door or Window tool to add an opening through the wall." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31240,8 +33983,8 @@ msgstr "Utilisez l’outil Porte ou Fenêtre pour ajouter une ouverture dans le # Source-Hash: c1fa8c24203a5dde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Vertical caps" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31250,8 +33993,8 @@ msgstr "Couvre-joints verticaux" # Source-Hash: 0560516882b93f0d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Vertical frame width" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31260,8 +34003,8 @@ msgstr "Largeur du cadre vertical" # Source-Hash: 4b903041c38cdd72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall system" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31270,8 +34013,8 @@ msgstr "Système de mur" # Source-Hash: 6c753f6234766116 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A straight or curved wall segment. Hosts doors, windows, lean-to extensions, and wall-mounted items." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -31280,8 +34023,8 @@ msgstr "Tronçon de mur droit ou courbe. Accueille portes, fenêtres, appentis e # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -31290,8 +34033,8 @@ msgstr "Mur" # Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31300,8 +34043,8 @@ msgstr "Actions" # Source-Hash: 67d2ec01cdce2bdc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Assembly" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31310,8 +34053,8 @@ msgstr "Composition" # Source-Hash: 05b65242d8c48791 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Auto" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31320,8 +34063,8 @@ msgstr "Auto" # Source-Hash: 69578b7dd7723fa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Both" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31330,8 +34073,8 @@ msgstr "Les deux" # Source-Hash: b3a163b453896bef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bottom" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31340,8 +34083,8 @@ msgstr "Bas" # Source-Hash: 75d323d0159b0df8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Brick veneer" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31350,8 +34093,8 @@ msgstr "Parement brique" # Source-Hash: 32d0bfee628c42a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Chair rail" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31360,8 +34103,8 @@ msgstr "Cimaise" # Source-Hash: a85f39db8f92f8e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "CMU" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31370,8 +34113,8 @@ msgstr "Parpaing" # Source-Hash: f76e125a47ed0612 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Colonial" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31380,8 +34123,8 @@ msgstr "Colonial" # Source-Hash: a4962c0f39d629ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Cove" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31390,8 +34133,8 @@ msgstr "Gorge" # Source-Hash: e5d425095ade6f06 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Craft" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31400,8 +34143,8 @@ msgstr "Artisanal" # Source-Hash: fa8a6b7f2f4eee63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Crown molding" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31410,8 +34153,8 @@ msgstr "Corniche" # Source-Hash: 9736e0a78294e68d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Curtain wall" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31420,8 +34163,8 @@ msgstr "Mur-rideau" # Source-Hash: f08fbb462e9afc0e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Curve" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31430,8 +34173,8 @@ msgstr "Courbe" # Source-Hash: 9e9715d52410c86f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Custom" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31440,8 +34183,8 @@ msgstr "Personnalisé" # Source-Hash: b2a1b3bc9676fe05 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Custom height" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31450,8 +34193,8 @@ msgstr "Hauteur personnalisée" # Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Depth" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31460,8 +34203,8 @@ msgstr "Profondeur" # Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dimensions" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31470,8 +34213,8 @@ msgstr "Dimensions" # Source-Hash: 4da800c75b9a6b23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Drywall" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31480,8 +34223,8 @@ msgstr "Plaque de plâtre" # Source-Hash: d6ba089e1ca40cdf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Extends downward to meet the terrain. Height and top stay unchanged." #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31490,8 +34233,8 @@ msgstr "Se prolonge vers le bas jusqu’au terrain. La hauteur et le dessus rest # Source-Hash: 0ead5e5711b98bf6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Exterior" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31500,8 +34243,8 @@ msgstr "Extérieur" # Source-Hash: fd89c31f16639f50 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fiber cement" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31510,8 +34253,8 @@ msgstr "Fibrociment" # Source-Hash: a6be391d580de5cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fill to terrain" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31520,8 +34263,8 @@ msgstr "Remplir jusqu’au terrain" # Source-Hash: 9cab4d4c95f63cdd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flat" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31530,8 +34273,8 @@ msgstr "Plat" # Source-Hash: a5c2353769b603d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follows level" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31540,18 +34283,28 @@ msgstr "Suit le niveau" # Source-Hash: fd413477f1a9e5ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Frame depth" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.frameDepth" msgstr "Profondeur du cadre" +# Source-Hash: cb22c8e4b0d92234 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framer's default" +#: packages/nodes/src/wall/panel.tsx +#, fuzzy +msgid "node.wall.panel.framersDefault" +msgstr "Par défaut du charpentier" + # Source-Hash: c7e72beff9fe4b37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Framing" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31560,8 +34313,8 @@ msgstr "Ossature" # Source-Hash: eda78e8a76f068d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gypsum" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31570,8 +34323,8 @@ msgstr "Plâtre" # Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Height" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31580,8 +34333,8 @@ msgstr "Hauteur" # Source-Hash: 2d89c1638aa8dd7e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide code" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31590,8 +34343,8 @@ msgstr "Masquer le code" # Source-Hash: 0c6dcbbbda6b4dbb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "ICF" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31600,8 +34353,8 @@ msgstr "Coffrage isolant" # Source-Hash: ff005196861cef68 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Interior" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31610,8 +34363,8 @@ msgstr "Intérieur" # Source-Hash: 9a4325140858cfec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Lap siding" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31620,8 +34373,8 @@ msgstr "Bardage à clin" # Source-Hash: 297b21e90e8c25f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Layered" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31630,8 +34383,8 @@ msgstr "Superposé" # Source-Hash: bf279d0f8f1e3b78 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Layer thicknesses follow the 2021 IRC assembly data. Drafting aid, not engineering — verify with the authority having jurisdiction." #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31640,8 +34393,8 @@ msgstr "Les épaisseurs des couches suivent les données de composition de l’I # Source-Hash: 643687bc3adaac76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Length" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31650,8 +34403,8 @@ msgstr "Longueur" # Source-Hash: 9e84d6d7b9885c4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Loading…" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31660,8 +34413,8 @@ msgstr "Chargement…" # Source-Hash: f6cbdaa17e989b91 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Modern" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31670,8 +34423,8 @@ msgstr "Moderne" # Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "None" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31680,8 +34433,8 @@ msgstr "Aucun" # Source-Hash: c7300ca33851fba7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "None (single layer)" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31690,8 +34443,8 @@ msgstr "Aucun (couche unique)" # Source-Hash: 0f0e13abf9b2bb67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Offset" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31700,8 +34453,8 @@ msgstr "Décalage" # Source-Hash: 04b3006bd4e6e207 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Ogee" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31710,8 +34463,8 @@ msgstr "Doucine" # Source-Hash: 4f7f8af75bf8e914 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "OSB" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31720,8 +34473,8 @@ msgstr "OSB" # Source-Hash: 1243161deca7d470 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Partition: the interior finish is applied to both faces." #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31730,8 +34483,8 @@ msgstr "Cloison : la finition intérieure s’applique aux deux faces." # Source-Hash: 3ee270463954f502 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Picture" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31740,8 +34493,8 @@ msgstr "Cadre" # Source-Hash: a6fd2cbf5c2154e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Plaster" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31750,8 +34503,8 @@ msgstr "Enduit" # Source-Hash: e669c2c08bd80e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Plywood" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31760,18 +34513,28 @@ msgstr "Contreplaqué" # Source-Hash: 441f7f652ea6a0d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Preset" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.preset" msgstr "Préréglage" +# Source-Hash: 240ed9c77627b9a1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" +#: packages/nodes/src/wall/panel.tsx +#, fuzzy +msgid "node.wall.panel.railing" +msgstr "Garde-corps" + # Source-Hash: 62bf2677b9ec30fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31780,8 +34543,8 @@ msgstr "Référence" # Source-Hash: 9469a102f04ea196 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Remove" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31790,8 +34553,8 @@ msgstr "Retirer" # Source-Hash: ad0457800a1f0eb4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Round" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31800,8 +34563,8 @@ msgstr "Rond" # Source-Hash: e9a0a3688faba18b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scripted finish" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31810,8 +34573,8 @@ msgstr "Finition scriptée" # Source-Hash: 36a588e44085108c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Sheathing" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31820,8 +34583,8 @@ msgstr "Voile de contreventement" # Source-Hash: 6ae9aa7061d8c617 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shoe" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31830,8 +34593,8 @@ msgstr "Quart-de-rond" # Source-Hash: 136762ac1bc96e6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Side A" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31840,8 +34603,8 @@ msgstr "Face A" # Source-Hash: 8b9cb16850549c35 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Side B" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31850,8 +34613,8 @@ msgstr "Face B" # Source-Hash: e6a27f6f8cd489b9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Side {face}" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31860,8 +34623,8 @@ msgstr "Face {face}" # Source-Hash: d9d55c5883a53789 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Skirting" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31870,8 +34633,8 @@ msgstr "Plinthe" # Source-Hash: d998c212030bc7c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Standard" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31880,8 +34643,8 @@ msgstr "Standard" # Source-Hash: da3e3dd077163ba0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Steel studs" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31890,8 +34653,8 @@ msgstr "Montants acier" # Source-Hash: ed3989f23a2d185e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Step" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31900,8 +34663,8 @@ msgstr "Gradin" # Source-Hash: 9450fcb4a14674af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stone veneer" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31910,18 +34673,28 @@ msgstr "Parement pierre" # Source-Hash: 687cf7bc64b0224e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stucco" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.stucco" msgstr "Enduit" +# Source-Hash: 4fce02ee3f69bf99 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Studs" +#: packages/nodes/src/wall/panel.tsx +#, fuzzy +msgid "node.wall.panel.studs" +msgstr "Montants" + # Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Thickness" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31930,18 +34703,28 @@ msgstr "Épaisseur" # Source-Hash: 00cb7b58f3a10140 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{thickness} · from assembly" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.thicknessFromAssembly" msgstr "{thickness} · selon la composition" +# Source-Hash: 9eef4c34dfbc970b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This project" +#: packages/nodes/src/wall/panel.tsx +#, fuzzy +msgid "node.wall.panel.thisProject" +msgstr "Ce projet" + # Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31950,8 +34733,8 @@ msgstr "Haut" # Source-Hash: 3ee03b0e9ae1be4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Total thickness" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31960,8 +34743,8 @@ msgstr "Épaisseur totale" # Source-Hash: ea7e8bbd87ce4152 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unverified: {presetNote}" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31970,8 +34753,8 @@ msgstr "Non vérifié : {presetNote}" # Source-Hash: 21242af83a2a6d17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "View code" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31980,8 +34763,8 @@ msgstr "Voir le code" # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31990,8 +34773,8 @@ msgstr "Mur" # Source-Hash: eab795728c4a3f5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall type" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32000,8 +34783,8 @@ msgstr "Type de mur" # Source-Hash: e97a456d667465f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Which face is outside is undetermined (no room detected on either side) — the exterior layers are drawn on side B." #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32010,18 +34793,108 @@ msgstr "Impossible de savoir quelle face est extérieure (aucune pièce détect # Source-Hash: 31e404a4a4870faf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wood studs" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.woodStuds" msgstr "Montants bois" +# Source-Hash: ece946252401f4ab +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A guard's openings must not pass a 4 in sphere (IRC R312.1.3)." +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.aGuardSOpeningsMustNot" +msgstr "Les ouvertures d’un garde-corps ne doivent pas laisser passer une sphère de 4 in (IRC R312.1.3)." + +# Source-Hash: 646ef0fbcbc58edf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.height" +msgstr "Hauteur" + +# Source-Hash: 7c339a5fae55681d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Infill" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.infill" +msgstr "Remplissage" + +# Source-Hash: d814a47c4eccee3f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "2x6 cap" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.n2x6Cap" +msgstr "Chapeau 2x6" + +# Source-Hash: 137b45940b723a6e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "36 in" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.n36In" +msgstr "36 in" + +# Source-Hash: ebf854ac4dd4daaf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "42 in" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.n42In" +msgstr "42 in" + +# Source-Hash: ede386e1d510ebfb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Posts" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.posts" +msgstr "Poteaux" + +# Source-Hash: 240ed9c77627b9a1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.railing" +msgstr "Garde-corps" + +# Source-Hash: 1a79a485d91f3f28 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.style" +msgstr "Style" + # Source-Hash: 5211341ed18f33f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Center" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32030,8 +34903,8 @@ msgstr "Centre" # Source-Hash: 09576259041494f3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Inside face" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32040,8 +34913,8 @@ msgstr "Face intérieure" # Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Left" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32050,8 +34923,8 @@ msgstr "Gauche" # Source-Hash: 697001376b872e74 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Outside face" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32060,8 +34933,8 @@ msgstr "Face extérieure" # Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Right" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32070,8 +34943,8 @@ msgstr "Droite" # Source-Hash: eac63d14f275db3d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{trim, select, skirting {Hide skirting} crown {Hide crown molding} other {Hide chair rail}}" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32080,18 +34953,28 @@ msgstr "{trim, select, skirting {Masquer la plinthe} crown {Masquer la corniche} # Source-Hash: 8db070a4247db221 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{trim, select, skirting {Show skirting} crown {Show crown molding} other {Show chair rail}}" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.trim.show" msgstr "{trim, select, skirting {Afficher la plinthe} crown {Afficher la corniche} other {Afficher la cimaise}}" +# Source-Hash: b1757d76048706b7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap hinge side" +#: packages/nodes/src/window/actions.tsx +#, fuzzy +msgid "node.window.actions.swapHingeSide" +msgstr "Inverser le côté des charnières" + # Source-Hash: ea6a51e66eb0c0dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A window cut into a wall. Animated open/close for opening windows." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -32100,8 +34983,8 @@ msgstr "Fenêtre découpée dans un mur, avec ouverture animée pour les ouvrant # Source-Hash: aa3c35ed33e181e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -32110,8 +34993,8 @@ msgstr "Fenêtre" # Source-Hash: 011e4de244050a78 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Raise" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32120,8 +35003,8 @@ msgstr "Guillotine" # Source-Hash: 19ca2434d4f7eb87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slats" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32130,8 +35013,8 @@ msgstr "Lames" # Source-Hash: c00de0e2c9b0ddcb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slide" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32140,8 +35023,8 @@ msgstr "Coulisser" # Source-Hash: e48604b5f7b2a5f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Swing" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32150,8 +35033,8 @@ msgstr "Battant" # Source-Hash: 1615637fe68e188a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Tilt" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32160,8 +35043,8 @@ msgstr "Basculer" # Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32170,8 +35053,8 @@ msgstr "Actions" # Source-Hash: 663175a9c461a96d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "All" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32180,8 +35063,8 @@ msgstr "Tout" # Source-Hash: 710261f5ffb32617 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Arch" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32190,8 +35073,8 @@ msgstr "Arc" # Source-Hash: 3715cd54e4775087 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Arch Height" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32201,7 +35084,7 @@ msgstr "Hauteur de l’arc" # Source-Hash: 05b65242d8c48791 # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 +# AI-Model: claude-opus-5-5 # English: "Auto" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32211,7 +35094,7 @@ msgstr "Auto" # Source-Hash: 8a04486ba122ea7d # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 +# AI-Model: claude-opus-5-5 # English: "Auto follows the wall" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32220,8 +35103,8 @@ msgstr "Auto suit le mur" # Source-Hash: 30edd1c180aac9b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Columns" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32230,8 +35113,8 @@ msgstr "Colonnes" # Source-Hash: 2f417371c399ad67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Col Widths" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32240,8 +35123,8 @@ msgstr "Largeurs de colonne" # Source-Hash: 2ee121dca87bb64a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Corner" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32250,8 +35133,8 @@ msgstr "Angle" # Source-Hash: 04e3425c5ea29359 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Corner post" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32260,8 +35143,8 @@ msgstr "Poteau d’angle" # Source-Hash: 7a90a42b578f2435 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Corner Radius" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32270,8 +35153,8 @@ msgstr "Rayon d’angle" # Source-Hash: 67d10b97eff316c1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Custom: the panes match no style." #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32280,8 +35163,8 @@ msgstr "Personnalisé : les carreaux ne correspondent à aucun style." # Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32290,8 +35173,8 @@ msgstr "Supprimer" # Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Depth" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32300,8 +35183,8 @@ msgstr "Profondeur" # Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dimensions" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32310,8 +35193,8 @@ msgstr "Dimensions" # Source-Hash: c53c3307e2a2a32a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Divider" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32320,8 +35203,8 @@ msgstr "Séparateur" # Source-Hash: 72c65752a1d1bbb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Down" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32330,8 +35213,8 @@ msgstr "Bas" # Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duplicate" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32340,8 +35223,8 @@ msgstr "Dupliquer" # Source-Hash: 8497c4373d5d18ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Enable Sill" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32350,8 +35233,8 @@ msgstr "Activer l’appui" # Source-Hash: 61f9413d3bbabde7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flip Side" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32360,8 +35243,8 @@ msgstr "Inverser le côté" # Source-Hash: ce3a6c03765dbbd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Frame" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32371,7 +35254,7 @@ msgstr "Cadre" # Source-Hash: 0cce8ae784f78478 # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 +# AI-Model: claude-opus-5-5 # English: "Depth (auto)" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32380,8 +35263,8 @@ msgstr "Profondeur (auto)" # Source-Hash: 092033938ca2debb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "French" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32390,8 +35273,8 @@ msgstr "Porte-fenêtre" # Source-Hash: a6362b937fffe999 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fused glass" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32400,8 +35283,8 @@ msgstr "Verre fusionné" # Source-Hash: 7e4a0a38f694be6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Grid" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32410,8 +35293,8 @@ msgstr "Grille" # Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Height" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32420,8 +35303,8 @@ msgstr "Hauteur" # Source-Hash: 42824e50de26bc14 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Individual" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32430,8 +35313,8 @@ msgstr "Individuel" # Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Left" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32440,8 +35323,8 @@ msgstr "Gauche" # Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Move" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32450,8 +35333,8 @@ msgstr "Déplacer" # Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opening" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32460,8 +35343,8 @@ msgstr "Ouverture" # Source-Hash: ecb81bd3eefa6a47 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opening Shape" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32470,8 +35353,8 @@ msgstr "Forme de l’ouverture" # Source-Hash: cf40395b71bedcca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Other side" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32480,8 +35363,8 @@ msgstr "Autre côté" # Source-Hash: 28fe6e9deddde6e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "pos" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32490,8 +35373,8 @@ msgstr "pos" # Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Position" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32500,8 +35383,8 @@ msgstr "Position" # Source-Hash: 3b6f225112035fde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rect" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32510,8 +35393,8 @@ msgstr "Rect." # Source-Hash: 59236bd016c6b904 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reveal Radius" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32520,8 +35403,8 @@ msgstr "Rayon de l’ébrasement" # Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Right" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32530,8 +35413,8 @@ msgstr "Droite" # Source-Hash: fc826da6c99303e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rounded" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32540,8 +35423,8 @@ msgstr "Arrondi" # Source-Hash: fb811056b862b6d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Row Heights" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32550,8 +35433,8 @@ msgstr "Hauteurs de rangée" # Source-Hash: c913b494c3901a17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rows" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32560,8 +35443,8 @@ msgstr "Rangées" # Source-Hash: 62ded63b01564969 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Sill" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32570,8 +35453,8 @@ msgstr "Appui" # Source-Hash: 62ab2eb3c775da95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Single" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32580,8 +35463,8 @@ msgstr "Simple" # Source-Hash: a8096eb4beaadeef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Size is limited to the wall, including clearance for the opening frame." #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32590,8 +35473,8 @@ msgstr "La taille est limitée au mur, dégagement du cadre d’ouverture compri # Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Style" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32600,8 +35483,8 @@ msgstr "Style" # Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Thickness" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32610,8 +35493,8 @@ msgstr "Épaisseur" # Source-Hash: 79ff1ae7250c1711 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "This side" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32620,8 +35503,8 @@ msgstr "Ce côté" # Source-Hash: 7e2505dd1d5e3513 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top Shape" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32630,8 +35513,8 @@ msgstr "Forme du haut" # Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Type" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32640,8 +35523,8 @@ msgstr "Type" # Source-Hash: c29767f86bd9df1e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unwrap" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32650,8 +35533,8 @@ msgstr "Détacher" # Source-Hash: 1d732503a54a532f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Up" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32660,8 +35543,8 @@ msgstr "Haut" # Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Width" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32670,8 +35553,8 @@ msgstr "Largeur" # Source-Hash: aa3c35ed33e181e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32680,8 +35563,8 @@ msgstr "Fenêtre" # Source-Hash: f59cd625e6082651 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window Type" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32690,8 +35573,8 @@ msgstr "Type de fenêtre" # Source-Hash: 7bf8c4e2b90b3021 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wraps the corner with {partner}" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32700,8 +35583,8 @@ msgstr "Fait l’angle avec {partner}" # Source-Hash: 8f1f8eff5fbe90e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wraps the corner with its partner" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32710,8 +35593,8 @@ msgstr "Fait l’angle avec sa jumelle" # Source-Hash: cccf75b8c8dc5ad6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wrap the corner" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32720,8 +35603,8 @@ msgstr "Faire l’angle" # Source-Hash: 9d63109edd8b22c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Casement" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32730,8 +35613,8 @@ msgstr "Battant" # Source-Hash: e06fc5a432b74a5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Double-hung" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32740,8 +35623,8 @@ msgstr "Double guillotine" # Source-Hash: 7e4a0a38f694be6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Grid" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32750,8 +35633,8 @@ msgstr "Grille" # Source-Hash: fbb293fe8aee84b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Horizontal bands" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32760,8 +35643,8 @@ msgstr "Bandes horizontales" # Source-Hash: 3ee270463954f502 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Picture" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32770,8 +35653,8 @@ msgstr "Cadre" # Source-Hash: 62ab2eb3c775da95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Single" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32780,8 +35663,8 @@ msgstr "Simple" # Source-Hash: 18cbc73c5e1590aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Sliding" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32790,8 +35673,8 @@ msgstr "Coulissante" # Source-Hash: 0c88aea2bd130193 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Tall grid" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32800,8 +35683,8 @@ msgstr "Grille haute" # Source-Hash: 9628d0cc155e29a3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Transom" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32810,8 +35693,8 @@ msgstr "Imposte" # Source-Hash: 305f3aba543b1962 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Triple-hung" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32820,8 +35703,8 @@ msgstr "Triple guillotine" # Source-Hash: 8af77effb76bc6e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wide grid" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32830,8 +35713,8 @@ msgstr "Grille large" # Source-Hash: 50393830365aaf2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Awning" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32840,8 +35723,8 @@ msgstr "À l’italienne" # Source-Hash: 8447ee52258e16e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bay" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32850,8 +35733,8 @@ msgstr "Fenêtre en baie" # Source-Hash: e828c89bd0ba1ea4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bow" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32860,8 +35743,8 @@ msgstr "Fenêtre en arc" # Source-Hash: 9d63109edd8b22c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Casement" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32870,8 +35753,8 @@ msgstr "Fenêtre battante" # Source-Hash: b0b737fc5cb1d32a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Double Hung" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32880,8 +35763,8 @@ msgstr "Guillotine double" # Source-Hash: 387ce45ca2eb045f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fixed" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32890,8 +35773,8 @@ msgstr "Fixe" # Source-Hash: 04a40f27911c3192 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hopper" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32900,8 +35783,8 @@ msgstr "Soufflet" # Source-Hash: 5746be19ba2a53be # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Louvered" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32910,8 +35793,8 @@ msgstr "À lames" # Source-Hash: de6ffb1cf676f270 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Single Hung" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32920,8 +35803,8 @@ msgstr "Guillotine simple" # Source-Hash: 18cbc73c5e1590aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Sliding" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32930,8 +35813,8 @@ msgstr "Coulissante" # Source-Hash: 4a4d97a4101793b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A polygonal site zone (lawn, water, paving) with a TSL gradient material." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -32940,8 +35823,8 @@ msgstr "Zone de terrain polygonale (pelouse, eau, revêtement) avec un matériau # Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -32950,8 +35833,8 @@ msgstr "Zone" # Source-Hash: e9a6d2e71b97e757 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Enclosed room" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -32960,8 +35843,8 @@ msgstr "Pièce fermée" # Source-Hash: 3660922f0a8f1d3c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Floor surface" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -32970,8 +35853,8 @@ msgstr "Surface du plancher" # Source-Hash: 88c8703c4ff21ee1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Footprint only" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -32980,8 +35863,8 @@ msgstr "Emprise seule" # Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "None" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -32990,8 +35873,8 @@ msgstr "Aucun" # Source-Hash: a9756a3da570c3dd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Not proven" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33000,8 +35883,8 @@ msgstr "Non prouvé" # Source-Hash: ff97d005a536cf58 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Room quantities" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33010,8 +35893,8 @@ msgstr "Quantités de la pièce" # Source-Hash: f520e6a06fbeb803 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top view with zone edge dimensions" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33020,8 +35903,8 @@ msgstr "Vue de dessus avec les cotes des bords de la zone" # Source-Hash: 062cc0f1afef0c52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unit" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33030,8 +35913,8 @@ msgstr "Lot" # Source-Hash: 429bd43d726de417 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Volume" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33040,8 +35923,8 @@ msgstr "Volume" # Source-Hash: a7941c60a3b6998a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall surface" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33050,8 +35933,8 @@ msgstr "Surface murale" # Source-Hash: b8b0dbdff53a83ca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone boundary unavailable" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33060,8 +35943,8 @@ msgstr "Limite de zone indisponible" # Source-Hash: 6bfb4c6f4d7b0ff2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone quantities" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy diff --git a/packages/editor/src/i18n/locales/fr/messages.ts b/packages/editor/src/i18n/locales/fr/messages.ts index 42848704ea..27712d5a95 100644 --- a/packages/editor/src/i18n/locales/fr/messages.ts +++ b/packages/editor/src/i18n/locales/fr/messages.ts @@ -1 +1 @@ -/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"core.level.basement\":[\"Sous-sol\"],\"core.level.basementNumber\":[\"Sous-sol \",[\"number\"]],\"core.level.floorNumber\":[\"Étage \",[\"number\"]],\"core.level.groundFloor\":[\"Rez-de-chaussée\"],\"editor.buildPanel.advanced\":[\"Avancé\"],\"editor.buildPanel.rooms.hint\":[\"murs · sol · plafond\"],\"editor.buildPanel.rooms.idle\":[\"Choisissez une forme pour commencer. Chaque pièce crée ses murs, son sol et son plafond.\"],\"editor.buildPanel.rooms.polygon.caption\":[[\"lead\"],\" puis de nouveau sur le premier pour fermer. Pour les pièces en L et les angles obliques.\"],\"editor.buildPanel.rooms.polygon.label\":[\"Polygone\"],\"editor.buildPanel.rooms.polygon.lead\":[\"Cliquez sur chaque angle,\"],\"editor.buildPanel.rooms.polygon.title\":[\"Pièce polygonale\"],\"editor.buildPanel.rooms.rectangle.caption\":[[\"lead\"],\" sur la grille. Les murs, le sol et le plafond sont créés ensemble.\"],\"editor.buildPanel.rooms.rectangle.label\":[\"Rectangle\"],\"editor.buildPanel.rooms.rectangle.lead\":[\"Cliquez sur deux angles\"],\"editor.buildPanel.rooms.rectangle.title\":[\"Pièce rectangulaire\"],\"editor.buildPanel.rooms.title\":[\"Pièces\"],\"editor.buildPanel.rooms.walls.caption\":[[\"lead\"],\" Fermez la boucle pour créer une pièce, ou laissez-la ouverte pour une cloison.\"],\"editor.buildPanel.rooms.walls.label\":[\"Murs\"],\"editor.buildPanel.rooms.walls.lead\":[\"Tracez un mur à la fois.\"],\"editor.buildPanel.rooms.walls.title\":[\"Murs\"],\"viewer.camera.orbitLeft\":[\"Pivoter à gauche\"],\"viewer.camera.orbitRight\":[\"Pivoter à droite\"],\"viewer.camera.topView\":[\"Vue de dessus\"],\"viewer.common.off\":[\"Désactivé\"],\"viewer.common.on\":[\"Activé\"],\"viewer.display.camera\":[\"Caméra\"],\"viewer.display.colored\":[\"En couleur\"],\"viewer.display.colors\":[\"Couleurs\"],\"viewer.display.edges.off\":[\"Désactivées\"],\"viewer.display.edges.offDetail\":[\"Aucune ligne d’arête\"],\"viewer.display.edges.soft\":[\"Douces\"],\"viewer.display.edges.softDetail\":[\"Contour léger des plis principaux\"],\"viewer.display.edges.strong\":[\"Marquées\"],\"viewer.display.edges.strongDetail\":[\"Lignes d’arête nettes et opaques\"],\"viewer.display.edges.title\":[\"Arêtes\"],\"viewer.display.monochrome\":[\"Monochrome\"],\"viewer.display.orthographic\":[\"Orthographique\"],\"viewer.display.perspective\":[\"Perspective\"],\"viewer.display.render.rendered\":[\"Réaliste\"],\"viewer.display.render.renderedDetail\":[\"Occlusion ambiante complète\"],\"viewer.display.render.solid\":[\"Solide\"],\"viewer.display.render.solidDetail\":[\"Rapide et uniforme, sans occlusion ambiante\"],\"viewer.display.render.title\":[\"Rendu\"],\"viewer.display.shadows\":[\"Ombres\"],\"viewer.display.title\":[\"Paramètres d’affichage\"],\"viewer.floorplan.alignNorth\":[\"Orienter la vue vers le nord\"],\"viewer.floorplan.empty\":[\"Aucun plan d’étage n’est disponible pour cette scène.\"],\"viewer.floorplan.fit\":[\"Ajuster le plan\"],\"viewer.floorplan.floor\":[\"Niveau\"],\"viewer.floorplan.floorPlan\":[\"Plan d’étage\"],\"viewer.floorplan.viewLabel\":[\"Vue 2D — \",[\"floor\"]],\"viewer.floorplan.zoomIn\":[\"Zoom avant\"],\"viewer.floorplan.zoomOut\":[\"Zoom arrière\"],\"viewer.header.back\":[\"Retour\"],\"viewer.header.levels\":[\"Niveaux\"],\"viewer.header.rooms\":[\"Pièces\"],\"viewer.header.selection\":[\"Sélection\"],\"viewer.header.units\":[\"Unités\"],\"viewer.header.untitled\":[\"Sans titre\"],\"viewer.header.zones\":[\"Zones\"],\"viewer.levels.exploded\":[\"Éclatés\"],\"viewer.levels.label\":[\"Niveaux : \",[\"mode\"]],\"viewer.levels.manual\":[\"Manuel\"],\"viewer.levels.solo\":[\"Isolé\"],\"viewer.levels.stacked\":[\"Superposés\"],\"viewer.stage.layout\":[\"Disposition des vues\"],\"viewer.stage.split\":[\"Partagé\"],\"viewer.theme.blueprint\":[\"Plan\"],\"viewer.theme.mediterranean\":[\"Méditerranéen\"],\"viewer.theme.night\":[\"Nuit\"],\"viewer.theme.overcast\":[\"Ciel couvert\"],\"viewer.theme.paper\":[\"Papier\"],\"viewer.theme.studio\":[\"Studio\"],\"viewer.theme.sunset\":[\"Coucher de soleil\"],\"viewer.theme.title\":[\"Ambiance\"],\"viewer.theme.twilight\":[\"Crépuscule\"],\"viewer.theme.verdant\":[\"Verdoyant\"],\"viewer.visibility.guides\":[\"Repères\"],\"viewer.visibility.scans\":[\"Relevés 3D\"],\"viewer.visibility.title\":[\"Visibilité\"],\"viewer.walkthrough.label\":[\"Visite : \",[\"state\"]],\"viewer.walls.cutaway\":[\"Vue en coupe\"],\"viewer.walls.fullHeight\":[\"Pleine hauteur\"],\"viewer.walls.label\":[\"Murs : \",[\"mode\"]],\"viewer.walls.low\":[\"Bas\"]}")as Messages; \ No newline at end of file +/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"core.level.basement\":[\"Sous-sol\"],\"core.level.basementNumber\":[\"Sous-sol \",[\"number\"]],\"core.level.floorNumber\":[\"Étage \",[\"number\"]],\"core.level.groundFloor\":[\"Rez-de-chaussée\"],\"editor.buildPanel.advanced\":[\"Avancé\"],\"editor.buildPanel.rooms.hint\":[\"murs · sol · plafond\"],\"editor.buildPanel.rooms.idle\":[\"Choisissez une forme pour commencer. Chaque pièce crée ses murs, son sol et son plafond.\"],\"editor.buildPanel.rooms.polygon.caption\":[[\"lead\"],\" puis de nouveau sur le premier pour fermer. Pour les pièces en L et les angles obliques.\"],\"editor.buildPanel.rooms.polygon.label\":[\"Polygone\"],\"editor.buildPanel.rooms.polygon.lead\":[\"Cliquez sur chaque angle,\"],\"editor.buildPanel.rooms.polygon.title\":[\"Pièce polygonale\"],\"editor.buildPanel.rooms.rectangle.caption\":[[\"lead\"],\" sur la grille. Les murs, le sol et le plafond sont créés ensemble.\"],\"editor.buildPanel.rooms.rectangle.label\":[\"Rectangle\"],\"editor.buildPanel.rooms.rectangle.lead\":[\"Cliquez sur deux angles\"],\"editor.buildPanel.rooms.rectangle.title\":[\"Pièce rectangulaire\"],\"editor.buildPanel.rooms.title\":[\"Pièces\"],\"editor.buildPanel.rooms.walls.label\":[\"Murs\"],\"editor.buildPanel.rooms.walls.title\":[\"Murs\"],\"viewer.camera.orbitLeft\":[\"Pivoter à gauche\"],\"viewer.camera.orbitRight\":[\"Pivoter à droite\"],\"viewer.camera.topView\":[\"Vue de dessus\"],\"viewer.common.off\":[\"Désactivé\"],\"viewer.common.on\":[\"Activé\"],\"viewer.display.camera\":[\"Caméra\"],\"viewer.display.colored\":[\"En couleur\"],\"viewer.display.colors\":[\"Couleurs\"],\"viewer.display.edges.off\":[\"Désactivées\"],\"viewer.display.edges.offDetail\":[\"Aucune ligne d’arête\"],\"viewer.display.edges.soft\":[\"Douces\"],\"viewer.display.edges.softDetail\":[\"Contour léger des plis principaux\"],\"viewer.display.edges.strong\":[\"Marquées\"],\"viewer.display.edges.strongDetail\":[\"Lignes d’arête nettes et opaques\"],\"viewer.display.edges.title\":[\"Arêtes\"],\"viewer.display.monochrome\":[\"Monochrome\"],\"viewer.display.orthographic\":[\"Orthographique\"],\"viewer.display.perspective\":[\"Perspective\"],\"viewer.display.render.rendered\":[\"Réaliste\"],\"viewer.display.render.renderedDetail\":[\"Occlusion ambiante complète\"],\"viewer.display.render.solid\":[\"Solide\"],\"viewer.display.render.solidDetail\":[\"Rapide et uniforme, sans occlusion ambiante\"],\"viewer.display.render.title\":[\"Rendu\"],\"viewer.display.shadows\":[\"Ombres\"],\"viewer.display.title\":[\"Paramètres d’affichage\"],\"viewer.floorplan.alignNorth\":[\"Orienter la vue vers le nord\"],\"viewer.floorplan.empty\":[\"Aucun plan d’étage n’est disponible pour cette scène.\"],\"viewer.floorplan.fit\":[\"Ajuster le plan\"],\"viewer.floorplan.floor\":[\"Niveau\"],\"viewer.floorplan.floorPlan\":[\"Plan d’étage\"],\"viewer.floorplan.viewLabel\":[\"Vue 2D — \",[\"floor\"]],\"viewer.floorplan.zoomIn\":[\"Zoom avant\"],\"viewer.floorplan.zoomOut\":[\"Zoom arrière\"],\"viewer.header.back\":[\"Retour\"],\"viewer.header.levels\":[\"Niveaux\"],\"viewer.header.rooms\":[\"Pièces\"],\"viewer.header.selection\":[\"Sélection\"],\"viewer.header.units\":[\"Unités\"],\"viewer.header.untitled\":[\"Sans titre\"],\"viewer.header.zones\":[\"Zones\"],\"viewer.levels.exploded\":[\"Éclatés\"],\"viewer.levels.label\":[\"Niveaux : \",[\"mode\"]],\"viewer.levels.manual\":[\"Manuel\"],\"viewer.levels.solo\":[\"Isolé\"],\"viewer.levels.stacked\":[\"Superposés\"],\"viewer.stage.layout\":[\"Disposition des vues\"],\"viewer.stage.split\":[\"Partagé\"],\"viewer.theme.blueprint\":[\"Plan\"],\"viewer.theme.mediterranean\":[\"Méditerranéen\"],\"viewer.theme.night\":[\"Nuit\"],\"viewer.theme.overcast\":[\"Ciel couvert\"],\"viewer.theme.paper\":[\"Papier\"],\"viewer.theme.studio\":[\"Studio\"],\"viewer.theme.sunset\":[\"Coucher de soleil\"],\"viewer.theme.title\":[\"Ambiance\"],\"viewer.theme.twilight\":[\"Crépuscule\"],\"viewer.theme.verdant\":[\"Verdoyant\"],\"viewer.visibility.guides\":[\"Repères\"],\"viewer.visibility.scans\":[\"Relevés 3D\"],\"viewer.visibility.title\":[\"Visibilité\"],\"viewer.walkthrough.label\":[\"Visite : \",[\"state\"]],\"viewer.walls.cutaway\":[\"Vue en coupe\"],\"viewer.walls.fullHeight\":[\"Pleine hauteur\"],\"viewer.walls.label\":[\"Murs : \",[\"mode\"]],\"viewer.walls.low\":[\"Bas\"]}")as Messages; \ No newline at end of file diff --git a/packages/editor/src/i18n/locales/ja/messages.po b/packages/editor/src/i18n/locales/ja/messages.po index 3897362781..0aa7d8e806 100644 --- a/packages/editor/src/i18n/locales/ja/messages.po +++ b/packages/editor/src/i18n/locales/ja/messages.po @@ -15,8 +15,8 @@ msgstr "" # Source-Hash: 8ffb1c5066e53a8d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Pascal home" #: apps/editor/components/app-home-link.tsx #, fuzzy @@ -25,8 +25,8 @@ msgstr "Pascal ホーム" # Source-Hash: 534540df302975a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Gate" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -35,8 +35,8 @@ msgstr "門を追加" # Source-Hash: 8b9110c4e72f2db2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Open Passage" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -45,8 +45,8 @@ msgstr "通路を追加" # Source-Hash: 9a4d56454dc89966 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add to rooms" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -55,8 +55,8 @@ msgstr "部屋に追加" # Source-Hash: a17210912addc85f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "← All build tools" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -65,8 +65,8 @@ msgstr "← すべての建築ツール" # Source-Hash: 6b63404967e1d5b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Choose Gate or Open Passage, then click its position on any fence. Find placed gates and openings under their fence in the scene graph." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -75,8 +75,8 @@ msgstr "門または通路を選び、フェンス上の位置をクリックし # Source-Hash: 8fd051e1e1a6c1a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Click a lineset to lay the line beside it." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -85,8 +85,8 @@ msgstr "冷媒配管をクリックして、その横に配管します。" # Source-Hash: 7308869944020839 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Double gate" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -95,8 +95,8 @@ msgstr "両開き門" # Source-Hash: 281d63a4b3e2de4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Features & extensions" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -105,8 +105,8 @@ msgstr "部材と増築" # Source-Hash: b18788f1d889c1d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fence features" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -115,8 +115,8 @@ msgstr "フェンスの部材" # Source-Hash: 62803100bd6e7cc2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follow lineset" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -125,8 +125,8 @@ msgstr "冷媒配管に沿う" # Source-Hash: 4a479aa23542d766 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gate" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -135,8 +135,8 @@ msgstr "門" # Source-Hash: 54098b5ee574737a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gate style" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -145,8 +145,8 @@ msgstr "門のスタイル" # Source-Hash: 8fec7e969045a8e7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Horizontal boards" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -155,8 +155,8 @@ msgstr "横板" # Source-Hash: 09197c4fea516277 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hover a fence to preview. Click to place. Esc cancels. Leave room between openings." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -165,8 +165,8 @@ msgstr "フェンスにホバーしてプレビュー。クリックで配置、 # Source-Hash: c390ba248e629b9e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Leaves" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -175,8 +175,8 @@ msgstr "扉" # Source-Hash: c34c9b36492c6e21 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Liquid Line" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -185,8 +185,8 @@ msgstr "液管" # Source-Hash: c15c1af69ec5c1eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Match fence style" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -195,8 +195,8 @@ msgstr "フェンスのスタイルに合わせる" # Source-Hash: 95057eef5cd69340 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "MEP" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -205,8 +205,8 @@ msgstr "設備" # Source-Hash: 50accd740fa2e736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Off" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -215,8 +215,8 @@ msgstr "オフ" # Source-Hash: 9cc01faad79c28da # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "On" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -225,8 +225,8 @@ msgstr "オン" # Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opening" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -235,8 +235,8 @@ msgstr "開口" # Source-Hash: 9514d3c022e68808 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opening width (m)" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -245,8 +245,8 @@ msgstr "開口幅(m)" # Source-Hash: 6b108fb1d0eb8f9d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Open rails" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -255,8 +255,8 @@ msgstr "横桟" # Source-Hash: a5a7af5e5fff1c81 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Outdoor" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -265,8 +265,8 @@ msgstr "屋外" # Source-Hash: 9295ddc2805b21e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Picket" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -275,8 +275,8 @@ msgstr "ピケット" # Source-Hash: 3a08ede9e51d5395 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Roof type" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -285,8 +285,8 @@ msgstr "屋根の種類" # Source-Hash: 0f9daa442776a317 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rooms already create their floor and ceiling. Use these for platforms and one-off structure." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -295,8 +295,8 @@ msgstr "部屋は床と天井を自動で作ります。これらは台やその # Source-Hash: fc79fd0c7730de76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Search build tools and kitchen items" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -305,8 +305,8 @@ msgstr "建築ツールとキッチンアイテムを検索" # Source-Hash: dc1901f276edca6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Search tools, fridge, sink…" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -315,8 +315,8 @@ msgstr "ツール、冷蔵庫、シンクを検索…" # Source-Hash: 9558db89023d4f05 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Select a curved wall to match its radius and arc." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -325,8 +325,8 @@ msgstr "曲面の壁を選ぶと、その半径と円弧に合わせます。" # Source-Hash: d327097d9ac1099f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Single gate" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -335,8 +335,8 @@ msgstr "片開き門" # Source-Hash: 99acd5128c51c8a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slab, ceiling, column…" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -345,8 +345,8 @@ msgstr "スラブ、天井、柱…" # Source-Hash: af6f8885fe0fa4e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Solid privacy" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -355,8 +355,8 @@ msgstr "目隠し" # Source-Hash: e2b1a3bb9630b33b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Trace a line alongside an existing lineset (F)." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -365,8 +365,8 @@ msgstr "既存の冷媒配管に沿って配管 (F)。" # Source-Hash: eba3df14a2de0812 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Vertical slats" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -375,8 +375,8 @@ msgstr "縦板" # Source-Hash: 2ee62be78ba76f53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "All projects" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -385,8 +385,8 @@ msgstr "すべてのプロジェクト" # Source-Hash: 20226b68d5467072 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Preview" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -395,8 +395,8 @@ msgstr "プレビュー" # Source-Hash: 9f2cbc9214c8f7b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Project name" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -405,8 +405,8 @@ msgstr "プロジェクト名" # Source-Hash: 150e143a84240eee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rename project" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -415,8 +415,8 @@ msgstr "プロジェクト名を変更" # Source-Hash: 331e1584943b09b9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Share" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -425,8 +425,8 @@ msgstr "共有" # Source-Hash: 4b2f676fb4c9ec63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add {label}" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -435,8 +435,8 @@ msgstr "{label}を追加" # Source-Hash: 53f98cc505aacbb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add to kitchen" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -445,8 +445,8 @@ msgstr "キッチンに追加" # Source-Hash: 923a2e81dcc77852 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Choose an item, then click to place it. Appliances include their cabinetry." #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -455,8 +455,8 @@ msgstr "アイテムを選び、クリックして配置します。家電には # Source-Hash: 44156a2c888e8a4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Find in this project · {length}" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -465,8 +465,8 @@ msgstr "このプロジェクト内を検索 · {length}" # Source-Hash: aeda65db67edac21 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Find {name}" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -475,8 +475,8 @@ msgstr "{name}を探す" # Source-Hash: c1d847411ba09cd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen · Add" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -485,8 +485,8 @@ msgstr "キッチン · 追加" # Source-Hash: bb3f4f8d3407c409 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen · In this project" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -495,8 +495,8 @@ msgstr "キッチン · このプロジェクト内" # Source-Hash: 25ffad31086309f1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen cabinet" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -505,8 +505,8 @@ msgstr "キッチンキャビネット" # Source-Hash: a5af7817a7e8947d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No matching kitchen items placed yet." #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -515,8 +515,8 @@ msgstr "該当するキッチンアイテムはまだ配置されていません # Source-Hash: 640155f99c25773b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Select and show in scene" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -525,8 +525,8 @@ msgstr "選択してシーンに表示" # Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Ceiling" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -535,8 +535,8 @@ msgstr "天井" # Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -545,8 +545,8 @@ msgstr "柱" # Source-Hash: 787e10f5db16904e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Door" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -555,8 +555,8 @@ msgstr "ドア" # Source-Hash: e971d82044e2f48e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duct" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -565,8 +565,8 @@ msgstr "ダクト" # Source-Hash: 457155657704f7cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "DWV Pipe" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -575,8 +575,8 @@ msgstr "排水管" # Source-Hash: ab5cbab7be160a1c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Elevator" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -585,8 +585,8 @@ msgstr "エレベーター" # Source-Hash: 02042fde61b5aa11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fence" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -595,8 +595,8 @@ msgstr "フェンス" # Source-Hash: 3bf1c1a8dbb93743 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "HVAC Unit" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -605,8 +605,8 @@ msgstr "空調機" # Source-Hash: 1176d2568d093bf1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -615,8 +615,8 @@ msgstr "キッチン" # Source-Hash: 362b03eba9d8234c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Lineset" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -625,8 +625,8 @@ msgstr "冷媒配管" # Source-Hash: c34c9b36492c6e21 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Liquid Line" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -635,18 +635,28 @@ msgstr "液管" # Source-Hash: 95057eef5cd69340 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "MEP" #: apps/editor/lib/build-palette.ts #, fuzzy msgid "app.lib.buildPalette.mep" msgstr "設備" +# Source-Hash: 5cc981e79d737694 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post" +#: apps/editor/lib/build-palette.ts +#, fuzzy +msgid "app.lib.buildPalette.post" +msgstr "支柱" + # Source-Hash: 161e5386b939e1bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Register" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -655,8 +665,8 @@ msgstr "吹出口" # Source-Hash: f5f730969df63d1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Roof" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -665,8 +675,8 @@ msgstr "屋根" # Source-Hash: d7145f84f8e0e3fe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shelf" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -675,8 +685,8 @@ msgstr "棚" # Source-Hash: 8775bc8dc9593964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slab" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -685,8 +695,8 @@ msgstr "スラブ" # Source-Hash: 95e8af5d2b3ca73d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Spawn point" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -695,8 +705,8 @@ msgstr "スポーン地点" # Source-Hash: f05bc67c57e4d530 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stairs" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -705,8 +715,8 @@ msgstr "階段" # Source-Hash: 96281876ce53ba08 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Terrace" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -715,8 +725,8 @@ msgstr "テラス" # Source-Hash: d457508edd5bb8cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Terrain" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -725,8 +735,8 @@ msgstr "地形" # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -735,8 +745,8 @@ msgstr "壁" # Source-Hash: aa3c35ed33e181e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -745,8 +755,8 @@ msgstr "窓" # Source-Hash: d40c50013043284f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Fitting" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -755,8 +765,8 @@ msgstr "継手を追加" # Source-Hash: 534540df302975a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Gate" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -765,8 +775,8 @@ msgstr "門を追加" # Source-Hash: 8b9110c4e72f2db2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Open Passage" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -775,8 +785,8 @@ msgstr "通路を追加" # Source-Hash: 7136b5836de6e69f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Trap" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -785,8 +795,8 @@ msgstr "トラップを追加" # Source-Hash: 8f4b2028ad75465d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Build" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -795,8 +805,8 @@ msgstr "建築" # Source-Hash: a23831beeb35ad3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Create from" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -805,8 +815,8 @@ msgstr "作成元" # Source-Hash: 8146c309bd8326f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Draw the roof footprint with two corner clicks." #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -815,8 +825,8 @@ msgstr "2つの角をクリックして屋根の外形を描きます。" # Source-Hash: e971d82044e2f48e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duct" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -825,8 +835,8 @@ msgstr "ダクト" # Source-Hash: 457155657704f7cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "DWV Pipe" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -835,8 +845,8 @@ msgstr "排水管" # Source-Hash: 281d63a4b3e2de4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Features & extensions" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -845,8 +855,8 @@ msgstr "部材と増築" # Source-Hash: 02042fde61b5aa11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fence" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -855,8 +865,8 @@ msgstr "フェンス" # Source-Hash: 62803100bd6e7cc2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follow lineset" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -865,8 +875,8 @@ msgstr "冷媒配管に沿う" # Source-Hash: c80972ec078ac551 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gates & openings" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -875,8 +885,8 @@ msgstr "門と開口" # Source-Hash: 3720347aa16ee777 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hover a room to preview its boundary, then click to place." #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -885,8 +895,8 @@ msgstr "部屋にホバーして境界をプレビューし、クリックで配 # Source-Hash: 1176d2568d093bf1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -895,8 +905,8 @@ msgstr "キッチン" # Source-Hash: 95057eef5cd69340 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "MEP" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -905,8 +915,8 @@ msgstr "設備" # Source-Hash: 2e6d8cda361c648d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Modular Cabinet" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -915,8 +925,8 @@ msgstr "モジュール式キャビネット" # Source-Hash: 50accd740fa2e736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Off" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -925,8 +935,8 @@ msgstr "オフ" # Source-Hash: 9cc01faad79c28da # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "On" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -935,8 +945,8 @@ msgstr "オン" # Source-Hash: 3fafdc69e7756f19 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Painting" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -945,8 +955,8 @@ msgstr "塗装" # Source-Hash: f5f730969df63d1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Roof" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -955,8 +965,8 @@ msgstr "屋根" # Source-Hash: 3a08ede9e51d5395 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Roof type" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -965,8 +975,8 @@ msgstr "屋根の種類" # Source-Hash: 0c35bee851cc57a2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {# tool} other {# tools}}" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -975,8 +985,8 @@ msgstr "{count, plural, other {ツール # 個}}" # Source-Hash: 3241ecabee8221a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Conical" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -985,8 +995,8 @@ msgstr "円錐" # Source-Hash: b5c56dd8c68de309 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Draw" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -995,8 +1005,8 @@ msgstr "描画" # Source-Hash: 6949d667043bee0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dutch" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1005,8 +1015,8 @@ msgstr "入母屋" # Source-Hash: 9cab4d4c95f63cdd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flat" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1015,8 +1025,8 @@ msgstr "陸屋根" # Source-Hash: deaffa095d126dfe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gable" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1025,8 +1035,8 @@ msgstr "切妻" # Source-Hash: 7f53d9ffca39984a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gambrel" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1035,8 +1045,8 @@ msgstr "腰折れ" # Source-Hash: 9eda0ea8d447066d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hip" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1045,8 +1055,8 @@ msgstr "寄棟" # Source-Hash: 7f7bb0e875af3260 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Mansard" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1055,8 +1065,8 @@ msgstr "マンサード" # Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Room" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1065,8 +1075,8 @@ msgstr "部屋" # Source-Hash: c8d0df27faa3feaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shed" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1075,8 +1085,8 @@ msgstr "片流れ" # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1085,8 +1095,8 @@ msgstr "壁" # Source-Hash: 8d17e7556ce142da # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Another session saved first — refresh?" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1095,8 +1105,8 @@ msgstr "別のセッションが先に保存しました。更新しますか? # Source-Hash: 8f4b2028ad75465d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Build" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1105,8 +1115,8 @@ msgstr "建築" # Source-Hash: a2bd204e93e90598 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dismiss" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1115,8 +1125,8 @@ msgstr "閉じる" # Source-Hash: daebc0755d239c99 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Items" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1125,8 +1135,8 @@ msgstr "アイテム" # Source-Hash: cf2e870fce0f2f51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Paint" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1135,8 +1145,8 @@ msgstr "塗装" # Source-Hash: 854555777b69a4b1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reload" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1145,8 +1155,8 @@ msgstr "再読み込み" # Source-Hash: 8dc78e215a97d9fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scene" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1155,8 +1165,8 @@ msgstr "シーン" # Source-Hash: 83909f82446ee9c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Settings" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1165,8 +1175,8 @@ msgstr "設定" # Source-Hash: ee255fa26d076dcc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Your changes haven't been saved. Reload to pick up the latest version." #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1175,8 +1185,8 @@ msgstr "変更は保存されていません。再読み込みして最新バー # Source-Hash: 703e1b4b9b715d3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Anyone with the link can view this project. They cannot edit it." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1185,8 +1195,8 @@ msgstr "リンクを知っている人は誰でもこのプロジェクトを閲 # Source-Hash: 07e04484867c17d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Copied" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1195,8 +1205,8 @@ msgstr "コピーしました" # Source-Hash: 4f60d1e142affa9c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Copy" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1205,8 +1215,8 @@ msgstr "コピー" # Source-Hash: 8ff50e1a9962a4db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Could not read the sharing state." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1215,8 +1225,8 @@ msgstr "共有状態を読み込めませんでした。" # Source-Hash: 791e281338a51483 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Could not turn off the public link." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1225,8 +1235,8 @@ msgstr "公開リンクをオフにできませんでした。" # Source-Hash: 2c5ddecfd652ba63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Could not turn on the public link." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1235,8 +1245,8 @@ msgstr "公開リンクをオンにできませんでした。" # Source-Hash: 15e49d4da8765318 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Embed code" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1245,8 +1255,8 @@ msgstr "埋め込みコード" # Source-Hash: d4523c2d303f99b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Embed link" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1255,8 +1265,8 @@ msgstr "埋め込みリンク" # Source-Hash: 252f2cbf5e1609a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide controls" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1265,8 +1275,8 @@ msgstr "コントロールを非表示" # Source-Hash: ba77c0610a63bb2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Link" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1275,8 +1285,8 @@ msgstr "リンク" # Source-Hash: a2560430aaec31d9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Only the 3D view, no header or toolbar." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1285,8 +1295,8 @@ msgstr "3D ビューのみ。ヘッダーとツールバーは表示しません # Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Open" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1295,8 +1305,8 @@ msgstr "開く" # Source-Hash: b34faaa5378056c6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Public link" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1305,38 +1315,78 @@ msgstr "公開リンク" # Source-Hash: 7525e8007fcab09b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Share project" #: apps/editor/components/share-panel.tsx #, fuzzy msgid "app.sharePanel.shareProject" msgstr "プロジェクトを共有" +# Source-Hash: c90de8776040735c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Above" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.above" +msgstr "上" + # Source-Hash: 3d3f438d5a49eba7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Automatic dimensions" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.automaticDimensions" msgstr "自動寸法" +# Source-Hash: 1794e014a604344c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Below" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.below" +msgstr "下" + +# Source-Hash: 69578b7dd7723fa1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Both" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.both" +msgstr "両方" + # Source-Hash: 14622745dbf93f4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Camera" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.camera" msgstr "カメラ" +# Source-Hash: a03ae72f209e32db +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceilings" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.ceilings" +msgstr "天井" + # Source-Hash: e6bce525c47ba3ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Clean plan; dimensions appear with selection" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1345,8 +1395,8 @@ msgstr "すっきりした図面。寸法は選択時に表示" # Source-Hash: 61ce356577cfb04a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Collapse sidebar" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1355,8 +1405,8 @@ msgstr "サイドバーを折りたたむ" # Source-Hash: 2416a48df28d6205 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Crisp, opaque edge lines" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1365,8 +1415,8 @@ msgstr "くっきりした不透明なエッジ線" # Source-Hash: 4da8b3678ed77b45 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Cutaway" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1375,18 +1425,28 @@ msgstr "カットアウェイ" # Source-Hash: 4ca0e0e73229540c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Default" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.default" msgstr "標準" +# Source-Hash: 12df69f42beb0643 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.dimensions" +msgstr "寸法" + # Source-Hash: a313661ef9dd0a65 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Display" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1395,8 +1455,8 @@ msgstr "表示" # Source-Hash: d0db46f206a88e2e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Display settings" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1405,8 +1465,8 @@ msgstr "表示設定" # Source-Hash: 0286962ab8e9cfcd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Door/window marks" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1415,18 +1475,28 @@ msgstr "建具記号" # Source-Hash: 027bbc8b7287c06a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Edges" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.edges" msgstr "エッジ" +# Source-Hash: 9bacee5dbd658209 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Editing" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.editing" +msgstr "編集" + # Source-Hash: d86126c5d16c6238 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Enter VR" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1435,8 +1505,8 @@ msgstr "VR を開始" # Source-Hash: eb99fb0b382e58cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Exit VR" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1445,8 +1515,8 @@ msgstr "VR を終了" # Source-Hash: aeac665749d3101d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Expand sidebar" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1455,8 +1525,8 @@ msgstr "サイドバーを展開" # Source-Hash: 08c178ee733ff009 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Expert" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1465,28 +1535,18 @@ msgstr "エキスパート" # Source-Hash: be12f8788f1f0a05 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Exploded" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.exploded" msgstr "分解" -# Source-Hash: c6f865a366ef5755 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Face of stud" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.faceOfStud" -msgstr "下地面" - # Source-Hash: 0c583f1d4201293b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Faint outline of major creases" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1495,28 +1555,18 @@ msgstr "主な折れ目の淡い輪郭" # Source-Hash: 08ecd5878b08139d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Feet & inches" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.feetInches" msgstr "フィート・インチ" -# Source-Hash: 43b8017fa821c46c -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finished faces" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.finishedFaces" -msgstr "仕上げ面" - # Source-Hash: 8827df1cdeb02ed9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flat and fast — no ambient occlusion" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1525,8 +1575,8 @@ msgstr "フラットで高速 — アンビエントオクルージョンなし" # Source-Hash: 060a718cdcff61b3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Floor plan annotations" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1535,8 +1585,8 @@ msgstr "平面図の注記" # Source-Hash: 483171f79dc32ae5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Floor plan mode" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1545,8 +1595,8 @@ msgstr "平面図モード" # Source-Hash: 8bb9e54fc786ca77 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Full ambient occlusion" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1555,8 +1605,8 @@ msgstr "フルアンビエントオクルージョン" # Source-Hash: 91fd3544d9ce16bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Full documentation and annotation controls" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1565,38 +1615,70 @@ msgstr "図面化と注記の全コントロール" # Source-Hash: 131bac2467f4fdf6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Full height" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.fullHeight" msgstr "全高" -# Source-Hash: c9838bc98cb35125 +# Source-Hash: 91c2dd3678e981b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Full wall thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ghosted for reference" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy -msgid "app.viewerToolbar.fullWallThickness" -msgstr "壁の全厚" +msgid "app.viewerToolbar.ghostedForReference" +msgstr "参照用に半透明で表示" # Source-Hash: 7e4a0a38f694be6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Grid" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.grid" msgstr "グリッド" +# Source-Hash: 81ef3a25ccb6eaf7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "ID" +#. Short for inside dimension: measured between the inside faces of walls. +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.id" +msgstr "内法" + +# Source-Hash: 09f615a2c6a14a76 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "ID + OD" +#. Inside and outside dimensions together. +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.idOd" +msgstr "内法 + 外法" + +# Source-Hash: 8a7ff5011275abbd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inside" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.inside" +msgstr "内側" + # Source-Hash: 4bf4a6861d7d633e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Levels: {mode}" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1605,8 +1687,8 @@ msgstr "階層: {mode}" # Source-Hash: 803532407fb5962b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Low" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1615,8 +1697,8 @@ msgstr "低" # Source-Hash: 32f9a404c0bdce10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Magnetic snap" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1625,8 +1707,8 @@ msgstr "マグネットスナップ" # Source-Hash: 387082cd5f118bed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Manual" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1635,8 +1717,8 @@ msgstr "手動" # Source-Hash: 2fb69122dd996c0a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Manual dimensions" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1645,18 +1727,28 @@ msgstr "手動寸法" # Source-Hash: c6aa74075f37313a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Measurements" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.measurements" msgstr "計測" +# Source-Hash: b2cac1ec253d4394 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Measure walls" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.measureWalls" +msgstr "壁の測り方" + # Source-Hash: 0a39470be3b84536 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Meters" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1665,38 +1757,59 @@ msgstr "メートル" # Source-Hash: 83cce6c521e71d01 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Millimeters" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.millimeters" msgstr "ミリメートル" -# Source-Hash: b784527bb90b9c5e +# Source-Hash: 340a0a4e7703227b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "3D measurements" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "2D only" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.n2dOnly" +msgstr "2Dのみ" + +# Source-Hash: ed5416e4329bd789 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "3D only" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy -msgid "app.viewerToolbar.n3dMeasurements" -msgstr "3D 計測" +msgid "app.viewerToolbar.n3dOnly" +msgstr "3Dのみ" # Source-Hash: 4ff58913a4492199 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No edge lines" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.noEdgeLines" msgstr "エッジ線なし" +# Source-Hash: fdaa3b3faa1844fd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "OD" +#. Short for outside dimension: measured between the outside faces of walls. +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.od" +msgstr "外法" + # Source-Hash: 50accd740fa2e736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Off" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1705,8 +1818,8 @@ msgstr "オフ" # Source-Hash: 9cc01faad79c28da # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "On" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1715,28 +1828,68 @@ msgstr "オン" # Source-Hash: ed59dd8ce7797a66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Orthographic" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.orthographic" msgstr "平行投影" +# Source-Hash: 370413dd021d6ea7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Other levels" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.otherLevels" +msgstr "他の階層" + +# Source-Hash: dc4fe6cb415ed882 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outside" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.outside" +msgstr "外側" + +# Source-Hash: 4b5cbc83a3533c2a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overall size, outside face to outside face" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.overallSizeOutsideFaceToOutsideFace" +msgstr "外形寸法(外面から外面まで)" + # Source-Hash: 316e25993ff72b88 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Perspective" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.perspective" msgstr "透視投影" +# Source-Hash: 007a63bd7c1e2b55 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plan" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.plan" +msgstr "平面図" + # Source-Hash: 20226b68d5467072 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Preview" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1745,8 +1898,8 @@ msgstr "プレビュー" # Source-Hash: 34c20b72a42ca618 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Preview mode" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1755,8 +1908,8 @@ msgstr "プレビューモード" # Source-Hash: 5e58af99d6d4fa6a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Render" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1765,8 +1918,8 @@ msgstr "レンダリング" # Source-Hash: f363702a10aedaeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rendered" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1775,18 +1928,48 @@ msgstr "レンダリング" # Source-Hash: 4959d5538efc595c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Room labels" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.roomLabels" msgstr "部屋ラベル" +# Source-Hash: 257efab00820fb67 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room sizes, inside face to inside face" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.roomSizesInsideFaceToInsideFace" +msgstr "部屋の寸法(内面から内面まで)" + +# Source-Hash: 1ed28930a451001d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room sizes inside, overall size outside" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.roomSizesInsideOverallSizeOutside" +msgstr "内側は部屋の寸法、外側は外形寸法" + +# Source-Hash: 8dc78e215a97d9fc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scene" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.scene" +msgstr "シーン" + # Source-Hash: 82720864e5034398 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scene theme" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1795,28 +1978,38 @@ msgstr "シーンテーマ" # Source-Hash: 4c6bcb30b40047fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shadows" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.shadows" msgstr "影" -# Source-Hash: 59dc62417b44931d +# Source-Hash: e04ae95c14479764 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single wall axis" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shared by 2D and 3D" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.sharedBy2dAnd3d" +msgstr "2Dと3Dで共通" + +# Source-Hash: 827e0c6ac9936b69 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy -msgid "app.viewerToolbar.singleWallAxis" -msgstr "壁の中心線" +msgid "app.viewerToolbar.show" +msgstr "表示" # Source-Hash: d266d83ec490df4e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Soft" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1825,8 +2018,8 @@ msgstr "ソフト" # Source-Hash: ef3e765e692faf4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Solid" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1835,8 +2028,8 @@ msgstr "ソリッド" # Source-Hash: e9f59b513f2f45ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Solo" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1845,8 +2038,8 @@ msgstr "単独" # Source-Hash: 481b7608ce12139b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stack" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1855,8 +2048,8 @@ msgstr "積み重ね" # Source-Hash: 61ad94ca68b0458e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stair annotations" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1865,28 +2058,18 @@ msgstr "階段の注記" # Source-Hash: f82927a01d4c5e45 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Strong" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.strong" msgstr "強" -# Source-Hash: e1be031e67d95382 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structural core face" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.structuralCoreFace" -msgstr "構造躯体面" - # Source-Hash: efc50964d7b0ec47 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Structural grids & column centers" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1895,18 +2078,28 @@ msgstr "構造通り芯と柱芯" # Source-Hash: 5ce4f6b80cd30f86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Translucent" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.translucent" msgstr "半透明" +# Source-Hash: 07511ce5a194e1ed +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turn on Dimensions to show them" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.turnOnDimensionsToShowThem" +msgstr "表示するには寸法をオンにしてください" + # Source-Hash: b404dded35241274 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Units" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1915,38 +2108,18 @@ msgstr "単位" # Source-Hash: faf51e28b748e0d9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Walkthrough" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.walkthrough" msgstr "ウォークスルー" -# Source-Hash: 62281975e51da7e3 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall centerline" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.wallCenterline" -msgstr "壁芯" - -# Source-Hash: ff145d7003118ec6 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall dimensions" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.wallDimensions" -msgstr "壁の寸法" - # Source-Hash: 13969d1d6e310aa4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Walls: {label}" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1983,8 +2156,8 @@ msgstr "1階" # Source-Hash: fdd8b3366021a1cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Orbit Left" #: packages/editor/src/components/ui/action-menu/camera-actions.tsx #, fuzzy @@ -1993,8 +2166,8 @@ msgstr "左に回る" # Source-Hash: 4a56359f284a3b17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Orbit Right" #: packages/editor/src/components/ui/action-menu/camera-actions.tsx #, fuzzy @@ -2003,8 +2176,8 @@ msgstr "右に回る" # Source-Hash: f5c12d738240f889 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top View" #: packages/editor/src/components/ui/action-menu/camera-actions.tsx #, fuzzy @@ -2013,8 +2186,8 @@ msgstr "上面図" # Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/editor/src/components/ui/action-menu/control-modes.tsx #, fuzzy @@ -2023,8 +2196,8 @@ msgstr "削除" # Source-Hash: a4395168488bb476 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Select" #: packages/editor/src/components/ui/action-menu/control-modes.tsx #, fuzzy @@ -2033,8 +2206,8 @@ msgstr "選択" # Source-Hash: d9a257653600d5a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Resume following" #: packages/editor/src/components/ui/action-menu/follow-pascal-pill.tsx #, fuzzy @@ -2043,8 +2216,8 @@ msgstr "追従を再開" # Source-Hash: 4f073f8051cca3ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follow Pascal: Off" #: packages/editor/src/components/ui/action-menu/follow-pascal-toggle.tsx #, fuzzy @@ -2053,8 +2226,8 @@ msgstr "Pascal を追従: オフ" # Source-Hash: 328ea04bb8cd12f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follow Pascal: On" #: packages/editor/src/components/ui/action-menu/follow-pascal-toggle.tsx #, fuzzy @@ -2063,8 +2236,8 @@ msgstr "Pascal を追従: オン" # Source-Hash: 7f4dcb90defe1ac2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Appliance" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2073,8 +2246,8 @@ msgstr "家電" # Source-Hash: 0655333424a8b6fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bathroom" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2083,8 +2256,8 @@ msgstr "浴室" # Source-Hash: ed68e72f5353712b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Furniture" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2093,8 +2266,8 @@ msgstr "家具" # Source-Hash: 1176d2568d093bf1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2103,8 +2276,8 @@ msgstr "キッチン" # Source-Hash: a5a7af5e5fff1c81 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Outdoor" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2113,8 +2286,8 @@ msgstr "屋外" # Source-Hash: c69865ec5d9d1ac9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Angle" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2123,8 +2296,8 @@ msgstr "角度" # Source-Hash: 622f566fe1e3d8e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Angular dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2133,8 +2306,8 @@ msgstr "角度寸法" # Source-Hash: 7e3b0d541355305e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Arc length" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2143,8 +2316,8 @@ msgstr "弧長" # Source-Hash: 8332ab41e22958f1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Area" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2153,8 +2326,8 @@ msgstr "面積" # Source-Hash: 88c7750ed51d47a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Center mark" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2163,8 +2336,8 @@ msgstr "中心マーク" # Source-Hash: 634912dabb092872 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Chord dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2173,8 +2346,8 @@ msgstr "弦の寸法" # Source-Hash: 3cb090120253f68f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Continuous dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2183,8 +2356,8 @@ msgstr "連続寸法" # Source-Hash: fb91b1d43b8362d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Coordinate dimensions" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2193,8 +2366,8 @@ msgstr "座標寸法" # Source-Hash: 530cb7ea461e8298 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Diameter dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2203,8 +2376,8 @@ msgstr "直径寸法" # Source-Hash: fe7ddb094aa8ff4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Distance" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2213,8 +2386,8 @@ msgstr "距離" # Source-Hash: fee6203bb9046929 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Floor plan" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2223,8 +2396,8 @@ msgstr "平面図" # Source-Hash: a73539fc472e2e12 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Linear dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2233,8 +2406,8 @@ msgstr "直線寸法" # Source-Hash: 6bba239f244c3d28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Measurement options" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2243,8 +2416,8 @@ msgstr "計測オプション" # Source-Hash: 2cf5ca9b834ce8d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Measurement type" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2253,8 +2426,8 @@ msgstr "計測の種類" # Source-Hash: 0431574a0e6d69d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Measure: {selectedLabel}" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2263,8 +2436,8 @@ msgstr "計測: {selectedLabel}" # Source-Hash: ac87e14dabd5a256 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Perimeter" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2273,8 +2446,8 @@ msgstr "周長" # Source-Hash: 6c9acc0589bdd4d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Radius dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2283,8 +2456,8 @@ msgstr "半径寸法" # Source-Hash: 01b0015e4e176124 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Smart" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2293,8 +2466,8 @@ msgstr "スマート" # Source-Hash: 429bd43d726de417 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Volume" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2303,8 +2476,8 @@ msgstr "体積" # Source-Hash: 64f3eb5e1936906d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Point and ask" #: packages/editor/src/components/ui/action-menu/point-ask-button.tsx #, fuzzy @@ -2313,8 +2486,8 @@ msgstr "指して質問" # Source-Hash: d86d31e83f6f0888 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Point and ask (C)" #: packages/editor/src/components/ui/action-menu/point-ask-button.tsx #, fuzzy @@ -2323,18 +2496,28 @@ msgstr "指して質問 (C)" # Source-Hash: 65622d2ef53c1f3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Point and ask works in the 3D view" #: packages/editor/src/components/ui/action-menu/point-ask-button.tsx #, fuzzy msgid "editor.actionMenu.pointAskButton.pointAndAskWorksInThe" msgstr "指して質問は 3D ビューで使えます" +# Source-Hash: e14858b33b6e2623 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam" +#: packages/editor/src/components/ui/action-menu/structure-tools.tsx +#, fuzzy +msgid "editor.actionMenu.structureTools.beam" +msgstr "梁" + # Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Ceiling" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2343,8 +2526,8 @@ msgstr "天井" # Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2353,8 +2536,8 @@ msgstr "柱" # Source-Hash: 787e10f5db16904e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Door" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2363,8 +2546,8 @@ msgstr "ドア" # Source-Hash: e971d82044e2f48e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duct" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2373,8 +2556,8 @@ msgstr "ダクト" # Source-Hash: 6d0c3833d87535e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duct Fitting" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2383,8 +2566,8 @@ msgstr "ダクト継手" # Source-Hash: 457155657704f7cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "DWV Pipe" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2393,8 +2576,8 @@ msgstr "排水管" # Source-Hash: ab5cbab7be160a1c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Elevator" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2403,8 +2586,8 @@ msgstr "エレベーター" # Source-Hash: 02042fde61b5aa11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fence" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2413,8 +2596,8 @@ msgstr "フェンス" # Source-Hash: 7f4d93d5f2083844 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gable Roof" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2423,8 +2606,8 @@ msgstr "切妻屋根" # Source-Hash: 3bf1c1a8dbb93743 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "HVAC Unit" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2433,8 +2616,8 @@ msgstr "空調機" # Source-Hash: 362b03eba9d8234c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Lineset" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2443,8 +2626,8 @@ msgstr "冷媒配管" # Source-Hash: c34c9b36492c6e21 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Liquid Line" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2453,8 +2636,8 @@ msgstr "液管" # Source-Hash: c040baa6ed4c7aa5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Pipe Fitting" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2463,8 +2646,8 @@ msgstr "配管継手" # Source-Hash: 161e5386b939e1bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Register" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2473,8 +2656,8 @@ msgstr "吹出口" # Source-Hash: d7145f84f8e0e3fe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shelf" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2483,8 +2666,8 @@ msgstr "棚" # Source-Hash: 8775bc8dc9593964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slab" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2493,8 +2676,8 @@ msgstr "スラブ" # Source-Hash: 3e2f6b4274f592c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Spawn Point" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2503,8 +2686,8 @@ msgstr "スポーン地点" # Source-Hash: f05bc67c57e4d530 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stairs" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2513,8 +2696,8 @@ msgstr "階段" # Source-Hash: b778a315e82065a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Trap" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2523,8 +2706,8 @@ msgstr "トラップ" # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2533,8 +2716,8 @@ msgstr "壁" # Source-Hash: aa3c35ed33e181e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2543,18 +2726,28 @@ msgstr "窓" # Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy msgid "editor.actionMenu.structureTools.zone" msgstr "ゾーン" +# Source-Hash: a309ae5ee641f072 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dashed outlines of the neighbouring levels’ walls, to line walls up and check a roof against the walls under it." +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.dashedOutlinesOfTheNeighbouringLevels" +msgstr "隣接する階層の壁を破線で表示します。壁の位置をそろえたり、屋根を下の壁と照らし合わせたりするのに使います。" + # Source-Hash: cdf3f12939ba108c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete guide image" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2563,8 +2756,8 @@ msgstr "ガイド画像を削除" # Source-Hash: 6add06abbafa8289 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete scan" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2573,8 +2766,8 @@ msgstr "3Dスキャンを削除" # Source-Hash: 6f5e541cb5fb502f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {# guide image on this level} other {# guide images on this level}}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2583,8 +2776,8 @@ msgstr "{count, plural, other {この階層のガイド画像 # 件}}" # Source-Hash: 8a832a2f33757bf8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guide image {number}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2593,8 +2786,8 @@ msgstr "ガイド画像 {number}" # Source-Hash: 7f3aaccfe8d1af1f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guide images" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2603,8 +2796,8 @@ msgstr "ガイド画像" # Source-Hash: 9b1de02505434d74 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guide image settings" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2613,8 +2806,8 @@ msgstr "ガイド画像の設定" # Source-Hash: 892d5dd34372028b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guides" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2623,8 +2816,8 @@ msgstr "ガイド" # Source-Hash: ccfb05c78d47d6f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guides: Hidden" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2633,8 +2826,8 @@ msgstr "ガイド: 非表示" # Source-Hash: 6d7ca85c4f389991 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guides: Visible" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2643,8 +2836,8 @@ msgstr "ガイド: 表示" # Source-Hash: 5f6264ac469f57c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide guide images" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2653,8 +2846,8 @@ msgstr "ガイド画像を非表示" # Source-Hash: cae234c23229c80b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide reference floor" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2663,8 +2856,8 @@ msgstr "参照階を非表示" # Source-Hash: 469a8416de876e0e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide scans" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2673,18 +2866,38 @@ msgstr "3Dスキャンを非表示" # Source-Hash: 873620c284a5651f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count} below" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy msgid "editor.actionMenu.viewToggles.levelsBelow" msgstr "{count} 階下" +# Source-Hash: 6661c6766fdd1a7f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No level above" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.noLevelAbove" +msgstr "上の階層なし" + +# Source-Hash: e34d9ec372c823ef +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No level below" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.noLevelBelow" +msgstr "下の階層なし" + # Source-Hash: 22a59ae72d8c9504 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No lower floor available." #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2693,8 +2906,8 @@ msgstr "下の階はありません。" # Source-Hash: 1c0b8a5503c5daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opacity" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2703,8 +2916,8 @@ msgstr "不透明度" # Source-Hash: 8bbd9bc90ac70a4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference floor" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2713,8 +2926,8 @@ msgstr "参照階" # Source-Hash: 45493691a23c7690 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference floor: {selectedLevelName}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2723,8 +2936,8 @@ msgstr "参照階: {selectedLevelName}" # Source-Hash: 7178c7b5a4581367 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference floor settings" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2733,8 +2946,8 @@ msgstr "参照階の設定" # Source-Hash: a52848021f822f5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "References" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2743,8 +2956,8 @@ msgstr "参照" # Source-Hash: e59c9eec7dbd6ba1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Upload GLB meshes as scan references or blueprint images as guide references." #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2753,8 +2966,8 @@ msgstr "GLB メッシュを3Dスキャン参照として、図面画像をガイ # Source-Hash: 3e73d06c3e96efba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference settings" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2763,8 +2976,8 @@ msgstr "参照の設定" # Source-Hash: aa0df2c2f00672e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "References: Hidden" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2773,8 +2986,8 @@ msgstr "参照: 非表示" # Source-Hash: 9976708fc92bfa91 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "References: Visible" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2783,8 +2996,8 @@ msgstr "参照: 表示" # Source-Hash: 320a5f1ec012900b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Riser diagram" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2793,8 +3006,8 @@ msgstr "立て管系統図" # Source-Hash: 357b3d3eaf878a9f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {# scan on this level} other {# scans on this level}}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2803,8 +3016,8 @@ msgstr "{count, plural, other {この階層の3Dスキャン # 件}}" # Source-Hash: f09f12547484c888 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scan {number}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2813,8 +3026,8 @@ msgstr "3Dスキャン {number}" # Source-Hash: 3260bfa69cca50e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scans" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2823,8 +3036,8 @@ msgstr "3Dスキャン" # Source-Hash: c9c52015095997e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scan settings" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2833,8 +3046,8 @@ msgstr "3Dスキャンの設定" # Source-Hash: 60abc9f1a8aec65c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scans: Hidden" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2843,8 +3056,8 @@ msgstr "3Dスキャン: 非表示" # Source-Hash: 2d2ff119a7dd7911 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scans: Visible" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2853,8 +3066,8 @@ msgstr "3Dスキャン: 表示" # Source-Hash: 8211234b205fd9a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Show guide images" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2863,8 +3076,8 @@ msgstr "ガイド画像を表示" # Source-Hash: 7786cae6acb04cfa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Show reference floor" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2873,28 +3086,90 @@ msgstr "参照階を表示" # Source-Hash: 6066f0b6cff8a910 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Show scans" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy msgid "editor.actionMenu.viewToggles.showScans" msgstr "3Dスキャンを表示" +# Source-Hash: c100768fc929ccf4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show walls below and above" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.showWallsBelowAndAbove" +msgstr "上下の階層の壁を表示" + # Source-Hash: def6dff836767bda # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Upload scan or guide image" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy msgid "editor.actionMenu.viewToggles.uploadScanOrGuideImage" msgstr "3Dスキャンまたはガイド画像をアップロード" -# Source-Hash: 6aee0962fc18c0f1 +# Source-Hash: e9ac75feeb58a5be # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls above" +#: apps/editor/components/viewer-toolbar.tsx +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsAbove" +msgstr "上の階層の壁" + +# Source-Hash: 790a0b5c6dbf0e9b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below" +#: apps/editor/components/viewer-toolbar.tsx +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsBelow" +msgstr "下の階層の壁" + +# Source-Hash: e74e28937511bce9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below and above" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsBelowAndAbove" +msgstr "上下の階層の壁" + +# Source-Hash: 7c7bd2a996dfd5ce +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below and above settings" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsBelowAndAboveSettings" +msgstr "上下の階層の壁の設定" + +# Source-Hash: 43bc80f62aeab442 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below and above: shown" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsBelowAndAboveShown" +msgstr "上下の階層の壁: 表示" + +# Source-Hash: 6aee0962fc18c0f1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Back to home" #: packages/editor/src/components/editor/index.tsx #, fuzzy @@ -2985,12 +3260,45 @@ msgstr "長方形の部屋" msgid "editor.buildPanel.rooms.title" msgstr "部屋" -# Source-Hash: 8a21a03c4acf396b -# Review: human -# English: "{lead} Close a loop and it becomes a room; leave it open for partitions." +# Source-Hash: 9755d557ce490458 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divides a room or closes off a porch without building a wall; rooms close on it. Change any wall later from its controls." +#: packages/editor/src/components/ui/build-panel/build-panel.tsx +#, fuzzy +msgid "editor.buildPanel.rooms.wallKinds.invisibleHelp" +msgstr "壁を建てずに部屋を区切ったりポーチを閉じたりします。部屋はこの線で閉じます。どの壁も後からコントロールで変更できます。" + +# Source-Hash: abe7e7de0d337058 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall kind" +#: packages/editor/src/components/ui/build-panel/build-panel.tsx +#, fuzzy +msgid "editor.buildPanel.rooms.wallKinds.label" +msgstr "壁の種類" + +# Source-Hash: b4d012ac50ef1e82 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A guard for stairs, balconies and mezzanines; rooms close on it. Change any wall later from its controls." +#: packages/editor/src/components/ui/build-panel/build-panel.tsx +#, fuzzy +msgid "editor.buildPanel.rooms.wallKinds.railingHelp" +msgstr "階段、バルコニー、中二階のための手すりです。部屋はこの線で閉じます。どの壁も後からコントロールで変更できます。" + +# Source-Hash: 5e6d896656f4e056 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "One wall per two clicks. Its sides become exterior or interior from the rooms it bounds. Change any wall later from its controls." #: packages/editor/src/components/ui/build-panel/build-panel.tsx -msgid "editor.buildPanel.rooms.walls.caption" -msgstr "{lead}輪郭を閉じると部屋になり、開いたままにすると間仕切りになります。" +#, fuzzy +msgid "editor.buildPanel.rooms.wallKinds.standardHelp" +msgstr "2回のクリックで壁を1枚描きます。面は接する部屋に応じて外部または内部になります。どの壁も後からコントロールで変更できます。" # Source-Hash: aac9a732d2159ccc # Review: human @@ -2999,13 +3307,6 @@ msgstr "{lead}輪郭を閉じると部屋になり、開いたままにすると msgid "editor.buildPanel.rooms.walls.label" msgstr "壁" -# Source-Hash: 9843edd68426fa2d -# Review: human -# English: "Draw one wall at a time." -#: packages/editor/src/components/ui/build-panel/build-panel.tsx -msgid "editor.buildPanel.rooms.walls.lead" -msgstr "壁を1面ずつ描画します。" - # Source-Hash: aac9a732d2159ccc # Review: human # English: "Walls" @@ -3013,26735 +3314,29167 @@ msgstr "壁を1面ずつ描画します。" msgid "editor.buildPanel.rooms.walls.title" msgstr "壁" -# Source-Hash: 1f3650da23603008 +# Source-Hash: 1dba2aacc55e0bb7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Camera controls hint" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete from this project" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.cameraControlsHint" -msgstr "カメラ操作のヒント" +msgid "editor.buildPanel.wallTypeControls.deleteFromThisProject" +msgstr "このプロジェクトから削除" -# Source-Hash: 101b6a54c377049a +# Source-Hash: 58a1b780e877ddc3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pan" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate as a new type…" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.cameraHint.pan" -msgstr "パン" +msgid "editor.buildPanel.wallTypeControls.duplicateAsANewType" +msgstr "新しい種類として複製…" -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: 43e7aad9a5f75b6a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit layers…" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.cameraHint.rotate" -msgstr "回転" +msgid "editor.buildPanel.wallTypeControls.editLayers" +msgstr "層を編集…" -# Source-Hash: 663cecc316eb91b8 +# Source-Hash: 8f1ea5a4c16ba810 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zoom" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit or duplicate this wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.cameraHint.zoom" -msgstr "ズーム" +msgid "editor.buildPanel.wallTypeControls.editOrDuplicateThisWallType" +msgstr "この壁の種類を編集または複製" -# Source-Hash: 34b7ca7ff46c44a9 +# Source-Hash: 273fcb71b4f9272f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{label}: {finish}" -#: packages/editor/src/components/ui/controls/finish-swatch.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New wall type…" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.controls.finishSwatch.ariaLabel" -msgstr "{label}:{finish}" +msgid "editor.buildPanel.wallTypeControls.newWallType" +msgstr "新しい壁の種類…" -# Source-Hash: 4ca0e0e73229540c +# Source-Hash: 079e4005e0093122 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default" -#: packages/editor/src/components/ui/controls/finish-swatch.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Presets stay as cited. Duplicate one to change its layers." +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.controls.finishSwatch.default" -msgstr "標準" +msgid "editor.buildPanel.wallTypeControls.presetsStayAsCitedDuplicateOne" +msgstr "プリセットは出典どおりのままです。層を変えるには複製してください。" -# Source-Hash: a2bd204e93e90598 +# Source-Hash: b071c943d8da1500 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dismiss" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.dismiss" -msgstr "閉じる" +msgid "editor.buildPanel.wallTypeEditorDialog.add" +msgstr "追加" -# Source-Hash: 9222f970dce6cc60 +# Source-Hash: fcc69acc0fd92288 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dismiss camera controls hint" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Air space" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.dismissCameraControlsHint" -msgstr "カメラ操作のヒントを閉じる" +msgid "editor.buildPanel.wallTypeEditorDialog.airSpace" +msgstr "空気層" -# Source-Hash: aeac665749d3101d +# Source-Hash: 46fb2832f979d656 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Expand sidebar" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A wall type holds at most {limit, plural, one {# layer} other {# layers}}." +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.expandSidebar" -msgstr "サイドバーを展開" +msgid "editor.buildPanel.wallTypeEditorDialog.aWallTypeHoldsAtMost" +msgstr "壁の種類に含められる層は最大 {limit, plural, other {# 層}}です。" -# Source-Hash: dd86efcab72fc5c7 +# Source-Hash: 75d323d0159b0df8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Axis" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brick veneer" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.axis" -msgstr "軸" +msgid "editor.buildPanel.wallTypeEditorDialog.brickVeneer" +msgstr "レンガ張り" -# Source-Hash: 5232a826549f915e +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "⌥ axis" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.axis2" -msgstr "⌥ 軸" +msgid "editor.buildPanel.wallTypeEditorDialog.cancel" +msgstr "キャンセル" -# Source-Hash: 7001600001844c92 +# Source-Hash: 4da800c75b9a6b23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "⚠ no equipment" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drywall" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.noEquipment" -msgstr "⚠ 機器なし" +msgid "editor.buildPanel.wallTypeEditorDialog.drywall" +msgstr "石膏ボード" -# Source-Hash: eae0194029f96edb +# Source-Hash: 1f2e15ce909adf0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {# register} other {# registers}}" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.registerCount" -msgstr "{count, plural, other {吹出口 # 個}}" +msgid "editor.buildPanel.wallTypeEditorDialog.duplicateWallType" +msgstr "壁の種類を複製" -# Source-Hash: 8fb180251a321cef +# Source-Hash: 832628bc67f36778 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.rTRotate" -msgstr "R/T で回転" +msgid "editor.buildPanel.wallTypeEditorDialog.editWallType" +msgstr "壁の種類を編集" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 6fb660d4eabe8d6a +# Source-Hash: 7d3d13d418b64f1b # Review: required -# English: "{count, plural, one {{number} run} other {{number} runs}}" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Every wall type has one framing core" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.runCount" -msgstr "{count, plural, other {{number} 系統}}" +msgid "editor.buildPanel.wallTypeEditorDialog.everyWallTypeHasOneFraming" +msgstr "壁の種類には必ず下地コアが 1 つあります" -# Source-Hash: 88e6c2e1c344b2fc +# Source-Hash: fd89c31f16639f50 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fiber cement" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.system" -msgstr "システム" +msgid "editor.buildPanel.wallTypeEditorDialog.fiberCement" +msgstr "繊維セメント" -# Source-Hash: f0e76aea883d4e48 +# Source-Hash: b3907da0ad234f10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add a floor under the roof" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.addAFloorUnderTheRoof" -msgstr "屋根の下に階層を追加" +msgid "editor.buildPanel.wallTypeEditorDialog.finish" +msgstr "仕上げ" -# Source-Hash: a982ff9b075af829 +# Source-Hash: 23306d290f066b1e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add level above" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framing core" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.addLevelAbove" -msgstr "上に階層を追加" +msgid "editor.buildPanel.wallTypeEditorDialog.framingCore" +msgstr "下地コア" -# Source-Hash: 0db7d221df08fa6b +# Source-Hash: b50fa488c2bfb502 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add level below" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{fullReason} Remove one to add another." +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.addLevelBelow" -msgstr "下に階層を追加" +msgid "editor.buildPanel.wallTypeEditorDialog.fullreasonRemoveOneToAddAnother" +msgstr "{fullReason}追加するには 1 つ削除してください。" -# Source-Hash: c0774c185060fc13 +# Source-Hash: e3e25fbbf14e97fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gypsum sheathing" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.cancel" -msgstr "キャンセル" +msgid "editor.buildPanel.wallTypeEditorDialog.gypsumSheathing" +msgstr "石膏ボード下張り" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 8a7ff5011275abbd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inside" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.delete" -msgstr "削除" +msgid "editor.buildPanel.wallTypeEditorDialog.inside" +msgstr "内側" -# Source-Hash: 8e29375893d63408 +# Source-Hash: 7d6ed24c02ab0c5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete level" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.deleteLevel" -msgstr "階層を削除" +msgid "editor.buildPanel.wallTypeEditorDialog.insulation" +msgstr "断熱材" -# Source-Hash: c3bc69ec52022250 +# Source-Hash: 9a4325140858cfec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Are you sure you want to delete {levelName}? All walls, floors, and objects on this level will be permanently removed." -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lap siding" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.deleteLevelConfirm" -msgstr "{levelName}を削除してもよろしいですか?この階層のすべての壁、床、オブジェクトが完全に削除されます。" +msgid "editor.buildPanel.wallTypeEditorDialog.lapSiding" +msgstr "下見板張り" -# Source-Hash: 5b2826ddac95cd0c +# Source-Hash: d7ee1cefa20d0e32 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag to reorder" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layer" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.dragToReorder" -msgstr "ドラッグして並べ替え" +msgid "editor.buildPanel.wallTypeEditorDialog.layer" +msgstr "層" -# Source-Hash: 933177338f5a03ed +# Source-Hash: bd00fff893ace820 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate level" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layer role" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.duplicateLevel" -msgstr "階層を複製" +msgid "editor.buildPanel.wallTypeEditorDialog.layerRole" +msgstr "層の役割" -# Source-Hash: 9614c6825a7c67bf +# Source-Hash: e5536deeaabfacec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate with options..." -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lining" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.duplicateWithOptions" -msgstr "オプションを指定して複製..." +msgid "editor.buildPanel.wallTypeEditorDialog.lining" +msgstr "内張り" -# Source-Hash: 5ec91bb339806413 +# Source-Hash: 964b86ae1474ff98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Exit unit focus" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Material" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.exitUnitFocus" -msgstr "ユニットのフォーカスを終了" +msgid "editor.buildPanel.wallTypeEditorDialog.material" +msgstr "材料" -# Source-Hash: a88c3f8bed58b4fa +# Source-Hash: 75d79fb9a2e8fcf6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Focused unit has zones here" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mineral wool board" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.focusedUnitHasZonesHere" -msgstr "フォーカス中のユニットにはここにゾーンがあります" +msgid "editor.buildPanel.wallTypeEditorDialog.mineralWoolBoard" +msgstr "ロックウールボード" -# Source-Hash: 655055a310fb5d13 +# Source-Hash: 78acc1bad880ce0f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The ground floor stands {distance} over grade. Seat the ground floor 8 in over grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move in" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.groundFloorOverGrade" -msgstr "1階は地盤面より {distance} 高い位置にあります。1階を地盤面から 8 in 上に据える" +msgid "editor.buildPanel.wallTypeEditorDialog.moveIn" +msgstr "内側へ移動" -# Source-Hash: 77548faae4869eec +# Source-Hash: 2de6ee30b4e608bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The ground floor stands {distance} under grade. Seat the ground floor 8 in over grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move out" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.groundFloorUnderGrade" -msgstr "1階は地盤面より {distance} 低い位置にあります。1階を地盤面から 8 in 上に据える" +msgid "editor.buildPanel.wallTypeEditorDialog.moveOut" +msgstr "外側へ移動" -# Source-Hash: e3763ae2dc62c03f +# Source-Hash: 6cc5df35f0338e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground line: the levels under it are below grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Name" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.groundLineTheLevelsUnderIt" -msgstr "地盤線:その下の階層は地盤面より下です" +msgid "editor.buildPanel.wallTypeEditorDialog.name" +msgstr "名前" -# Source-Hash: e12035eb47cc61cc +# Source-Hash: 4b3edeb00b32607e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground · {offset}" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.groundOffset" -msgstr "地盤 · {offset}" +msgid "editor.buildPanel.wallTypeEditorDialog.newWallType" +msgstr "新しい壁の種類" -# Source-Hash: 5661c11383217661 +# Source-Hash: 4f7f8af75bf8e914 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Insert level here" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "OSB" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.insertLevelHere" -msgstr "ここに階層を挿入" +msgid "editor.buildPanel.wallTypeEditorDialog.osb" +msgstr "OSB" -# Source-Hash: 0215b36d5a08597a +# Source-Hash: dc4fe6cb415ed882 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level height" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outside" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.levelHeight" -msgstr "階層の高さ" +msgid "editor.buildPanel.wallTypeEditorDialog.outside" +msgstr "外側" -# Source-Hash: 91af436e81bb0875 +# Source-Hash: a6fd2cbf5c2154e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paste copied selection" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plaster" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.pasteCopiedSelection" -msgstr "コピーした選択を貼り付け" +msgid "editor.buildPanel.wallTypeEditorDialog.plaster" +msgstr "漆喰" -# Source-Hash: 68bc52f53240cbec +# Source-Hash: e669c2c08bd80e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reorder {levelName}" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plywood" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.reorderLevelname" -msgstr "{levelName}を並べ替え" +msgid "editor.buildPanel.wallTypeEditorDialog.plywood" +msgstr "合板" -# Source-Hash: 625d53de72ebc2ef +# Source-Hash: ca36e9fd7fba1fce # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Seat the building so this floor stands at grade; the floors under it are below grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove layer" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.seatTheBuildingSoThisFloor" -msgstr "この階が地盤面に来るよう建物を据えます。その下の階は地盤面より下になります" +msgid "editor.buildPanel.wallTypeEditorDialog.removeLayer" +msgstr "層を削除" -# Source-Hash: 7ac9c00895c30d76 +# Source-Hash: 7d8f351c35f89b94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set as ground floor" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rigid foam" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.setAsGroundFloor" -msgstr "1階に設定" +msgid "editor.buildPanel.wallTypeEditorDialog.rigidFoam" +msgstr "硬質フォーム" -# Source-Hash: d6b381247066a7aa +# Source-Hash: e8bc984965d5753d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The ground level cannot be deleted" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Save wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.theGroundLevelCannotBeDeleted" -msgstr "1階の階層は削除できません" +msgid "editor.buildPanel.wallTypeEditorDialog.saveWallType" +msgstr "壁の種類を保存" -# Source-Hash: b1122051dce0d7a1 +# Source-Hash: 36a588e44085108c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "This floor stands at grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sheathing" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.thisFloorStandsAtGrade" -msgstr "この階は地盤面にあります" +msgid "editor.buildPanel.wallTypeEditorDialog.sheathing" +msgstr "下張り" -# Source-Hash: 062cc0f1afef0c52 +# Source-Hash: 9450fcb4a14674af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unit" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stone veneer" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.unit" -msgstr "住戸" +msgid "editor.buildPanel.wallTypeEditorDialog.stoneVeneer" +msgstr "石張り" -# Source-Hash: 5871b7c20478f4a1 +# Source-Hash: 687cf7bc64b0224e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor area" -#: packages/editor/src/i18n/floor-footprint-name.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stucco" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floorFootprint.area" -msgstr "床面積" +msgid "editor.buildPanel.wallTypeEditorDialog.stucco" +msgstr "スタッコ" -# Source-Hash: 8b2e1435272aa86a +# Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{room} floor" -#: packages/editor/src/i18n/floor-footprint-name.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floorFootprint.room" -msgstr "{room}の床" +msgid "editor.buildPanel.wallTypeEditorDialog.thickness" +msgstr "厚さ" -# Source-Hash: 4731183fec06cbdf +# Source-Hash: 72e31eecaeb87447 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shared floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx -#: packages/editor/src/i18n/floor-footprint-name.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Total {thickness}" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floorFootprint.shared" -msgstr "共有の床" +msgid "editor.buildPanel.wallTypeEditorDialog.totalThickness" +msgstr "総厚 {thickness}" -# Source-Hash: c0774c185060fc13 +# Source-Hash: eab795728c4a3f5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/helpers/building-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.helpers.buildingHelper.cancel" -msgstr "キャンセル" +msgid "editor.buildPanel.wallTypeEditorDialog.wallType" +msgstr "壁の種類" -# Source-Hash: 4c6ca3441c74da9e +# Source-Hash: 3744d42a0e4ee161 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place building" -#: packages/editor/src/components/ui/helpers/building-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plain wall" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.helpers.buildingHelper.placeBuilding" -msgstr "建物を配置" +msgid "editor.buildPanel.wallTypes.plainWall" +msgstr "単層の壁" -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: 1f3650da23603008 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" -#: packages/editor/src/components/ui/helpers/building-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera controls hint" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.buildingHelper.rotate" -msgstr "回転" +msgid "editor.cameraControlsHint" +msgstr "カメラ操作のヒント" -# Source-Hash: 832470d3aeee82fd +# Source-Hash: 101b6a54c377049a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel placement" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pan" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.cancelPlacement" -msgstr "配置をキャンセル" +msgid "editor.cameraHint.pan" +msgstr "パン" -# Source-Hash: e374fcaee33c3e2c +# Source-Hash: 306d409f8a1cf480 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuation — click or press C to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.continuationClickOrPressCTo" -msgstr "連続配置 — クリックまたは C で切り替え" +msgid "editor.cameraHint.rotate" +msgstr "回転" -# Source-Hash: b108c7dc2ec2b9de +# Source-Hash: 663cecc316eb91b8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuation: {label}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx -#, fuzzy -msgid "editor.helpers.contextualHelperPanel.continuationLabel" -msgstr "連続配置: {label}" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zoom" +#: packages/editor/src/components/editor/index.tsx +#, fuzzy +msgid "editor.cameraHint.zoom" +msgstr "ズーム" -# Source-Hash: 729d87891cb7dbb1 +# Source-Hash: 34b7ca7ff46c44a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag to draw fence" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label}: {finish}" +#: packages/editor/src/components/ui/controls/finish-swatch.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.dragToDrawFence" -msgstr "ドラッグしてフェンスを描く" +msgid "editor.controls.finishSwatch.ariaLabel" +msgstr "{label}:{finish}" -# Source-Hash: b52e874718af1916 +# Source-Hash: 4ca0e0e73229540c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Erase: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default" +#: packages/editor/src/components/ui/controls/finish-swatch.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.eraseScope" -msgstr "消去: {scope}" +msgid "editor.controls.finishSwatch.default" +msgstr "標準" -# Source-Hash: 61f7494abc319e66 +# Source-Hash: a2bd204e93e90598 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Erase scope — click or press Shift to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dismiss" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.eraseScopeClickOrPressShift" -msgstr "消去の範囲 — クリックまたは Shift で切り替え" +msgid "editor.dismiss" +msgstr "閉じる" -# Source-Hash: 59993c163d68cc53 +# Source-Hash: 9222f970dce6cc60 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Erase scope: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dismiss camera controls hint" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.eraseScopeLabel" -msgstr "消去の範囲: {scope}" +msgid "editor.dismissCameraControlsHint" +msgstr "カメラ操作のヒントを閉じる" -# Source-Hash: a4bdcbc6cab772bf +# Source-Hash: aeac665749d3101d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fence type — click or press T to switch between straight, curved and freehand" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Expand sidebar" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.fenceTypeClickOrPressT" -msgstr "フェンスの種類 — クリックまたは T で直線・曲線・フリーハンドを切り替え" +msgid "editor.expandSidebar" +msgstr "サイドバーを展開" -# Source-Hash: 2a9ed258727078ac +# Source-Hash: dd86efcab72fc5c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fewer shortcuts" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Axis" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.fewerShortcuts" -msgstr "ショートカットを減らす" +msgid "editor.floatingActionMenu.axis" +msgstr "軸" -# Source-Hash: 698fa6e78af4d4b7 +# Source-Hash: 5232a826549f915e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish curve (or double-click)" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "⌥ axis" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.finishCurveOrDoubleClick" -msgstr "曲線を完了(またはダブルクリック)" +msgid "editor.floatingActionMenu.axis2" +msgstr "⌥ 軸" -# Source-Hash: 09f6d79edf5cfd16 +# Source-Hash: 7001600001844c92 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid: {length}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "⚠ no equipment" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.gridLength" -msgstr "グリッド: {length}" +msgid "editor.floatingActionMenu.noEquipment" +msgstr "⚠ 機器なし" -# Source-Hash: c493b562040c4328 +# Source-Hash: eae0194029f96edb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid step — click or tap Ctrl to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# register} other {# registers}}" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.gridStepClickOrTapCtrl" -msgstr "グリッド間隔 — クリックまたは Ctrl で切り替え" +msgid "editor.floatingActionMenu.registerCount" +msgstr "{count, plural, other {吹出口 # 個}}" -# Source-Hash: d36a8c93d81b3a36 +# Source-Hash: 8fb180251a321cef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid step: {length}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.gridStepLength" -msgstr "グリッド間隔: {length}" +msgid "editor.floatingActionMenu.rTRotate" +msgstr "R/T で回転" -# Source-Hash: abea993ede7daa7e +# Source-Hash: 6fb660d4eabe8d6a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a painted surface to erase" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {{number} run} other {{number} runs}}" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.hoverAPaintedSurfaceToErase" -msgstr "塗装面にホバーして消去" +msgid "editor.floatingActionMenu.runCount" +msgstr "{count, plural, other {{number} 系統}}" -# Source-Hash: fc1ed0ddc0cfcef5 +# Source-Hash: 88e6c2e1c344b2fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a surface to paint" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.hoverASurfaceToPaint" -msgstr "面にホバーして塗装" +msgid "editor.floatingActionMenu.system" +msgstr "システム" -# Source-Hash: 63dec5de4a337015 +# Source-Hash: f0e76aea883d4e48 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a surface to pick its material" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add a floor under the roof" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.hoverASurfaceToPickIts" -msgstr "面にホバーして素材を取得" +msgid "editor.floatingLevelSelector.addAFloorUnderTheRoof" +msgstr "屋根の下に階層を追加" -# Source-Hash: 7ad6dc1b1f03f970 +# Source-Hash: a982ff9b075af829 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "More shortcuts" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add level above" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.moreShortcuts" -msgstr "その他のショートカット" +msgid "editor.floatingLevelSelector.addLevelAbove" +msgstr "上に階層を追加" -# Source-Hash: 476b8f5f9ee542e6 +# Source-Hash: 0db7d221df08fa6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add level below" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.paintScope" -msgstr "塗装: {scope}" +msgid "editor.floatingLevelSelector.addLevelBelow" +msgstr "下に階層を追加" -# Source-Hash: 9c09ce4c34122277 +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint scope — click or press Shift to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.paintScopeClickOrPressShift" -msgstr "塗装の範囲 — クリックまたは Shift で切り替え" +msgid "editor.floatingLevelSelector.cancel" +msgstr "キャンセル" -# Source-Hash: 7890aa81687f6654 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint scope: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.paintScopeLabel" -msgstr "塗装の範囲: {scope}" +msgid "editor.floatingLevelSelector.delete" +msgstr "削除" -# Source-Hash: a75b3abc0784b12b +# Source-Hash: 8e29375893d63408 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete level" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.pickScope" -msgstr "取得: {scope}" +msgid "editor.floatingLevelSelector.deleteLevel" +msgstr "階層を削除" -# Source-Hash: 69c1044e6ea87ccf +# Source-Hash: c3bc69ec52022250 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place gate on a fence" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Are you sure you want to delete {levelName}? All walls, floors, and objects on this level will be permanently removed." +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.placeGateOnAFence" -msgstr "フェンスに門を配置" +msgid "editor.floatingLevelSelector.deleteLevelConfirm" +msgstr "{levelName}を削除してもよろしいですか?この階層のすべての壁、床、オブジェクトが完全に削除されます。" -# Source-Hash: 3754255b8affc7a0 +# Source-Hash: 5b2826ddac95cd0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place passage on a fence" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag to reorder" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.placePassageOnAFence" -msgstr "フェンスに通路を配置" +msgid "editor.floatingLevelSelector.dragToReorder" +msgstr "ドラッグして並べ替え" -# Source-Hash: a8328c8964e947fa +# Source-Hash: 933177338f5a03ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select a material to paint" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate level" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.selectAMaterialToPaint" -msgstr "塗る素材を選択" +msgid "editor.floatingLevelSelector.duplicateLevel" +msgstr "階層を複製" -# Source-Hash: 6f95d7116aea5738 +# Source-Hash: 9614c6825a7c67bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping: Angles" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate with options..." +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingAngles" -msgstr "スナップ: 角度" +msgid "editor.floatingLevelSelector.duplicateWithOptions" +msgstr "オプションを指定して複製..." -# Source-Hash: 2d6d8d85d2ebed47 +# Source-Hash: 5ec91bb339806413 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping: Grid" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Exit unit focus" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingGrid" -msgstr "スナップ: グリッド" +msgid "editor.floatingLevelSelector.exitUnitFocus" +msgstr "ユニットのフォーカスを終了" -# Source-Hash: 9096c5f9d8ce0f7c +# Source-Hash: a88c3f8bed58b4fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping: Lines" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Focused unit has zones here" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingLines" -msgstr "スナップ: 線" +msgid "editor.floatingLevelSelector.focusedUnitHasZonesHere" +msgstr "フォーカス中のユニットにはここにゾーンがあります" -# Source-Hash: b663afbf0835cf32 +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The ground floor stands {distance} over grade. Seat the ground floor 8 in over grade" +# Source-Hash: 6a00e82fda812178 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping mode — click or press Shift to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingModeClickOrPressShift" -msgstr "スナップモード — クリックまたは Shift で切り替え" +msgid "editor.floatingLevelSelector.groundFloorOverGrade" +msgstr "1階は地盤面より {distance} 高い位置にあります。{action}" -# Source-Hash: d00e984fc88f71aa +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The ground floor stands {distance} under grade. Seat the ground floor 8 in over grade" +# Source-Hash: 61f400e77494df9b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping: Off" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingOff" -msgstr "スナップ: オフ" +msgid "editor.floatingLevelSelector.groundFloorUnderGrade" +msgstr "1階は地盤面より {distance} 低い位置にあります。{action}" -# Source-Hash: 6be9d0d312200761 +# Source-Hash: e3763ae2dc62c03f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight continuation is unavailable for curved or freehand fences" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground line: the levels under it are below grade" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.straightContinuationIsUnavailableForCurved" -msgstr "曲線・フリーハンドのフェンスでは直線の連続配置は使えません" +msgid "editor.floatingLevelSelector.groundLineTheLevelsUnderIt" +msgstr "地盤線:その下の階層は地盤面より下です" -# Source-Hash: 0d56b1f0a0493302 +# Source-Hash: e12035eb47cc61cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight: Continuous" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground · {offset}" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.straightContinuous" -msgstr "直線: 連続" +msgid "editor.floatingLevelSelector.groundOffset" +msgstr "地盤 · {offset}" -# Source-Hash: c034e85d3e7fd27e +# Source-Hash: 5661c11383217661 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight fence continuation — click or press C to toggle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insert level here" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.straightFenceContinuationClickOrPress" -msgstr "直線フェンスの連続配置 — クリックまたは C で切り替え" +msgid "editor.floatingLevelSelector.insertLevelHere" +msgstr "ここに階層を挿入" -# Source-Hash: e3f679cdb4a3d603 +# Source-Hash: 0215b36d5a08597a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight: Single" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level height" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.straightSingle" -msgstr "直線: 単体" +msgid "editor.floatingLevelSelector.levelHeight" +msgstr "階層の高さ" -# Source-Hash: 9a56d90d461b4bca +# Source-Hash: 91af436e81bb0875 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add point" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paste copied selection" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.addPoint" -msgstr "点を追加" +msgid "editor.floatingLevelSelector.pasteCopiedSelection" +msgstr "コピーした選択を貼り付け" -# Source-Hash: c3dc3918c823a5e6 +# Source-Hash: 68bc52f53240cbec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add point · click the first to close" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reorder {levelName}" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.addPointClickTheFirstTo" -msgstr "点を追加 · 最初の点をクリックして閉じる" +msgid "editor.floatingLevelSelector.reorderLevelname" +msgstr "{levelName}を並べ替え" -# Source-Hash: d8cf72d482d56cd7 +# Source-Hash: 625d53de72ebc2ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Brush size" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Seat the building so this floor stands at grade; the floors under it are below grade" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.brushSize" -msgstr "ブラシサイズ" +msgid "editor.floatingLevelSelector.seatTheBuildingSoThisFloor" +msgstr "この階が地盤面に来るよう建物を据えます。その下の階は地盤面より下になります" -# Source-Hash: c0774c185060fc13 +# Source-Hash: 7ac9c00895c30d76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set as ground floor" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.cancel" -msgstr "キャンセル" +msgid "editor.floatingLevelSelector.setAsGroundFloor" +msgstr "1階に設定" -# Source-Hash: 104fdab7934ec66c +# Source-Hash: d6b381247066a7aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel picking" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The ground level cannot be deleted" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.cancelPicking" -msgstr "選択をキャンセル" +msgid "editor.floatingLevelSelector.theGroundLevelCannotBeDeleted" +msgstr "1階の階層は削除できません" -# Source-Hash: c318cf0ce70b8977 +# Source-Hash: b1122051dce0d7a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel stroke" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This floor stands at grade" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.cancelStroke" -msgstr "ストロークをキャンセル" +msgid "editor.floatingLevelSelector.thisFloorStandsAtGrade" +msgstr "この階は地盤面にあります" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: 062cc0f1afef0c52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unit" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.done" -msgstr "完了" +msgid "editor.floatingLevelSelector.unit" +msgstr "住戸" -# Source-Hash: e297db9ca0ce6d31 +# Source-Hash: 5871b7c20478f4a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw the mezzanine" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor area" +#: packages/editor/src/i18n/floor-footprint-name.ts #, fuzzy -msgid "editor.helpers.helperManager.drawTheMezzanine" -msgstr "中二階を描く" +msgid "editor.floorFootprint.area" +msgstr "床面積" -# Source-Hash: c8be604718a7a9fd +# Source-Hash: 8b2e1435272aa86a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw the opening" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{room} floor" +#: packages/editor/src/i18n/floor-footprint-name.ts #, fuzzy -msgid "editor.helpers.helperManager.drawTheOpening" -msgstr "開口を描く" +msgid "editor.floorFootprint.room" +msgstr "{room}の床" -# Source-Hash: 231386ae6d534163 +# Source-Hash: 4731183fec06cbdf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw the terrace" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shared floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +#: packages/editor/src/i18n/floor-footprint-name.ts #, fuzzy -msgid "editor.helpers.helperManager.drawTheTerrace" -msgstr "テラスを描く" +msgid "editor.floorFootprint.shared" +msgstr "共有の床" -# Source-Hash: e092e803eb60af69 +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Exit smart measure" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/helpers/building-helper.tsx #, fuzzy -msgid "editor.helpers.helperManager.exitSmartMeasure" -msgstr "スマート計測を終了" +msgid "editor.helpers.buildingHelper.cancel" +msgstr "キャンセル" -# Source-Hash: b3907da0ad234f10 +# Source-Hash: 4c6ca3441c74da9e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place building" +#: packages/editor/src/components/ui/helpers/building-helper.tsx #, fuzzy -msgid "editor.helpers.helperManager.finish" -msgstr "完了" +msgid "editor.helpers.buildingHelper.placeBuilding" +msgstr "建物を配置" -# Source-Hash: f74bd937ae2e3a40 +# Source-Hash: 306d409f8a1cf480 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish at the edge" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/editor/src/components/ui/helpers/building-helper.tsx #, fuzzy -msgid "editor.helpers.helperManager.finishAtTheEdge" -msgstr "端で完了" +msgid "editor.helpers.buildingHelper.rotate" +msgstr "回転" -# Source-Hash: 21029cf1c45697cc +# Source-Hash: 832470d3aeee82fd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Free move" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel placement" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.freeMove" -msgstr "自由移動" +msgid "editor.helpers.contextualHelperPanel.cancelPlacement" +msgstr "配置をキャンセル" -# Source-Hash: 3247d8689bed6ff6 +# Source-Hash: e374fcaee33c3e2c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Free move · slide doors and windows" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuation — click or press C to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.freeMoveSlideDoorsAndWindows" -msgstr "自由移動 · ドアと窓をスライド" +msgid "editor.helpers.contextualHelperPanel.continuationClickOrPressCTo" +msgstr "連続配置 — クリックまたは C で切り替え" -# Source-Hash: b5ad765b43e75a5c +# Source-Hash: b108c7dc2ec2b9de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hold to pick a material" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuation: {label}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.holdToPickAMaterial" -msgstr "押したままで素材を取得" +msgid "editor.helpers.contextualHelperPanel.continuationLabel" +msgstr "連続配置: {label}" -# Source-Hash: 46b53c5449c98964 +# Source-Hash: 729d87891cb7dbb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inspect surface dimensions" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag to draw fence" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.inspectSurfaceDimensions" -msgstr "面の寸法を確認" +msgid "editor.helpers.contextualHelperPanel.dragToDrawFence" +msgstr "ドラッグしてフェンスを描く" -# Source-Hash: 63f1f7006ae14177 +# Source-Hash: b52e874718af1916 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint with this material" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Erase: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.paintWithThisMaterial" -msgstr "この素材で塗る" +msgid "editor.helpers.contextualHelperPanel.eraseScope" +msgstr "消去: {scope}" -# Source-Hash: 188f55cc5afbe34f +# Source-Hash: 61f7494abc319e66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick target height" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Erase scope — click or press Shift to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.pickTargetHeight" -msgstr "目標の高さを選ぶ" +msgid "editor.helpers.contextualHelperPanel.eraseScopeClickOrPressShift" +msgstr "消去の範囲 — クリックまたは Shift で切り替え" -# Source-Hash: 2880fc9752eababa +# Source-Hash: 59993c163d68cc53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pin measurement lens" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Erase scope: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.pinMeasurementLens" -msgstr "計測レンズを固定" +msgid "editor.helpers.contextualHelperPanel.eraseScopeLabel" +msgstr "消去の範囲: {scope}" -# Source-Hash: 722741535b346e09 +# Source-Hash: a4bdcbc6cab772bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fence type — click or press T to switch between straight, curved and freehand" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.place" -msgstr "配置" +msgid "editor.helpers.contextualHelperPanel.fenceTypeClickOrPressT" +msgstr "フェンスの種類 — クリックまたは T で直線・曲線・フリーハンドを切り替え" -# Source-Hash: 82010a7fd6350c93 +# Source-Hash: 2a9ed258727078ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place inside the room" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fewer shortcuts" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.placeInsideTheRoom" -msgstr "部屋の中に配置" +msgid "editor.helpers.contextualHelperPanel.fewerShortcuts" +msgstr "ショートカットを減らす" -# Source-Hash: 8b97f4503edb27b9 +# Source-Hash: 698fa6e78af4d4b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Press anywhere, drag to the opposite corner" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish curve (or double-click)" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.pressAnywhereDragToTheOpposite" -msgstr "どこかを押して、対角までドラッグ" +msgid "editor.helpers.contextualHelperPanel.finishCurveOrDoubleClick" +msgstr "曲線を完了(またはダブルクリック)" -# Source-Hash: 786f0b1c81b2a6c0 +# Source-Hash: 09f6d79edf5cfd16 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raise or lower" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid: {length}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.raiseOrLower" -msgstr "上げる・下げる" +msgid "editor.helpers.contextualHelperPanel.gridLength" +msgstr "グリッド: {length}" -# Source-Hash: b033f46ae3a0cbb7 +# Source-Hash: c493b562040c4328 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove a painted part, or reset a surface" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid step — click or tap Ctrl to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.removeAPaintedPartOrReset" -msgstr "塗装部分を削除、または面をリセット" +msgid "editor.helpers.contextualHelperPanel.gridStepClickOrTapCtrl" +msgstr "グリッド間隔 — クリックまたは Ctrl で切り替え" -# Source-Hash: 0dc6d121791696f7 +# Source-Hash: d36a8c93d81b3a36 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove last point" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid step: {length}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.removeLastPoint" -msgstr "最後の点を削除" +msgid "editor.helpers.contextualHelperPanel.gridStepLength" +msgstr "グリッド間隔: {length}" -# Source-Hash: f85bdac0a1d16603 +# Source-Hash: abea993ede7daa7e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Resize" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a painted surface to erase" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.resize" -msgstr "サイズ変更" +msgid "editor.helpers.contextualHelperPanel.hoverAPaintedSurfaceToErase" +msgstr "塗装面にホバーして消去" -# Source-Hash: 8a665ecaeffa9308 +# Source-Hash: fc1ed0ddc0cfcef5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ±45°" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a surface to paint" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.rotate45" -msgstr "±45°回転" +msgid "editor.helpers.contextualHelperPanel.hoverASurfaceToPaint" +msgstr "面にホバーして塗装" -# Source-Hash: 6099ee99f8c38700 +# Source-Hash: 63dec5de4a337015 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate the selection ±45°" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a surface to pick its material" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.rotateTheSelection45" -msgstr "選択を±45°回転" +msgid "editor.helpers.contextualHelperPanel.hoverASurfaceToPickIts" +msgstr "面にホバーして素材を取得" -# Source-Hash: c93ae898b4d59f6f +# Source-Hash: 7ad6dc1b1f03f970 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set one corner, then the opposite" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "More shortcuts" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.setOneCornerThenTheOpposite" -msgstr "1つの角、次に対角を設定" +msgid "editor.helpers.contextualHelperPanel.moreShortcuts" +msgstr "その他のショートカット" -# Source-Hash: c0774c185060fc13 +# Source-Hash: 476b8f5f9ee542e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/helpers/item-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.itemHelper.cancel" -msgstr "キャンセル" +msgid "editor.helpers.contextualHelperPanel.paintScope" +msgstr "塗装: {scope}" -# Source-Hash: ed7f3d8417a3e074 +# Source-Hash: 9c09ce4c34122277 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Force place" -#: packages/editor/src/components/ui/helpers/item-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint scope — click or press Shift to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.itemHelper.forcePlace" -msgstr "強制配置" +msgid "editor.helpers.contextualHelperPanel.paintScopeClickOrPressShift" +msgstr "塗装の範囲 — クリックまたは Shift で切り替え" -# Source-Hash: 722741535b346e09 +# Source-Hash: 7890aa81687f6654 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place" -#: packages/editor/src/components/ui/helpers/item-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint scope: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.itemHelper.place" -msgstr "配置" +msgid "editor.helpers.contextualHelperPanel.paintScopeLabel" +msgstr "塗装の範囲: {scope}" -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: a75b3abc0784b12b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" -#: packages/editor/src/components/ui/helpers/item-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.itemHelper.rotate" -msgstr "回転" +msgid "editor.helpers.contextualHelperPanel.pickScope" +msgstr "取得: {scope}" -# Source-Hash: e9dfc2a178bca5f7 +# Source-Hash: 69c1044e6ea87ccf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guided constraints bypassed" -#: packages/editor/src/components/ui/helpers/registered-tool-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place gate on a fence" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.registeredToolHelper.guidedConstraintsBypassed" -msgstr "ガイド制約を無視中" +msgid "editor.helpers.contextualHelperPanel.placeGateOnAFence" +msgstr "フェンスに門を配置" -# Source-Hash: c69865ec5d9d1ac9 +# Source-Hash: 3754255b8affc7a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Angle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place passage on a fence" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.angle.g10zaw" -msgstr "角度" +msgid "editor.helpers.contextualHelperPanel.placePassageOnAFence" +msgstr "フェンスに通路を配置" -# Source-Hash: 9c562983f6fed685 +# Source-Hash: a8328c8964e947fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arm length m" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select a material to paint" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.armLengthM.1jclqgw" -msgstr "アーム長 m" +msgid "editor.helpers.contextualHelperPanel.selectAMaterialToPaint" +msgstr "塗る素材を選択" -# Source-Hash: 38461bc364321749 +# Source-Hash: 6f95d7116aea5738 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Attachment side" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping: Angles" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.attachmentSide.6n9s5v" -msgstr "接続側" +msgid "editor.helpers.contextualHelperPanel.snappingAngles" +msgstr "スナップ: 角度" -# Source-Hash: 441124187e7da2fc +# Source-Hash: 2d6d8d85d2ebed47 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping: Grid" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.autoHangers.10554ka" -msgstr "自動吊り金具" +msgid "editor.helpers.contextualHelperPanel.snappingGrid" +msgstr "スナップ: グリッド" -# Source-Hash: e20033e4b0045f1c +# Source-Hash: 9096c5f9d8ce0f7c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto miter corners" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping: Lines" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.autoMiterCorners.zxr5lt" -msgstr "コーナーを自動留め" +msgid "editor.helpers.contextualHelperPanel.snappingLines" +msgstr "スナップ: 線" -# Source-Hash: 92f3a8b63963daeb +# Source-Hash: b663afbf0835cf32 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto span" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping mode — click or press Shift to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.autoSpan.1gas9r6" -msgstr "自動スパン" +msgid "editor.helpers.contextualHelperPanel.snappingModeClickOrPressShift" +msgstr "スナップモード — クリックまたは Shift で切り替え" -# Source-Hash: 8b2dfb9b9137fda0 +# Source-Hash: d00e984fc88f71aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back ratio" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping: Off" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.backRatio.1ughd99" -msgstr "背面比率" +msgid "editor.helpers.contextualHelperPanel.snappingOff" +msgstr "スナップ: オフ" -# Source-Hash: 75dfae8d9f03fa0e +# Source-Hash: 6be9d0d312200761 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight continuation is unavailable for curved or freehand fences" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.baseHeight.1hs4zdf" -msgstr "ベースの高さ" +msgid "editor.helpers.contextualHelperPanel.straightContinuationIsUnavailableForCurved" +msgstr "曲線・フリーハンドのフェンスでは直線の連続配置は使えません" -# Source-Hash: 1cc2da12e8463e85 +# Source-Hash: 0d56b1f0a0493302 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base style" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight: Continuous" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.baseStyle.24vty5" -msgstr "ベースのスタイル" +msgid "editor.helpers.contextualHelperPanel.straightContinuous" +msgstr "直線: 連続" -# Source-Hash: f9d95c6df06b6223 +# Source-Hash: c034e85d3e7fd27e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Beam height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight fence continuation — click or press C to toggle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.beamHeight.1kq0oh1" -msgstr "梁せい" +msgid "editor.helpers.contextualHelperPanel.straightFenceContinuationClickOrPress" +msgstr "直線フェンスの連続配置 — クリックまたは C で切り替え" -# Source-Hash: a133f8d23b1274dc +# Source-Hash: e3f679cdb4a3d603 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Beam width" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight: Single" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.beamWidth.1q1mzbe" -msgstr "梁幅" +msgid "editor.helpers.contextualHelperPanel.straightSingle" +msgstr "直線: 単体" -# Source-Hash: b98c0d0189526335 +# Source-Hash: 9a56d90d461b4bca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Body shape" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add point" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.bodyShape.arvkuw" -msgstr "本体の形状" +msgid "editor.helpers.helperManager.addPoint" +msgstr "点を追加" -# Source-Hash: 2251ecab18467631 +# Source-Hash: c3dc3918c823a5e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bracket style" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add point · click the first to close" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.bracketStyle.1vvoptm" -msgstr "ブラケットのスタイル" +msgid "editor.helpers.helperManager.addPointClickTheFirstTo" +msgstr "点を追加 · 最初の点をクリックして閉じる" -# Source-Hash: 5e9d4a4fcea481ca +# Source-Hash: d8cf72d482d56cd7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Branch angle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brush size" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.branchAngle.v56zme" -msgstr "分岐角度" +msgid "editor.helpers.helperManager.brushSize" +msgstr "ブラシサイズ" -# Source-Hash: dec709f1f9c714ee +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cab height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cabHeight.1yn34mk" -msgstr "かごの高さ" +msgid "editor.helpers.helperManager.cancel" +msgstr "キャンセル" -# Source-Hash: 87863f8366e1c88a +# Source-Hash: 104fdab7934ec66c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Canopy form" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel picking" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.canopyForm.1czzggp" -msgstr "庇の形状" +msgid "editor.helpers.helperManager.cancelPicking" +msgstr "選択をキャンセル" -# Source-Hash: d52b53241789ee63 +# Source-Hash: c318cf0ce70b8977 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel stroke" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cap.s0thej" -msgstr "キャップ" +msgid "editor.helpers.helperManager.cancelStroke" +msgstr "ストロークをキャンセル" -# Source-Hash: 2f2e49598ec8188e +# Source-Hash: 16552c2580bbe8b8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap overhang" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.capOverhang.kxxz9j" -msgstr "キャップの張り出し" +msgid "editor.helpers.helperManager.done" +msgstr "完了" -# Source-Hash: 8523c086e95b83e2 +# Source-Hash: e297db9ca0ce6d31 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap shape" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw the mezzanine" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.capShape.17mbxhu" -msgstr "キャップの形状" +msgid "editor.helpers.helperManager.drawTheMezzanine" +msgstr "中二階を描く" -# Source-Hash: acd98600a518dd95 +# Source-Hash: c8be604718a7a9fd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap thickness" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw the opening" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.capThickness.u835q9" -msgstr "キャップの厚さ" +msgid "editor.helpers.helperManager.drawTheOpening" +msgstr "開口を描く" -# Source-Hash: 7af3b69b4b5aeb19 +# Source-Hash: 231386ae6d534163 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Carcass height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw the terrace" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.carcassHeight.1aks0zy" -msgstr "本体の高さ" +msgid "editor.helpers.helperManager.drawTheTerrace" +msgstr "テラスを描く" -# Source-Hash: 827709caa79db37f +# Source-Hash: e092e803eb60af69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cleanout style" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Exit smart measure" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cleanoutStyle.127zz6z" -msgstr "掃除口のスタイル" +msgid "editor.helpers.helperManager.exitSmartMeasure" +msgstr "スマート計測を終了" -# Source-Hash: a549dc98e2a1bd07 +# Source-Hash: b3907da0ad234f10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar diameter" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.collarDiameter.1d5k28r" -msgstr "カラー径" +msgid "editor.helpers.helperManager.finish" +msgstr "完了" -# Source-Hash: aa0232fc6f3eeadc +# Source-Hash: f74bd937ae2e3a40 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish at the edge" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.collarHeight.1dqwsrf" -msgstr "カラーの高さ" +msgid "editor.helpers.helperManager.finishAtTheEdge" +msgstr "端で完了" -# Source-Hash: cbd8079c3f540a4c +# Source-Hash: 21029cf1c45697cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar shape" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free move" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.collarShape.1gacv11" -msgstr "カラーの形状" +msgid "editor.helpers.helperManager.freeMove" +msgstr "自由移動" -# Source-Hash: 557cde7f95616454 +# Source-Hash: 3247d8689bed6ff6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar width" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free move · slide doors and windows" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.collarWidth.qvc9ik" -msgstr "カラー幅" +msgid "editor.helpers.helperManager.freeMoveSlideDoorsAndWindows" +msgstr "自由移動 · ドアと窓をスライド" -# Source-Hash: 30edd1c180aac9b4 +# Source-Hash: b5ad765b43e75a5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Columns" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hold to pick a material" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.columns.1sy73ks" -msgstr "列" +msgid "editor.helpers.helperManager.holdToPickAMaterial" +msgstr "押したままで素材を取得" -# Source-Hash: cd5b2f70924b7c2d +# Source-Hash: 46b53c5449c98964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Conical full circle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inspect surface dimensions" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.conicalFullCircle.1pgkpz5" -msgstr "円錐(全周)" +msgid "editor.helpers.helperManager.inspectSurfaceDimensions" +msgstr "面の寸法を確認" -# Source-Hash: dc90f3abb935e7e2 +# Source-Hash: 63f1f7006ae14177 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connection mode" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint with this material" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.connectionMode.1nty478" -msgstr "接続モード" +msgid "editor.helpers.helperManager.paintWithThisMaterial" +msgstr "この素材で塗る" -# Source-Hash: 1a9a49d7135d4f15 +# Source-Hash: 188f55cc5afbe34f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connection offset" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick target height" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.connectionOffset.2m70s8" -msgstr "接続オフセット" +msgid "editor.helpers.helperManager.pickTargetHeight" +msgstr "目標の高さを選ぶ" -# Source-Hash: 69be301fcb8030e2 +# Source-Hash: 2880fc9752eababa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner bevel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pin measurement lens" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cornerBevel.16iniho" -msgstr "コーナーの面取り" +msgid "editor.helpers.helperManager.pinMeasurementLens" +msgstr "計測レンズを固定" -# Source-Hash: b997a96a9dc7e450 +# Source-Hash: 722741535b346e09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Covering type" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.coveringType.95yd3k" -msgstr "仕上げの種類" +msgid "editor.helpers.helperManager.place" +msgstr "配置" -# Source-Hash: 03b33160d8baa966 +# Source-Hash: 82010a7fd6350c93 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place inside the room" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cricketHeight.pok31n" -msgstr "クリケットの高さ" +msgid "editor.helpers.helperManager.placeInsideTheRoom" +msgstr "部屋の中に配置" -# Source-Hash: 21552eee05ccb5d6 +# Source-Hash: 8b97f4503edb27b9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket length" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Press anywhere, drag to the opposite corner" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cricketLength.i2aht8" -msgstr "クリケットの長さ" +msgid "editor.helpers.helperManager.pressAnywhereDragToTheOpposite" +msgstr "どこかを押して、対角までドラッグ" -# Source-Hash: c13b707bfdeac855 +# Source-Hash: 786f0b1c81b2a6c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket side" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raise or lower" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cricketSide.1xnwil7" -msgstr "クリケットの側" +msgid "editor.helpers.helperManager.raiseOrLower" +msgstr "上げる・下げる" -# Source-Hash: 4ee7089fa1b3e63b +# Source-Hash: b033f46ae3a0cbb7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket style" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove a painted part, or reset a surface" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cricketStyle.10j0lat" -msgstr "クリケットのスタイル" +msgid "editor.helpers.helperManager.removeAPaintedPartOrReset" +msgstr "塗装部分を削除、または面をリセット" -# Source-Hash: b8ff053666ee326b +# Source-Hash: 0dc6d121791696f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curb" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove last point" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.curb.5xi2ol" -msgstr "立ち上がり" +msgid "editor.helpers.helperManager.removeLastPoint" +msgstr "最後の点を削除" -# Source-Hash: 8da648df210dbc0d +# Source-Hash: f85bdac0a1d16603 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curb height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Resize" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.curbHeight.1yn97sg" -msgstr "立ち上がりの高さ" +msgid "editor.helpers.helperManager.resize" +msgstr "サイズ変更" -# Source-Hash: 0c01b9848f5d9673 +# Source-Hash: 8a665ecaeffa9308 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curve offset" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ±45°" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.curveOffset.l4xhvr" -msgstr "曲線のオフセット" +msgid "editor.helpers.helperManager.rotate45" +msgstr "±45°回転" -# Source-Hash: 69179f4caa384585 +# Source-Hash: 6099ee99f8c38700 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Damper angle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate the selection ±45°" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.damperAngle.h5fxn7" -msgstr "ダンパー角度" +msgid "editor.helpers.helperManager.rotateTheSelection45" +msgstr "選択を±45°回転" -# Source-Hash: 15cff91231e806a4 +# Source-Hash: c93ae898b4d59f6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Deck thickness" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set one corner, then the opposite" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.deckThickness.4jmqze" -msgstr "デッキの厚さ" +msgid "editor.helpers.helperManager.setOneCornerThenTheOpposite" +msgstr "1つの角、次に対角を設定" -# Source-Hash: eff1e7dc0901b9d0 +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default level id" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/helpers/item-helper.tsx #, fuzzy -msgid "editor.inspector.field.defaultLevelId.xmrjzp" -msgstr "既定の階層 ID" +msgid "editor.helpers.itemHelper.cancel" +msgstr "キャンセル" -# Source-Hash: 99ac4d03c3061f3a +# Source-Hash: ed7f3d8417a3e074 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Force place" +#: packages/editor/src/components/ui/helpers/item-helper.tsx #, fuzzy -msgid "editor.inspector.field.depth.1lu11u2" -msgstr "奥行き" +msgid "editor.helpers.itemHelper.forcePlace" +msgstr "強制配置" -# Source-Hash: 016d8e70618916d4 +# Source-Hash: 722741535b346e09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diameter" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place" +#: packages/editor/src/components/ui/helpers/item-helper.tsx #, fuzzy -msgid "editor.inspector.field.diameter.s3robe" -msgstr "直径" +msgid "editor.helpers.itemHelper.place" +msgstr "配置" -# Source-Hash: dab4100e83e4e6b3 +# Source-Hash: 306d409f8a1cf480 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diameter2" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/editor/src/components/ui/helpers/item-helper.tsx #, fuzzy -msgid "editor.inspector.field.diameter2.pm6cl4" -msgstr "直径2" +msgid "editor.helpers.itemHelper.rotate" +msgstr "回転" -# Source-Hash: 5747145349432396 +# Source-Hash: e9dfc2a178bca5f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door duration ms" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guided constraints bypassed" +#: packages/editor/src/components/ui/helpers/registered-tool-helper.tsx #, fuzzy -msgid "editor.inspector.field.doorDurationMs.13nx909" -msgstr "ドア動作時間 ms" +msgid "editor.helpers.registeredToolHelper.guidedConstraintsBypassed" +msgstr "ガイド制約を無視中" -# Source-Hash: 6f4aca26196c221f +# Source-Hash: c69865ec5d9d1ac9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.doorHeight.92r9k4" -msgstr "ドアの高さ" +msgid "editor.inspector.field.angle.g10zaw" +msgstr "角度" -# Source-Hash: 990ae81752236e3a +# Source-Hash: 9c562983f6fed685 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door panel style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arm length m" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.doorPanelStyle.2qog4q" -msgstr "ドアパネルのスタイル" +msgid "editor.inspector.field.armLengthM.1jclqgw" +msgstr "アーム長 m" -# Source-Hash: c94e002123bb1199 +# Source-Hash: 38461bc364321749 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Attachment side" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.doorStyle.gerpos" -msgstr "ドアのスタイル" +msgid "editor.inspector.field.attachmentSide.6n9s5v" +msgstr "接続側" -# Source-Hash: 91aeb04b0b7b605e +# Source-Hash: 441124187e7da2fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.doorWidth.sy732l" -msgstr "ドア幅" +msgid "editor.inspector.field.autoHangers.10554ka" +msgstr "自動吊り金具" -# Source-Hash: baad1238f70f79ea +# Source-Hash: e20033e4b0045f1c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspout enabled" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto miter corners" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.downspoutEnabled.1gn00nv" -msgstr "縦樋を有効化" +msgid "editor.inspector.field.autoMiterCorners.zxr5lt" +msgstr "コーナーを自動留め" -# Source-Hash: e288531858c4c44d +# Source-Hash: 92f3a8b63963daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspout position" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto span" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.downspoutPosition.fxcsop" -msgstr "縦樋の位置" +msgid "editor.inspector.field.autoSpan.1gas9r6" +msgstr "自動スパン" -# Source-Hash: 861d28317325cf61 +# Source-Hash: 8b2dfb9b9137fda0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct material" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.ductMaterial.i8eonq" -msgstr "ダクトの材料" +msgid "editor.inspector.field.backRatio.1ughd99" +msgstr "背面比率" -# Source-Hash: ad8ab4ae38c3299c +# Source-Hash: 75dfae8d9f03fa0e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch gablet rake" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchGabletRake.6paydp" -msgstr "入母屋の破風" +msgid "editor.inspector.field.baseHeight.1hs4zdf" +msgstr "ベースの高さ" -# Source-Hash: 913d25cf2c5ff179 +# Source-Hash: 1cc2da12e8463e85 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch hip height ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchHipHeightRatio.1etnwgg" -msgstr "入母屋の高さ比" +msgid "editor.inspector.field.baseStyle.24vty5" +msgstr "ベースのスタイル" -# Source-Hash: f4a80233d49f2b20 +# Source-Hash: f9d95c6df06b6223 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch hip width ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchHipWidthRatio.1dopfvb" -msgstr "入母屋の幅比" +msgid "editor.inspector.field.beamHeight.1kq0oh1" +msgstr "梁せい" -# Source-Hash: 92021b0e37f9a25a +# Source-Hash: a133f8d23b1274dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch top rake thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchTopRakeThickness.1w9khxt" -msgstr "入母屋上部破風の厚さ" +msgid "editor.inspector.field.beamWidth.1q1mzbe" +msgstr "梁幅" -# Source-Hash: d0a2ec13d71ce659 +# Source-Hash: b98c0d0189526335 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch waist length ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Body shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchWaistLengthRatio.agtoxw" -msgstr "入母屋の腰の長さ比" +msgid "editor.inspector.field.bodyShape.arvkuw" +msgstr "本体の形状" -# Source-Hash: 993396ccca2cd1d5 +# Source-Hash: 2251ecab18467631 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dwell ms" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bracket style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dwellMs.1lkk0o5" -msgstr "停止時間 ms" +msgid "editor.inspector.field.bracketStyle.1vvoptm" +msgstr "ブラケットのスタイル" -# Source-Hash: 9cf550eb019bca1b +# Source-Hash: 5e9d4a4fcea481ca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edge inset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Branch angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.edgeInset.1obeimx" -msgstr "縁の内側オフセット" +msgid "editor.inspector.field.branchAngle.v56zme" +msgstr "分岐角度" -# Source-Hash: 8a3bc5111b9e97f4 +# Source-Hash: dec709f1f9c714ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cab height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.elevation.4jbp44" -msgstr "高さ" +msgid "editor.inspector.field.cabHeight.1yn34mk" +msgstr "かごの高さ" -# Source-Hash: 1fc91958e30dbeaf +# Source-Hash: 87863f8366e1c88a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End cap left" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Canopy form" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.endCapLeft.19jel4v" -msgstr "左エンドキャップ" +msgid "editor.inspector.field.canopyForm.1czzggp" +msgstr "庇の形状" -# Source-Hash: 4c9ae62e0ed70635 +# Source-Hash: d52b53241789ee63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End cap right" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.endCapRight.lhse9c" -msgstr "右エンドキャップ" +msgid "editor.inspector.field.cap.s0thej" +msgstr "キャップ" -# Source-Hash: a9cba06250228a55 +# Source-Hash: 2f2e49598ec8188e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End caps" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.endCaps.4fsb5b" -msgstr "エンドキャップ" +msgid "editor.inspector.field.capOverhang.kxxz9j" +msgstr "キャップの張り出し" -# Source-Hash: ebad74353b5a7610 +# Source-Hash: 8523c086e95b83e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End post" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.endPost.1guwsk0" -msgstr "端の支柱" +msgid "editor.inspector.field.capShape.17mbxhu" +msgstr "キャップの形状" -# Source-Hash: ecbe36df4238439e +# Source-Hash: acd98600a518dd95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equipment type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.equipmentType.1mc2ywt" -msgstr "機器の種類" +msgid "editor.inspector.field.capThickness.u835q9" +msgstr "キャップの厚さ" -# Source-Hash: 66f1018b50c2e426 +# Source-Hash: 7af3b69b4b5aeb19 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fill to floor" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Carcass height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.fillToFloor.1oppnkf" -msgstr "床まで埋める" +msgid "editor.inspector.field.carcassHeight.1aks0zy" +msgstr "本体の高さ" -# Source-Hash: 1cfe33235b30b1d8 +# Source-Hash: 827709caa79db37f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finial" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cleanout style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.finial.1ertf4s" -msgstr "フィニアル" +msgid "editor.inspector.field.cleanoutStyle.127zz6z" +msgstr "掃除口のスタイル" -# Source-Hash: 28cd69e506709f16 +# Source-Hash: a549dc98e2a1bd07 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fitting type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.fittingType.18mz17s" -msgstr "継手の種類" +msgid "editor.inspector.field.collarDiameter.1d5k28r" +msgstr "カラー径" -# Source-Hash: 3c1aec5e6fb180cf +# Source-Hash: aa0232fc6f3eeadc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flashing height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flashingHeight.3e8nn6" -msgstr "水切りの高さ" +msgid "editor.inspector.field.collarHeight.1dqwsrf" +msgstr "カラーの高さ" -# Source-Hash: 327ba762101db94d +# Source-Hash: cbd8079c3f540a4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flashing projection" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flashingProjection.hhf0fk" -msgstr "水切りの出" +msgid "editor.inspector.field.collarShape.1gacv11" +msgstr "カラーの形状" -# Source-Hash: 9473e2ab53370b40 +# Source-Hash: 557cde7f95616454 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueCount.j3t2ci" -msgstr "煙道の数" +msgid "editor.inspector.field.collarWidth.qvc9ik" +msgstr "カラー幅" -# Source-Hash: fd0b65425ed3df8b +# Source-Hash: 30edd1c180aac9b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Columns" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueDiameter.cjhubg" -msgstr "煙道の直径" +msgid "editor.inspector.field.columns.1sy73ks" +msgstr "列" -# Source-Hash: 07ebe5e3780c624b +# Source-Hash: cd5b2f70924b7c2d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Conical full circle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueHeight.1dhc4y4" -msgstr "煙道の高さ" +msgid "editor.inspector.field.conicalFullCircle.1pgkpz5" +msgstr "円錐(全周)" -# Source-Hash: ff8319792830d591 +# Source-Hash: dc90f3abb935e7e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connection mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueShape.1ealiy4" -msgstr "煙道の形状" +msgid "editor.inspector.field.connectionMode.1nty478" +msgstr "接続モード" -# Source-Hash: 5acf77854a0030ec +# Source-Hash: 1a9a49d7135d4f15 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connection offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueSpacing.exhzco" -msgstr "煙道の間隔" +msgid "editor.inspector.field.connectionOffset.2m70s8" +msgstr "接続オフセット" -# Source-Hash: 0a64209c0edacaa1 +# Source-Hash: 69be301fcb8030e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Footing style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner bevel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.footingStyle.e3btg6" -msgstr "フーチングのスタイル" +msgid "editor.inspector.field.cornerBevel.16iniho" +msgstr "コーナーの面取り" -# Source-Hash: fd413477f1a9e5ed +# Source-Hash: b997a96a9dc7e450 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Covering type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.frameDepth.1934a5n" -msgstr "枠の奥行き" +msgid "editor.inspector.field.coveringType.95yd3k" +msgstr "仕上げの種類" -# Source-Hash: 6aa2318fa815e5f2 +# Source-Hash: 03b33160d8baa966 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.frameThickness.1agxzd8" -msgstr "枠の厚さ" +msgid "editor.inspector.field.cricketHeight.pok31n" +msgstr "クリケットの高さ" -# Source-Hash: 9a3495a1e3181b56 +# Source-Hash: 21552eee05ccb5d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Framing strategy" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket length" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.framingStrategy.3jx9qe" -msgstr "下地の方式" +msgid "editor.inspector.field.cricketLength.i2aht8" +msgstr "クリケットの長さ" -# Source-Hash: 49f329aab535fd3a +# Source-Hash: c13b707bfdeac855 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "From level id" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket side" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.fromLevelId.15ieejs" -msgstr "開始階層 ID" +msgid "editor.inspector.field.cricketSide.1xnwil7" +msgstr "クリケットの側" -# Source-Hash: dbd062efc7f4fd7f +# Source-Hash: 4ee7089fa1b3e63b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gableOverhang.2z0obw" -msgstr "妻側のけらば" +msgid "editor.inspector.field.cricketStyle.10j0lat" +msgstr "クリケットのスタイル" -# Source-Hash: 517caa8af48afb22 +# Source-Hash: b8ff053666ee326b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel lower height ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curb" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gambrelLowerHeightRatio.wqq7lg" -msgstr "腰折れ下部の高さ比" +msgid "editor.inspector.field.curb.5xi2ol" +msgstr "立ち上がり" -# Source-Hash: 03ecb8f3b625d49d +# Source-Hash: 8da648df210dbc0d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel lower width ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curb height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gambrelLowerWidthRatio.uvyb1v" -msgstr "腰折れ下部の幅比" +msgid "editor.inspector.field.curbHeight.1yn97sg" +msgstr "立ち上がりの高さ" -# Source-Hash: f3ca5555e8c54375 +# Source-Hash: 0c01b9848f5d9673 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap x" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curve offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gapX.wjxa7" -msgstr "隙間 x" +msgid "editor.inspector.field.curveOffset.l4xhvr" +msgstr "曲線のオフセット" -# Source-Hash: 2736f7c5dfc7d917 +# Source-Hash: 69179f4caa384585 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap y" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Damper angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gapY.mkbl8" -msgstr "隙間 y" +msgid "editor.inspector.field.damperAngle.h5fxn7" +msgstr "ダンパー角度" -# Source-Hash: 5d03ca50d712339b +# Source-Hash: 15cff91231e806a4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.glassThickness.s97b0x" -msgstr "ガラスの厚さ" +msgid "editor.inspector.field.deckThickness.4jmqze" +msgstr "デッキの厚さ" -# Source-Hash: 4fc3e60be28f60d5 +# Source-Hash: eff1e7dc0901b9d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground clearance" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default level id" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.groundClearance.4os7f0" -msgstr "地面とのクリアランス" +msgid "editor.inspector.field.defaultLevelId.xmrjzp" +msgstr "既定の階層 ID" -# Source-Hash: 6a22a09b67309545 +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guard infill" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.guardInfill.16heiig" -msgstr "手すり壁の充填" +msgid "editor.inspector.field.depth.1lu11u2" +msgstr "奥行き" -# Source-Hash: 98dfdac04af3c762 +# Source-Hash: 016d8e70618916d4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gutter enabled" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gutterEnabled.1oxiltf" -msgstr "雨樋を有効化" +msgid "editor.inspector.field.diameter.s3robe" +msgstr "直径" -# Source-Hash: 4bdc3cdf0fe0ac3c +# Source-Hash: dab4100e83e4e6b3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gutter profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diameter2" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gutterProfile.1ngzqi3" -msgstr "雨樋の形状" +msgid "editor.inspector.field.diameter2.pm6cl4" +msgstr "直径2" -# Source-Hash: 76555670cba9bb13 +# Source-Hash: 5747145349432396 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gutter size" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door duration ms" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gutterSize.jgavtz" -msgstr "雨樋のサイズ" +msgid "editor.inspector.field.doorDurationMs.13nx909" +msgstr "ドア動作時間 ms" -# Source-Hash: c14d3aa4a98efa98 +# Source-Hash: 6f4aca26196c221f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger max reach" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.hangerMaxReach.1869epv" -msgstr "吊りの最大到達距離" +msgid "editor.inspector.field.doorHeight.92r9k4" +msgstr "ドアの高さ" -# Source-Hash: dfbc357fb556559b +# Source-Hash: 990ae81752236e3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door panel style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.hangerSpacing.i2b5d7" -msgstr "吊りの間隔" +msgid "editor.inspector.field.doorPanelStyle.2qog4q" +msgstr "ドアパネルのスタイル" -# Source-Hash: 3ce5e50c572644ed +# Source-Hash: c94e002123bb1199 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.hangerStyle.l7v7gb" -msgstr "吊りのスタイル" +msgid "editor.inspector.field.doorStyle.gerpos" +msgstr "ドアのスタイル" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: 91aeb04b0b7b605e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.height.7puwki" -msgstr "高さ" +msgid "editor.inspector.field.doorWidth.sy732l" +msgstr "ドア幅" -# Source-Hash: d0b836103c795726 +# Source-Hash: baad1238f70f79ea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height2" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspout enabled" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.height2.7b3jlc" -msgstr "高さ2" +msgid "editor.inspector.field.downspoutEnabled.1gn00nv" +msgstr "縦樋を有効化" -# Source-Hash: 681fd794e601ace5 +# Source-Hash: e288531858c4c44d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height above ridge" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspout position" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.heightAboveRidge.1k99brk" -msgstr "棟からの高さ" +msgid "editor.inspector.field.downspoutPosition.fxcsop" +msgstr "縦樋の位置" -# Source-Hash: b4905e5ec62a170f +# Source-Hash: 861d28317325cf61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High edge height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct material" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.highEdgeHeight.1s7v90t" -msgstr "高い側の高さ" +msgid "editor.inspector.field.ductMaterial.i8eonq" +msgstr "ダクトの材料" -# Source-Hash: c136d5cd7f3ce04a +# Source-Hash: ad8ab4ae38c3299c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch gablet rake" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.highOverhang.67w55d" -msgstr "高い側の出" +msgid "editor.inspector.field.dutchGabletRake.6paydp" +msgstr "入母屋の破風" -# Source-Hash: 8b4cd537cc650dac +# Source-Hash: 913d25cf2c5ff179 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High side mode" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch hip height ratio" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.highSideMode.1rc1r5j" -msgstr "高い側のモード" +msgid "editor.inspector.field.dutchHipHeightRatio.1etnwgg" +msgstr "入母屋の高さ比" -# Source-Hash: c38e4e73ed9779f4 +# Source-Hash: f4a80233d49f2b20 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hood overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch hip width ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.hoodOverhang.1q1hcin" -msgstr "フードの張り出し" +msgid "editor.inspector.field.dutchHipWidthRatio.1dopfvb" +msgstr "入母屋の幅比" -# Source-Hash: 9884ee52a0e84c0d +# Source-Hash: 92021b0e37f9a25a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Infill placement" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch top rake thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.infillPlacement.11dxzpo" -msgstr "充填の位置" +msgid "editor.inspector.field.dutchTopRakeThickness.1w9khxt" +msgstr "入母屋上部破風の厚さ" -# Source-Hash: 37fde9f9290ddc59 +# Source-Hash: d0a2ec13d71ce659 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inlet shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch waist length ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.inletShape.ypayh2" -msgstr "入口の形状" +msgid "editor.inspector.field.dutchWaistLengthRatio.agtoxw" +msgstr "入母屋の腰の長さ比" -# Source-Hash: d840917007332b94 +# Source-Hash: 993396ccca2cd1d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inner radius" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dwell ms" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.innerRadius.1fkmg0j" -msgstr "内半径" +msgid "editor.inspector.field.dwellMs.1lkk0o5" +msgstr "停止時間 ms" -# Source-Hash: c8ce389856a90ae2 +# Source-Hash: 9cf550eb019bca1b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Insulated" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edge inset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.insulated.iwziey" -msgstr "断熱" +msgid "editor.inspector.field.edgeInset.1obeimx" +msgstr "縁の内側オフセット" -# Source-Hash: 043a7a10b6c91f4f +# Source-Hash: 8a3bc5111b9e97f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Insulation r" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.insulationR.663ufx" -msgstr "断熱 R" +msgid "editor.inspector.field.elevation.4jbp44" +msgstr "高さ" -# Source-Hash: fe661655ba41b709 +# Source-Hash: 1fc91958e30dbeaf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End cap left" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lanternHeight.oz7zpm" -msgstr "ランタンの高さ" +msgid "editor.inspector.field.endCapLeft.19jel4v" +msgstr "左エンドキャップ" -# Source-Hash: ab22022e7d5597af +# Source-Hash: 4c9ae62e0ed70635 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern top scale" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End cap right" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lanternTopScale.hkmpp2" -msgstr "ランタン上部の比率" +msgid "editor.inspector.field.endCapRight.lhse9c" +msgstr "右エンドキャップ" -# Source-Hash: 17f854a76ebc033a +# Source-Hash: a9cba06250228a55 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ledger depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End caps" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.ledgerDepth.7av8k9" -msgstr "受け材の奥行き" +msgid "editor.inspector.field.endCaps.4fsb5b" +msgstr "エンドキャップ" -# Source-Hash: 547d3a8a9e3e24f5 +# Source-Hash: ebad74353b5a7610 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ledger height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End post" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.ledgerHeight.zo2oif" -msgstr "受け材の高さ" +msgid "editor.inspector.field.endPost.1guwsk0" +msgstr "端の支柱" -# Source-Hash: 88603f884243c81e +# Source-Hash: ecbe36df4238439e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ledger vertical offset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equipment type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.ledgerVerticalOffset.1athbgt" -msgstr "受け材の垂直オフセット" +msgid "editor.inspector.field.equipmentType.1mc2ywt" +msgstr "機器の種類" -# Source-Hash: 6519f495202b830d +# Source-Hash: 66f1018b50c2e426 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left end condition" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fill to floor" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.leftEndCondition.1syqlaw" -msgstr "左端の条件" +msgid "editor.inspector.field.fillToFloor.1oppnkf" +msgstr "床まで埋める" -# Source-Hash: d041b8217c356977 +# Source-Hash: 1cfe33235b30b1d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finial" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.leftOverhang.1ydl9ma" -msgstr "左の張り出し" +msgid "editor.inspector.field.finial.1ertf4s" +msgstr "フィニアル" -# Source-Hash: 643687bc3adaac76 +# Source-Hash: 28cd69e506709f16 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fitting type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.length.1kpdcfp" -msgstr "長さ" +msgid "editor.inspector.field.fittingType.18mz17s" +msgstr "継手の種類" -# Source-Hash: d6deaf0ceb9f43af +# Source-Hash: 3c1aec5e6fb180cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Liquid diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flashing height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.liquidDiameter.w3pk7c" -msgstr "液管の直径" +msgid "editor.inspector.field.flashingHeight.3e8nn6" +msgstr "水切りの高さ" -# Source-Hash: 45aca762426392fa +# Source-Hash: 327ba762101db94d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Louver count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flashing projection" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.louverCount.lhw2gr" -msgstr "ルーバーの数" +msgid "editor.inspector.field.flashingProjection.hhf0fk" +msgstr "水切りの出" -# Source-Hash: c645a86c55eb0075 +# Source-Hash: 9473e2ab53370b40 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low beam inset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lowBeamInset.1g7yw5l" -msgstr "低い梁の内側オフセット" +msgid "editor.inspector.field.flueCount.j3t2ci" +msgstr "煙道の数" -# Source-Hash: 7e7b896682c78c5b +# Source-Hash: fd0b65425ed3df8b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low edge height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lowEdgeHeight.47mae1" -msgstr "低い側の高さ" +msgid "editor.inspector.field.flueDiameter.cjhubg" +msgstr "煙道の直径" -# Source-Hash: 9deb775fc64854b2 +# Source-Hash: 07ebe5e3780c624b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lowOverhang.t4nz1h" -msgstr "低い側の出" +msgid "editor.inspector.field.flueHeight.1dhc4y4" +msgstr "煙道の高さ" -# Source-Hash: 9aa621d270fe64b1 +# Source-Hash: ff8319792830d591 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard steep height ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.mansardSteepHeightRatio.1hbb8rq" -msgstr "マンサード急勾配部の高さ比" +msgid "editor.inspector.field.flueShape.1ealiy4" +msgstr "煙道の形状" -# Source-Hash: 7cb03b27c632949b +# Source-Hash: 5acf77854a0030ec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard steep width ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.mansardSteepWidthRatio.6xk6vd" -msgstr "マンサード急勾配部の幅比" +msgid "editor.inspector.field.flueSpacing.exhzco" +msgstr "煙道の間隔" -# Source-Hash: 95772435857a7424 +# Source-Hash: 0a64209c0edacaa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match host roof material" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Footing style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.matchHostRoofMaterial.s56zwj" -msgstr "母屋根の素材に合わせる" +msgid "editor.inspector.field.footingStyle.e3btg6" +msgstr "フーチングのスタイル" -# Source-Hash: dc22618e31654bde +# Source-Hash: fd413477f1a9e5ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match host roof structure" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame depth" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.matchHostRoofStructure.bojht3" -msgstr "母屋根の構造に合わせる" +msgid "editor.inspector.field.frameDepth.1934a5n" +msgstr "枠の奥行き" -# Source-Hash: 06b36a09a84fa8b1 +# Source-Hash: 6aa2318fa815e5f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mount" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.mount.h80tay" -msgstr "取り付け" +msgid "editor.inspector.field.frameThickness.1agxzd8" +msgstr "枠の厚さ" -# Source-Hash: a288700f96d2b362 +# Source-Hash: 9a3495a1e3181b56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framing strategy" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.mountingType.1xvin1e" -msgstr "取り付けの種類" +msgid "editor.inspector.field.framingStrategy.3jx9qe" +msgstr "下地の方式" -# Source-Hash: 3087bc9b219af9ef +# Source-Hash: 49f329aab535fd3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Neck height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "From level id" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.neckHeight.19ym8n1" -msgstr "首の高さ" +msgid "editor.inspector.field.fromLevelId.15ieejs" +msgstr "開始階層 ID" -# Source-Hash: 1c0b8a5503c5daeb +# Source-Hash: dbd062efc7f4fd7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opacity" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.opacity.1pmpfd2" -msgstr "不透明度" +msgid "editor.inspector.field.gableOverhang.2z0obw" +msgstr "妻側のけらば" -# Source-Hash: 51b7ab6a0a78d90a +# Source-Hash: 517caa8af48afb22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel lower height ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.openingAngle.brhi7c" -msgstr "開き角度" +msgid "editor.inspector.field.gambrelLowerHeightRatio.wqq7lg" +msgstr "腰折れ下部の高さ比" -# Source-Hash: 1d714b576a057902 +# Source-Hash: 03ecb8f3b625d49d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening offset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel lower width ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.openingOffset.wpoqt6" -msgstr "開口のオフセット" +msgid "editor.inspector.field.gambrelLowerWidthRatio.uvyb1v" +msgstr "腰折れ下部の幅比" -# Source-Hash: 55e5629865efd03d +# Source-Hash: f3ca5555e8c54375 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening side" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap x" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.openingSide.18l2iwe" -msgstr "開く側" +msgid "editor.inspector.field.gapX.wjxa7" +msgstr "隙間 x" -# Source-Hash: 9824d357692ecb8a +# Source-Hash: 2736f7c5dfc7d917 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Operation state" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap y" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.operationState.1lwrz07" -msgstr "開閉状態" +msgid "editor.inspector.field.gapY.mkbl8" +msgstr "隙間 y" -# Source-Hash: 4f1cbc14dcfb8f3b +# Source-Hash: 5d03ca50d712339b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Outlet shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.outletShape.lgpqhx" -msgstr "出口の形状" +msgid "editor.inspector.field.glassThickness.s97b0x" +msgstr "ガラスの厚さ" -# Source-Hash: 88540def2ce16ac5 +# Source-Hash: 4fc3e60be28f60d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground clearance" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.overhang.b5ljpv" -msgstr "張り出し" +msgid "editor.inspector.field.groundClearance.4os7f0" +msgstr "地面とのクリアランス" -# Source-Hash: 50d7e5e370667f63 +# Source-Hash: 6a22a09b67309545 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guard infill" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.panelHeight.1kf31vk" -msgstr "パネルの高さ" +msgid "editor.inspector.field.guardInfill.16heiig" +msgstr "手すり壁の充填" -# Source-Hash: 068d9e0adabc4578 +# Source-Hash: 98dfdac04af3c762 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gutter enabled" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.panelWidth.946581" -msgstr "パネル幅" +msgid "editor.inspector.field.gutterEnabled.1oxiltf" +msgstr "雨樋を有効化" -# Source-Hash: aca94a3adc0b0f01 +# Source-Hash: 4bdc3cdf0fe0ac3c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern alignment" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gutter profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.patternAlignment.jd1ht0" -msgstr "パターンの揃え" +msgid "editor.inspector.field.gutterProfile.1ngzqi3" +msgstr "雨樋の形状" -# Source-Hash: 9e9f9408ec2c8f0b +# Source-Hash: 76555670cba9bb13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gutter size" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.patternCount.1r37pve" -msgstr "パターン数" +msgid "editor.inspector.field.gutterSize.jgavtz" +msgstr "雨樋のサイズ" -# Source-Hash: 4712c449e9a42d3b +# Source-Hash: c14d3aa4a98efa98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern distribution" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger max reach" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.patternDistribution.fmam51" -msgstr "パターンの配分" +msgid "editor.inspector.field.hangerMaxReach.1869epv" +msgstr "吊りの最大到達距離" -# Source-Hash: 63f833f219b9a592 +# Source-Hash: dfbc357fb556559b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern remainder" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.patternRemainder.i47p5y" -msgstr "パターンの余り" +msgid "editor.inspector.field.hangerSpacing.i2b5d7" +msgstr "吊りの間隔" -# Source-Hash: e0b8f766411329ff +# Source-Hash: 3ce5e50c572644ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketProfile.1xgzuyc" -msgstr "ピケットの形状" +msgid "editor.inspector.field.hangerStyle.l7v7gb" +msgstr "吊りのスタイル" -# Source-Hash: dfac7d68ea16e8a8 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket rail count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketRailCount.atgt6w" -msgstr "ピケットのレール数" +msgid "editor.inspector.field.height.7puwki" +msgstr "高さ" -# Source-Hash: cd2652254a81d288 +# Source-Hash: d0b836103c795726 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height2" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketSpacing.p8d98w" -msgstr "ピケットの間隔" +msgid "editor.inspector.field.height2.7b3jlc" +msgstr "高さ2" -# Source-Hash: 462f6cb03b23d773 +# Source-Hash: 681fd794e601ace5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket top" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height above ridge" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketTop.1tskplu" -msgstr "ピケットの上端" +msgid "editor.inspector.field.heightAboveRidge.1k99brk" +msgstr "棟からの高さ" -# Source-Hash: 0a4dbbe1cf592326 +# Source-Hash: b4905e5ec62a170f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket top clearance" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High edge height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketTopClearance.16eq1k0" -msgstr "ピケット上端のクリアランス" +msgid "editor.inspector.field.highEdgeHeight.1s7v90t" +msgstr "高い側の高さ" -# Source-Hash: c99ccea380ca41bf +# Source-Hash: c136d5cd7f3ce04a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket variation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketVariation.f7vl1c" -msgstr "ピケットのばらつき" +msgid "editor.inspector.field.highOverhang.67w55d" +msgstr "高い側の出" -# Source-Hash: 798382373625fecd +# Source-Hash: 8b4cd537cc650dac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High side mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketWidth.3fr3rh" -msgstr "ピケットの幅" - -# Source-Hash: 48ce215c3be034c7 +msgid "editor.inspector.field.highSideMode.1rc1r5j" +msgstr "高い側のモード" + +# Source-Hash: c38e4e73ed9779f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pipe material" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hood overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.pipeMaterial.1ggc2wy" -msgstr "配管の材料" +msgid "editor.inspector.field.hoodOverhang.1q1hcin" +msgstr "フードの張り出し" -# Source-Hash: 75e3449fc1776d09 +# Source-Hash: 9884ee52a0e84c0d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pitch" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Infill placement" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.pitch.xe6ekx" -msgstr "勾配" +msgid "editor.inspector.field.infillPlacement.11dxzpo" +msgstr "充填の位置" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: 37fde9f9290ddc59 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inlet shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.position.1quewx6" -msgstr "位置" +msgid "editor.inspector.field.inletShape.ypayh2" +msgstr "入口の形状" -# Source-Hash: d090baf9f08c2280 +# Source-Hash: d840917007332b94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post bracing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inner radius" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postBracing.crq8nn" -msgstr "支柱の筋交い" +msgid "editor.inspector.field.innerRadius.1fkmg0j" +msgstr "内半径" -# Source-Hash: 6467b580eed1d333 +# Source-Hash: c8ce389856a90ae2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post cap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulated" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postCap.1xcvxrv" -msgstr "支柱キャップ" +msgid "editor.inspector.field.insulated.iwziey" +msgstr "断熱" -# Source-Hash: e1d91cdd16cc6593 +# Source-Hash: 043a7a10b6c91f4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation r" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postCount.22r56c" -msgstr "支柱の数" +msgid "editor.inspector.field.insulationR.663ufx" +msgstr "断熱 R" -# Source-Hash: d6d8b8653cb43624 +# Source-Hash: fe661655ba41b709 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postDepth.1ko6j1m" -msgstr "支柱の奥行き" +msgid "editor.inspector.field.lanternHeight.oz7zpm" +msgstr "ランタンの高さ" -# Source-Hash: dd071e84e259ee48 +# Source-Hash: ab22022e7d5597af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post inset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern top scale" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postInset.le36li" -msgstr "支柱の内側オフセット" +msgid "editor.inspector.field.lanternTopScale.hkmpp2" +msgstr "ランタン上部の比率" -# Source-Hash: 88c5d586822e58f0 +# Source-Hash: 17f854a76ebc033a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post layout mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ledger depth" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postLayoutMode.16jre62" -msgstr "支柱配置モード" +msgid "editor.inspector.field.ledgerDepth.7av8k9" +msgstr "受け材の奥行き" -# Source-Hash: faa36308c1ecb2a9 +# Source-Hash: 547d3a8a9e3e24f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post size" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ledger height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postSize.1jodxek" -msgstr "支柱のサイズ" +msgid "editor.inspector.field.ledgerHeight.zo2oif" +msgstr "受け材の高さ" -# Source-Hash: c8e8490c957e01f3 +# Source-Hash: 88603f884243c81e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ledger vertical offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postSpacing.voppfi" -msgstr "支柱の間隔" +msgid "editor.inspector.field.ledgerVerticalOffset.1athbgt" +msgstr "受け材の垂直オフセット" -# Source-Hash: b98cbe8478508d41 +# Source-Hash: 6519f495202b830d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post through" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left end condition" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postThrough.1abgu4a" -msgstr "支柱を貫通" +msgid "editor.inspector.field.leftEndCondition.1syqlaw" +msgstr "左端の条件" -# Source-Hash: d1492df1fbb22c29 +# Source-Hash: d041b8217c356977 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postWidth.rk26fz" -msgstr "支柱の幅" +msgid "editor.inspector.field.leftOverhang.1ydl9ma" +msgstr "左の張り出し" -# Source-Hash: 96ad4bd0f7baa40e +# Source-Hash: 643687bc3adaac76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.profile.1kwlci6" -msgstr "形状" +msgid "editor.inspector.field.length.1kpdcfp" +msgstr "長さ" -# Source-Hash: d01cd36d3939abab +# Source-Hash: d6deaf0ceb9f43af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Projection" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Liquid diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.projection.jhtig0" -msgstr "出" +msgid "editor.inspector.field.liquidDiameter.w3pk7c" +msgstr "液管の直径" -# Source-Hash: 800a7a9159519b46 +# Source-Hash: 45aca762426392fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Purlin height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Louver count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.purlinHeight.eo9cjm" -msgstr "母屋の高さ" +msgid "editor.inspector.field.louverCount.lhw2gr" +msgstr "ルーバーの数" -# Source-Hash: da4d0d12715d6c33 +# Source-Hash: c645a86c55eb0075 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Purlin spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low beam inset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.purlinSpacing.4gbzb2" -msgstr "母屋の間隔" +msgid "editor.inspector.field.lowBeamInset.1g7yw5l" +msgstr "低い梁の内側オフセット" -# Source-Hash: b4774bcbdf599812 +# Source-Hash: 7e7b896682c78c5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Purlin width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low edge height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.purlinWidth.r6tu3j" -msgstr "母屋の幅" +msgid "editor.inspector.field.lowEdgeHeight.47mae1" +msgstr "低い側の高さ" -# Source-Hash: 2a4dd54f8a8c15ef +# Source-Hash: 9deb775fc64854b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafter end inset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rafterEndInset.14c0wy5" -msgstr "垂木端の内側オフセット" +msgid "editor.inspector.field.lowOverhang.t4nz1h" +msgstr "低い側の出" -# Source-Hash: 5a80a11b97c0e043 +# Source-Hash: 9aa621d270fe64b1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafter height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard steep height ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rafterHeight.1e1n99w" -msgstr "垂木の高さ" +msgid "editor.inspector.field.mansardSteepHeightRatio.1hbb8rq" +msgstr "マンサード急勾配部の高さ比" -# Source-Hash: b6348d554660af5b +# Source-Hash: 7cb03b27c632949b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafter spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard steep width ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rafterSpacing.19subc0" -msgstr "垂木の間隔" +msgid "editor.inspector.field.mansardSteepWidthRatio.6xk6vd" +msgstr "マンサード急勾配部の幅比" -# Source-Hash: 112c447946c3beaa +# Source-Hash: 95772435857a7424 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafter width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match host roof material" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rafterWidth.eksj4t" -msgstr "垂木の幅" +msgid "editor.inspector.field.matchHostRoofMaterial.s56zwj" +msgstr "母屋根の素材に合わせる" -# Source-Hash: 7020d720876a2106 +# Source-Hash: dc22618e31654bde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match host roof structure" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.railingHeight.6wf4bm" -msgstr "手すりの高さ" +msgid "editor.inspector.field.matchHostRoofStructure.bojht3" +msgstr "母屋根の構造に合わせる" -# Source-Hash: 3e89ce193885b5b4 +# Source-Hash: 06b36a09a84fa8b1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mount" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.railingMode.ov7xpu" -msgstr "手すりのモード" +msgid "editor.inspector.field.mount.h80tay" +msgstr "取り付け" -# Source-Hash: 174342bb31a86afc +# Source-Hash: a288700f96d2b362 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.railingStyle.1nyd2u" -msgstr "手すりのスタイル" +msgid "editor.inspector.field.mountingType.1xvin1e" +msgstr "取り付けの種類" -# Source-Hash: a44eedc895b95474 +# Source-Hash: 3087bc9b219af9ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Resize lock" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Neck height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.resizeLock.b2hbr0" -msgstr "比率を固定" +msgid "editor.inspector.field.neckHeight.19ym8n1" +msgstr "首の高さ" -# Source-Hash: edd319917231def8 +# Source-Hash: 1c0b8a5503c5daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opacity" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.returnDiameter.166ozhe" -msgstr "還気の直径" +msgid "editor.inspector.field.opacity.1pmpfd2" +msgstr "不透明度" -# Source-Hash: dafa151b183daa77 +# Source-Hash: 51b7ab6a0a78d90a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.returnHeight.b9sq6y" -msgstr "還気の高さ" +msgid "editor.inspector.field.openingAngle.brhi7c" +msgstr "開き角度" -# Source-Hash: cd55fd029ad2803b +# Source-Hash: 1d714b576a057902 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.returnShape.1e3a27i" -msgstr "還気の形状" +msgid "editor.inspector.field.openingOffset.wpoqt6" +msgstr "開口のオフセット" -# Source-Hash: 6a7c411667124177 +# Source-Hash: 55e5629865efd03d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening side" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.returnWidth.z9r3h3" -msgstr "還気の幅" +msgid "editor.inspector.field.openingSide.18l2iwe" +msgstr "開く側" -# Source-Hash: 460bd11bfc2e5697 +# Source-Hash: 9824d357692ecb8a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right end condition" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Operation state" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rightEndCondition.tjlw3l" -msgstr "右端の条件" +msgid "editor.inspector.field.operationState.1lwrz07" +msgstr "開閉状態" -# Source-Hash: 1ed35f8d27ae5583 +# Source-Hash: 4f1cbc14dcfb8f3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outlet shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rightOverhang.yqbeft" -msgstr "右の張り出し" +msgid "editor.inspector.field.outletShape.lgpqhx" +msgstr "出口の形状" -# Source-Hash: 39c02aa2d97a62ba +# Source-Hash: 88540def2ce16ac5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.roofHeight.1uhy6qy" -msgstr "屋根の高さ" +msgid "editor.inspector.field.overhang.b5ljpv" +msgstr "張り出し" -# Source-Hash: d62f8833d77ca8a1 +# Source-Hash: 50d7e5e370667f63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.roofStyle.pawqfy" -msgstr "屋根のスタイル" +msgid "editor.inspector.field.panelHeight.1kf31vk" +msgstr "パネルの高さ" -# Source-Hash: 0ddd561a4126b826 +# Source-Hash: 068d9e0adabc4578 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.roofThickness.1xlr3rx" -msgstr "屋根の厚さ" +msgid "editor.inspector.field.panelWidth.946581" +msgstr "パネル幅" -# Source-Hash: 3a08ede9e51d5395 +# Source-Hash: aca94a3adc0b0f01 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern alignment" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.roofType.1m9kv5h" -msgstr "屋根の種類" +msgid "editor.inspector.field.patternAlignment.jd1ht0" +msgstr "パターンの揃え" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: 9e9f9408ec2c8f0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rotation.ly2rj" -msgstr "回転" +msgid "editor.inspector.field.patternCount.1r37pve" +msgstr "パターン数" -# Source-Hash: c913b494c3901a17 +# Source-Hash: 4712c449e9a42d3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rows" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern distribution" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rows.1ba1neg" -msgstr "行" +msgid "editor.inspector.field.patternDistribution.fmam51" +msgstr "パターンの配分" -# Source-Hash: 8210f376c0d29acc +# Source-Hash: 63f833f219b9a592 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scale" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern remainder" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.scale.b6rpxt" -msgstr "縮尺" +msgid "editor.inspector.field.patternRemainder.i47p5y" +msgstr "パターンの余り" -# Source-Hash: adb6face4bac5245 +# Source-Hash: e0b8f766411329ff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Seam detail" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.seamDetail.197za48" -msgstr "継ぎ目の詳細" +msgid "editor.inspector.field.picketProfile.1xgzuyc" +msgstr "ピケットの形状" -# Source-Hash: 4b2aed9d56cc4dee +# Source-Hash: dfac7d68ea16e8a8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segment type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket rail count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.segmentType.l667sy" -msgstr "セグメントの種類" +msgid "editor.inspector.field.picketRailCount.atgt6w" +msgstr "ピケットのレール数" -# Source-Hash: a7794a81141b4de4 +# Source-Hash: cd2652254a81d288 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shaftStyle.1i5ampa" -msgstr "シャフトのスタイル" +msgid "editor.inspector.field.picketSpacing.p8d98w" +msgstr "ピケットの間隔" -# Source-Hash: 8eb6438543b18cdb +# Source-Hash: 462f6cb03b23d773 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft wall thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket top" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shaftWallThickness.bduslr" -msgstr "シャフト壁の厚さ" +msgid "editor.inspector.field.picketTop.1tskplu" +msgstr "ピケットの上端" -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: 0a4dbbe1cf592326 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket top clearance" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shape.iq9t52" -msgstr "形状" +msgid "editor.inspector.field.picketTopClearance.16eq1k0" +msgstr "ピケット上端のクリアランス" -# Source-Hash: 44a8ab89c854cad1 +# Source-Hash: c99ccea380ca41bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape2" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket variation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shape2.fi0nx8" -msgstr "形状2" +msgid "editor.inspector.field.picketVariation.f7vl1c" +msgstr "ピケットのばらつき" -# Source-Hash: fcee9712879570ae +# Source-Hash: 798382373625fecd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed high side" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shedHighSide.bzzddg" -msgstr "片流れの高い側" +msgid "editor.inspector.field.picketWidth.3fr3rh" +msgstr "ピケットの幅" -# Source-Hash: f5a931cd6e97e5e2 +# Source-Hash: 48ce215c3be034c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingle thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pipe material" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shingleThickness.1hn5wxr" -msgstr "シングルの厚さ" +msgid "editor.inspector.field.pipeMaterial.1ggc2wy" +msgstr "配管の材料" -# Source-Hash: b14990b3e4222dd3 +# Source-Hash: 75e3449fc1776d09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder extent" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pitch" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shoulderExtent.11j8uiv" -msgstr "ショルダーの範囲" +msgid "editor.inspector.field.pitch.xe6ekx" +msgstr "勾配" -# Source-Hash: 505de343ec5010e6 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shoulderHeight.xyqn6g" -msgstr "ショルダーの高さ" +msgid "editor.inspector.field.position.1quewx6" +msgstr "位置" -# Source-Hash: 58d48c01b7ec1a40 +# Source-Hash: d090baf9f08c2280 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post bracing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shoulderStyle.1hkcv2w" -msgstr "ショルダーのスタイル" +msgid "editor.inspector.field.postBracing.crq8nn" +msgstr "支柱の筋交い" -# Source-Hash: af84db1026bf2e6c +# Source-Hash: 6467b580eed1d333 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show center column" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post cap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.showCenterColumn.1uggg45" -msgstr "中央の柱を表示" +msgid "editor.inspector.field.postCap.1xcvxrv" +msgstr "支柱キャップ" -# Source-Hash: 80214dc086ebc1b1 +# Source-Hash: e1d91cdd16cc6593 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show infill" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.showInfill.33rv7u" -msgstr "充填を表示" +msgid "editor.inspector.field.postCount.22r56c" +msgstr "支柱の数" -# Source-Hash: f02d6cdfb4c6ad08 +# Source-Hash: d6d8b8653cb43624 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show step supports" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post depth" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.showStepSupports.1kg8h8m" -msgstr "段の支持材を表示" +msgid "editor.inspector.field.postDepth.1ko6j1m" +msgstr "支柱の奥行き" -# Source-Hash: 5d1147c774718b76 +# Source-Hash: dd071e84e259ee48 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Side flashing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post inset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.sideFlashing.cv744o" -msgstr "側面の水切り" +msgid "editor.inspector.field.postInset.le36li" +msgstr "支柱の内側オフセット" -# Source-Hash: 60bb3338e0ad558c +# Source-Hash: 88c5d586822e58f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Size" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post layout mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.size.1a4x3zw" -msgstr "サイズ" +msgid "editor.inspector.field.postLayoutMode.16jre62" +msgstr "支柱配置モード" -# Source-Hash: fbdbc6c97c75b030 +# Source-Hash: faa36308c1ecb2a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Skylight type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post size" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.skylightType.1a5vj3i" -msgstr "天窓の種類" +msgid "editor.inspector.field.postSize.1jodxek" +msgstr "支柱のサイズ" -# Source-Hash: c9a6561cb3c3da82 +# Source-Hash: c8e8490c957e01f3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab opening mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.slabOpeningMode.g4f730" -msgstr "スラブ開口のモード" +msgid "editor.inspector.field.postSpacing.voppfi" +msgstr "支柱の間隔" -# Source-Hash: ef0efc845ccdba78 +# Source-Hash: b98cbe8478508d41 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slat gap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post through" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.slatGap.slmk93" -msgstr "スラットの隙間" +msgid "editor.inspector.field.postThrough.1abgu4a" +msgstr "支柱を貫通" -# Source-Hash: 4daab7a2ce2ecef3 +# Source-Hash: d1492df1fbb22c29 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slide direction" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.slideDirection.1527q13" -msgstr "スライド方向" +msgid "editor.inspector.field.postWidth.rk26fz" +msgstr "支柱の幅" -# Source-Hash: 93b34a5b546664c4 +# Source-Hash: 96ad4bd0f7baa40e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Span" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.span.1bmmuw1" -msgstr "スパン" +msgid "editor.inspector.field.profile.1kwlci6" +msgstr "形状" -# Source-Hash: 3b006be0b1f0493f +# Source-Hash: d01cd36d3939abab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Speed" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Projection" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.speed.2w2xwg" -msgstr "速度" +msgid "editor.inspector.field.projection.jhtig0" +msgstr "出" -# Source-Hash: c8cfb8336a240cb1 +# Source-Hash: 800a7a9159519b46 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spin speed" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Purlin height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.spinSpeed.1ozx746" -msgstr "回転速度" +msgid "editor.inspector.field.purlinHeight.eo9cjm" +msgstr "母屋の高さ" -# Source-Hash: c9f54c3b258961c7 +# Source-Hash: da4d0d12715d6c33 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Purlin spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.stairType.1u05e02" -msgstr "階段の種類" +msgid "editor.inspector.field.purlinSpacing.4gbzb2" +msgstr "母屋の間隔" -# Source-Hash: 0af6194a8b8d8be6 +# Source-Hash: b4774bcbdf599812 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standoff" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Purlin width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.standoff.4wv2g0" -msgstr "スタンドオフ" +msgid "editor.inspector.field.purlinWidth.r6tu3j" +msgstr "母屋の幅" -# Source-Hash: 0464d4efa1e80c62 +# Source-Hash: 2a4dd54f8a8c15ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standoff height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafter end inset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.standoffHeight.1qdnff" -msgstr "スタンドオフの高さ" +msgid "editor.inspector.field.rafterEndInset.14c0wy5" +msgstr "垂木端の内側オフセット" -# Source-Hash: 85da28b0b26b8c2a +# Source-Hash: 5a80a11b97c0e043 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start post" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafter height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.startPost.1ood9kv" -msgstr "始端の支柱" +msgid "editor.inspector.field.rafterHeight.1e1n99w" +msgstr "垂木の高さ" -# Source-Hash: d5dc1ba8cca3193d +# Source-Hash: b6348d554660af5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Step count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafter spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.stepCount.nzorrw" -msgstr "段数" +msgid "editor.inspector.field.rafterSpacing.19subc0" +msgstr "垂木の間隔" -# Source-Hash: cadbb9cadd6a5e6f +# Source-Hash: 112c447946c3beaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Strap spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafter width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.strapSpacing.1cyt3dc" -msgstr "バンドの間隔" +msgid "editor.inspector.field.rafterWidth.eksj4t" +msgstr "垂木の幅" -# Source-Hash: c017cd56b3ae5865 +# Source-Hash: 7020d720876a2106 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Strap style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.strapStyle.fh1oy4" -msgstr "バンドのスタイル" +msgid "editor.inspector.field.railingHeight.6wf4bm" +msgstr "手すりの高さ" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: 3e89ce193885b5b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing mode" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.style.nf3vcm" -msgstr "スタイル" +msgid "editor.inspector.field.railingMode.ov7xpu" +msgstr "手すりのモード" -# Source-Hash: 7b3f016989c631a7 +# Source-Hash: 174342bb31a86afc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Suction diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.suctionDiameter.nutxtj" -msgstr "吸入管の直径" +msgid "editor.inspector.field.railingStyle.1nyd2u" +msgstr "手すりのスタイル" -# Source-Hash: 3f1e0fd30e5b1f39 +# Source-Hash: a44eedc895b95474 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Resize lock" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supplyDiameter.h5ldh5" -msgstr "給気の直径" +msgid "editor.inspector.field.resizeLock.b2hbr0" +msgstr "比率を固定" -# Source-Hash: 05c9b608538e181d +# Source-Hash: edd319917231def8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supplyHeight.zy6ru1" -msgstr "給気の高さ" +msgid "editor.inspector.field.returnDiameter.166ozhe" +msgstr "還気の直径" -# Source-Hash: 3c9400722baa474d +# Source-Hash: dafa151b183daa77 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supplyShape.k39wnb" -msgstr "給気の形状" +msgid "editor.inspector.field.returnHeight.b9sq6y" +msgstr "還気の高さ" -# Source-Hash: af7619025438f995 +# Source-Hash: cd55fd029ad2803b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supplyWidth.g66axi" -msgstr "給気の幅" +msgid "editor.inspector.field.returnShape.1e3a27i" +msgstr "還気の形状" -# Source-Hash: 617e198cf3f214d3 +# Source-Hash: 6a7c411667124177 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Support offset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supportOffset.1w4cocr" -msgstr "支持のオフセット" +msgid "editor.inspector.field.returnWidth.z9r3h3" +msgstr "還気の幅" -# Source-Hash: 2686abc093f3dfb1 +# Source-Hash: 460bd11bfc2e5697 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sweep angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right end condition" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.sweepAngle.ucmmlw" -msgstr "スイープ角度" +msgid "editor.inspector.field.rightEndCondition.tjlw3l" +msgstr "右端の条件" -# Source-Hash: 88e6c2e1c344b2fc +# Source-Hash: 1ed35f8d27ae5583 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.system.13qbhrw" -msgstr "システム" +msgid "editor.inspector.field.rightOverhang.yqbeft" +msgstr "右の張り出し" -# Source-Hash: ccb3afc48bd9a284 +# Source-Hash: 39c02aa2d97a62ba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terminal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.terminal.1501knl" -msgstr "端末" +msgid "editor.inspector.field.roofHeight.1uhy6qy" +msgstr "屋根の高さ" -# Source-Hash: de1777c521046f7d +# Source-Hash: d62f8833d77ca8a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terminal type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.terminalType.1ne8lgb" -msgstr "端末の種類" +msgid "editor.inspector.field.roofStyle.pawqfy" +msgstr "屋根のスタイル" -# Source-Hash: fdbb503f0941bd56 +# Source-Hash: 0ddd561a4126b826 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.thickness.1l8hu45" -msgstr "厚さ" +msgid "editor.inspector.field.roofThickness.1xlr3rx" +msgstr "屋根の厚さ" -# Source-Hash: 58cb60c14826f1d0 +# Source-Hash: 3a08ede9e51d5395 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilt angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.tiltAngle.1312yw1" -msgstr "傾斜角度" +msgid "editor.inspector.field.roofType.1m9kv5h" +msgstr "屋根の種類" -# Source-Hash: 7057972ff4c78dc7 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "To level id" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.toLevelId.8i5qx7" -msgstr "終了階層 ID" +msgid "editor.inspector.field.rotation.ly2rj" +msgstr "回転" -# Source-Hash: fa8fc3d5c612e774 +# Source-Hash: c913b494c3901a17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top landing depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rows" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.topLandingDepth.ki7gk2" -msgstr "上部の踊り場の奥行き" +msgid "editor.inspector.field.rows.1ba1neg" +msgstr "行" -# Source-Hash: 6e4a0b98089ec2cd +# Source-Hash: 8210f376c0d29acc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top landing mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scale" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.topLandingMode.zk0h7e" -msgstr "上部の踊り場のモード" +msgid "editor.inspector.field.scale.b6rpxt" +msgstr "縮尺" -# Source-Hash: c182bb3c8a701085 +# Source-Hash: adb6face4bac5245 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top rail height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Seam detail" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.topRailHeight.fscisv" -msgstr "上部レールの高さ" +msgid "editor.inspector.field.seamDetail.197za48" +msgstr "継ぎ目の詳細" -# Source-Hash: 8c5502f1d8087b7b +# Source-Hash: 4b2aed9d56cc4dee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transition mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segment type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.transitionMode.f3evgt" -msgstr "トランジションのモード" +msgid "editor.inspector.field.segmentType.l667sy" +msgstr "セグメントの種類" -# Source-Hash: 96eb5997f0aa2dde +# Source-Hash: a7794a81141b4de4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transition width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.transitionWidth.rtgz3m" -msgstr "トランジションの幅" +msgid "editor.inspector.field.shaftStyle.1i5ampa" +msgstr "シャフトのスタイル" -# Source-Hash: 812d27902509339f +# Source-Hash: 8eb6438543b18cdb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vane count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft wall thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.vaneCount.55vtye" -msgstr "羽根の数" +msgid "editor.inspector.field.shaftWallThickness.bduslr" +msgstr "シャフト壁の厚さ" -# Source-Hash: 1e7dcd717c8ac239 +# Source-Hash: 85ea1d3c8b749680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.wallHeight.18vmh5c" -msgstr "壁の高さ" +msgid "editor.inspector.field.shape.iq9t52" +msgstr "形状" -# Source-Hash: f14bdaed6101896a +# Source-Hash: 44a8ab89c854cad1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall shell" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape2" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.wallShell.vqsyhv" -msgstr "壁の外殻" +msgid "editor.inspector.field.shape2.fi0nx8" +msgstr "形状2" -# Source-Hash: 801268585c9a679b +# Source-Hash: fcee9712879570ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall skirt height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed high side" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.wallSkirtHeight.1uea2ad" -msgstr "腰壁の高さ" +msgid "editor.inspector.field.shedHighSide.bzzddg" +msgstr "片流れの高い側" -# Source-Hash: 6b377d0ba1565477 +# Source-Hash: f5a931cd6e97e5e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingle thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.wallThickness.17wn4iv" -msgstr "壁の厚さ" +msgid "editor.inspector.field.shingleThickness.1hn5wxr" +msgstr "シングルの厚さ" -# Source-Hash: 3a0ccd6c46877a87 +# Source-Hash: b14990b3e4222dd3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder extent" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.width.gfxz9b" -msgstr "幅" +msgid "editor.inspector.field.shoulderExtent.11j8uiv" +msgstr "ショルダーの範囲" -# Source-Hash: de05070474f589b4 +# Source-Hash: 505de343ec5010e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width2" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.width2.1nqawvr" -msgstr "幅2" +msgid "editor.inspector.field.shoulderHeight.xyqn6g" +msgstr "ショルダーの高さ" -# Source-Hash: 6199b641888a83fa +# Source-Hash: 58d48c01b7ec1a40 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "With back" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.withBack.1ay8nus" -msgstr "背板付き" +msgid "editor.inspector.field.shoulderStyle.1hkcv2w" +msgstr "ショルダーのスタイル" -# Source-Hash: 699934d8b9571b64 +# Source-Hash: af84db1026bf2e6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "With bottom" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show center column" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.withBottom.1x1z1vo" -msgstr "底板付き" +msgid "editor.inspector.field.showCenterColumn.1uggg45" +msgstr "中央の柱を表示" -# Source-Hash: 03987b9aadaab50f +# Source-Hash: 80214dc086ebc1b1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "With sides" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show infill" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.withSides.uq066x" -msgstr "側板付き" +msgid "editor.inspector.field.showInfill.33rv7u" +msgstr "充填を表示" -# Source-Hash: f571cb2d06ae01ae +# Source-Hash: f02d6cdfb4c6ad08 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Advanced" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show step supports" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.advanced.qwfkor" -msgstr "詳細" +msgid "editor.inspector.field.showStepSupports.1kg8h8m" +msgstr "段の支持材を表示" -# Source-Hash: a886619d15bae47e +# Source-Hash: 5d1147c774718b76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Air" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Side flashing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.air.15jotdj" -msgstr "空気" +msgid "editor.inspector.field.sideFlashing.cv744o" +msgstr "側面の水切り" -# Source-Hash: b69fc1f8128958fc +# Source-Hash: 60bb3338e0ad558c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Appearance" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Size" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.appearance.dli9wf" -msgstr "外観" +msgid "editor.inspector.field.size.1a4x3zw" +msgstr "サイズ" -# Source-Hash: faaa4f6b40001667 +# Source-Hash: fbdbc6c97c75b030 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Body" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Skylight type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.body.ign4wl" -msgstr "本体" +msgid "editor.inspector.field.skylightType.1a5vj3i" +msgstr "天窓の種類" -# Source-Hash: fdf7108a011bd94b +# Source-Hash: c9a6561cb3c3da82 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cab" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab opening mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.cab.o4z1ox" -msgstr "かご" +msgid "editor.inspector.field.slabOpeningMode.g4f730" +msgstr "スラブ開口のモード" -# Source-Hash: 5737c4567e0f6863 +# Source-Hash: ef0efc845ccdba78 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slat gap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.cabinet.rzvymr" -msgstr "キャビネット" +msgid "editor.inspector.field.slatGap.slmk93" +msgstr "スラットの隙間" -# Source-Hash: d52b53241789ee63 +# Source-Hash: 4daab7a2ce2ecef3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slide direction" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.cap.s0thej" -msgstr "キャップ" +msgid "editor.inspector.field.slideDirection.1527q13" +msgstr "スライド方向" -# Source-Hash: 93a545688c917e69 +# Source-Hash: 93b34a5b546664c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Span" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.collar.1am2iqo" -msgstr "カラー" +msgid "editor.inspector.field.span.1bmmuw1" +msgstr "スパン" -# Source-Hash: 7a9c55b1c5a6e61d +# Source-Hash: 3b006be0b1f0493f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connection" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Speed" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.connection.2r1h4p" -msgstr "接続" +msgid "editor.inspector.field.speed.2w2xwg" +msgstr "速度" -# Source-Hash: d613df280aa13b42 +# Source-Hash: c8cfb8336a240cb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connections" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spin speed" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.connections.ai4w8u" -msgstr "接続" +msgid "editor.inspector.field.spinSpeed.1ozx746" +msgstr "回転速度" -# Source-Hash: ce1429556f57d7ee +# Source-Hash: c9f54c3b258961c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Construction" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.construction.j6p9kc" -msgstr "構造" +msgid "editor.inspector.field.stairType.1u05e02" +msgstr "階段の種類" -# Source-Hash: f8ba7d73d3006d57 +# Source-Hash: 0af6194a8b8d8be6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standoff" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.cricket.6iwg8g" -msgstr "クリケット" +msgid "editor.inspector.field.standoff.4wv2g0" +msgstr "スタンドオフ" -# Source-Hash: b8ff053666ee326b +# Source-Hash: 0464d4efa1e80c62 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curb" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standoff height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.curb.5xi2ol" -msgstr "立ち上がり" +msgid "editor.inspector.field.standoffHeight.1qdnff" +msgstr "スタンドオフの高さ" -# Source-Hash: 3b9c59e996dcc9c5 +# Source-Hash: 85da28b0b26b8c2a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curve points" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start post" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.curvePoints.ztdcnn" -msgstr "曲線の点" +msgid "editor.inspector.field.startPost.1ood9kv" +msgstr "始端の支柱" -# Source-Hash: 12df69f42beb0643 +# Source-Hash: d5dc1ba8cca3193d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Step count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.dimensions.pewa8g" -msgstr "寸法" +msgid "editor.inspector.field.stepCount.nzorrw" +msgstr "段数" -# Source-Hash: 20f60b98de67849b +# Source-Hash: cadbb9cadd6a5e6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Doors" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Strap spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.doors.18w2kpa" -msgstr "ドア" +msgid "editor.inspector.field.strapSpacing.1cyt3dc" +msgstr "バンドの間隔" -# Source-Hash: 6b6f8068bbc4c902 +# Source-Hash: c017cd56b3ae5865 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dormer" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Strap style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.dormer.1fjs5tq" -msgstr "ドーマー" +msgid "editor.inspector.field.strapStyle.fh1oy4" +msgstr "バンドのスタイル" -# Source-Hash: cda262793b4cc754 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dormer roof" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.dormerRoof.u9uy2g" -msgstr "ドーマー屋根" - -# Source-Hash: 00a4416e0a33d856 +msgid "editor.inspector.field.style.nf3vcm" +msgstr "スタイル" + +# Source-Hash: 7b3f016989c631a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drainage" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Suction diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.drainage.7easy0" -msgstr "排水" +msgid "editor.inspector.field.suctionDiameter.nutxtj" +msgstr "吸入管の直径" -# Source-Hash: 8a3bc5111b9e97f4 +# Source-Hash: 3f1e0fd30e5b1f39 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.elevation.4jbp44" -msgstr "高さ" +msgid "editor.inspector.field.supplyDiameter.h5ldh5" +msgstr "給気の直径" -# Source-Hash: a9cba06250228a55 +# Source-Hash: 05c9b608538e181d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End caps" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.endCaps.4fsb5b" -msgstr "エンドキャップ" +msgid "editor.inspector.field.supplyHeight.zy6ru1" +msgstr "給気の高さ" -# Source-Hash: 228f2206862e41cf +# Source-Hash: 3c9400722baa474d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equipment" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.equipment.1xtq0ev" -msgstr "機器" +msgid "editor.inspector.field.supplyShape.k39wnb" +msgstr "給気の形状" -# Source-Hash: a19276baa3688cbf +# Source-Hash: af7619025438f995 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Face" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.face.1531fr0" -msgstr "面" +msgid "editor.inspector.field.supplyWidth.g66axi" +msgstr "給気の幅" -# Source-Hash: fb34ee7c59cb84ac +# Source-Hash: 617e198cf3f214d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fitting" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Support offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.fitting.171z1r4" -msgstr "継手" +msgid "editor.inspector.field.supportOffset.1w4cocr" +msgstr "支持のオフセット" -# Source-Hash: f817c09ef0bb6d69 +# Source-Hash: 2686abc093f3dfb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flues" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sweep angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.flues.nq6pye" -msgstr "煙道" +msgid "editor.inspector.field.sweepAngle.ucmmlw" +msgstr "スイープ角度" -# Source-Hash: a3c10560fa3c1612 +# Source-Hash: 88e6c2e1c344b2fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Footprint" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.footprint.g8q2pg" -msgstr "フットプリント" +msgid "editor.inspector.field.system.13qbhrw" +msgstr "システム" -# Source-Hash: ce3a6c03765dbbd8 +# Source-Hash: ccb3afc48bd9a284 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terminal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.frame.q7q9fq" -msgstr "枠" +msgid "editor.inspector.field.terminal.1501knl" +msgstr "端末" -# Source-Hash: 523b9912e283b644 +# Source-Hash: de1777c521046f7d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Geometry" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terminal type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.geometry.a21os1" -msgstr "ジオメトリ" +msgid "editor.inspector.field.terminalType.1ne8lgb" +msgstr "端末の種類" -# Source-Hash: 7e4a0a38f694be6b +# Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.grid.d8gwxd" -msgstr "グリッド" +msgid "editor.inspector.field.thickness.1l8hu45" +msgstr "厚さ" -# Source-Hash: 30d8dba84c42040e +# Source-Hash: 58cb60c14826f1d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hangers" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilt angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.hangers.agnfzn" -msgstr "吊り金具" +msgid "editor.inspector.field.tiltAngle.1312yw1" +msgstr "傾斜角度" -# Source-Hash: 8c1bc3a078056ff7 +# Source-Hash: 7057972ff4c78dc7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hardware" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "To level id" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.hardware.1nygwm1" -msgstr "金物" +msgid "editor.inspector.field.toLevelId.8i5qx7" +msgstr "終了階層 ID" -# Source-Hash: 2a47557eb4a5f766 +# Source-Hash: fa8fc3d5c612e774 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hung wall" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top landing depth" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.hungWall.1ftr1gz" -msgstr "吊り壁" +msgid "editor.inspector.field.topLandingDepth.ki7gk2" +msgstr "上部の踊り場の奥行き" -# Source-Hash: 7d6ed24c02ab0c5c +# Source-Hash: 6e4a0b98089ec2cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Insulation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top landing mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.insulation.1kyo5e7" -msgstr "断熱材" +msgid "editor.inspector.field.topLandingMode.zk0h7e" +msgstr "上部の踊り場のモード" -# Source-Hash: d4c6c2495c233bb5 +# Source-Hash: c182bb3c8a701085 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top rail height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.lantern.1h7o2xb" -msgstr "ランタン" +msgid "editor.inspector.field.topRailHeight.fscisv" +msgstr "上部レールの高さ" -# Source-Hash: cc3d601d59e2e26c +# Source-Hash: 8c5502f1d8087b7b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Levels" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transition mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.levels.1s6yaru" -msgstr "階層" +msgid "editor.inspector.field.transitionMode.f3evgt" +msgstr "トランジションのモード" -# Source-Hash: 1a849e52a46d5087 +# Source-Hash: 96eb5997f0aa2dde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Line" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transition width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.line.166mv5z" -msgstr "線" +msgid "editor.inspector.field.transitionWidth.rtgz3m" +msgstr "トランジションの幅" -# Source-Hash: 9ab4f7a738ebee13 +# Source-Hash: 812d27902509339f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lines" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vane count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.lines.12bghr0" -msgstr "線" +msgid "editor.inspector.field.vaneCount.55vtye" +msgstr "羽根の数" -# Source-Hash: c0ff16d77ebc9593 +# Source-Hash: 1e7dcd717c8ac239 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Motion" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.motion.1be7sjr" -msgstr "動き" +msgid "editor.inspector.field.wallHeight.18vmh5c" +msgstr "壁の高さ" -# Source-Hash: 81d365ccef73068c +# Source-Hash: f14bdaed6101896a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall shell" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.mounting.feutd2" -msgstr "取り付け方法" +msgid "editor.inspector.field.wallShell.vqsyhv" +msgstr "壁の外殻" -# Source-Hash: e04298381837252f +# Source-Hash: 801268585c9a679b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall skirt height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.opening.dfet3" -msgstr "開口" +msgid "editor.inspector.field.wallSkirtHeight.1uea2ad" +msgstr "腰壁の高さ" -# Source-Hash: f46314c54627858d +# Source-Hash: 6b377d0ba1565477 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel dimensions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.panelDimensions.b59qe6" -msgstr "パネルの寸法" +msgid "editor.inspector.field.wallThickness.17wn4iv" +msgstr "壁の厚さ" -# Source-Hash: 4712c449e9a42d3b +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern distribution" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.patternDistribution.fmam51" -msgstr "パターンの配分" +msgid "editor.inspector.field.width.gfxz9b" +msgstr "幅" -# Source-Hash: b3be684ac62fbf53 +# Source-Hash: de05070474f589b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width2" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.placement.13lcvts" -msgstr "配置" +msgid "editor.inspector.field.width2.1nqawvr" +msgstr "幅2" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: 6199b641888a83fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "With back" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.position.1quewx6" -msgstr "位置" +msgid "editor.inspector.field.withBack.1ay8nus" +msgstr "背板付き" -# Source-Hash: 96ad4bd0f7baa40e +# Source-Hash: 699934d8b9571b64 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "With bottom" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.profile.1kwlci6" -msgstr "形状" +msgid "editor.inspector.field.withBottom.1x1z1vo" +msgstr "底板付き" -# Source-Hash: 240ed9c77627b9a1 +# Source-Hash: 03987b9aadaab50f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "With sides" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.railing.19a5bnr" -msgstr "手すり" +msgid "editor.inspector.field.withSides.uq066x" +msgstr "側板付き" -# Source-Hash: 2e0aa7113b021c67 +# Source-Hash: f571cb2d06ae01ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Advanced" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.return.1klrjrz" -msgstr "還気" +msgid "editor.inspector.group.advanced.qwfkor" +msgstr "詳細" -# Source-Hash: 83909f82446ee9c3 +# Source-Hash: a886619d15bae47e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Settings" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Air" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.settings.ktdb8o" -msgstr "設定" +msgid "editor.inspector.group.air.15jotdj" +msgstr "空気" -# Source-Hash: 4fc63ad21de30103 +# Source-Hash: b69fc1f8128958fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Appearance" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.shaft.mad9cv" -msgstr "シャフト" +msgid "editor.inspector.group.appearance.dli9wf" +msgstr "外観" -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: faaa4f6b40001667 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Body" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.shape.iq9t52" -msgstr "形状" +msgid "editor.inspector.group.body.ign4wl" +msgstr "本体" -# Source-Hash: 8c6e3985459dacf9 +# Source-Hash: fdf7108a011bd94b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cab" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.shoulder.1nyfx25" -msgstr "ショルダー" +msgid "editor.inspector.group.cab.o4z1ox" +msgstr "かご" -# Source-Hash: 60bb3338e0ad558c +# Source-Hash: 5737c4567e0f6863 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Size" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.size.1a4x3zw" -msgstr "サイズ" +msgid "editor.inspector.group.cabinet.rzvymr" +msgstr "キャビネット" -# Source-Hash: a20c89205a4448d2 +# Source-Hash: d52b53241789ee63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.structure.gezdra" -msgstr "構造" +msgid "editor.inspector.group.cap.s0thej" +msgstr "キャップ" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: 93a545688c917e69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.style.nf3vcm" -msgstr "スタイル" +msgid "editor.inspector.group.collar.1am2iqo" +msgstr "カラー" -# Source-Hash: b45f382a67d6c0eb +# Source-Hash: 7a9c55b1c5a6e61d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connection" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.supply.1oy2zwu" -msgstr "給気" +msgid "editor.inspector.group.connection.2r1h4p" +msgstr "接続" -# Source-Hash: 78a454b7ac7a3cd9 +# Source-Hash: d613df280aa13b42 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connections" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.surface.wtamqk" -msgstr "面" +msgid "editor.inspector.group.connections.ai4w8u" +msgstr "接続" -# Source-Hash: ccb3afc48bd9a284 +# Source-Hash: ce1429556f57d7ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terminal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Construction" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.terminal.1501knl" -msgstr "端末" +msgid "editor.inspector.group.construction.j6p9kc" +msgstr "構造" -# Source-Hash: 399fc3e62f491f08 +# Source-Hash: f8ba7d73d3006d57 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Topology" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.topology.18t8dyc" -msgstr "トポロジー" +msgid "editor.inspector.group.cricket.6iwg8g" +msgstr "クリケット" -# Source-Hash: f425799b82e085ed +# Source-Hash: b8ff053666ee326b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transform" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curb" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.transform.1c55ayj" -msgstr "変形" +msgid "editor.inspector.group.curb.5xi2ol" +msgstr "立ち上がり" -# Source-Hash: b778a315e82065a0 +# Source-Hash: 3b9c59e996dcc9c5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curve points" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.trap.1qc7vhe" -msgstr "トラップ" +msgid "editor.inspector.group.curvePoints.ztdcnn" +msgstr "曲線の点" -# Source-Hash: c44f7ab8bbd24858 +# Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.type.1m2zofh" -msgstr "種類" +msgid "editor.inspector.group.dimensions.pewa8g" +msgstr "寸法" -# Source-Hash: c8fd17853839516f +# Source-Hash: 20f60b98de67849b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Abs" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Doors" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.abs.132mz8b" -msgstr "ABS" +msgid "editor.inspector.group.doors.18w2kpa" +msgstr "ドア" -# Source-Hash: fd9eb1a16cb6b996 +# Source-Hash: 6b6f8068bbc4c902 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Access panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dormer" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.accessPanel.13sptb5" -msgstr "点検口" +msgid "editor.inspector.group.dormer.1fjs5tq" +msgstr "ドーマー" -# Source-Hash: db8064add8c27a5c +# Source-Hash: cda262793b4cc754 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Air handler" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dormer roof" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.airHandler.1crnyg3" -msgstr "エアハンドラー" +msgid "editor.inspector.group.dormerRoof.u9uy2g" +msgstr "ドーマー屋根" -# Source-Hash: d8234782848be927 +# Source-Hash: 00a4416e0a33d856 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Alternating" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drainage" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.alternating.5jashi" -msgstr "交互" +msgid "editor.inspector.group.drainage.7easy0" +msgstr "排水" -# Source-Hash: 63cbda7b09662368 +# Source-Hash: 8a3bc5111b9e97f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arched" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.arched.14188w0" -msgstr "アーチ型" +msgid "editor.inspector.group.elevation.4jbp44" +msgstr "高さ" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: a9cba06250228a55 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End caps" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.auto.540b06" -msgstr "自動" +msgid "editor.inspector.group.endCaps.4fsb5b" +msgstr "エンドキャップ" -# Source-Hash: d18036b75b2c3e4f +# Source-Hash: 228f2206862e41cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Automatic" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equipment" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.automatic.r122ro" -msgstr "自動" +msgid "editor.inspector.group.equipment.1xtq0ev" +msgstr "機器" -# Source-Hash: 7ceade8f25b58fe9 +# Source-Hash: a19276baa3688cbf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Face" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.back.1hzmxtu" -msgstr "戻る" +msgid "editor.inspector.group.face.1531fr0" +msgstr "面" -# Source-Hash: 3eda29328f91485d +# Source-Hash: fb34ee7c59cb84ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Balusters" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fitting" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.balusters.1j3w6ng" -msgstr "手すり子" +msgid "editor.inspector.group.fitting.171z1r4" +msgstr "継手" -# Source-Hash: f211248ec8619e4c +# Source-Hash: f817c09ef0bb6d69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Band" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flues" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.band.160umau" -msgstr "帯" +msgid "editor.inspector.group.flues.nq6pye" +msgstr "煙道" -# Source-Hash: 8f9ff05c6a3b08a6 +# Source-Hash: a3c10560fa3c1612 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base plate" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Footprint" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.basePlate.17fcg8k" -msgstr "ベースプレート" +msgid "editor.inspector.group.footprint.g8q2pg" +msgstr "フットプリント" -# Source-Hash: 19ae2360207ecf5a +# Source-Hash: ce3a6c03765dbbd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Boards" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.boards.u14hig" -msgstr "板" +msgid "editor.inspector.group.frame.q7q9fq" +msgstr "枠" -# Source-Hash: c0fee00bdfb09d37 +# Source-Hash: 523b9912e283b644 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bookshelf" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Geometry" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.bookshelf.ls0zqk" -msgstr "本棚" +msgid "editor.inspector.group.geometry.a21os1" +msgstr "ジオメトリ" -# Source-Hash: 69578b7dd7723fa1 +# Source-Hash: 7e4a0a38f694be6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Both" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.both.mkyb42" -msgstr "両方" +msgid "editor.inspector.group.grid.d8gwxd" +msgstr "グリッド" -# Source-Hash: b3a163b453896bef +# Source-Hash: 30d8dba84c42040e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hangers" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.bottom.9mpruy" -msgstr "下" +msgid "editor.inspector.group.hangers.agnfzn" +msgstr "吊り金具" -# Source-Hash: e9a89a5e4ac8cd61 +# Source-Hash: 8c1bc3a078056ff7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hardware" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.box.1nbjcuq" -msgstr "ボックス" +msgid "editor.inspector.group.hardware.1nygwm1" +msgstr "金物" -# Source-Hash: 2c2815df4f724abe +# Source-Hash: 2a47557eb4a5f766 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Break" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hung wall" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.break.17spnvc" -msgstr "分割" +msgid "editor.inspector.group.hungWall.1ftr1gz" +msgstr "吊り壁" -# Source-Hash: 0d5a25303d3d8058 +# Source-Hash: 7d6ed24c02ab0c5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Butterfly" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.butterfly.pvv0g4" -msgstr "バタフライ" +msgid "editor.inspector.group.insulation.1kyo5e7" +msgstr "断熱材" -# Source-Hash: 5e2429ced8144ab4 +# Source-Hash: d4c6c2495c233bb5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cable" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cable.fp50zq" -msgstr "ケーブル" +msgid "editor.inspector.group.lantern.1h7o2xb" +msgstr "ランタン" -# Source-Hash: 69129e514347672a +# Source-Hash: cc3d601d59e2e26c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cast iron" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Levels" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.castIron.1q2z4qk" -msgstr "鋳鉄" +msgid "editor.inspector.group.levels.1s6yaru" +msgstr "階層" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: 1a849e52a46d5087 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Line" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.ceiling.1t2zaqo" -msgstr "天井" +msgid "editor.inspector.group.line.166mv5z" +msgstr "線" -# Source-Hash: 5211341ed18f33f6 +# Source-Hash: 9ab4f7a738ebee13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lines" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.center.kzdxno" -msgstr "中央" +msgid "editor.inspector.group.lines.12bghr0" +msgstr "線" -# Source-Hash: 65f410261609060b +# Source-Hash: c0ff16d77ebc9593 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center opening" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Motion" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.centerOpening.bn1rvw" -msgstr "中央開き" +msgid "editor.inspector.group.motion.1be7sjr" +msgstr "動き" -# Source-Hash: cf5f9756cc866f3e +# Source-Hash: 81d365ccef73068c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cleanout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cleanout.lww8bm" -msgstr "掃除口" +msgid "editor.inspector.group.mounting.feutd2" +msgstr "取り付け方法" -# Source-Hash: e71d1d949f1d1b41 +# Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Concrete pad" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.concretePad.m1zdij" -msgstr "コンクリートパッド" +msgid "editor.inspector.group.opening.dfet3" +msgstr "開口" -# Source-Hash: a3804c4f5e6aefbc +# Source-Hash: f46314c54627858d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Condenser" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel dimensions" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.condenser.a74nps" -msgstr "室外機" +msgid "editor.inspector.group.panelDimensions.b59qe6" +msgstr "パネルの寸法" -# Source-Hash: 6786ac75cbe9af57 +# Source-Hash: 4712c449e9a42d3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corbeled" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern distribution" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.corbeled.bovs4v" -msgstr "持ち送り" +msgid "editor.inspector.group.patternDistribution.fmam51" +msgstr "パターンの配分" -# Source-Hash: 8a4beb9a57edc26e +# Source-Hash: b3be684ac62fbf53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.count.1qoi4r8" -msgstr "数" +msgid "editor.inspector.group.placement.13lcvts" +msgstr "配置" -# Source-Hash: db1f8f141714b363 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Coupling" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.coupling.111aap2" -msgstr "カップリング" +msgid "editor.inspector.group.position.1quewx6" +msgstr "位置" -# Source-Hash: 7a9a92d2e59a3bbc +# Source-Hash: 96ad4bd0f7baa40e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Covering specific" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.coveringSpecific.1h9fo8w" -msgstr "仕上げ固有" +msgid "editor.inspector.group.profile.1kwlci6" +msgstr "形状" -# Source-Hash: d500c4b7827d3390 +# Source-Hash: 240ed9c77627b9a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cross" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cross.1elubzv" -msgstr "クロス" +msgid "editor.inspector.group.railing.19a5bnr" +msgstr "手すり" -# Source-Hash: 7ca7f00b3ba531f4 +# Source-Hash: 2e0aa7113b021c67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cubby" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cubby.ivq4qc" -msgstr "小物入れ" +msgid "editor.inspector.group.return.1klrjrz" +msgstr "還気" -# Source-Hash: a028e08962c388e0 +# Source-Hash: 83909f82446ee9c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curved" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Settings" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.curved.6noz1s" -msgstr "曲線" +msgid "editor.inspector.group.settings.ktdb8o" +msgstr "設定" -# Source-Hash: c65f02bcdc3231d6 +# Source-Hash: 4fc63ad21de30103 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cylinder" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cylinder.eol6vj" -msgstr "円柱" +msgid "editor.inspector.group.shaft.mad9cv" +msgstr "シャフト" -# Source-Hash: 53f224e2828d5ab7 +# Source-Hash: 85ea1d3c8b749680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Damper" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.damper.wgri80" -msgstr "ダンパー" +msgid "editor.inspector.group.shape.iq9t52" +msgstr "形状" -# Source-Hash: 748877ae309c313c +# Source-Hash: 8c6e3985459dacf9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Destination" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.destination.gfzm1r" -msgstr "接続先" +msgid "editor.inspector.group.shoulder.1nyfx25" +msgstr "ショルダー" -# Source-Hash: bfb3561e28d92a39 +# Source-Hash: 60bb3338e0ad558c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diffuser" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Size" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.diffuser.1igj0jh" -msgstr "ディフューザー" +msgid "editor.inspector.group.size.1a4x3zw" +msgstr "サイズ" -# Source-Hash: 6cff941e10ff22b3 +# Source-Hash: a20c89205a4448d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dog ear" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.dogEar.xhtvjt" -msgstr "ドッグイヤー" +msgid "editor.inspector.group.structure.gezdra" +msgstr "構造" -# Source-Hash: de47e23eb81efe02 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dome" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.dome.1c87e56" -msgstr "ドーム" +msgid "editor.inspector.group.style.nf3vcm" +msgstr "スタイル" -# Source-Hash: 3cd71355956a1821 +# Source-Hash: b45f382a67d6c0eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.double.13h5354" -msgstr "両開き" +msgid "editor.inspector.group.supply.1oy2zwu" +msgstr "給気" -# Source-Hash: 72a84a9762461745 +# Source-Hash: 78a454b7ac7a3cd9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct board" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.ductBoard.lc3o4t" -msgstr "ダクトボード" +msgid "editor.inspector.group.surface.wtamqk" +msgstr "面" -# Source-Hash: 6949d667043bee0b +# Source-Hash: ccb3afc48bd9a284 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terminal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.dutch.1djx429" -msgstr "入母屋" +msgid "editor.inspector.group.terminal.1501knl" +msgstr "端末" -# Source-Hash: e6637bddef6aabd6 +# Source-Hash: 399fc3e62f491f08 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elbow" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Topology" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.elbow.1flup74" -msgstr "エルボ" +msgid "editor.inspector.group.topology.18t8dyc" +msgstr "トポロジー" -# Source-Hash: 135874d189176d13 +# Source-Hash: f425799b82e085ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transform" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.end.1llf32i" -msgstr "終点" +msgid "editor.inspector.group.transform.1c55ayj" +msgstr "変形" -# Source-Hash: ada9fc2eec2c7d61 +# Source-Hash: b778a315e82065a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End cap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.endCap.1p4v4na" -msgstr "エンドキャップ" +msgid "editor.inspector.group.trap.1qc7vhe" +msgstr "トラップ" -# Source-Hash: 73916b8395208874 +# Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equal fit" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.equalFit.11vw52c" -msgstr "均等配置" +msgid "editor.inspector.group.type.1m2zofh" +msgstr "種類" -# Source-Hash: 83579a6e420df2ec +# Source-Hash: c8fd17853839516f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fixed count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Abs" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.fixedCount.1o3dznu" -msgstr "固定数" +msgid "editor.inspector.option.abs.132mz8b" +msgstr "ABS" -# Source-Hash: 4fb65101d0b1a222 +# Source-Hash: fd9eb1a16cb6b996 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fixed spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Access panel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.fixedSpacing.hl4dr4" -msgstr "固定間隔" +msgid "editor.inspector.option.accessPanel.13sptb5" +msgstr "点検口" -# Source-Hash: 9cab4d4c95f63cdd +# Source-Hash: db8064add8c27a5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Air handler" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.flat.ly0bei" -msgstr "陸屋根" +msgid "editor.inspector.option.airHandler.1crnyg3" +msgstr "エアハンドラー" -# Source-Hash: a9cad0badcc16693 +# Source-Hash: d8234782848be927 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flex" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Alternating" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.flex.ktpamq" -msgstr "フレキシブル" +msgid "editor.inspector.option.alternating.5jashi" +msgstr "交互" -# Source-Hash: 7843c5142b7d066d +# Source-Hash: 63cbda7b09662368 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floating" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arched" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.floating.1oadpln" -msgstr "浮き" +msgid "editor.inspector.option.arched.14188w0" +msgstr "アーチ型" -# Source-Hash: d7148fa065bc709b +# Source-Hash: 05b65242d8c48791 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.floor.q9caf1" -msgstr "階" +msgid "editor.inspector.option.auto.540b06" +msgstr "自動" -# Source-Hash: eaaa20f3b603140f +# Source-Hash: d18036b75b2c3e4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flush" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Automatic" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.flush.olwwu5" -msgstr "面一" +msgid "editor.inspector.option.automatic.r122ro" +msgstr "自動" -# Source-Hash: e360f89d3c0ec456 +# Source-Hash: 7ceade8f25b58fe9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.front.uhugl4" -msgstr "前面" +msgid "editor.inspector.option.back.1hzmxtu" +msgstr "戻る" -# Source-Hash: bccfc0565157dae6 +# Source-Hash: 3eda29328f91485d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Furnace" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Balusters" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.furnace.w0mzpf" -msgstr "暖房炉" +msgid "editor.inspector.option.balusters.1j3w6ng" +msgstr "手すり子" -# Source-Hash: deaffa095d126dfe +# Source-Hash: f211248ec8619e4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Band" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.gable.1ekyx6" -msgstr "切妻" +msgid "editor.inspector.option.band.160umau" +msgstr "帯" -# Source-Hash: 7f53d9ffca39984a +# Source-Hash: 8f9ff05c6a3b08a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base plate" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.gambrel.1yo90d9" -msgstr "腰折れ" +msgid "editor.inspector.option.basePlate.17fcg8k" +msgstr "ベースプレート" -# Source-Hash: 3c4900155c96b139 +# Source-Hash: 19ae2360207ecf5a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Generic" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Boards" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.generic.1074oey" -msgstr "汎用" +msgid "editor.inspector.option.boards.u14hig" +msgstr "板" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: c0fee00bdfb09d37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bookshelf" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.glass.163tc5n" -msgstr "ガラス" +msgid "editor.inspector.option.bookshelf.ls0zqk" +msgstr "本棚" -# Source-Hash: 88810658a2b97bc6 +# Source-Hash: 69578b7dd7723fa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass frame" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Both" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.glassFrame.jp9s3m" -msgstr "ガラス枠" +msgid "editor.inspector.option.both.mkyb42" +msgstr "両方" -# Source-Hash: 2d4223f80dc3945c +# Source-Hash: b3a163b453896bef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Globe" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.globe.1avkqoy" -msgstr "グローブ" +msgid "editor.inspector.option.bottom.9mpruy" +msgstr "下" -# Source-Hash: 398af4f45ba60c85 +# Source-Hash: e9a89a5e4ac8cd61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grounded" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.grounded.jwoq73" -msgstr "接地" +msgid "editor.inspector.option.box.1nbjcuq" +msgstr "ボックス" -# Source-Hash: 4972a0e68d69be58 +# Source-Hash: 2c2815df4f724abe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guard" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Break" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.guard.1m575se" -msgstr "手すり壁" +msgid "editor.inspector.option.break.17spnvc" +msgstr "分割" -# Source-Hash: 67be98efb58a7767 +# Source-Hash: 0d5a25303d3d8058 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Half round" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Butterfly" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.halfRound.m5hob0" -msgstr "半丸" +msgid "editor.inspector.option.butterfly.pvv0g4" +msgstr "バタフライ" -# Source-Hash: 229199467e9cf2db +# Source-Hash: 5e2429ced8144ab4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hidden" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cable" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.hidden.gp48rd" -msgstr "非表示" +msgid "editor.inspector.option.cable.fp50zq" +msgstr "ケーブル" -# Source-Hash: 9eda0ea8d447066d +# Source-Hash: 69129e514347672a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hip" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cast iron" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.hip.r0jnjy" -msgstr "寄棟" +msgid "editor.inspector.option.castIron.1q2z4qk" +msgstr "鋳鉄" -# Source-Hash: ac9c79f08ef130a1 +# Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Horizontal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.horizontal.tyapah" -msgstr "水平" +msgid "editor.inspector.option.ceiling.1t2zaqo" +msgstr "天井" -# Source-Hash: 6a9b4142ab179557 +# Source-Hash: 5211341ed18f33f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Include" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.include.1a27vnr" -msgstr "含める" +msgid "editor.inspector.option.center.kzdxno" +msgstr "中央" -# Source-Hash: 8061b426b9d1b5fa +# Source-Hash: 65f410261609060b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Independent high beam" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center opening" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.independentHighBeam.1tn0zvy" -msgstr "独立した高い梁" +msgid "editor.inspector.option.centerOpening.bn1rvw" +msgstr "中央開き" -# Source-Hash: 1dc686f2068f976b +# Source-Hash: cf5f9756cc866f3e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Industrial" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cleanout" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.industrial.8sd9u" -msgstr "インダストリアル" +msgid "editor.inspector.option.cleanout.lww8bm" +msgstr "掃除口" -# Source-Hash: 0c9b1ec8947ee177 +# Source-Hash: e71d1d949f1d1b41 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inline" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Concrete pad" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.inline.1uh05lg" -msgstr "インライン" +msgid "editor.inspector.option.concretePad.m1zdij" +msgstr "コンクリートパッド" -# Source-Hash: 88d5b9ecb242c650 +# Source-Hash: a3804c4f5e6aefbc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Integrated" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Condenser" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.integrated.1xd9lv0" -msgstr "一体型" +msgid "editor.inspector.option.condenser.a74nps" +msgstr "室外機" -# Source-Hash: bb197b9219f32603 +# Source-Hash: 6786ac75cbe9af57 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Joined" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corbeled" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.joined.1x2o8ds" -msgstr "結合済み" - -# Source-Hash: 0299cc0ee05d17fc +msgid "editor.inspector.option.corbeled.bovs4v" +msgstr "持ち送り" + +# Source-Hash: 8a4beb9a57edc26e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kickout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.kickout.vt8s6p" -msgstr "キックアウト" +msgid "editor.inspector.option.count.1qoi4r8" +msgstr "数" -# Source-Hash: a0712c8461bb0758 +# Source-Hash: db1f8f141714b363 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Knee" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Coupling" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.knee.186hcui" -msgstr "ニー" +msgid "editor.inspector.option.coupling.111aap2" +msgstr "カップリング" -# Source-Hash: 083febe9876348ec +# Source-Hash: 7a9a92d2e59a3bbc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "K style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Covering specific" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.kStyle.m8kfwz" -msgstr "K型" +msgid "editor.inspector.option.coveringSpecific.1h9fo8w" +msgstr "仕上げ固有" -# Source-Hash: de9566487b17a73b +# Source-Hash: d500c4b7827d3390 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cross" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.landing.tyqarg" -msgstr "踊り場" +msgid "editor.inspector.option.cross.1elubzv" +msgstr "クロス" -# Source-Hash: d4c6c2495c233bb5 +# Source-Hash: 7ca7f00b3ba531f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cubby" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.lantern.1h7o2xb" -msgstr "ランタン" +msgid "editor.inspector.option.cubby.ivq4qc" +msgstr "小物入れ" -# Source-Hash: 9477f663422698ae +# Source-Hash: a028e08962c388e0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Leave" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curved" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.leave.1xf0sbk" -msgstr "離れる" +msgid "editor.inspector.option.curved.6noz1s" +msgstr "曲線" -# Source-Hash: f365c6b6dd9ebab9 +# Source-Hash: c65f02bcdc3231d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cylinder" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.left.14n06mo" -msgstr "左" +msgid "editor.inspector.option.cylinder.eol6vj" +msgstr "円柱" -# Source-Hash: 0608743fc1736d86 +# Source-Hash: 53f224e2828d5ab7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Damper" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.level.i4lhtp" -msgstr "階層" +msgid "editor.inspector.option.damper.wgri80" +msgstr "ダンパー" -# Source-Hash: a281a83a9fef6b88 +# Source-Hash: 748877ae309c313c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Destination" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.lowProfile.1h9lgzg" -msgstr "ロープロファイル" +msgid "editor.inspector.option.destination.gfzm1r" +msgstr "接続先" -# Source-Hash: 7f7bb0e875af3260 +# Source-Hash: bfb3561e28d92a39 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diffuser" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.mansard.dwzck9" -msgstr "マンサード" +msgid "editor.inspector.option.diffuser.1igj0jh" +msgstr "ディフューザー" -# Source-Hash: 387082cd5f118bed +# Source-Hash: 6cff941e10ff22b3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Manual" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dog ear" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.manual.1wu7r43" -msgstr "手動" +msgid "editor.inspector.option.dogEar.xhtvjt" +msgstr "ドッグイヤー" -# Source-Hash: 321ca5101ab61db7 +# Source-Hash: de47e23eb81efe02 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Maximum spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dome" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.maximumSpacing.n1fzl4" -msgstr "最大間隔" +msgid "editor.inspector.option.dome.1c87e56" +msgstr "ドーム" -# Source-Hash: 8e464a8f52254f27 +# Source-Hash: 3cd71355956a1821 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Metal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.metal.1az9fgc" -msgstr "金属" +msgid "editor.inspector.option.double.13h5354" +msgstr "両開き" -# Source-Hash: c6185ecb219a9435 +# Source-Hash: 72a84a9762461745 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Metal panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct board" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.metalPanel.1xdz476" -msgstr "金属パネル" +msgid "editor.inspector.option.ductBoard.lc3o4t" +msgstr "ダクトボード" -# Source-Hash: 2fd92342f3986843 +# Source-Hash: 6949d667043bee0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Minimal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.minimal.fwmiwg" -msgstr "ミニマル" +msgid "editor.inspector.option.dutch.1djx429" +msgstr "入母屋" -# Source-Hash: 5d8a5912056f83ce +# Source-Hash: e6637bddef6aabd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mono" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elbow" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.mono.oszvd6" -msgstr "片流れ" +msgid "editor.inspector.option.elbow.1flup74" +msgstr "エルボ" -# Source-Hash: f2953d2931e36d0c +# Source-Hash: 135874d189176d13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.none.deku7v" -msgstr "なし" +msgid "editor.inspector.option.end.1llf32i" +msgstr "終点" -# Source-Hash: 7b6e4a6b86ba5112 +# Source-Hash: ada9fc2eec2c7d61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Omit" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End cap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.omit.okcs7w" -msgstr "省略" +msgid "editor.inspector.option.endCap.1p4v4na" +msgstr "エンドキャップ" -# Source-Hash: 3e52f04f92e08070 +# Source-Hash: 73916b8395208874 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equal fit" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.open.n6hn1l" -msgstr "開く" +msgid "editor.inspector.option.equalFit.11vw52c" +msgstr "均等配置" -# Source-Hash: e04298381837252f +# Source-Hash: 83579a6e420df2ec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fixed count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.opening.dfet3" -msgstr "開口" +msgid "editor.inspector.option.fixedCount.1o3dznu" +msgstr "固定数" -# Source-Hash: cc72b9bda6b30b5c +# Source-Hash: 4fb65101d0b1a222 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open rack" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fixed spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.openRack.mvt1x0" -msgstr "オープンラック" +msgid "editor.inspector.option.fixedSpacing.hl4dr4" +msgstr "固定間隔" -# Source-Hash: ed6d7b3dd9d5fc69 +# Source-Hash: 9cab4d4c95f63cdd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Oval" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.oval.1jiqzxx" -msgstr "楕円" +msgid "editor.inspector.option.flat.ly0bei" +msgstr "陸屋根" -# Source-Hash: 9295ddc2805b21e2 +# Source-Hash: a9cad0badcc16693 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flex" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.picket.zyeoy1" -msgstr "ピケット" +msgid "editor.inspector.option.flex.ktpamq" +msgstr "フレキシブル" -# Source-Hash: 180ffb8b75c977aa +# Source-Hash: 7843c5142b7d066d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pointed" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floating" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.pointed.effedk" -msgstr "尖頭" +msgid "editor.inspector.option.floating.1oadpln" +msgstr "浮き" -# Source-Hash: fca7919fb0c0669c +# Source-Hash: d7148fa065bc709b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post and rail" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.postAndRail.lajk2u" -msgstr "支柱とレール" +msgid "editor.inspector.option.floor.q9caf1" +msgstr "階" -# Source-Hash: a78b28a428b27e20 +# Source-Hash: eaaa20f3b603140f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preserve high edge" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flush" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.preserveHighEdge.y6ywf0" -msgstr "高い側を保つ" +msgid "editor.inspector.option.flush.olwwu5" +msgstr "面一" -# Source-Hash: 325c6f53f6dc7634 +# Source-Hash: e360f89d3c0ec456 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preserve low edge" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.preserveLowEdge.196m5pk" -msgstr "低い側を保つ" +msgid "editor.inspector.option.front.uhugl4" +msgstr "前面" -# Source-Hash: 95c0b860d22a62cb +# Source-Hash: bccfc0565157dae6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preserve pitch" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Furnace" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.preservePitch.1uq973r" -msgstr "勾配を保つ" +msgid "editor.inspector.option.furnace.w0mzpf" +msgstr "暖房炉" -# Source-Hash: d4e11841abf22593 +# Source-Hash: deaffa095d126dfe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Privacy" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.privacy.1th4hrb" -msgstr "目隠し" +msgid "editor.inspector.option.gable.1ekyx6" +msgstr "切妻" -# Source-Hash: 1a8c46c7712a83b6 +# Source-Hash: 7f53d9ffca39984a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Purlins" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.purlins.od124c" -msgstr "母屋" +msgid "editor.inspector.option.gambrel.1yo90d9" +msgstr "腰折れ" -# Source-Hash: a9650f6f94de9247 +# Source-Hash: 3c4900155c96b139 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pvc" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Generic" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.pvc.1oc4u2w" -msgstr "PVC" +msgid "editor.inspector.option.generic.1074oey" +msgstr "汎用" -# Source-Hash: 47587b825e9a696b +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pyramid" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.pyramid.17ucsqv" -msgstr "ピラミッド" +msgid "editor.inspector.option.glass.163tc5n" +msgstr "ガラス" -# Source-Hash: a9cb232546779779 +# Source-Hash: 88810658a2b97bc6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafters" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass frame" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.rafters.16tzbby" -msgstr "垂木" +msgid "editor.inspector.option.glassFrame.jp9s3m" +msgstr "ガラス枠" -# Source-Hash: 947eacd2689daced +# Source-Hash: 2d4223f80dc3945c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rail" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Globe" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.rail.39zqc9" -msgstr "レール" +msgid "editor.inspector.option.globe.1avkqoy" +msgstr "グローブ" -# Source-Hash: bd50bd18e682db41 +# Source-Hash: 398af4f45ba60c85 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grounded" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.raised.4kyx9h" -msgstr "上げ" +msgid "editor.inspector.option.grounded.jwoq73" +msgstr "接地" -# Source-Hash: 3b6f225112035fde +# Source-Hash: 4972a0e68d69be58 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rect" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guard" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.rect.tpfvaf" -msgstr "矩形" +msgid "editor.inspector.option.guard.1m575se" +msgstr "手すり壁" -# Source-Hash: 68206f70689b2340 +# Source-Hash: 67be98efb58a7767 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reducer" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Half round" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.reducer.18byt67" -msgstr "レジューサー" +msgid "editor.inspector.option.halfRound.m5hob0" +msgstr "半丸" -# Source-Hash: 2e0aa7113b021c67 +# Source-Hash: 229199467e9cf2db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hidden" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.return.1klrjrz" -msgstr "還気" +msgid "editor.inspector.option.hidden.gp48rd" +msgstr "非表示" -# Source-Hash: 63b39b1681f74fe4 +# Source-Hash: 9eda0ea8d447066d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return grille" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hip" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.returnGrille.r28ncm" -msgstr "還気グリル" +msgid "editor.inspector.option.hip.r0jnjy" +msgstr "寄棟" -# Source-Hash: b34d5ee0f218221d +# Source-Hash: ac9c79f08ef130a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Horizontal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.right.8humpx" -msgstr "右" +msgid "editor.inspector.option.horizontal.tyapah" +msgstr "水平" -# Source-Hash: ad0457800a1f0eb4 +# Source-Hash: 6a9b4142ab179557 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Include" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.round.1vx0wyj" -msgstr "丸" +msgid "editor.inspector.option.include.1a27vnr" +msgstr "含める" -# Source-Hash: fc826da6c99303e6 +# Source-Hash: 8061b426b9d1b5fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rounded" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Independent high beam" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.rounded.199nwpm" -msgstr "角丸" +msgid "editor.inspector.option.independentHighBeam.1tn0zvy" +msgstr "独立した高い梁" -# Source-Hash: dc67a1cdb2482f23 +# Source-Hash: 1dc686f2068f976b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sanitary tee" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Industrial" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.sanitaryTee.oro3d4" -msgstr "排水T字管" +msgid "editor.inspector.option.industrial.8sd9u" +msgstr "インダストリアル" -# Source-Hash: beb3fec22c287185 +# Source-Hash: 0c9b1ec8947ee177 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scalloped" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inline" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.scalloped.1eltba0" -msgstr "スカラップ" +msgid "editor.inspector.option.inline.1uh05lg" +msgstr "インライン" -# Source-Hash: e16f85e4bebfefb1 +# Source-Hash: 88d5b9ecb242c650 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scoop" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Integrated" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.scoop.qy5zdv" -msgstr "スクープ" +msgid "editor.inspector.option.integrated.1xd9lv0" +msgstr "一体型" -# Source-Hash: f9a95d8407fafda4 +# Source-Hash: bb197b9219f32603 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segmented panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Joined" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.segmentedPanel.5r3hwl" -msgstr "分割パネル" +msgid "editor.inspector.option.joined.1x2o8ds" +msgstr "結合済み" -# Source-Hash: c8d0df27faa3feaa +# Source-Hash: 0299cc0ee05d17fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kickout" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.shed.6t994v" -msgstr "片流れ" +msgid "editor.inspector.option.kickout.vt8s6p" +msgstr "キックアウト" -# Source-Hash: 7fbc26cd497cfd12 +# Source-Hash: a0712c8461bb0758 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sheet metal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Knee" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.sheetMetal.l164lv" -msgstr "板金" +msgid "editor.inspector.option.knee.186hcui" +msgstr "ニー" -# Source-Hash: 26e2c261223cbb46 +# Source-Hash: 083febe9876348ec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "K style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.shingle.pfmynh" -msgstr "シングル" +msgid "editor.inspector.option.kStyle.m8kfwz" +msgstr "K型" -# Source-Hash: e9046e9823b400a0 +# Source-Hash: de9566487b17a73b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingled" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.shingled.1nm9inf" -msgstr "シングル葺き" +msgid "editor.inspector.option.landing.tyqarg" +msgstr "踊り場" -# Source-Hash: a05a390ae205fdd8 +# Source-Hash: d4c6c2495c233bb5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Simple" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.simple.12mfu73" -msgstr "シンプル" +msgid "editor.inspector.option.lantern.1h7o2xb" +msgstr "ランタン" -# Source-Hash: 62ab2eb3c775da95 +# Source-Hash: 9477f663422698ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Leave" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.single.1uzxurt" -msgstr "片開き" +msgid "editor.inspector.option.leave.1xf0sbk" +msgstr "離れる" -# Source-Hash: aee3b2bd78c87d0b +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single left" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.singleLeft.1atdh02" -msgstr "片開き(左)" +msgid "editor.inspector.option.left.14n06mo" +msgstr "左" -# Source-Hash: cc43ffbef4ac7ae0 +# Source-Hash: 0608743fc1736d86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single right" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.singleRight.1axbu67" -msgstr "片開き(右)" +msgid "editor.inspector.option.level.i4lhtp" +msgstr "階層" -# Source-Hash: 7672d2764445c110 +# Source-Hash: a281a83a9fef6b88 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slant box" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.slantBox.1ta99vy" -msgstr "斜めボックス" +msgid "editor.inspector.option.lowProfile.1h9lgzg" +msgstr "ロープロファイル" -# Source-Hash: 405e07a8cc2c88e1 +# Source-Hash: 7f7bb0e875af3260 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slat" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.slat.1p9njbz" -msgstr "スラット" +msgid "editor.inspector.option.mansard.dwzck9" +msgstr "マンサード" -# Source-Hash: 18cbc73c5e1590aa +# Source-Hash: 387082cd5f118bed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sliding" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Manual" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.sliding.cd0jox" -msgstr "引き戸" +msgid "editor.inspector.option.manual.1wu7r43" +msgstr "手動" -# Source-Hash: e6d82e606b8c9301 +# Source-Hash: 321ca5101ab61db7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slope" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Maximum spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.slope.1bn2qw" -msgstr "勾配" +msgid "editor.inspector.option.maximumSpacing.n1fzl4" +msgstr "最大間隔" -# Source-Hash: f6998707123fe72d +# Source-Hash: 8e464a8f52254f27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sloped" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Metal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.sloped.lo4sh0" -msgstr "傾斜" +msgid "editor.inspector.option.metal.1az9fgc" +msgstr "金属" -# Source-Hash: ef3e765e692faf4c +# Source-Hash: c6185ecb219a9435 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Metal panel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.solid.o4uy6s" -msgstr "ソリッド" +msgid "editor.inspector.option.metalPanel.1xdz476" +msgstr "金属パネル" -# Source-Hash: 8008b6f17089beaf +# Source-Hash: 2fd92342f3986843 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Minimal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.solidPanel.2yaw62" -msgstr "不透明パネル" +msgid "editor.inspector.option.minimal.fwmiwg" +msgstr "ミニマル" -# Source-Hash: f9a4a870cb3d3c41 +# Source-Hash: 5d8a5912056f83ce # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spiral" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mono" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.spiral.91hcl4" -msgstr "らせん" +msgid "editor.inspector.option.mono.oszvd6" +msgstr "片流れ" -# Source-Hash: beef1cf79388b77b +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Splash" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.splash.1uke4cm" -msgstr "跳ね返り" +msgid "editor.inspector.option.none.deku7v" +msgstr "なし" -# Source-Hash: 324677a79ab15e22 +# Source-Hash: 7b6e4a6b86ba5112 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spread" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Omit" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.spread.1g1zysu" -msgstr "広がり" +msgid "editor.inspector.option.omit.okcs7w" +msgstr "省略" -# Source-Hash: 39287346366fc206 +# Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.square.1xl1lk6" -msgstr "正方形" +msgid "editor.inspector.option.open.n6hn1l" +msgstr "開く" -# Source-Hash: 53d7084bc41c1ad6 +# Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.stair.1xf86e" -msgstr "階段" +msgid "editor.inspector.option.opening.dfet3" +msgstr "開口" -# Source-Hash: d998c212030bc7c2 +# Source-Hash: cc72b9bda6b30b5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open rack" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.standard.vuco" -msgstr "標準" +msgid "editor.inspector.option.openRack.mvt1x0" +msgstr "オープンラック" -# Source-Hash: 0a26a1e61c825660 +# Source-Hash: ed6d7b3dd9d5fc69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Oval" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.start.30xvgf" -msgstr "始点" +msgid "editor.inspector.option.oval.1jiqzxx" +msgstr "楕円" -# Source-Hash: ed3989f23a2d185e +# Source-Hash: 9295ddc2805b21e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Step" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.step.jtn9kf" -msgstr "段" +msgid "editor.inspector.option.picket.zyeoy1" +msgstr "ピケット" -# Source-Hash: 2c6b1cf17a973d67 +# Source-Hash: 180ffb8b75c977aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stepped" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pointed" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.stepped.naxzh0" -msgstr "段状" +msgid "editor.inspector.option.pointed.effedk" +msgstr "尖頭" -# Source-Hash: 4ee35f740730ae87 +# Source-Hash: fca7919fb0c0669c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post and rail" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.straight.lxqbfr" -msgstr "直進" +msgid "editor.inspector.option.postAndRail.lajk2u" +msgstr "支柱とレール" -# Source-Hash: b9b45ac5ba1daeee +# Source-Hash: a78b28a428b27e20 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Strap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preserve high edge" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.strap.14q0ps9" -msgstr "バンド" +msgid "editor.inspector.option.preserveHighEdge.y6ywf0" +msgstr "高い側を保つ" -# Source-Hash: b45f382a67d6c0eb +# Source-Hash: 325c6f53f6dc7634 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preserve low edge" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.supply.1oy2zwu" -msgstr "給気" +msgid "editor.inspector.option.preserveLowEdge.196m5pk" +msgstr "低い側を保つ" -# Source-Hash: 00e7a2b3b2aa36ac +# Source-Hash: 95c0b860d22a62cb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply register" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preserve pitch" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.supplyRegister.1lzdbbn" -msgstr "給気口" +msgid "editor.inspector.option.preservePitch.1uq973r" +msgstr "勾配を保つ" -# Source-Hash: f86f1f22230596b7 +# Source-Hash: d4e11841abf22593 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tapered" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Privacy" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.tapered.3y5blo" -msgstr "テーパー" +msgid "editor.inspector.option.privacy.1th4hrb" +msgstr "目隠し" -# Source-Hash: 5fed23c2217b83fb +# Source-Hash: 1a8c46c7712a83b6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Purlins" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.targetSpacing.14uibc9" -msgstr "目標の間隔" +msgid "editor.inspector.option.purlins.od124c" +msgstr "母屋" -# Source-Hash: f3ceed7f867f090f +# Source-Hash: a9650f6f94de9247 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tee" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pvc" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.tee.7d6tjp" -msgstr "T字管" +msgid "editor.inspector.option.pvc.1oc4u2w" +msgstr "PVC" -# Source-Hash: 787005b26aec58a3 +# Source-Hash: 47587b825e9a696b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilted" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pyramid" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.tilted.6n0u5j" -msgstr "傾斜" +msgid "editor.inspector.option.pyramid.17ucsqv" +msgstr "ピラミッド" -# Source-Hash: 27644f0497fd9849 +# Source-Hash: a9cb232546779779 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafters" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.top.2nypcs" -msgstr "上" +msgid "editor.inspector.option.rafters.16tzbby" +msgstr "垂木" -# Source-Hash: e6657000554dfe53 +# Source-Hash: 947eacd2689daced # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transition" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rail" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.transition.1rziz9e" -msgstr "トランジション" +msgid "editor.inspector.option.rail.39zqc9" +msgstr "レール" -# Source-Hash: 04bc0909a133a7e9 +# Source-Hash: bd50bd18e682db41 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vent" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.vent.xda5j2" -msgstr "換気口" +msgid "editor.inspector.option.raised.4kyx9h" +msgstr "上げ" -# Source-Hash: 7eee9aff0dd520b6 +# Source-Hash: 3b6f225112035fde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walk on" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rect" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.walkOn.1n5sg9l" -msgstr "歩行面" +msgid "editor.inspector.option.rect.tpfvaf" +msgstr "矩形" -# Source-Hash: 2210e5ee50b74dc9 +# Source-Hash: 68206f70689b2340 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reducer" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wall.blj585" -msgstr "壁" +msgid "editor.inspector.option.reducer.18byt67" +msgstr "レジューサー" -# Source-Hash: f3578f7177ad0054 +# Source-Hash: 2e0aa7113b021c67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall abutment" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wallAbutment.lza941" -msgstr "壁との取り合い" +msgid "editor.inspector.option.return.1klrjrz" +msgstr "還気" -# Source-Hash: 8dcf182f91ba3245 +# Source-Hash: 63b39b1681f74fe4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall ledger" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return grille" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wallLedger.5m8ana" -msgstr "壁の受け材" +msgid "editor.inspector.option.returnGrille.r28ncm" +msgstr "還気グリル" -# Source-Hash: 0adda30be5f17975 +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall shelf" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wallShelf.yiozfl" -msgstr "壁棚" +msgid "editor.inspector.option.right.8humpx" +msgstr "右" -# Source-Hash: 29d8590334492601 +# Source-Hash: ad0457800a1f0eb4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waste" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.waste.3xrp79" -msgstr "排水" +msgid "editor.inspector.option.round.1vx0wyj" +msgstr "丸" -# Source-Hash: 00249876bb37079f +# Source-Hash: fc826da6c99303e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wye" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rounded" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wye.14vupc8" -msgstr "Y字管" +msgid "editor.inspector.option.rounded.199nwpm" +msgstr "角丸" -# Source-Hash: 179b025e25f9a091 +# Source-Hash: dc67a1cdb2482f23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collapse" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sanitary tee" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.collapse" -msgstr "折りたたむ" +msgid "editor.inspector.option.sanitaryTee.oro3d4" +msgstr "排水T字管" -# Source-Hash: dbeae4c43f49327f +# Source-Hash: beb3fec22c287185 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling ({area})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scalloped" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.ceiling" -msgstr "天井({area})" +msgid "editor.inspector.option.scalloped.1eltba0" +msgstr "スカラップ" -# Source-Hash: d29165c9d4bfc3cb +# Source-Hash: e16f85e4bebfefb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collection" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scoop" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.collection" -msgstr "コレクション" +msgid "editor.inspector.option.scoop.qy5zdv" +msgstr "スクープ" -# Source-Hash: 8f536b859be662a0 +# Source-Hash: f9a95d8407fafda4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flight ({width}×{length}m)" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segmented panel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.flight" -msgstr "階段({width}×{length}m)" +msgid "editor.inspector.option.segmentedPanel.5r3hwl" +msgstr "分割パネル" -# Source-Hash: 46dcbf4548374073 +# Source-Hash: c8d0df27faa3feaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing ({width}×{length}m)" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.landing" -msgstr "踊り場({width}×{length}m)" +msgid "editor.inspector.option.shed.6t994v" +msgstr "片流れ" -# Source-Hash: 3ea44453fcd08a6e +# Source-Hash: 7fbc26cd497cfd12 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Node" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sheet metal" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.node" -msgstr "ノード" +msgid "editor.inspector.option.sheetMetal.l164lv" +msgstr "板金" -# Source-Hash: 93f3a04e15b6fb49 +# Source-Hash: 26e2c261223cbb46 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof ({count, plural, one {# segment} other {# segments}})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.roof" -msgstr "屋根({count, plural, other {# セグメント}})" +msgid "editor.inspector.option.shingle.pfmynh" +msgstr "シングル" -# Source-Hash: a730fab01c172704 +# Source-Hash: e9046e9823b400a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{roofType, select, hip {Hip} gable {Gable} shed {Shed} gambrel {Gambrel} dutch {Dutch} mansard {Mansard} flat {Flat} conical {Conical} barrel {Barrel} other {Roof}} ({width}×{depth}m)" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingled" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.roofSegment" -msgstr "{roofType, select, hip {寄棟} gable {切妻} shed {片流れ} gambrel {腰折れ} dutch {入母屋} mansard {マンサード} flat {陸屋根} conical {円錐} barrel {ヴォールト} other {屋根}}({width}×{depth}m)" +msgid "editor.inspector.option.shingled.1nm9inf" +msgstr "シングル葺き" -# Source-Hash: 54efcb0756c2f2c1 +# Source-Hash: a05a390ae205fdd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room ({area})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Simple" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.room" -msgstr "部屋({area})" +msgid "editor.inspector.option.simple.12mfu73" +msgstr "シンプル" -# Source-Hash: e38a4b9986a9d21a +# Source-Hash: 62ab2eb3c775da95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab ({area})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.slab" -msgstr "スラブ({area})" +msgid "editor.inspector.option.single.1uzxurt" +msgstr "片開き" -# Source-Hash: 57398365d4b9066f +# Source-Hash: aee3b2bd78c87d0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Staircase ({count, plural, one {# segment} other {# segments}})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single left" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.staircase" -msgstr "階段({count, plural, other {# セグメント}})" +msgid "editor.inspector.option.singleLeft.1atdh02" +msgstr "片開き(左)" -# Source-Hash: a17f8fc29aae896e +# Source-Hash: cc43ffbef4ac7ae0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone ({area})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single right" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.zone" -msgstr "ゾーン({area})" +msgid "editor.inspector.option.singleRight.1axbu67" +msgstr "片開き(右)" -# Source-Hash: 5cabcabb8bc14809 +# Source-Hash: 7672d2764445c110 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Expand" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slant box" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.expand" -msgstr "展開" +msgid "editor.inspector.option.slantBox.1ta99vy" +msgstr "斜めボックス" -# Source-Hash: 6731e9dd94e8b268 +# Source-Hash: 405e07a8cc2c88e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{levelName} options" -#: packages/editor/src/components/ui/floating-level-selector.tsx -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slat" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.levelOptions" -msgstr "{levelName}のオプション" +msgid "editor.inspector.option.slat.1p9njbz" +msgstr "スラット" -# Source-Hash: d6952b4e54d246dd +# Source-Hash: 18cbc73c5e1590aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rename" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sliding" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.rename" -msgstr "名前を変更" +msgid "editor.inspector.option.sliding.cd0jox" +msgstr "引き戸" -# Source-Hash: 21eafa019ad62fea +# Source-Hash: e6d82e606b8c9301 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{role, select, room {Room colour} other {Zone colour}}" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx -#: packages/editor/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slope" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.spaceColour" -msgstr "{role, select, room {部屋の色} other {ゾーンの色}}" +msgid "editor.inspector.option.slope.1bn2qw" +msgstr "勾配" -# Source-Hash: f5de042416a2c04f +# Source-Hash: f6998707123fe72d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unit colour" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sloped" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.unitColour" -msgstr "ユニットの色" +msgid "editor.inspector.option.sloped.lo4sh0" +msgstr "傾斜" -# Source-Hash: c0774c185060fc13 +# Source-Hash: ef3e765e692faf4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.cancel" -msgstr "キャンセル" +msgid "editor.inspector.option.solid.o4uy6s" +msgstr "ソリッド" -# Source-Hash: 07c11e7e4d4681d6 +# Source-Hash: 8008b6f17089beaf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose what to copy from {levelName}." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid panel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.chooseWhatToCopyFromLevel" -msgstr "{levelName}からコピーする内容を選択してください。" +msgid "editor.inspector.option.solidPanel.2yaw62" +msgstr "不透明パネル" -# Source-Hash: 9500d4378a319532 +# Source-Hash: f9a4a870cb3d3c41 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose what to copy from this level." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spiral" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.chooseWhatToCopyFromThisLevel" -msgstr "この階層からコピーする内容を選択してください。" +msgid "editor.inspector.option.spiral.91hcl4" +msgstr "らせん" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: beef1cf79388b77b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Splash" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.duplicate" -msgstr "複製" +msgid "editor.inspector.option.splash.1uke4cm" +msgstr "跳ね返り" -# Source-Hash: a56e3eb43e60b45c +# Source-Hash: 324677a79ab15e22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate Level" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spread" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.duplicateLevel" -msgstr "階層を複製" +msgid "editor.inspector.option.spread.1g1zysu" +msgstr "広がり" -# Source-Hash: e4c6ab1ea473a082 +# Source-Hash: 39287346366fc206 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Everything" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.everything" -msgstr "すべて" +msgid "editor.inspector.option.square.1xl1lk6" +msgstr "正方形" -# Source-Hash: ac3f119e560388ab +# Source-Hash: 53d7084bc41c1ad6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure, finishes, and placed items, without guide references." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureFinishesAndPlacedItemsWithout" -msgstr "構造、仕上げ、配置済みアイテム(ガイド参照を除く)。" +msgid "editor.inspector.option.stair.1xf86e" +msgstr "階段" -# Source-Hash: acbdf968391d5273 +# Source-Hash: d998c212030bc7c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure + furniture" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureFurniture" -msgstr "構造 + 家具" +msgid "editor.inspector.option.standard.vuco" +msgstr "標準" -# Source-Hash: ce682864a140fe75 +# Source-Hash: 0a26a1e61c825660 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure + materials" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureMaterials" -msgstr "構造 + マテリアル" +msgid "editor.inspector.option.start.30xvgf" +msgstr "始点" -# Source-Hash: 5ee44d53847c5ea2 +# Source-Hash: ed3989f23a2d185e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure, materials, furniture, and references." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Step" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureMaterialsFurnitureAndReferences" -msgstr "構造、マテリアル、家具、参照。" +msgid "editor.inspector.option.step.jtn9kf" +msgstr "段" -# Source-Hash: 95aa1b43dbdb3f02 +# Source-Hash: 2c6b1cf17a973d67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure only" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stepped" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureOnly" -msgstr "構造のみ" +msgid "editor.inspector.option.stepped.naxzh0" +msgstr "段状" -# Source-Hash: 2c53b46c9ca9fe2f +# Source-Hash: 4ee35f740730ae87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure with the current material and finish assignments." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureWithTheCurrentMaterialAnd" -msgstr "現在のマテリアルと仕上げの割り当てを含む構造。" +msgid "editor.inspector.option.straight.lxqbfr" +msgstr "直進" -# Source-Hash: 3350e9008eaba15d +# Source-Hash: b9b45ac5ba1daeee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls, slabs, roofs, stairs, windows, and doors without finishes." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Strap" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.wallsSlabsRoofsStairsWindowsAnd" -msgstr "壁、スラブ、屋根、階段、窓、ドア(仕上げなし)。" +msgid "editor.inspector.option.strap.14q0ps9" +msgstr "バンド" -# Source-Hash: 395fd0821b203517 +# Source-Hash: b45f382a67d6c0eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add or remove objects from the selection" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.addOrRemoveObjectsFromThe" -msgstr "選択にオブジェクトを追加・除外" +msgid "editor.inspector.option.supply.1oy2zwu" +msgstr "給気" -# Source-Hash: 8428cb0af9c6d6a0 +# Source-Hash: 00e7a2b3b2aa36ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Adjust one side’s corner radius" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply register" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.adjustOneSideSCornerRadius" -msgstr "片側の角の半径を調整" +msgid "editor.inspector.option.supplyRegister.1lzdbbn" +msgstr "給気口" -# Source-Hash: d63b45c195713993 +# Source-Hash: f86f1f22230596b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear the selection (or click outside)" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tapered" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.clearTheSelectionOrClickOutside" -msgstr "選択を解除(または外側をクリック)" +msgid "editor.inspector.option.tapered.3y5blo" +msgstr "テーパー" -# Source-Hash: 40b1afbeadbd6213 +# Source-Hash: 5fed23c2217b83fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click a handle dot to show move arrows" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target spacing" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.clickAHandleDotToShow" -msgstr "ハンドルの点をクリックして移動矢印を表示" +msgid "editor.inspector.option.targetSpacing.14uibc9" +msgstr "目標の間隔" -# Source-Hash: 0b82a35c71549580 +# Source-Hash: f3ceed7f867f090f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click or drag the selection to move it as one" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tee" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.clickOrDragTheSelectionTo" -msgstr "選択をクリックまたはドラッグしてまとめて移動" +msgid "editor.inspector.option.tee.7d6tjp" +msgstr "T字管" -# Source-Hash: 73a761f393f69cb9 +# Source-Hash: 787005b26aec58a3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click the handle dot to show move + rotate handles" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilted" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.clickTheHandleDotToShow" -msgstr "ハンドルの点をクリックして移動・回転ハンドルを表示" +msgid "editor.inspector.option.tilted.6n0u5j" +msgstr "傾斜" -# Source-Hash: c0045cef191fee69 +# Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Detach the joint while dragging an arrow" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.detachTheJointWhileDraggingAn" -msgstr "矢印のドラッグ中に接合を外す" +msgid "editor.inspector.option.top.2nypcs" +msgstr "上" -# Source-Hash: a019c8948c104a9e +# Source-Hash: e6657000554dfe53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag left or right to rotate selected object" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transition" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.dragLeftOrRightToRotate" -msgstr "左右にドラッグして選択オブジェクトを回転" +msgid "editor.inspector.option.transition.1rziz9e" +msgstr "トランジション" -# Source-Hash: 7db0364deb12f06e +# Source-Hash: 04bc0909a133a7e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag selected movable object" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vent" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.dragSelectedMovableObject" -msgstr "選択した可動オブジェクトをドラッグ" +msgid "editor.inspector.option.vent.xda5j2" +msgstr "換気口" -# Source-Hash: 0f258dd389afdc73 +# Source-Hash: 7eee9aff0dd520b6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Group selection (session only)" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walk on" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.groupSelectionSessionOnly" -msgstr "選択をグループ化(このセッションのみ)" +msgid "editor.inspector.option.walkOn.1n5sg9l" +msgstr "歩行面" -# Source-Hash: 85330d62893a45c3 +# Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hold to rotate freely" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.holdToRotateFreely" -msgstr "押したままで自由に回転" +msgid "editor.inspector.option.wall.blj585" +msgstr "壁" -# Source-Hash: 8a665ecaeffa9308 +# Source-Hash: f3578f7177ad0054 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ±45°" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall abutment" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.rotate45" -msgstr "±45°回転" +msgid "editor.inspector.option.wallAbutment.lza941" +msgstr "壁との取り合い" -# Source-Hash: 6099ee99f8c38700 +# Source-Hash: 8dcf182f91ba3245 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate the selection ±45°" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall ledger" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.rotateTheSelection45" -msgstr "選択を±45°回転" - +msgid "editor.inspector.option.wallLedger.5m8ana" +msgstr "壁の受け材" + +# Source-Hash: 0adda30be5f17975 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall shelf" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "editor.inspector.option.wallShelf.yiozfl" +msgstr "壁棚" + +# Source-Hash: 29d8590334492601 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waste" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "editor.inspector.option.waste.3xrp79" +msgstr "排水" + +# Source-Hash: 00249876bb37079f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wye" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "editor.inspector.option.wye.14vupc8" +msgstr "Y字管" + +# Source-Hash: 179b025e25f9a091 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collapse" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +#, fuzzy +msgid "editor.layers.collapse" +msgstr "折りたたむ" + +# Source-Hash: dbeae4c43f49327f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling ({area})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +#, fuzzy +msgid "editor.layers.defaultName.ceiling" +msgstr "天井({area})" + +# Source-Hash: d29165c9d4bfc3cb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collection" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +#, fuzzy +msgid "editor.layers.defaultName.collection" +msgstr "コレクション" + +# Source-Hash: 8f536b859be662a0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight ({width}×{length}m)" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +#, fuzzy +msgid "editor.layers.defaultName.flight" +msgstr "階段({width}×{length}m)" + +# Source-Hash: 46dcbf4548374073 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing ({width}×{length}m)" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +#, fuzzy +msgid "editor.layers.defaultName.landing" +msgstr "踊り場({width}×{length}m)" + +# Source-Hash: 3ea44453fcd08a6e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Node" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +#, fuzzy +msgid "editor.layers.defaultName.node" +msgstr "ノード" + +# Source-Hash: 93f3a04e15b6fb49 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof ({count, plural, one {# segment} other {# segments}})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +#, fuzzy +msgid "editor.layers.defaultName.roof" +msgstr "屋根({count, plural, other {# セグメント}})" + +# Source-Hash: a730fab01c172704 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{roofType, select, hip {Hip} gable {Gable} shed {Shed} gambrel {Gambrel} dutch {Dutch} mansard {Mansard} flat {Flat} conical {Conical} barrel {Barrel} other {Roof}} ({width}×{depth}m)" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +#, fuzzy +msgid "editor.layers.defaultName.roofSegment" +msgstr "{roofType, select, hip {寄棟} gable {切妻} shed {片流れ} gambrel {腰折れ} dutch {入母屋} mansard {マンサード} flat {陸屋根} conical {円錐} barrel {ヴォールト} other {屋根}}({width}×{depth}m)" + +# Source-Hash: 54efcb0756c2f2c1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room ({area})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +#, fuzzy +msgid "editor.layers.defaultName.room" +msgstr "部屋({area})" + +# Source-Hash: e38a4b9986a9d21a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab ({area})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +#, fuzzy +msgid "editor.layers.defaultName.slab" +msgstr "スラブ({area})" + +# Source-Hash: 57398365d4b9066f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Staircase ({count, plural, one {# segment} other {# segments}})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +#, fuzzy +msgid "editor.layers.defaultName.staircase" +msgstr "階段({count, plural, other {# セグメント}})" + +# Source-Hash: a17f8fc29aae896e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone ({area})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +#, fuzzy +msgid "editor.layers.defaultName.zone" +msgstr "ゾーン({area})" + +# Source-Hash: 5cabcabb8bc14809 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Expand" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +#, fuzzy +msgid "editor.layers.expand" +msgstr "展開" + +# Source-Hash: 6731e9dd94e8b268 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{levelName} options" +#: packages/editor/src/components/ui/floating-level-selector.tsx +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.layers.levelOptions" +msgstr "{levelName}のオプション" + +# Source-Hash: d6952b4e54d246dd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rename" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx +#, fuzzy +msgid "editor.layers.rename" +msgstr "名前を変更" + +# Source-Hash: 21eafa019ad62fea +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{role, select, room {Room colour} other {Zone colour}}" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#: packages/editor/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +#, fuzzy +msgid "editor.layers.spaceColour" +msgstr "{role, select, room {部屋の色} other {ゾーンの色}}" + +# Source-Hash: f5de042416a2c04f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unit colour" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +#, fuzzy +msgid "editor.layers.unitColour" +msgstr "ユニットの色" + +# Source-Hash: c0774c185060fc13 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +#, fuzzy +msgid "editor.levelDuplicateDialog.cancel" +msgstr "キャンセル" + +# Source-Hash: 07c11e7e4d4681d6 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose what to copy from {levelName}." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +#, fuzzy +msgid "editor.levelDuplicateDialog.chooseWhatToCopyFromLevel" +msgstr "{levelName}からコピーする内容を選択してください。" + +# Source-Hash: 9500d4378a319532 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose what to copy from this level." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +#, fuzzy +msgid "editor.levelDuplicateDialog.chooseWhatToCopyFromThisLevel" +msgstr "この階層からコピーする内容を選択してください。" + +# Source-Hash: 34dc96fe77a31e51 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +#, fuzzy +msgid "editor.levelDuplicateDialog.duplicate" +msgstr "複製" + +# Source-Hash: a56e3eb43e60b45c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate Level" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +#, fuzzy +msgid "editor.levelDuplicateDialog.duplicateLevel" +msgstr "階層を複製" + +# Source-Hash: e4c6ab1ea473a082 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Everything" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +#, fuzzy +msgid "editor.levelDuplicateDialog.everything" +msgstr "すべて" + +# Source-Hash: ac3f119e560388ab +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure, finishes, and placed items, without guide references." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +#, fuzzy +msgid "editor.levelDuplicateDialog.structureFinishesAndPlacedItemsWithout" +msgstr "構造、仕上げ、配置済みアイテム(ガイド参照を除く)。" + +# Source-Hash: acbdf968391d5273 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure + furniture" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +#, fuzzy +msgid "editor.levelDuplicateDialog.structureFurniture" +msgstr "構造 + 家具" + +# Source-Hash: ce682864a140fe75 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure + materials" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +#, fuzzy +msgid "editor.levelDuplicateDialog.structureMaterials" +msgstr "構造 + マテリアル" + +# Source-Hash: 5ee44d53847c5ea2 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure, materials, furniture, and references." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +#, fuzzy +msgid "editor.levelDuplicateDialog.structureMaterialsFurnitureAndReferences" +msgstr "構造、マテリアル、家具、参照。" + +# Source-Hash: 95aa1b43dbdb3f02 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure only" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +#, fuzzy +msgid "editor.levelDuplicateDialog.structureOnly" +msgstr "構造のみ" + +# Source-Hash: 2c53b46c9ca9fe2f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure with the current material and finish assignments." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +#, fuzzy +msgid "editor.levelDuplicateDialog.structureWithTheCurrentMaterialAnd" +msgstr "現在のマテリアルと仕上げの割り当てを含む構造。" + +# Source-Hash: 3350e9008eaba15d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls, slabs, roofs, stairs, windows, and doors without finishes." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +#, fuzzy +msgid "editor.levelDuplicateDialog.wallsSlabsRoofsStairsWindowsAnd" +msgstr "壁、スラブ、屋根、階段、窓、ドア(仕上げなし)。" + +# Source-Hash: 4f60d1e142affa9c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Copy" +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx +#, fuzzy +msgid "editor.levelWallCopyPrompt.copy" +msgstr "コピー" + +# Source-Hash: 8ccaf4c98e335cc8 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Copy exterior walls from the level {direction}?" +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx +#, fuzzy +msgid "editor.levelWallCopyPrompt.copyExteriorWallsFromTheLevel" +msgstr "{direction, select, below {下} above {上} other {{direction}}}の階層から外壁をコピーしますか?" + +# Source-Hash: f6ad0e813d2945bb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No thanks" +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx +#, fuzzy +msgid "editor.levelWallCopyPrompt.noThanks" +msgstr "結構です" + +# Source-Hash: d2aecc3c47120ad5 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{sourceName}’s outside walls, in place, so this level lines up with it." +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx +#, fuzzy +msgid "editor.levelWallCopyPrompt.sourcenameSOutsideWallsInPlace" +msgstr "{sourceName}の外壁を同じ位置にコピーし、この階層の位置をそろえます。" + +# Source-Hash: 395fd0821b203517 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add or remove objects from the selection" +#: packages/editor/src/lib/contextual-help.ts +#, fuzzy +msgid "editor.lib.contextualHelp.addOrRemoveObjectsFromThe" +msgstr "選択にオブジェクトを追加・除外" + +# Source-Hash: 8428cb0af9c6d6a0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Adjust one side’s corner radius" +#: packages/editor/src/lib/contextual-help.ts +#, fuzzy +msgid "editor.lib.contextualHelp.adjustOneSideSCornerRadius" +msgstr "片側の角の半径を調整" + +# Source-Hash: d63b45c195713993 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear the selection (or click outside)" +#: packages/editor/src/lib/contextual-help.ts +#, fuzzy +msgid "editor.lib.contextualHelp.clearTheSelectionOrClickOutside" +msgstr "選択を解除(または外側をクリック)" + +# Source-Hash: 40b1afbeadbd6213 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click a handle dot to show move arrows" +#: packages/editor/src/lib/contextual-help.ts +#, fuzzy +msgid "editor.lib.contextualHelp.clickAHandleDotToShow" +msgstr "ハンドルの点をクリックして移動矢印を表示" + +# Source-Hash: 0b82a35c71549580 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click or drag the selection to move it as one" +#: packages/editor/src/lib/contextual-help.ts +#, fuzzy +msgid "editor.lib.contextualHelp.clickOrDragTheSelectionTo" +msgstr "選択をクリックまたはドラッグしてまとめて移動" + +# Source-Hash: 73a761f393f69cb9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click the handle dot to show move + rotate handles" +#: packages/editor/src/lib/contextual-help.ts +#, fuzzy +msgid "editor.lib.contextualHelp.clickTheHandleDotToShow" +msgstr "ハンドルの点をクリックして移動・回転ハンドルを表示" + +# Source-Hash: c0045cef191fee69 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Detach the joint while dragging an arrow" +#: packages/editor/src/lib/contextual-help.ts +#, fuzzy +msgid "editor.lib.contextualHelp.detachTheJointWhileDraggingAn" +msgstr "矢印のドラッグ中に接合を外す" + +# Source-Hash: a019c8948c104a9e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag left or right to rotate selected object" +#: packages/editor/src/lib/contextual-help.ts +#, fuzzy +msgid "editor.lib.contextualHelp.dragLeftOrRightToRotate" +msgstr "左右にドラッグして選択オブジェクトを回転" + +# Source-Hash: 7db0364deb12f06e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag selected movable object" +#: packages/editor/src/lib/contextual-help.ts +#, fuzzy +msgid "editor.lib.contextualHelp.dragSelectedMovableObject" +msgstr "選択した可動オブジェクトをドラッグ" + +# Source-Hash: 0f258dd389afdc73 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Group selection (session only)" +#: packages/editor/src/lib/contextual-help.ts +#, fuzzy +msgid "editor.lib.contextualHelp.groupSelectionSessionOnly" +msgstr "選択をグループ化(このセッションのみ)" + +# Source-Hash: 85330d62893a45c3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hold to rotate freely" +#: packages/editor/src/lib/contextual-help.ts +#, fuzzy +msgid "editor.lib.contextualHelp.holdToRotateFreely" +msgstr "押したままで自由に回転" + +# Source-Hash: 8a665ecaeffa9308 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ±45°" +#: packages/editor/src/lib/contextual-help.ts +#, fuzzy +msgid "editor.lib.contextualHelp.rotate45" +msgstr "±45°回転" + +# Source-Hash: 6099ee99f8c38700 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate the selection ±45°" +#: packages/editor/src/lib/contextual-help.ts +#, fuzzy +msgid "editor.lib.contextualHelp.rotateTheSelection45" +msgstr "選択を±45°回転" + # Source-Hash: 0f6b418b18ff96f3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotating freely (no angle step)" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotating freely (no angle step)" +#: packages/editor/src/lib/contextual-help.ts +#, fuzzy +msgid "editor.lib.contextualHelp.rotatingFreely" +msgstr "自由回転中(角度ステップなし)" + +# Source-Hash: 7ed174d6b03563b1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Switch the rotation axis (Y → X → Z)" +#: packages/editor/src/lib/contextual-help.ts +#, fuzzy +msgid "editor.lib.contextualHelp.switchTheRotationAxisYX" +msgstr "回転軸を切り替え(Y → X → Z)" + +# Source-Hash: d6f2c5cea683de62 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ungroup session selection" +#: packages/editor/src/lib/contextual-help.ts +#, fuzzy +msgid "editor.lib.contextualHelp.ungroupSessionSelection" +msgstr "セッションのグループを解除" + +# Source-Hash: 384842ae1e1c6825 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuous" +#: packages/editor/src/lib/continuation.ts +#, fuzzy +msgid "editor.lib.continuation.continuous" +msgstr "連続" + +# Source-Hash: ebf0eb7af4636a16 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuous canopy" +#: packages/editor/src/lib/continuation.ts +#, fuzzy +msgid "editor.lib.continuation.continuousCanopy" +msgstr "連続キャノピー" + +# Source-Hash: 1d8e87cd807e8d40 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuous run" +#: packages/editor/src/lib/continuation.ts +#, fuzzy +msgid "editor.lib.continuation.continuousRun" +msgstr "連続配置" + +# Source-Hash: 8990683667567c6b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curved fence" +#: packages/editor/src/lib/continuation.ts +#, fuzzy +msgid "editor.lib.continuation.curvedFence" +msgstr "曲線フェンス" + +# Source-Hash: edf1b9a2ad3ab910 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Freehand fence" +#: packages/editor/src/lib/continuation.ts +#, fuzzy +msgid "editor.lib.continuation.freehandFence" +msgstr "フリーハンドのフェンス" + +# Source-Hash: 2cdb7c1c7cd7c4fd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place multiple" +#: packages/editor/src/lib/continuation.ts +#, fuzzy +msgid "editor.lib.continuation.placeMultiple" +msgstr "複数配置" + +# Source-Hash: 90bf945df6f9c979 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place once" +#: packages/editor/src/lib/continuation.ts +#, fuzzy +msgid "editor.lib.continuation.placeOnce" +msgstr "1回だけ配置" + +# Source-Hash: 8ec6152e139b0e3f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Polygon room" +#: packages/editor/src/lib/continuation.ts +#, fuzzy +msgid "editor.lib.continuation.polygonRoom" +msgstr "多角形の部屋" + +# Source-Hash: 83a45603ac7f41e8 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangle room" +#: packages/editor/src/lib/continuation.ts +#, fuzzy +msgid "editor.lib.continuation.rectangleRoom" +msgstr "矩形の部屋" + +# Source-Hash: 7fd85d0408141157 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single cabinet" +#: packages/editor/src/lib/continuation.ts +#, fuzzy +msgid "editor.lib.continuation.singleCabinet" +msgstr "単体キャビネット" + +# Source-Hash: dd1bdbc26165baa5 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single canopy" +#: packages/editor/src/lib/continuation.ts +#, fuzzy +msgid "editor.lib.continuation.singleCanopy" +msgstr "単体キャノピー" + +# Source-Hash: 5fb1a69316be983e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single fence" +#: packages/editor/src/lib/continuation.ts +#, fuzzy +msgid "editor.lib.continuation.singleFence" +msgstr "単体フェンス" + +# Source-Hash: aac9a732d2159ccc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls" +#: packages/editor/src/lib/continuation.ts +#, fuzzy +msgid "editor.lib.continuation.walls" +msgstr "壁" + +# Source-Hash: 4e4f1a24e4a9d61e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut opening" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.cutOpening" +msgstr "開口を切る" + +# Source-Hash: 60e8d235f3084a9e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divide room" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.divideRoom" +msgstr "部屋を分割" + +# Source-Hash: aa496ec33d21ab03 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit {kind}" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.editKind" +msgstr "{kind}を編集" + +# Source-Hash: f3ea3efa7102844f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Erase" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.erase" +msgstr "消去" + +# Source-Hash: 3f907e76526472bf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level terrain" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.levelTerrain" +msgstr "地形を平らにする" + +# Source-Hash: 4e911c300d74eb47 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lower terrain" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.lowerTerrain" +msgstr "地形を下げる" + +# Source-Hash: 194a147d4618a994 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.mezzanine" +msgstr "中二階" + +# Source-Hash: c48c4129c9ed249a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move {kind}" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.moveKind" +msgstr "{kind}を移動" + +# Source-Hash: 89f6b7ca8904c656 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move room" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.moveRoom" +msgstr "部屋を移動" + +# Source-Hash: 9c707069572fb3db +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move selection" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.moveSelection" +msgstr "選択を移動" + +# Source-Hash: cf2e870fce0f2f51 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.paint" +msgstr "塗装" + +# Source-Hash: ca197314cb70aa56 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint a rectangle" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.paintARectangle" +msgstr "矩形を塗る" + +# Source-Hash: ea4ce729e17254f8 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint a shape" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.paintAShape" +msgstr "形を塗る" + +# Source-Hash: 01359502b07284d4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick material" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.pickMaterial" +msgstr "素材を取得" + +# Source-Hash: 4066e8a3f60b1711 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raise terrain" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.raiseTerrain" +msgstr "地形を上げる" + +# Source-Hash: f85bdac0a1d16603 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Resize" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.resize" +msgstr "サイズ変更" + +# Source-Hash: 306d409f8a1cf480 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.rotate" +msgstr "回転" + +# Source-Hash: a4395168488bb476 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.select" +msgstr "選択" + +# Source-Hash: ec1f1d68af469867 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Smart measure" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.smartMeasure" +msgstr "スマート計測" + +# Source-Hash: 5ba5f22bd1a69e09 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Smooth terrain" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.smoothTerrain" +msgstr "地形を滑らかにする" + +# Source-Hash: cbb4687261739397 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Split {kind}" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.splitKind" +msgstr "{kind}を分割" + +# Source-Hash: 96281876ce53ba08 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terrace" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.terrace" +msgstr "テラス" + +# Source-Hash: 472d127eb9416ec5 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invisible" +#: packages/editor/src/lib/wall-draw-variant.ts +#, fuzzy +msgid "editor.lib.wallDrawVariant.kind.invisible" +msgstr "見えない壁" + +# Source-Hash: 240ed9c77627b9a1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" +#: packages/editor/src/lib/wall-draw-variant.ts +#, fuzzy +msgid "editor.lib.wallDrawVariant.kind.railing" +msgstr "手すり" + +# Source-Hash: d998c212030bc7c2 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/editor/src/lib/wall-draw-variant.ts +#, fuzzy +msgid "editor.lib.wallDrawVariant.kind.standard" +msgstr "標準" + +# Source-Hash: 8ec6152e139b0e3f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Polygon room" +#: packages/editor/src/lib/wall-draw-variant.ts +#, fuzzy +msgid "editor.lib.wallDrawVariant.polygonRoom" +msgstr "多角形の部屋" + +# Source-Hash: 83a45603ac7f41e8 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangle room" +#: packages/editor/src/lib/wall-draw-variant.ts +#, fuzzy +msgid "editor.lib.wallDrawVariant.rectangleRoom" +msgstr "矩形の部屋" + +# Source-Hash: aac9a732d2159ccc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls" +#: packages/editor/src/lib/wall-draw-variant.ts +#, fuzzy +msgid "editor.lib.wallDrawVariant.walls" +msgstr "壁" + +# Source-Hash: c2626e1fbf89b3c9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{action, select, close {Close} open {Open} stop {Stop} other {Play}}" +#: packages/editor/src/components/editor/registry-action-contributions.tsx +#, fuzzy +msgid "editor.mechanismAction" +msgstr "{action, select, close {閉じる} open {開く} stop {停止} other {再生}}" + +# Source-Hash: f08fbb462e9afc0e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curve" +#: packages/editor/src/components/editor/node-action-menu.tsx +#, fuzzy +msgid "editor.nodeActionMenu.curve" +msgstr "曲線" + +# Source-Hash: 5af05fb6661e4d6a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut out" +#: packages/editor/src/components/editor/node-action-menu.tsx +#, fuzzy +msgid "editor.nodeActionMenu.cutOut" +msgstr "切り抜き" + +# Source-Hash: b26de372b4b0eaac +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/editor/node-action-menu.tsx +#, fuzzy +msgid "editor.nodeActionMenu.delete" +msgstr "削除" + +# Source-Hash: 34dc96fe77a31e51 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/editor/node-action-menu.tsx +#, fuzzy +msgid "editor.nodeActionMenu.duplicate" +msgstr "複製" + +# Source-Hash: 94b212bd79c05141 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit mesh" +#: packages/editor/src/components/editor/node-action-menu.tsx +#, fuzzy +msgid "editor.nodeActionMenu.editMesh" +msgstr "メッシュを編集" + +# Source-Hash: ce90cf37224f73cd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Find in catalog" +#: packages/editor/src/components/editor/node-action-menu.tsx +#, fuzzy +msgid "editor.nodeActionMenu.findInCatalog" +msgstr "カタログで探す" + +# Source-Hash: d5e550c345e7161c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Group selection" +#: packages/editor/src/components/editor/node-action-menu.tsx +#, fuzzy +msgid "editor.nodeActionMenu.groupSelection" +msgstr "選択をグループ化" + +# Source-Hash: bd02c614454fbd2b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/editor/src/components/editor/node-action-menu.tsx +#, fuzzy +msgid "editor.nodeActionMenu.move" +msgstr "移動" + +# Source-Hash: 473a9d4463761107 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate left" +#: packages/editor/src/components/editor/node-action-menu.tsx +#, fuzzy +msgid "editor.nodeActionMenu.rotateLeft" +msgstr "左に回転" + +# Source-Hash: b1bf4e65c8d8c8ef +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate right" +#: packages/editor/src/components/editor/node-action-menu.tsx +#, fuzzy +msgid "editor.nodeActionMenu.rotateRight" +msgstr "右に回転" + +# Source-Hash: 6f4dbbc4a3f58fca +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ungroup selection" +#: packages/editor/src/components/editor/node-action-menu.tsx +#, fuzzy +msgid "editor.nodeActionMenu.ungroupSelection" +msgstr "選択のグループを解除" + +# Source-Hash: 4275c05172abd7fb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/editor/src/components/ui/panels/node-display.ts +#, fuzzy +msgid "editor.nodeDisplay.ceiling" +msgstr "天井" + +# Source-Hash: 3530ac1f4046cd22 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Column" +#: packages/editor/src/components/ui/panels/node-display.ts +#, fuzzy +msgid "editor.nodeDisplay.column" +msgstr "柱" + +# Source-Hash: 787e10f5db16904e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door" +#: packages/editor/src/components/ui/panels/node-display.ts +#, fuzzy +msgid "editor.nodeDisplay.door" +msgstr "ドア" + +# Source-Hash: ab5cbab7be160a1c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevator" +#: packages/editor/src/components/ui/panels/node-display.ts +#, fuzzy +msgid "editor.nodeDisplay.elevator" +msgstr "エレベーター" + +# Source-Hash: 02042fde61b5aa11 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fence" +#: packages/editor/src/components/ui/panels/node-display.ts +#, fuzzy +msgid "editor.nodeDisplay.fence" +msgstr "フェンス" + +# Source-Hash: 4c3ff8cdc6feda97 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guide image" +#: packages/editor/src/components/ui/panels/node-display.ts +#, fuzzy +msgid "editor.nodeDisplay.guide" +msgstr "ガイド画像" + +# Source-Hash: 2743a0e9d2743807 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Item" +#: packages/editor/src/components/ui/panels/node-display.ts +#, fuzzy +msgid "editor.nodeDisplay.item" +msgstr "アイテム" + +# Source-Hash: f5f730969df63d1d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof" +#: packages/editor/src/components/ui/panels/node-display.ts +#, fuzzy +msgid "editor.nodeDisplay.roof" +msgstr "屋根" + +# Source-Hash: a130b4eec084c79a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof segment" +#: packages/editor/src/components/ui/panels/node-display.ts +#, fuzzy +msgid "editor.nodeDisplay.roofSegment" +msgstr "屋根セグメント" + +# Source-Hash: 612dcd5bf06a79c4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/ui/panels/node-display.ts +#, fuzzy +msgid "editor.nodeDisplay.room" +msgstr "部屋" + +# Source-Hash: b22b2f20cc7cd416 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "3D Scan" +#: packages/editor/src/components/ui/panels/node-display.ts +#, fuzzy +msgid "editor.nodeDisplay.scan" +msgstr "3Dスキャン" + +# Source-Hash: 170b2049ef0f9131 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selection" +#: packages/editor/src/components/ui/panels/node-display.ts +#, fuzzy +msgid "editor.nodeDisplay.selection" +msgstr "選択" + +# Source-Hash: 8775bc8dc9593964 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/editor/src/components/ui/panels/node-display.ts +#, fuzzy +msgid "editor.nodeDisplay.slab" +msgstr "スラブ" + +# Source-Hash: 53d7084bc41c1ad6 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair" +#: packages/editor/src/components/ui/panels/node-display.ts +#, fuzzy +msgid "editor.nodeDisplay.stair" +msgstr "階段" + +# Source-Hash: 52de428c16bb81e6 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair segment" +#: packages/editor/src/components/ui/panels/node-display.ts +#, fuzzy +msgid "editor.nodeDisplay.stairSegment" +msgstr "階段セグメント" + +# Source-Hash: 2210e5ee50b74dc9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall" +#: packages/editor/src/components/ui/panels/node-display.ts +#, fuzzy +msgid "editor.nodeDisplay.wall" +msgstr "壁" + +# Source-Hash: aa3c35ed33e181e5 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Window" +#: packages/editor/src/components/ui/panels/node-display.ts +#, fuzzy +msgid "editor.nodeDisplay.window" +msgstr "窓" + +# Source-Hash: a107b4d76d6972e3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone" +#: packages/editor/src/components/ui/panels/node-display.ts +#, fuzzy +msgid "editor.nodeDisplay.zone" +msgstr "ゾーン" + +# Source-Hash: c0774c185060fc13 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +#, fuzzy +msgid "editor.panels.collections.collectionsPopover.cancel" +msgstr "キャンセル" + +# Source-Hash: 6dbabf32ff8c6f37 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collection name…" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +#, fuzzy +msgid "editor.panels.collections.collectionsPopover.collectionName" +msgstr "コレクション名…" + +# Source-Hash: 135af27a14a4cda7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collections" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +#, fuzzy +msgid "editor.panels.collections.collectionsPopover.collections" +msgstr "コレクション" + +# Source-Hash: b26de372b4b0eaac +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +#, fuzzy +msgid "editor.panels.collections.collectionsPopover.delete" +msgstr "削除" + +# Source-Hash: c53d71b05b8163b2 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete \"{name}\"?" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +#, fuzzy +msgid "editor.panels.collections.collectionsPopover.deleteName" +msgstr "「{name}」を削除しますか?" + +# Source-Hash: e9f7cceb39860c56 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +#, fuzzy +msgid "editor.panels.collections.collectionsPopover.new" +msgstr "新規" + +# Source-Hash: 649bc1b1799f2311 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No collections yet. Create one to group elements together." +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +#, fuzzy +msgid "editor.panels.collections.collectionsPopover.noCollectionsYetCreateOneTo" +msgstr "コレクションはまだありません。作成すると要素をまとめられます。" + +# Source-Hash: d6952b4e54d246dd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rename" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +#, fuzzy +msgid "editor.panels.collections.collectionsPopover.rename" +msgstr "名前を変更" + +# Source-Hash: 0a605a51555bb514 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Along house" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx +#, fuzzy +msgid "editor.panels.deckBoardsFields.alongHouse" +msgstr "住宅と平行" + +# Source-Hash: 19ae2360207ecf5a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Boards" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx +#, fuzzy +msgid "editor.panels.deckBoardsFields.boards" +msgstr "板材" + +# Source-Hash: 2bc05aaf1fc289b3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label} boards {thickness} × {width} in, {gap} in apart, {direction, select, parallel {along the house, on joists square to it} diagonal {at 45° to the house} other {out from the house, on joists along it, carried by beams square to the house}}; joists {spacing} in on centre." +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx +#, fuzzy +msgid "editor.panels.deckBoardsFields.boardsSummary" +msgstr "{label} のデッキ板 {thickness} × {width} in、隙間 {gap} in、{direction, select, parallel {住宅と平行に張り、根太は住宅と直交} diagonal {住宅に対して 45° に張る} other {住宅から外向きに張り、根太は住宅と平行で、住宅と直交する梁が支える}}。根太は芯々 {spacing} in。" + +# Source-Hash: 24c6255bfa1abd8f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck boards" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx +#, fuzzy +msgid "editor.panels.deckBoardsFields.deckBoards" +msgstr "デッキ板" + +# Source-Hash: 7420c0d2caee1c22 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diagonal" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx +#, fuzzy +msgid "editor.panels.deckBoardsFields.diagonal" +msgstr "斜め" + +# Source-Hash: df708ece3529bcba +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx +#, fuzzy +msgid "editor.panels.deckBoardsFields.gap" +msgstr "隙間" + +# Source-Hash: 3660fcdd12159277 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Out from house" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx +#, fuzzy +msgid "editor.panels.deckBoardsFields.outFromHouse" +msgstr "住宅と直交" + +# Source-Hash: 9ac7e4955593cc34 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Run" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx +#, fuzzy +msgid "editor.panels.deckBoardsFields.run" +msgstr "張り方向" + +# Source-Hash: 2000cf124b4e1139 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A thicker floor grows upward: the rooms below keep their height." +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.aThickerFloorGrowsUpwardThe" +msgstr "床を厚くすると上方向に伸び、下の部屋の高さは変わりません。" + +# Source-Hash: 0d57958b99b6b352 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edge finish" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.edgeFinish" +msgstr "縁の仕上げ" + +# Source-Hash: 8e458d8b21f26f09 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.floorPlate" +msgstr "床版" + +# Source-Hash: 2bb71e5633801afb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate {thicknessLabel} thick, resting on the walls below" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.floorPlateThicknesslabelThickRestingOn" +msgstr "厚さ {thicknessLabel} の床版、下の壁の上に載ります" + +# Source-Hash: 73614b8faa059cd6 +# Review: required +# AI-Provider: cursor-agent +# AI-Model: claude-opus +# English: "Floor thickness" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.floorThickness" +msgstr "床の厚さ" + +# Source-Hash: a40a1fbacd5d2551 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor top +{height}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.floorTopAbove" +msgstr "床上面 +{height}" + +# Source-Hash: 5c3849e15933737f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor top {height}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.floorTopValue" +msgstr "床上面 {height}" + +# Source-Hash: 19802dd369749ea7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation finish" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.foundationFinish" +msgstr "基礎の仕上げ" + +# Source-Hash: 3a4599be1ad687be +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation height" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.foundationHeight" +msgstr "基礎の高さ" + +# Source-Hash: 8e458d8b21f26f09 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.kicker" +msgstr "床版" + +# Source-Hash: 66d52bfbb94f7bb3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate · {level}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.kickerLevel" +msgstr "床版 · {level}" + +# Source-Hash: 0189e5a1987b4ec0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate · {level} · rests on {below}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.kickerRestsOn" +msgstr "床版 · {level} · {below}の上" + +# Source-Hash: 648ef10535b0af73 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, =2 {Lower both} other {Lower all {number}}}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.lowerTogether" +msgstr "{count, plural, =2 {両方を下げる} other {{number} 個すべてを下げる}}" + +# Source-Hash: c2fcc43bb7f1c5e2 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not to scale" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.notToScale" +msgstr "縮尺なし" + +# Source-Hash: e9440fa9f770b7a4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On the ground" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.onTheGround" +msgstr "地面上" + +# Source-Hash: 7c3692a361075ecf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised on a foundation" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.raisedOnAFoundation" +msgstr "基礎の上に上げる" + +# Source-Hash: 769c3ca1ca0cd4f0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, =2 {Raise both} other {Raise all {number}}}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.raiseTogether" +msgstr "{count, plural, =2 {両方を上げる} other {{number} 個すべてを上げる}}" + +# Source-Hash: 719ae422da204ca7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate · {thickness}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.section.floorPlate" +msgstr "床版 · {thickness}" + +# Source-Hash: 069d64adffa05db7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor top" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.section.floorTop" +msgstr "床上面" + +# Source-Hash: 48c832c1fc389290 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.section.foundation" +msgstr "基礎" + +# Source-Hash: 7759a59b8685c885 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation · {foundation}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.section.foundationKind" +msgstr "基礎 · {foundation}" + +# Source-Hash: 94cc8e9f1ee16edb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.section.ground" +msgstr "地面" + +# Source-Hash: 51e274b2c90e2cf3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab · {thickness}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.section.slab" +msgstr "スラブ · {thickness}" + +# Source-Hash: 790a0b5c6dbf0e9b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.section.wallsBelow" +msgstr "下の壁" + +# Source-Hash: 90e96ae5f3d3f69c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab {thickness} thick on the ground, floor top {top} above the ground" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.sectionOnGround" +msgstr "厚さ {thickness} のスラブ、地面の上、床上面は地面から {top}" + +# Source-Hash: 71ed2295d9932ed0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab {thickness} thick on a {foundation} foundation, floor top {top} above the ground" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.sectionRaised" +msgstr "厚さ {thickness} のスラブ、{foundation}基礎の上、床上面は地面から {top}" + +# Source-Hash: 8775bc8dc9593964 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.slab" +msgstr "スラブ" + +# Source-Hash: ca51d643691c29ae +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab thickness" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.slabThickness" +msgstr "スラブの厚さ" + +# Source-Hash: 678c39468593275b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The floor's outside edge, all around the footprint." +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.theFloorSOutsideEdgeAll" +msgstr "フットプリント全周にわたる床の外縁。" + +# Source-Hash: 6638ed5caa43bdb9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The foundation stands on the ground; the slab sits on it." +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.theFoundationStandsOnTheGround" +msgstr "基礎は地面の上に、スラブは基礎の上に載ります。" + +# Source-Hash: 5321416b442f23b4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The slab sits on the foundation (or the ground): a thicker slab raises the floor top and everything on it." +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.theSlabSitsOnTheFoundation" +msgstr "スラブは基礎(または地面)の上に載ります。厚くすると床上面とその上のすべてが上がります。" + +# Source-Hash: 044ccae8bec574e7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Under the floor" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +#, fuzzy +msgid "editor.panels.floorFoundationPanel.underTheFloor" +msgstr "床下" + +# Source-Hash: 6aca44df3e582a81 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A hatch in the mezzanine: it cuts only the mezzanine’s floor." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +#, fuzzy +msgid "editor.panels.floorOpeningPanel.aHatchInTheMezzanineIt" +msgstr "中二階のハッチ:中二階の床だけを切り抜きます。" + +# Source-Hash: 2ce79639d42da658 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Also cut the ceiling below" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +#, fuzzy +msgid "editor.panels.floorOpeningPanel.alsoCutTheCeilingBelow" +msgstr "下の天井も切り抜く" + +# Source-Hash: e360814f64792300 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Also cut the floor above" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +#, fuzzy +msgid "editor.panels.floorOpeningPanel.alsoCutTheFloorAbove" +msgstr "上の床も切り抜く" + +# Source-Hash: c25cddf8b831c2b2 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} · Drag its corners to change the shape." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +#, fuzzy +msgid "editor.panels.floorOpeningPanel.areaDragCorners" +msgstr "{area} · 角をドラッグして形状を変更します。" + +# Source-Hash: 32b168cf010a5daa +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} · Shape follows its owner." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +#, fuzzy +msgid "editor.panels.floorOpeningPanel.areaOwned" +msgstr "{area} · 形状は所有元に従います。" + +# Source-Hash: 71b5c7184cbd2e5d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} · Drag its sides or corners to resize it; it moves with the stair." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +#, fuzzy +msgid "editor.panels.floorOpeningPanel.areaStairResize" +msgstr "{area} · 辺または角をドラッグしてサイズを変更します。階段と一緒に動きます。" + +# Source-Hash: b26de372b4b0eaac +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +#, fuzzy +msgid "editor.panels.floorOpeningPanel.delete" +msgstr "削除" + +# Source-Hash: 16552c2580bbe8b8 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +#, fuzzy +msgid "editor.panels.floorOpeningPanel.done" +msgstr "完了" + +# Source-Hash: e04298381837252f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +#, fuzzy +msgid "editor.panels.floorOpeningPanel.kicker" +msgstr "開口" + +# Source-Hash: 079ad92dac7947cf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening · {level}" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.lib.contextualHelp.rotatingFreely" -msgstr "自由回転中(角度ステップなし)" +msgid "editor.panels.floorOpeningPanel.kickerLevel" +msgstr "開口 · {level}" -# Source-Hash: 7ed174d6b03563b1 +# Source-Hash: baf2c2c209637e5f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Switch the rotation axis (Y → X → Z)" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening · in {room}" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +#, fuzzy +msgid "editor.panels.floorOpeningPanel.kickerRoom" +msgstr "開口 · {room}内" + +# Source-Hash: 1712c164335ecd86 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening · in {room} · {level}" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +#, fuzzy +msgid "editor.panels.floorOpeningPanel.kickerRoomLevel" +msgstr "開口 · {room}内 · {level}" + +# Source-Hash: 88e673123b9dbfe1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On {level}, as one void with this opening." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +#, fuzzy +msgid "editor.panels.floorOpeningPanel.oneVoidWith" +msgstr "{level}で、この開口と一体の吹き抜けになります。" + +# Source-Hash: c38959fc8fd3e59d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Owned by Elevator" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +#, fuzzy +msgid "editor.panels.floorOpeningPanel.ownedByElevator" +msgstr "エレベーターに属する" + +# Source-Hash: 01494805cf60d78d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Owned by Staircase" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +#, fuzzy +msgid "editor.panels.floorOpeningPanel.ownedByStaircase" +msgstr "階段に属する" + +# Source-Hash: 612dcd5bf06a79c4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +#, fuzzy +msgid "editor.panels.floorOpeningPanel.room" +msgstr "部屋" + +# Source-Hash: 1405b914a324b153 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "There is no floor above this storey." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +#, fuzzy +msgid "editor.panels.floorOpeningPanel.thereIsNoFloorAboveThis" +msgstr "この階の上に床はありません。" + +# Source-Hash: 776170dcae88e969 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "There is no storey below." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +#, fuzzy +msgid "editor.panels.floorOpeningPanel.thereIsNoStoreyBelow" +msgstr "下の階はありません。" + +# Source-Hash: 0fdd1877a0f2d777 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{source, select, stair {Stair opening} elevator {Elevator opening} ceiling {Ceiling opening} other {Floor opening}}" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +#, fuzzy +msgid "editor.panels.floorOpeningPanel.title" +msgstr "{source, select, stair {階段の開口} elevator {エレベーターの開口} ceiling {天井の開口} other {床の開口}}" + +# Source-Hash: fa35c7653e1f649e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "One of them already wraps another corner. Unwrap it first." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +#, fuzzy +msgid "editor.panels.mergeRefusal.alreadyJoined" +msgstr "どちらかがすでに別のコーナーを回っています。先に解除してください。" + +# Source-Hash: dd87eb1983876459 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{kind, select, item {There is an item between them.} door {There is a door between them.} window {There is a window between them.} shelf {There is a shelf between them.} other {There is something between them.}}" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +#, fuzzy +msgid "editor.panels.mergeRefusal.between" +msgstr "{kind, select, item {間にアイテムがあります。} door {間にドアがあります。} window {間に窓があります。} shelf {間に棚があります。} other {間に何かがあります。}}" + +# Source-Hash: 58aea0b9789ae280 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "These windows cannot be merged." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +#, fuzzy +msgid "editor.panels.mergeRefusal.cannotMerge" +msgstr "これらの窓は結合できません。" + +# Source-Hash: 15170cfd9d666c4f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Their walls meet at too sharp or too flat an angle for a corner window." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +#, fuzzy +msgid "editor.panels.mergeRefusal.cornerAngle" +msgstr "壁の角度が鋭すぎるか平らすぎて、コーナー窓にできません。" + +# Source-Hash: f2818a1e20ebd6ca +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The window selected first is taller than the other wall. Select the other one first." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +#, fuzzy +msgid "editor.panels.mergeRefusal.heightExceedsWall" +msgstr "最初に選んだ窓がもう一方の壁より高いです。先にもう一方を選んでください。" + +# Source-Hash: 7c97fb4af929d4db +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "They are too far apart. Windows merge with at most {reach} between them." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +#, fuzzy +msgid "editor.panels.mergeRefusal.notAdjacent" +msgstr "離れすぎています。窓は間隔が {reach} 以内のときに結合します。" + +# Source-Hash: 57a281bdc4229b6d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "One of them is too far from the corner. A window joins one within {reach} of it." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +#, fuzzy +msgid "editor.panels.mergeRefusal.notAtCorner" +msgstr "どちらかがコーナーから離れすぎています。窓は {reach} 以内の窓と結合します。" + +# Source-Hash: e7d41ce7879ec075 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A roof or dormer window cannot join another window." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +#, fuzzy +msgid "editor.panels.mergeRefusal.notOnWall" +msgstr "屋根窓やドーマー窓は他の窓と結合できません。" + +# Source-Hash: eaad567d5e4257dc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{kind, select, item {Sliding them to the corner would overlap an item.} door {Sliding them to the corner would overlap a door.} window {Sliding them to the corner would overlap a window.} shelf {Sliding them to the corner would overlap a shelf.} other {Sliding them to the corner would overlap something.}}" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +#, fuzzy +msgid "editor.panels.mergeRefusal.overlap" +msgstr "{kind, select, item {コーナーまでずらすとアイテムと重なります。} door {コーナーまでずらすとドアと重なります。} window {コーナーまでずらすと窓と重なります。} shelf {コーナーまでずらすと棚と重なります。} other {コーナーまでずらすと何かと重なります。}}" + +# Source-Hash: ecb092821ed5b5e8 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Their walls do not meet at a corner." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +#, fuzzy +msgid "editor.panels.mergeRefusal.wallsNotMeeting" +msgstr "それぞれの壁がコーナーで接していません。" + +# Source-Hash: 37d9f63758abdb67 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mixed" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +#: packages/editor/src/components/ui/panels/parametric-field-control.tsx +#, fuzzy +msgid "editor.panels.mixed" +msgstr "混在" + +# Source-Hash: d7cf5045c01b2eb9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close" +#: packages/editor/src/components/ui/panels/mobile-panel-sheet.tsx +#, fuzzy +msgid "editor.panels.mobilePanelSheet.close" +msgstr "閉じる" + +# Source-Hash: b26de372b4b0eaac +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +#, fuzzy +msgid "editor.panels.mobileSelectionBar.delete" +msgstr "削除" + +# Source-Hash: 34dc96fe77a31e51 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +#, fuzzy +msgid "editor.panels.mobileSelectionBar.duplicate" +msgstr "複製" + +# Source-Hash: 7eb955d866c2668b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit properties" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +#, fuzzy +msgid "editor.panels.mobileSelectionBar.editProperties" +msgstr "プロパティを編集" + +# Source-Hash: 89f25aa13e8192bc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit {resolvedLabel}" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +#, fuzzy +msgid "editor.panels.mobileSelectionBar.editResolvedlabel" +msgstr "{resolvedLabel}を編集" + +# Source-Hash: bd02c614454fbd2b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +#, fuzzy +msgid "editor.panels.mobileSelectionBar.move" +msgstr "移動" + +# Source-Hash: 72be05e1796526c9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Currently {currentLabel}" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.lib.contextualHelp.switchTheRotationAxisYX" -msgstr "回転軸を切り替え(Y → X → Z)" +msgid "editor.panels.multiHeightMode.currentlyCurrentlabel" +msgstr "現在:{currentLabel}" -# Source-Hash: d6f2c5cea683de62 +# Source-Hash: b2a1b3bc9676fe05 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ungroup session selection" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom height" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.lib.contextualHelp.ungroupSessionSelection" -msgstr "セッションのグループを解除" +msgid "editor.panels.multiHeightMode.customHeight" +msgstr "カスタムの高さ" -# Source-Hash: 384842ae1e1c6825 +# Source-Hash: a5c2353769b603d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuous" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows level" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.lib.continuation.continuous" -msgstr "連続" +msgid "editor.panels.multiHeightMode.followsLevel" +msgstr "階層に従う" -# Source-Hash: ebf0eb7af4636a16 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuous canopy" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.lib.continuation.continuousCanopy" -msgstr "連続キャノピー" +msgid "editor.panels.multiHeightMode.height" +msgstr "高さ" -# Source-Hash: 1d8e87cd807e8d40 +# Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuous run" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.lib.continuation.continuousRun" -msgstr "連続配置" +msgid "editor.panels.multiHeightMode.top" +msgstr "上" -# Source-Hash: 8990683667567c6b +# Source-Hash: 70f48b0141b656f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curved fence" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label} (session only). Plain click reselects all members. Not saved with the project." +#: packages/editor/src/components/ui/panels/multi-parametric-inspector.tsx #, fuzzy -msgid "editor.lib.continuation.curvedFence" -msgstr "曲線フェンス" +msgid "editor.panels.multiParametricInspector.labelSessionOnlyPlainClickReselects" +msgstr "{label}(このセッションのみ)。通常クリックで全メンバーを再選択します。プロジェクトには保存されません。" -# Source-Hash: edf1b9a2ad3ab910 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Freehand fence" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.lib.continuation.freehandFence" -msgstr "フリーハンドのフェンス" +msgid "editor.panels.multiSelectionPanel.delete" +msgstr "削除" -# Source-Hash: 2cdb7c1c7cd7c4fd +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place multiple" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.lib.continuation.placeMultiple" -msgstr "複数配置" +msgid "editor.panels.multiSelectionPanel.duplicate" +msgstr "複製" -# Source-Hash: 90bf945df6f9c979 +# Source-Hash: b0e7e3b47dfb5a0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place once" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Group" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.lib.continuation.placeOnce" -msgstr "1回だけ配置" +msgid "editor.panels.multiSelectionPanel.group" +msgstr "グループ化" -# Source-Hash: 8ec6152e139b0e3f +# Source-Hash: ca0a95fe0b08b8b6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Polygon room" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Group (Ctrl/Cmd+G)" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.lib.continuation.polygonRoom" -msgstr "多角形の部屋" +msgid "editor.panels.multiSelectionPanel.groupCtrlCmdG" +msgstr "グループ化(Ctrl/Cmd+G)" -# Source-Hash: 83a45603ac7f41e8 +# Source-Hash: 70f48b0141b656f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangle room" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label} (session only). Plain click reselects all members. Not saved with the project." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.lib.continuation.rectangleRoom" -msgstr "矩形の部屋" +msgid "editor.panels.multiSelectionPanel.labelSessionOnlyPlainClickReselects" +msgstr "{label}(このセッションのみ)。通常クリックで全メンバーを再選択します。プロジェクトには保存されません。" -# Source-Hash: 7fd85d0408141157 +# Source-Hash: fc98ef29c2842341 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single cabinet" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{length} selected" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.lib.continuation.singleCabinet" -msgstr "単体キャビネット" +msgid "editor.panels.multiSelectionPanel.lengthSelected" +msgstr "{length} 個選択中" -# Source-Hash: dd1bdbc26165baa5 +# Source-Hash: 323aaf1ebd04ada7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single canopy" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Merge windows" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.lib.continuation.singleCanopy" -msgstr "単体キャノピー" +msgid "editor.panels.multiSelectionPanel.mergeWindows" +msgstr "窓を結合" -# Source-Hash: 5fb1a69316be983e +# Source-Hash: 7855d03a6140af77 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single fence" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Merge windows into a corner window: both take the height, sill and type of the one you selected first" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.lib.continuation.singleFence" -msgstr "単体フェンス" +msgid "editor.panels.multiSelectionPanel.mergeWindowsIntoACornerWindow" +msgstr "コーナー窓に結合:両方とも最初に選んだ窓の高さ、窓台、種類になります" -# Source-Hash: aac9a732d2159ccc +# Source-Hash: b79da96502d2e1c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Merge windows into one across both: it keeps the type and style of the one you selected first" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.lib.continuation.walls" -msgstr "壁" +msgid "editor.panels.multiSelectionPanel.mergeWindowsIntoOneAcrossBoth" +msgstr "両方にまたがる1つの窓に結合:最初に選んだ窓の種類とスタイルを保ちます" -# Source-Hash: 4e4f1a24e4a9d61e +# Source-Hash: f409934681a046e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut opening" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select building" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.lib.hudTitle.cutOpening" -msgstr "開口を切る" +msgid "editor.panels.multiSelectionPanel.selectBuilding" +msgstr "建物を選択" -# Source-Hash: 60e8d235f3084a9e +# Source-Hash: c62a73873bd0164d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Divide room" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select the whole building to move all its levels" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.lib.hudTitle.divideRoom" -msgstr "部屋を分割" +msgid "editor.panels.multiSelectionPanel.selectTheWholeBuildingToMove" +msgstr "建物全体を選ぶとすべての階層を移動できます" -# Source-Hash: aa496ec33d21ab03 +# Source-Hash: 7bd5f29203a28efb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit {kind}" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ungroup" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.lib.hudTitle.editKind" -msgstr "{kind}を編集" +msgid "editor.panels.multiSelectionPanel.ungroup" +msgstr "グループ解除" -# Source-Hash: f3ea3efa7102844f +# Source-Hash: aec9c3983a440d4a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Erase" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ungroup (Ctrl/Cmd+Shift+G)" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.lib.hudTitle.erase" -msgstr "消去" +msgid "editor.panels.multiSelectionPanel.ungroupCtrlCmdShiftG" +msgstr "グループ解除(Ctrl/Cmd+Shift+G)" -# Source-Hash: 3f907e76526472bf +# Source-Hash: 420385f27c627cee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level terrain" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unwrap the corner" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.lib.hudTitle.levelTerrain" -msgstr "地形を平らにする" +msgid "editor.panels.multiSelectionPanel.unwrapTheCorner" +msgstr "コーナーを解除" -# Source-Hash: 4e911c300d74eb47 +# Source-Hash: 7906c9f4baebc70b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lower terrain" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unwrap the corner: both windows stay, each framed at the corner" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.lib.hudTitle.lowerTerrain" -msgstr "地形を下げる" +msgid "editor.panels.multiSelectionPanel.unwrapTheCornerBothWindowsStay" +msgstr "コーナーを解除:両方の窓は残り、それぞれコーナーで枠が付きます" -# Source-Hash: 194a147d4618a994 +# Source-Hash: 170b2049ef0f9131 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selection" +#: packages/editor/src/components/ui/panels/panel-manager.tsx #, fuzzy -msgid "editor.lib.hudTitle.mezzanine" -msgstr "中二階" +msgid "editor.panels.panelManager.selection" +msgstr "選択" -# Source-Hash: c48c4129c9ed249a +# Source-Hash: 7ceade8f25b58fe9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move {kind}" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.lib.hudTitle.moveKind" -msgstr "{kind}を移動" +msgid "editor.panels.panelWrapper.back" +msgstr "戻る" -# Source-Hash: 89f6b7ca8904c656 +# Source-Hash: d7cf5045c01b2eb9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move room" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.lib.hudTitle.moveRoom" -msgstr "部屋を移動" +msgid "editor.panels.panelWrapper.close" +msgstr "閉じる" -# Source-Hash: 9c707069572fb3db +# Source-Hash: 4f15c3e0fe6178b5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move selection" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collapse panel" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.lib.hudTitle.moveSelection" -msgstr "選択を移動" +msgid "editor.panels.panelWrapper.collapsePanel" +msgstr "パネルを折りたたむ" -# Source-Hash: cf2e870fce0f2f51 +# Source-Hash: 135af27a14a4cda7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collections" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.lib.hudTitle.paint" -msgstr "塗装" +msgid "editor.panels.panelWrapper.collections" +msgstr "コレクション" -# Source-Hash: ca197314cb70aa56 +# Source-Hash: 64916cc9ea80f43f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint a rectangle" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Expand panel" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.lib.hudTitle.paintARectangle" -msgstr "矩形を塗る" +msgid "editor.panels.panelWrapper.expandPanel" +msgstr "パネルを展開" -# Source-Hash: ea4ce729e17254f8 +# Source-Hash: 8a9a25621f200922 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint a shape" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Manage collections…" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.lib.hudTitle.paintAShape" -msgstr "形を塗る" +msgid "editor.panels.panelWrapper.manageCollections" +msgstr "コレクションを管理…" -# Source-Hash: 01359502b07284d4 +# Source-Hash: bf91b71a9aa76e94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick material" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.lib.hudTitle.pickMaterial" -msgstr "素材を取得" +msgid "editor.panels.panelWrapper.reset" +msgstr "リセット" -# Source-Hash: 4066e8a3f60b1711 +# Source-Hash: 04a212d6317f6787 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raise terrain" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "“{title}” hit an error and was unloaded for this session." +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.lib.hudTitle.raiseTerrain" -msgstr "地形を上げる" +msgid "editor.panels.panelWrapper.titleHitAnErrorAndWas" +msgstr "「{title}」でエラーが発生したため、このセッションではアンロードされました。" -# Source-Hash: f85bdac0a1d16603 +# Source-Hash: 37d9f63758abdb67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Resize" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mixed" +#: packages/editor/src/components/ui/panels/parametric-field-control.tsx #, fuzzy -msgid "editor.lib.hudTitle.resize" -msgstr "サイズ変更" +msgid "editor.panels.parametricFieldControl.mixed" +msgstr "混在" -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/editor/src/components/ui/panels/parametric-inspector.tsx #, fuzzy -msgid "editor.lib.hudTitle.rotate" -msgstr "回転" +msgid "editor.panels.parametricInspector.actions" +msgstr "操作" -# Source-Hash: a4395168488bb476 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/parametric-inspector.tsx #, fuzzy -msgid "editor.lib.hudTitle.select" -msgstr "選択" +msgid "editor.panels.parametricInspector.delete" +msgstr "削除" -# Source-Hash: ec1f1d68af469867 +# Source-Hash: e2411929697b7ed4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Smart measure" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete with contents" +#: packages/editor/src/components/ui/panels/parametric-inspector.tsx #, fuzzy -msgid "editor.lib.hudTitle.smartMeasure" -msgstr "スマート計測" +msgid "editor.panels.parametricInspector.deleteWithContents" +msgstr "内容ごと削除" -# Source-Hash: 5ba5f22bd1a69e09 +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Smooth terrain" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/editor/src/components/ui/panels/parametric-inspector.tsx #, fuzzy -msgid "editor.lib.hudTitle.smoothTerrain" -msgstr "地形を滑らかにする" +msgid "editor.panels.parametricInspector.move" +msgstr "移動" -# Source-Hash: cbb4687261739397 +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Split {kind}" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.lib.hudTitle.splitKind" -msgstr "{kind}を分割" +msgid "editor.panels.referencePanel.cancel" +msgstr "キャンセル" -# Source-Hash: 96281876ce53ba08 +# Source-Hash: 3a0701ebcb9f26cb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terrace" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Capture" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.lib.hudTitle.terrace" -msgstr "テラス" +msgid "editor.panels.referencePanel.capture" +msgstr "キャプチャ" -# Source-Hash: 8ec6152e139b0e3f +# Source-Hash: 5211341ed18f33f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Polygon room" -#: packages/editor/src/lib/wall-draw-variant.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.lib.wallDrawVariant.polygonRoom" -msgstr "多角形の部屋" +msgid "editor.panels.referencePanel.center" +msgstr "中央" -# Source-Hash: 83a45603ac7f41e8 +# Source-Hash: a5b965dfb0bf2cd3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangle room" -#: packages/editor/src/lib/wall-draw-variant.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.lib.wallDrawVariant.rectangleRoom" -msgstr "矩形の部屋" +msgid "editor.panels.referencePanel.clearScale" +msgstr "縮尺をクリア" -# Source-Hash: aac9a732d2159ccc +# Source-Hash: 4edc6e45b0c19447 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls" -#: packages/editor/src/lib/wall-draw-variant.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click both ends of a known distance on the plan, then type its real length." +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.lib.wallDrawVariant.walls" -msgstr "壁" +msgid "editor.panels.referencePanel.clickBothEndsOfAKnown" +msgstr "図面上で既知の距離の両端をクリックし、実際の長さを入力します。" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: c2626e1fbf89b3c9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{action, select, close {Close} open {Open} stop {Stop} other {Play}}" -#: packages/editor/src/components/editor/registry-action-contributions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.mechanismAction" -msgstr "{action, select, close {閉じる} open {開く} stop {停止} other {再生}}" +msgid "editor.panels.referencePanel.delete" +msgstr "削除" +# Source-Hash: 59f7d81e8d36a157 # Review: required -# Source-Hash: f08fbb462e9afc0e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curve" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw a line over a known dimension on the plan, then type its real length to scale the image exactly." +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeActionMenu.curve" -msgstr "曲線" +msgid "editor.panels.referencePanel.drawALineOverAKnown" +msgstr "図面上の既知の寸法に線を引き、実際の長さを入力すると画像の縮尺を正確に合わせられます。" +# Source-Hash: 42f6d0e4f065f114 # Review: required -# Source-Hash: 5af05fb6661e4d6a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut out" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeActionMenu.cutOut" -msgstr "切り抜き" +msgid "editor.panels.referencePanel.editScale" +msgstr "縮尺を編集" +# Source-Hash: e156c84cbc90e0a7 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guide Image" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeActionMenu.delete" -msgstr "削除" +msgid "editor.panels.referencePanel.guideImage" +msgstr "ガイド画像" +# Source-Hash: 591087ea83a48ead # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeActionMenu.duplicate" -msgstr "複製" +msgid "editor.panels.referencePanel.hide" +msgstr "非表示" +# Source-Hash: dd282ce13b9085ba # Review: required -# Source-Hash: 94b212bd79c05141 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit mesh" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeActionMenu.editMesh" -msgstr "メッシュを編集" +msgid "editor.panels.referencePanel.hideScale" +msgstr "縮尺を隠す" +# Source-Hash: fc6eaa65315f601d # Review: required -# Source-Hash: ce90cf37224f73cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Find in catalog" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Image" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeActionMenu.findInCatalog" -msgstr "カタログで探す" +msgid "editor.panels.referencePanel.image" +msgstr "画像" +# Source-Hash: 241399e11d93bd7b # Review: required -# Source-Hash: d5e550c345e7161c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Group selection" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lock" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeActionMenu.groupSelection" -msgstr "選択をグループ化" +msgid "editor.panels.referencePanel.lock" +msgstr "ロック" -# Review: required # Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Move" -#: packages/editor/src/components/editor/node-action-menu.tsx +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeActionMenu.move" +msgid "editor.panels.referencePanel.move" msgstr "移動" +# Source-Hash: 1c0b8a5503c5daeb # Review: required -# Source-Hash: 473a9d4463761107 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate left" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opacity" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeActionMenu.rotateLeft" -msgstr "左に回転" +msgid "editor.panels.referencePanel.opacity" +msgstr "不透明度" +# Source-Hash: 6ca213a6b299f19f # Review: required -# Source-Hash: b1bf4e65c8d8c8ef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate right" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overlay image unavailable. Replace the image to restore it." +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeActionMenu.rotateRight" -msgstr "右に回転" +msgid "editor.panels.referencePanel.overlayImageUnavailableReplaceTheImage" +msgstr "重ね合わせ画像が利用できません。画像を置き換えると復元されます。" +# Source-Hash: 28fe6e9deddde6e8 # Review: required -# Source-Hash: 6f4dbbc4a3f58fca -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ungroup selection" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "pos" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeActionMenu.ungroupSelection" -msgstr "選択のグループを解除" +msgid "editor.panels.referencePanel.pos" +msgstr "位置" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeDisplay.ceiling" -msgstr "天井" +msgid "editor.panels.referencePanel.position" +msgstr "位置" -# Source-Hash: 3530ac1f4046cd22 +# Source-Hash: 8b003432b36230c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Column" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Quick Actions" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeDisplay.column" -msgstr "柱" +msgid "editor.panels.referencePanel.quickActions" +msgstr "クイック操作" -# Source-Hash: 787e10f5db16904e +# Source-Hash: dcd4728e9ca90181 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reference Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeDisplay.door" -msgstr "ドア" +msgid "editor.panels.referencePanel.referenceScale" +msgstr "参照縮尺" -# Source-Hash: ab5cbab7be160a1c +# Source-Hash: 0cb87327b8076151 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevator" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeDisplay.elevator" -msgstr "エレベーター" +msgid "editor.panels.referencePanel.replace" +msgstr "置き換え" -# Source-Hash: 02042fde61b5aa11 +# Source-Hash: 08b45f9ba66eab3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fence" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replacing..." +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeDisplay.fence" -msgstr "フェンス" +msgid "editor.panels.referencePanel.replacing" +msgstr "置き換え中..." -# Source-Hash: 4c3ff8cdc6feda97 +# Source-Hash: 2714b5a81cedb625 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guide image" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset Image Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeDisplay.guide" -msgstr "ガイド画像" +msgid "editor.panels.referencePanel.resetImageScale" +msgstr "画像の縮尺をリセット" -# Source-Hash: 2743a0e9d2743807 +# Source-Hash: a05d3e429ae259ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Item" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset Rotation" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeDisplay.item" -msgstr "アイテム" +msgid "editor.panels.referencePanel.resetRotation" +msgstr "回転をリセット" -# Source-Hash: f5f730969df63d1d +# Source-Hash: 5f433581c8f404fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "rot" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeDisplay.roof" -msgstr "屋根" +msgid "editor.panels.referencePanel.rot" +msgstr "回転" -# Source-Hash: a130b4eec084c79a +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof segment" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeDisplay.roofSegment" -msgstr "屋根セグメント" +msgid "editor.panels.referencePanel.rotation" +msgstr "回転" -# Source-Hash: 612dcd5bf06a79c4 +# Source-Hash: 58fee802997c811c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeDisplay.room" -msgstr "部屋" +msgid "editor.panels.referencePanel.scale" +msgstr "縮尺" -# Source-Hash: b22b2f20cc7cd416 +# Source-Hash: e7d0e7d41a775fd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "3D Scan" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scaled · {scale}" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeDisplay.scan" -msgstr "3Dスキャン" +msgid "editor.panels.referencePanel.scaled" +msgstr "縮尺設定済み · {scale}" -# Source-Hash: 170b2049ef0f9131 +# Source-Hash: cd92eebfb30e708f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Selection" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scaled (hidden) · {scale}" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeDisplay.selection" -msgstr "選択" +msgid "editor.panels.referencePanel.scaledHidden" +msgstr "縮尺設定済み(非表示)· {scale}" -# Source-Hash: 8775bc8dc9593964 +# Source-Hash: bfd20999de7f216a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scale & Opacity" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeDisplay.slab" -msgstr "スラブ" +msgid "editor.panels.referencePanel.scaleOpacity" +msgstr "縮尺と不透明度" -# Source-Hash: 53d7084bc41c1ad6 +# Source-Hash: 8d8777505acdf78e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeDisplay.stair" -msgstr "階段" +msgid "editor.panels.referencePanel.setScale" +msgstr "縮尺を設定" -# Source-Hash: 52de428c16bb81e6 +# Source-Hash: 827e0c6ac9936b69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair segment" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeDisplay.stairSegment" -msgstr "階段セグメント" +msgid "editor.panels.referencePanel.show" +msgstr "表示" -# Source-Hash: 2210e5ee50b74dc9 +# Source-Hash: 78be2337f0e81973 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeDisplay.wall" -msgstr "壁" +msgid "editor.panels.referencePanel.showScale" +msgstr "縮尺を表示" -# Source-Hash: aa3c35ed33e181e5 +# Source-Hash: ad85a193442c8f76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Window" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Uncalibrated" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeDisplay.window" -msgstr "窓" +msgid "editor.panels.referencePanel.uncalibrated" +msgstr "未校正" -# Source-Hash: a107b4d76d6972e3 +# Source-Hash: 6c500cc253ab3fd4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unlock" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.nodeDisplay.zone" -msgstr "ゾーン" +msgid "editor.panels.referencePanel.unlock" +msgstr "ロック解除" -# Source-Hash: c0774c185060fc13 +# Source-Hash: 4b8d7e52013d1691 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "XYZ" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.collections.collectionsPopover.cancel" -msgstr "キャンセル" +msgid "editor.panels.referencePanel.xyz" +msgstr "XYZ" -# Source-Hash: 6dbabf32ff8c6f37 +# Source-Hash: e01549105012f8d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collection name…" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "+ Add mezzanine" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.collections.collectionsPopover.collectionName" -msgstr "コレクション名…" +msgid "editor.panels.roomConstructionRows.addMezzanine" +msgstr "+ 中二階を追加" -# Source-Hash: 135af27a14a4cda7 +# Source-Hash: 167b0fe7fdbcd51d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collections" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A drawn slab: set its thickness and finishes here. It has no footprint height or foundation." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.collections.collectionsPopover.collections" -msgstr "コレクション" +msgid "editor.panels.roomConstructionRows.aDrawnSlabSetItsThickness" +msgstr "描画されたスラブ:ここで厚さと仕上げを設定します。フットプリントの高さや基礎はありません。" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 6cb0969b65fb60bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "At floor level" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.collections.collectionsPopover.delete" -msgstr "削除" +msgid "editor.panels.roomConstructionRows.atFloorLevel" +msgstr "床レベル" -# Source-Hash: c53d71b05b8163b2 +# Source-Hash: e14858b33b6e2623 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete \"{name}\"?" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.collections.collectionsPopover.deleteName" -msgstr "「{name}」を削除しますか?" +msgid "editor.panels.roomConstructionRows.beam" +msgstr "梁" -# Source-Hash: e9f7cceb39860c56 +# Source-Hash: 4b03c226d5f88a42 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "New" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam size" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.collections.collectionsPopover.new" -msgstr "新規" +msgid "editor.panels.roomConstructionRows.beamSize" +msgstr "梁のサイズ" -# Source-Hash: 649bc1b1799f2311 +# Source-Hash: e8563d5ae1ee7390 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No collections yet. Create one to group elements together." -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Built on" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.collections.collectionsPopover.noCollectionsYetCreateOneTo" -msgstr "コレクションはまだありません。作成すると要素をまとめられます。" +msgid "editor.panels.roomConstructionRows.builtOn" +msgstr "建築先" -# Source-Hash: d6952b4e54d246dd +# Source-Hash: 8e5ca7510677460c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rename" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Built with" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.collections.collectionsPopover.rename" -msgstr "名前を変更" +msgid "editor.panels.roomConstructionRows.builtWith" +msgstr "構成" -# Source-Hash: 2000cf124b4e1139 +# Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A thicker floor grows upward: the rooms below keep their height." -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.aThickerFloorGrowsUpwardThe" -msgstr "床を厚くすると上方向に伸び、下の部屋の高さは変わりません。" +msgid "editor.panels.roomConstructionRows.ceiling" +msgstr "天井" -# Source-Hash: 0d57958b99b6b352 +# Source-Hash: 9bf177f59f971033 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edge finish" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "At {height}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.edgeFinish" -msgstr "縁の仕上げ" +msgid "editor.panels.roomConstructionRows.ceilingAt" +msgstr "{height} の位置" -# Source-Hash: 8e458d8b21f26f09 +# Source-Hash: 48768dc0fc7b86a4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close with walls" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorPlate" -msgstr "床版" +msgid "editor.panels.roomConstructionRows.closeWithWalls" +msgstr "壁で閉じる" -# Source-Hash: 2bb71e5633801afb +# Source-Hash: 75c84b4f21aefde4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate {thicknessLabel} thick, resting on the walls below" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{ambiguous, select, yes {Floor is several drawn slabs, mostly {name}} other {Floor is a drawn slab: {name}}}{shared, plural, =0 {} one { (shared with {sharedCount} room)} other { (shared with {sharedCount} rooms)}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorPlateThicknesslabelThickRestingOn" -msgstr "厚さ {thicknessLabel} の床版、下の壁の上に載ります" +msgid "editor.panels.roomConstructionRows.drawnFloor" +msgstr "{ambiguous, select, yes {床は複数の描画スラブで、主に{name}} other {床は描画スラブです:{name}}}{shared, plural, =0 {} other {({sharedCount} 部屋と共有)}}" -# Source-Hash: 73614b8faa059cd6 +# Source-Hash: 97e0fab8ffda6d6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor thickness" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This floor is a drawn slab: select it to edit or delete it." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorThickness" -msgstr "床の厚さ" +msgid "editor.panels.roomConstructionRows.drawnFloorSwitchHint" +msgstr "この床は描画スラブです。選択して編集または削除してください。" -# Source-Hash: a40a1fbacd5d2551 +# Source-Hash: ad5426620188242c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor top +{height}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawn slab" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorTopAbove" -msgstr "床上面 +{height}" +msgid "editor.panels.roomConstructionRows.drawnSlab" +msgstr "描画スラブ" -# Source-Hash: 5c3849e15933737f +# Source-Hash: 0da0d104eaefbbad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor top {height}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawn slab at {height}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorTopValue" -msgstr "床上面 {height}" +msgid "editor.panels.roomConstructionRows.drawnSlabAt" +msgstr "描画スラブ({height})" -# Source-Hash: 19802dd369749ea7 +# Source-Hash: 5dfead58503dbc86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation finish" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit shape" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.foundationFinish" -msgstr "基礎の仕上げ" +msgid "editor.panels.roomConstructionRows.editShape" +msgstr "形状を編集" -# Source-Hash: 3a4599be1ad687be +# Source-Hash: fadf264be55063e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation height" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat, at wall height" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.foundationHeight" -msgstr "基礎の高さ" +msgid "editor.panels.roomConstructionRows.flatAtWallHeight" +msgstr "平ら(壁の高さ)" -# Source-Hash: 8e458d8b21f26f09 +# Source-Hash: d7148fa065bc709b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.kicker" -msgstr "床版" +msgid "editor.panels.roomConstructionRows.floor" +msgstr "階" -# Source-Hash: 66d52bfbb94f7bb3 +# Source-Hash: 996e8191c069e779 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate · {level}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{distance} down" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.kickerLevel" -msgstr "床版 · {level}" +msgid "editor.panels.roomConstructionRows.floorDown" +msgstr "{distance} 下" -# Source-Hash: 0189e5a1987b4ec0 +# Source-Hash: 73614b8faa059cd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate · {level} · rests on {below}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor thickness" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.kickerRestsOn" -msgstr "床版 · {level} · {below}の上" +msgid "editor.panels.roomConstructionRows.floorThickness" +msgstr "床の厚さ" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 648ef10535b0af73 +# Source-Hash: 79cdde853c3e8f61 # Review: required -# English: "{count, plural, =2 {Lower both} other {Lower all {number}}}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{distance} up" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.lowerTogether" -msgstr "{count, plural, =2 {両方を下げる} other {{number} 個すべてを下げる}}" +msgid "editor.panels.roomConstructionRows.floorUp" +msgstr "{distance} 上" -# Source-Hash: c2fcc43bb7f1c5e2 +# Source-Hash: b6b724f9f4db6d3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Not to scale" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{posts, plural, one {{postCount} post} other {{postCount} posts}} and {beams, plural, one {{beamCount} beam} other {{beamCount} beams}}, a post on each outside corner, kept with {room, select, deck {the deck} patio {the patio} other {the porch}}." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.notToScale" -msgstr "縮尺なし" +msgid "editor.panels.roomConstructionRows.framingAutoHint" +msgstr "{posts, plural, other {支柱 {postCount} 本}}と{beams, plural, other {梁 {beamCount} 本}}。外側の各角に支柱があり、{room, select, deck {デッキ} patio {パティオ} other {ポーチ}}と連動します。" -# Source-Hash: e9440fa9f770b7a4 +# Source-Hash: d18036b75b2c3e4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "On the ground" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Automatic" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.onTheGround" -msgstr "地面上" +msgid "editor.panels.roomConstructionRows.framingAutomatic" +msgstr "自動" -# Source-Hash: 7c3692a361075ecf +# Source-Hash: 387082cd5f118bed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised on a foundation" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Manual" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.raisedOnAFoundation" -msgstr "基礎の上に上げる" +msgid "editor.panels.roomConstructionRows.framingManual" +msgstr "手動" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 769c3ca1ca0cd4f0 +# Source-Hash: 287400b1b4b46abd # Review: required -# English: "{count, plural, =2 {Raise both} other {Raise all {number}}}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kept as you edited them. Automatic rebuilds them from these settings." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.raiseTogether" -msgstr "{count, plural, =2 {両方を上げる} other {{number} 個すべてを上げる}}" +msgid "editor.panels.roomConstructionRows.framingManualHint" +msgstr "編集した状態のまま保持されます。「自動」にすると、これらの設定から作り直します。" -# Source-Hash: 719ae422da204ca7 +# Source-Hash: 50accd740fa2e736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate · {thickness}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Off" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.floorPlate" -msgstr "床版 · {thickness}" +msgid "editor.panels.roomConstructionRows.framingOff" +msgstr "オフ" -# Source-Hash: 069d64adffa05db7 +# Source-Hash: 4dfa7082b7e30280 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor top" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None. Automatic puts a post on each outside corner and a beam on them, to carry a roof over {room, select, deck {the deck} patio {the patio} other {the porch}}." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.floorTop" -msgstr "床上面" +msgid "editor.panels.roomConstructionRows.framingOffHint" +msgstr "なし。「自動」にすると外側の各角に支柱を、その上に梁を配置し、{room, select, deck {デッキ} patio {パティオ} other {ポーチ}}の上に屋根を架けられるようにします。" -# Source-Hash: 48c832c1fc389290 +# Source-Hash: 77bc12b7aba0eb60 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hand-drawn ceiling" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.foundation" -msgstr "基礎" +msgid "editor.panels.roomConstructionRows.handDrawnCeiling" +msgstr "手描きの天井" -# Source-Hash: 7759a59b8685c885 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation · {foundation}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.foundationKind" -msgstr "基礎 · {foundation}" +msgid "editor.panels.roomConstructionRows.height" +msgstr "高さ" -# Source-Hash: 94cc8e9f1ee16edb +# Source-Hash: 4d35023efe090b82 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Include floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.ground" -msgstr "地面" +msgid "editor.panels.roomConstructionRows.includeFloor" +msgstr "床を含める" -# Source-Hash: 51e274b2c90e2cf3 +# Source-Hash: 6398ac77644eb5f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab · {thickness}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{part, select, floor {Include floor} walls {Include walls} other {Include ceiling}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.slab" -msgstr "スラブ · {thickness}" +msgid "editor.panels.roomConstructionRows.includePart" +msgstr "{part, select, floor {床を含める} walls {壁を含める} other {天井を含める}}" -# Source-Hash: 790a0b5c6dbf0e9b +# Source-Hash: 3629e64a6e796ca9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls below" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Include walls" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.wallsBelow" -msgstr "下の壁" +msgid "editor.panels.roomConstructionRows.includeWalls" +msgstr "壁を含める" -# Source-Hash: 90e96ae5f3d3f69c +# Source-Hash: f6d07fc7f239278b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab {thickness} thick on the ground, floor top {top} above the ground" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keep outside dimensions" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.sectionOnGround" -msgstr "厚さ {thickness} のスラブ、地面の上、床上面は地面から {top}" +msgid "editor.panels.roomConstructionRows.keepOutsideDimensions" +msgstr "外形寸法を保つ" -# Source-Hash: 71ed2295d9932ed0 +# Source-Hash: 544410e3cb0e0b07 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab {thickness} thick on a {foundation} foundation, floor top {top} above the ground" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lowered {lift}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.sectionRaised" -msgstr "厚さ {thickness} のスラブ、{foundation}基礎の上、床上面は地面から {top}" +msgid "editor.panels.roomConstructionRows.lowered" +msgstr "{lift} 下げる" -# Source-Hash: 8775bc8dc9593964 +# Source-Hash: c2daf78b740e4397 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "+ New floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.slab" -msgstr "スラブ" +msgid "editor.panels.roomConstructionRows.newFloor" +msgstr "+ 新しい床" -# Source-Hash: ca51d643691c29ae +# Source-Hash: ba9edc7910a60cea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab thickness" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.slabThickness" -msgstr "スラブの厚さ" +msgid "editor.panels.roomConstructionRows.noFloor" +msgstr "床なし" -# Source-Hash: 678c39468593275b +# Source-Hash: ea2675041df74f40 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The floor's outside edge, all around the footprint." -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Nothing to change." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.theFloorSOutsideEdgeAll" -msgstr "フットプリント全周にわたる床の外縁。" +msgid "editor.panels.roomConstructionRows.nothingToChange" +msgstr "変更する内容はありません。" -# Source-Hash: 6638ed5caa43bdb9 +# Source-Hash: ebe0d375d7938c93 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The foundation stands on the ground; the slab sits on it." -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not included" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.theFoundationStandsOnTheGround" -msgstr "基礎は地面の上に、スラブは基礎の上に載ります。" +msgid "editor.panels.roomConstructionRows.notIncluded" +msgstr "含まれていません" -# Source-Hash: 5321416b442f23b4 +# Source-Hash: e9440fa9f770b7a4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The slab sits on the foundation (or the ground): a thicker slab raises the floor top and everything on it." -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On the ground" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.theSlabSitsOnTheFoundation" -msgstr "スラブは基礎(または地面)の上に載ります。厚くすると床上面とその上のすべてが上がります。" +msgid "editor.panels.roomConstructionRows.onTheGround" +msgstr "地面上" -# Source-Hash: 044ccae8bec574e7 +# Source-Hash: a5deb36c485d91bd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Under the floor" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On the walls below" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.underTheFloor" -msgstr "床下" +msgid "editor.panels.roomConstructionRows.onTheWallsBelow" +msgstr "下の壁の上" -# Source-Hash: 6aca44df3e582a81 +# Source-Hash: 2256aec0d5bdc3ea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A hatch in the mezzanine: it cuts only the mezzanine’s floor." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{openSides, plural, one {{openSideCount} open side} other {{openSideCount} open sides}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.aHatchInTheMezzanineIt" -msgstr "中二階のハッチ:中二階の床だけを切り抜きます。" +msgid "editor.panels.roomConstructionRows.openSides" +msgstr "{openSides, plural, other {{openSideCount} 個の開放辺}}" -# Source-Hash: 2ce79639d42da658 +# Source-Hash: f704520c5e5b92b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Also cut the ceiling below" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Partial · {coverage, number, percent} covered" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.alsoCutTheCeilingBelow" -msgstr "下の天井も切り抜く" +msgid "editor.panels.roomConstructionRows.partialCovered" +msgstr "部分 · {coverage, number, percent} を覆う" -# Source-Hash: e360814f64792300 +# Source-Hash: b648bee0231a41cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Also cut the floor above" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Partial · {walls, plural, one {{wallCount} wall} other {{wallCount} walls}}, {openSides, plural, one {{openSideCount} open side} other {{openSideCount} open sides}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.alsoCutTheFloorAbove" -msgstr "上の床も切り抜く" +msgid "editor.panels.roomConstructionRows.partialWalls" +msgstr "部分 · {walls, plural, other {{wallCount} 枚の壁}}、{openSides, plural, other {{openSideCount} 個の開放辺}}" -# Source-Hash: c25cddf8b831c2b2 +# Source-Hash: 4b2a51c39b382184 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{area} · Drag its corners to change the shape." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Posts and beam" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.areaDragCorners" -msgstr "{area} · 角をドラッグして形状を変更します。" +msgid "editor.panels.roomConstructionRows.postsAndBeam" +msgstr "支柱と梁" -# Source-Hash: 32b168cf010a5daa +# Source-Hash: faa36308c1ecb2a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{area} · Shape follows its owner." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post size" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.areaOwned" -msgstr "{area} · 形状は所有元に従います。" +msgid "editor.panels.roomConstructionRows.postSize" +msgstr "支柱のサイズ" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: cc25439729a97f76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post spacing (max)" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.delete" -msgstr "削除" +msgid "editor.panels.roomConstructionRows.postSpacingMax" +msgstr "支柱の間隔(最大)" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: e503250e8ecb0030 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised {lift}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.done" -msgstr "完了" +msgid "editor.panels.roomConstructionRows.raised" +msgstr "{lift} 上げ" -# Source-Hash: e04298381837252f +# Source-Hash: 0cb87327b8076151 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.kicker" -msgstr "開口" +msgid "editor.panels.roomConstructionRows.replace" +msgstr "置き換え" -# Source-Hash: 079ad92dac7947cf +# Source-Hash: be1c56bb3ddc63c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening · {level}" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room type" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.kickerLevel" -msgstr "開口 · {level}" +msgid "editor.panels.roomConstructionRows.roomType" +msgstr "部屋の種類" -# Source-Hash: baf2c2c209637e5f +# Source-Hash: f3aa561772702108 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening · in {room}" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.kickerRoom" -msgstr "開口 · {room}内" +msgid "editor.panels.roomConstructionRows.roomTypeDeck" +msgstr "デッキ" -# Source-Hash: 1712c164335ecd86 +# Source-Hash: f0028986efecf7d1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening · in {room} · {level}" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outdoors: deck boards on a wood frame and posts, 1 in down from the house; no ceiling." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.kickerRoomLevel" -msgstr "開口 · {room}内 · {level}" +msgid "editor.panels.roomConstructionRows.roomTypeDeckHint" +msgstr "屋外:木製の床組と支柱の上にデッキ板を張り、住宅の床より 1 in 下げます。天井なし。" -# Source-Hash: 88e673123b9dbfe1 +# Source-Hash: 78dbe13192c0894b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "On {level}, as one void with this opening." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Patio" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +#, fuzzy +msgid "editor.panels.roomConstructionRows.roomTypePatio" +msgstr "パティオ" + +# Source-Hash: 5e4ea6a084f67808 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outdoors and open: a concrete slab 1½ in down from the house, no ceiling." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.oneVoidWith" -msgstr "{level}で、この開口と一体の吹き抜けになります。" +msgid "editor.panels.roomConstructionRows.roomTypePatioHint" +msgstr "屋外・開放:住宅の床より 1½ in 低いコンクリートスラブ。天井なし。" -# Source-Hash: c38959fc8fd3e59d +# Source-Hash: 97d20e41044a3235 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Owned by Elevator" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Porch" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.ownedByElevator" -msgstr "エレベーターに属する" +msgid "editor.panels.roomConstructionRows.roomTypePorch" +msgstr "ポーチ" -# Source-Hash: 01494805cf60d78d +# Source-Hash: af2c941e8ef874bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Owned by Staircase" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outdoors under a ceiling: a concrete slab 1½ in down from the house, ceiling at the house’s." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.ownedByStaircase" -msgstr "階段に属する" +msgid "editor.panels.roomConstructionRows.roomTypePorchHint" +msgstr "屋外(天井あり):住宅の床より 1½ in 低いコンクリートスラブ。天井は住宅と同じ高さ。" # Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Room" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.room" +msgid "editor.panels.roomConstructionRows.roomTypeRoom" msgstr "部屋" -# Source-Hash: 1405b914a324b153 +# Source-Hash: fb0a6cc444058631 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "There is no floor above this storey." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An ordinary room inside the house." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.thereIsNoFloorAboveThis" -msgstr "この階の上に床はありません。" +msgid "editor.panels.roomConstructionRows.roomTypeRoomHint" +msgstr "住宅内の通常の部屋。" -# Source-Hash: 776170dcae88e969 +# Source-Hash: a4395168488bb476 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "There is no storey below." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.thereIsNoStoreyBelow" -msgstr "下の階はありません。" +msgid "editor.panels.roomConstructionRows.select" +msgstr "選択" -# Source-Hash: 0fdd1877a0f2d777 +# Source-Hash: 85ea1d3c8b749680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{source, select, stair {Stair opening} elevator {Elevator opening} ceiling {Ceiling opening} other {Floor opening}}" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.title" -msgstr "{source, select, stair {階段の開口} elevator {エレベーターの開口} ceiling {天井の開口} other {床の開口}}" +msgid "editor.panels.roomConstructionRows.shape" +msgstr "形状" -# Source-Hash: fa35c7653e1f649e +# Source-Hash: aafd84823715d698 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "One of them already wraps another corner. Unwrap it first." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turning walls off keeps the ones shared with {rooms}." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.alreadyJoined" -msgstr "どちらかがすでに別のコーナーを回っています。先に解除してください。" +msgid "editor.panels.roomConstructionRows.sharedWallsNote" +msgstr "壁をオフにしても、{rooms}と共有する壁は残ります。" -# Source-Hash: dd87eb1983876459 +# Source-Hash: c98df900d43f77bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{kind, select, item {There is an item between them.} door {There is a door between them.} window {There is a window between them.} shelf {There is a shelf between them.} other {There is something between them.}}" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sits on: {name} · {preset}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.between" -msgstr "{kind, select, item {間にアイテムがあります。} door {間にドアがあります。} window {間に窓があります。} shelf {間に棚があります。} other {間に何かがあります。}}" +msgid "editor.panels.roomConstructionRows.sitsOnPreset" +msgstr "設置先:{name} · {preset}" -# Source-Hash: 58aea0b9789ae280 +# Source-Hash: a17a79e835fa2064 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "These windows cannot be merged." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "the next room" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.cannotMerge" -msgstr "これらの窓は結合できません。" +msgid "editor.panels.roomConstructionRows.theNextRoom" +msgstr "隣の部屋" -# Source-Hash: 15170cfd9d666c4f +# Source-Hash: ebae699e0cb18ea6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Their walls meet at too sharp or too flat an angle for a corner window." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use existing" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.cornerAngle" -msgstr "壁の角度が鋭すぎるか平らすぎて、コーナー窓にできません。" +msgid "editor.panels.roomConstructionRows.useExisting" +msgstr "既存を使用" -# Source-Hash: f2818a1e20ebd6ca +# Source-Hash: 9976021d9162cd5e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The window selected first is taller than the other wall. Select the other one first." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{walls, plural, one {{wallCount} wall} other {{wallCount} walls}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.heightExceedsWall" -msgstr "最初に選んだ窓がもう一方の壁より高いです。先にもう一方を選んでください。" +msgid "editor.panels.roomConstructionRows.wallCount" +msgstr "{walls, plural, other {{wallCount} 枚の壁}}" -# Source-Hash: 7c97fb4af929d4db +# Source-Hash: aac9a732d2159ccc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "They are too far apart. Windows merge with at most {reach} between them." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.notAdjacent" -msgstr "離れすぎています。窓は間隔が {reach} 以内のときに結合します。" +msgid "editor.panels.roomConstructionRows.walls" +msgstr "壁" -# Source-Hash: 57a281bdc4229b6d +# Source-Hash: 6c69eb46a0c40d52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "One of them is too far from the corner. A window joins one within {reach} of it." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls thicken inward, so the building's outer size stays the same." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.notAtCorner" -msgstr "どちらかがコーナーから離れすぎています。窓は {reach} 以内の窓と結合します。" +msgid "editor.panels.roomConstructionRows.wallsThickenInwardSoTheBuilding" +msgstr "壁は内側に厚くなるため、建物の外形寸法は変わりません。" -# Source-Hash: e7d41ce7879ec075 +# Source-Hash: 4e4f1a24e4a9d61e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A roof or dormer window cannot join another window." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut opening" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.notOnWall" -msgstr "屋根窓やドーマー窓は他の窓と結合できません。" +msgid "editor.panels.roomOpeningsField.cutOpening" +msgstr "開口を切る" -# Source-Hash: eaad567d5e4257dc +# Source-Hash: 16552c2580bbe8b8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{kind, select, item {Sliding them to the corner would overlap an item.} door {Sliding them to the corner would overlap a door.} window {Sliding them to the corner would overlap a window.} shelf {Sliding them to the corner would overlap a shelf.} other {Sliding them to the corner would overlap something.}}" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.overlap" -msgstr "{kind, select, item {コーナーまでずらすとアイテムと重なります。} door {コーナーまでずらすとドアと重なります。} window {コーナーまでずらすと窓と重なります。} shelf {コーナーまでずらすと棚と重なります。} other {コーナーまでずらすと何かと重なります。}}" +msgid "editor.panels.roomOpeningsField.done" +msgstr "完了" -# Source-Hash: ecb092821ed5b5e8 +# Source-Hash: 2c89abb1778a3f9b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Their walls do not meet at a corner." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit floor" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.wallsNotMeeting" -msgstr "それぞれの壁がコーナーで接していません。" +msgid "editor.panels.roomOpeningsField.editFloor" +msgstr "床を編集" -# Source-Hash: 37d9f63758abdb67 +# Source-Hash: ca18a6c5398fc8ab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mixed" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx -#: packages/editor/src/components/ui/panels/parametric-field-control.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevator opening" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.panels.mixed" -msgstr "混在" +msgid "editor.panels.roomOpeningsField.elevatorOpening" +msgstr "エレベーター開口" -# Source-Hash: d7cf5045c01b2eb9 +# Source-Hash: eafea43e795f3708 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close" -#: packages/editor/src/components/ui/panels/mobile-panel-sheet.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No openings yet. Cut one for a stair void or a hatch." +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.panels.mobilePanelSheet.close" -msgstr "閉じる" +msgid "editor.panels.roomOpeningsField.noOpeningsYetCutOneFor" +msgstr "開口はまだありません。階段の吹き抜けやハッチ用に切り抜いてください。" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 60fac94ffa614238 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening {number}" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx +#, fuzzy +msgid "editor.panels.roomOpeningsField.openingNumber" +msgstr "開口 {number}" + +# Source-Hash: 7aafbf90d659dcf6 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, =0 {No openings} one {{number} opening} other {{number} openings}}" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx +#, fuzzy +msgid "editor.panels.roomOpeningsField.openings" +msgstr "{count, plural, =0 {開口なし} other {開口 {number} 個}}" + +# Source-Hash: c1a1794d31990f5a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair opening" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx +#, fuzzy +msgid "editor.panels.roomOpeningsField.stairOpening" +msgstr "階段の開口" + +# Source-Hash: f0a46329fef44d94 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add stairs" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.delete" -msgstr "削除" +msgid "editor.panels.roomPanel.addStairs" +msgstr "階段を追加" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 8a2ab34a61b9d181 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add to a unit" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.duplicate" -msgstr "複製" +msgid "editor.panels.roomPanel.addToAUnit" +msgstr "ユニットに追加" -# Source-Hash: 7eb955d866c2668b +# Source-Hash: 8332ab41e22958f1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit properties" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Area" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.editProperties" -msgstr "プロパティを編集" +msgid "editor.panels.roomPanel.area" +msgstr "面積" -# Source-Hash: 89f25aa13e8192bc +# Source-Hash: 88f1a727e5528c10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit {resolvedLabel}" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Browse" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.editResolvedlabel" -msgstr "{resolvedLabel}を編集" +msgid "editor.panels.roomPanel.browse" +msgstr "閲覧" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 8e5ca7510677460c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Built with" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.move" -msgstr "移動" +msgid "editor.panels.roomPanel.builtWith" +msgstr "構成" -# Source-Hash: 72be05e1796526c9 +# Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Currently {currentLabel}" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.currentlyCurrentlabel" -msgstr "現在:{currentLabel}" +msgid "editor.panels.roomPanel.ceiling" +msgstr "天井" -# Source-Hash: b2a1b3bc9676fe05 +# Source-Hash: a5e4fe4960deced9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom height" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete room" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.customHeight" -msgstr "カスタムの高さ" +msgid "editor.panels.roomPanel.deleteRoom" +msgstr "部屋を削除" -# Source-Hash: a5c2353769b603d5 +# Source-Hash: 5dfead58503dbc86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows level" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit shape" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.followsLevel" -msgstr "階層に従う" +msgid "editor.panels.roomPanel.editShape" +msgstr "形状を編集" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: d7148fa065bc709b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.height" -msgstr "高さ" +msgid "editor.panels.roomPanel.floor" +msgstr "階" -# Source-Hash: 27644f0497fd9849 +# Source-Hash: d17c3b63449c052b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{height} headroom" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.top" -msgstr "上" +msgid "editor.panels.roomPanel.headroom" +msgstr "頭上空間 {height}" -# Source-Hash: 70f48b0141b656f2 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{label} (session only). Plain click reselects all members. Not saved with the project." -#: packages/editor/src/components/ui/panels/multi-parametric-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiParametricInspector.labelSessionOnlyPlainClickReselects" -msgstr "{label}(このセッションのみ)。通常クリックで全メンバーを再選択します。プロジェクトには保存されません。" +msgid "editor.panels.roomPanel.height" +msgstr "高さ" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 2d89c1638aa8dd7e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide code" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.delete" -msgstr "削除" +msgid "editor.panels.roomPanel.hideCode" +msgstr "コードを隠す" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: e93969f5a7cbb140 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room · {level}" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.duplicate" -msgstr "複製" +msgid "editor.panels.roomPanel.kickerLevel" +msgstr "部屋 · {level}" -# Source-Hash: b0e7e3b47dfb5a0b +# Source-Hash: f4ad56b4e0c014b3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Group" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine · in {room}" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.group" -msgstr "グループ化" +msgid "editor.panels.roomPanel.kickerMezzanineIn" +msgstr "中二階 · {room}内" -# Source-Hash: ca0a95fe0b08b8b6 +# Source-Hash: de37205633316011 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Group (Ctrl/Cmd+G)" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room · not enclosed" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.groupCtrlCmdG" -msgstr "グループ化(Ctrl/Cmd+G)" +msgid "editor.panels.roomPanel.kickerNotEnclosed" +msgstr "部屋 · 囲まれていない" -# Source-Hash: 70f48b0141b656f2 +# Source-Hash: 9e84d6d7b9885c4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{label} (session only). Plain click reselects all members. Not saved with the project." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Loading…" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.labelSessionOnlyPlainClickReselects" -msgstr "{label}(このセッションのみ)。通常クリックで全メンバーを再選択します。プロジェクトには保存されません。" +msgid "editor.panels.roomPanel.loading" +msgstr "読み込み中…" -# Source-Hash: fc98ef29c2842341 +# Source-Hash: 194a147d4618a994 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{length} selected" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.lengthSelected" -msgstr "{length} 個選択中" +msgid "editor.panels.roomPanel.mezzanine" +msgstr "中二階" -# Source-Hash: 323aaf1ebd04ada7 +# Source-Hash: 97de3df03c4a0be6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Merge windows" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine name" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.mergeWindows" -msgstr "窓を結合" +msgid "editor.panels.roomPanel.mezzanineName" +msgstr "中二階の名前" -# Source-Hash: 7855d03a6140af77 +# Source-Hash: 42cfb1bcb80d09e7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Merge windows into a corner window: both take the height, sill and type of the one you selected first" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine names" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.mergeWindowsIntoACornerWindow" -msgstr "コーナー窓に結合:両方とも最初に選んだ窓の高さ、窓台、種類になります" +msgid "editor.panels.roomPanel.mezzanineNames" +msgstr "中二階の名前" -# Source-Hash: b79da96502d2e1c0 +# Source-Hash: 13b3e6a6afe319d1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Merge windows into one across both: it keeps the type and style of the one you selected first" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New unit" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.mergeWindowsIntoOneAcrossBoth" -msgstr "両方にまたがる1つの窓に結合:最初に選んだ窓の種類とスタイルを保ちます" +msgid "editor.panels.roomPanel.newUnit" +msgstr "新規ユニット" -# Source-Hash: f409934681a046e8 +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select building" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.selectBuilding" -msgstr "建物を選択" +msgid "editor.panels.roomPanel.none" +msgstr "なし" -# Source-Hash: c62a73873bd0164d +# Source-Hash: e92d6108b57df9e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select the whole building to move all its levels" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not enough headroom" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.selectTheWholeBuildingToMove" -msgstr "建物全体を選ぶとすべての階層を移動できます" +msgid "editor.panels.roomPanel.notEnoughHeadroom" +msgstr "頭上空間が不足" -# Source-Hash: 7bd5f29203a28efb +# Source-Hash: 81a6770092b05d48 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ungroup" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{doors, plural, one {{doorCount} door} other {{doorCount} doors}} · {windows, plural, one {{windowCount} window} other {{windowCount} windows}}" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.ungroup" -msgstr "グループ解除" +msgid "editor.panels.roomPanel.openingCounts" +msgstr "{doors, plural, other {ドア {doorCount} 枚}} · {windows, plural, other {窓 {windowCount} 枚}}" -# Source-Hash: aec9c3983a440d4a +# Source-Hash: a8cd9507ce472a48 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ungroup (Ctrl/Cmd+Shift+G)" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} · Close its walls to build its floor and ceiling." +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.ungroupCtrlCmdShiftG" -msgstr "グループ解除(Ctrl/Cmd+Shift+G)" +msgid "editor.panels.roomPanel.openRoomArea" +msgstr "{area} · 壁を閉じると床と天井が作られます。" -# Source-Hash: 420385f27c627cee +# Source-Hash: f8aa48ec39a15616 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unwrap the corner" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Over the mezzanine" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.unwrapTheCorner" -msgstr "コーナーを解除" +msgid "editor.panels.roomPanel.overTheMezzanine" +msgstr "中二階の上" -# Source-Hash: 7906c9f4baebc70b +# Source-Hash: ac87e14dabd5a256 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unwrap the corner: both windows stay, each framed at the corner" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Perimeter" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.unwrapTheCornerBothWindowsStay" -msgstr "コーナーを解除:両方の窓は残り、それぞれコーナーで枠が付きます" +msgid "editor.panels.roomPanel.perimeter" +msgstr "周長" -# Source-Hash: 170b2049ef0f9131 +# Source-Hash: ed2aaf0a8d5a9b7b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Selection" -#: packages/editor/src/components/ui/panels/panel-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.panelManager.selection" +msgid "editor.panels.roomPanel.pick" msgstr "選択" -# Source-Hash: 7ceade8f25b58fe9 +# Source-Hash: 7baaebbd411cc837 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picking it adds a number" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.back" -msgstr "戻る" +msgid "editor.panels.roomPanel.pickingItAddsANumber" +msgstr "選ぶと番号が付きます" -# Source-Hash: d7cf5045c01b2eb9 +# Source-Hash: 9469a102f04ea196 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.close" -msgstr "閉じる" +msgid "editor.panels.roomPanel.remove" +msgstr "削除" -# Source-Hash: 2dff25ca30c80559 +# Source-Hash: 41ac9dd23bb558d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close {title}" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove from unit" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.closeTitle" -msgstr "{title}を閉じる" +msgid "editor.panels.roomPanel.removeFromUnit" +msgstr "ユニットから外す" -# Source-Hash: 4f15c3e0fe6178b5 +# Source-Hash: a11d13b92b3cefdb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collapse panel" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove from {unit}" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.collapsePanel" -msgstr "パネルを折りたたむ" +msgid "editor.panels.roomPanel.removeFromUnitNamed" +msgstr "{unit}から外す" -# Source-Hash: 135af27a14a4cda7 +# Source-Hash: d6952b4e54d246dd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collections" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rename" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.collections" -msgstr "コレクション" +msgid "editor.panels.roomPanel.rename" +msgstr "名前を変更" -# Source-Hash: 64916cc9ea80f43f +# Source-Hash: 3562f9bea0a4a8f3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Expand panel" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{name} · Rename" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.expandPanel" -msgstr "パネルを展開" +msgid "editor.panels.roomPanel.renameNamed" +msgstr "{name} · 名前を変更" -# Source-Hash: 8a9a25621f200922 +# Source-Hash: d0d4e919bb58a977 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Manage collections…" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Revert" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.manageCollections" -msgstr "コレクションを管理…" +msgid "editor.panels.roomPanel.revert" +msgstr "元に戻す" -# Source-Hash: 2ff02ed91f54235c +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open {title}" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.openTitle" -msgstr "{title}を開く" +msgid "editor.panels.roomPanel.room" +msgstr "部屋" -# Source-Hash: bf91b71a9aa76e94 +# Source-Hash: 15ae260fae44f42f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room colour — used in the plan and labels" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.reset" -msgstr "リセット" +msgid "editor.panels.roomPanel.roomColourUsedInThePlan" +msgstr "部屋の色 — 平面図とラベルで使用" -# Source-Hash: 04a212d6317f6787 +# Source-Hash: bf75e739dd7e5877 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "“{title}” hit an error and was unloaded for this session." -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room name" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.titleHitAnErrorAndWas" -msgstr "「{title}」でエラーが発生したため、このセッションではアンロードされました。" +msgid "editor.panels.roomPanel.roomName" +msgstr "部屋名" -# Source-Hash: 37d9f63758abdb67 +# Source-Hash: 2ecf8c059646873b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mixed" -#: packages/editor/src/components/ui/panels/parametric-field-control.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room names" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.parametricFieldControl.mixed" -msgstr "混在" +msgid "editor.panels.roomPanel.roomNames" +msgstr "部屋名" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: e9a0a3688faba18b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/editor/src/components/ui/panels/parametric-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scripted finish" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.parametricInspector.actions" -msgstr "操作" +msgid "editor.panels.roomPanel.scriptedFinish" +msgstr "スクリプトの仕上げ" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 85ea1d3c8b749680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/parametric-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.parametricInspector.delete" -msgstr "削除" +msgid "editor.panels.roomPanel.shape" +msgstr "形状" -# Source-Hash: e2411929697b7ed4 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete with contents" -#: packages/editor/src/components/ui/panels/parametric-inspector.tsx +# Source-Hash: e51144ca1759a7bf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show mezzanine names" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.parametricInspector.deleteWithContents" -msgstr "内容ごと削除" +msgid "editor.panels.roomPanel.showMezzanineNames" +msgstr "中二階の名前を表示" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 875b7303c47df33f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/editor/src/components/ui/panels/parametric-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show room names" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.parametricInspector.move" -msgstr "移動" +msgid "editor.panels.roomPanel.showRoomNames" +msgstr "部屋名を表示" -# Source-Hash: c0774c185060fc13 +# Source-Hash: f05bc67c57e4d530 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stairs" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.cancel" -msgstr "キャンセル" +msgid "editor.panels.roomPanel.stairs" +msgstr "階段" -# Source-Hash: 3a0701ebcb9f26cb +# Source-Hash: 062cc0f1afef0c52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Capture" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unit" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.capture" -msgstr "キャプチャ" +msgid "editor.panels.roomPanel.unit" +msgstr "住戸" -# Source-Hash: 5211341ed18f33f6 +# Source-Hash: 91436d6b374e8263 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.center" -msgstr "中央" +msgid "editor.panels.roomPanel.use" +msgstr "使用" -# Source-Hash: a5b965dfb0bf2cd3 +# Source-Hash: 61880aff6cd698c9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{used} on this level" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.clearScale" -msgstr "縮尺をクリア" +msgid "editor.panels.roomPanel.usedOnThisLevel" +msgstr "この階層に {used} 個" -# Source-Hash: 4edc6e45b0c19447 +# Source-Hash: 611604740ed4549c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click both ends of a known distance on the plan, then type its real length." -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{use} “{name}”" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.clickBothEndsOfAKnown" -msgstr "図面上で既知の距離の両端をクリックし、実際の長さを入力します。" +msgid "editor.panels.roomPanel.useTyped" +msgstr "「{name}」を{use}" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 21242af83a2a6d17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "View code" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.delete" -msgstr "削除" +msgid "editor.panels.roomPanel.viewCode" +msgstr "コードを表示" -# Source-Hash: 59f7d81e8d36a157 +# Source-Hash: ba15840e60ce672b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw a line over a known dimension on the plan, then type its real length to scale the image exactly." -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The script could not be read." +#: packages/editor/src/components/ui/panels/room-panel.tsx +#: packages/nodes/src/wall/panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.drawALineOverAKnown" -msgstr "図面上の既知の寸法に線を引き、実際の長さを入力すると画像の縮尺を正確に合わせられます。" +msgid "editor.panels.scriptUnreadable" +msgstr "スクリプトを読み込めませんでした。" -# Source-Hash: 42f6d0e4f065f114 +# Source-Hash: 4e186fc057733162 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Polygon" +#: packages/editor/src/components/ui/panels/shape-choice.tsx #, fuzzy -msgid "editor.panels.referencePanel.editScale" -msgstr "縮尺を編集" +msgid "editor.panels.shapeChoice.polygon" +msgstr "多角形" -# Source-Hash: e156c84cbc90e0a7 +# Source-Hash: 2c2c20272b0370cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guide Image" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangle" +#: packages/editor/src/components/ui/panels/shape-choice.tsx #, fuzzy -msgid "editor.panels.referencePanel.guideImage" -msgstr "ガイド画像" +msgid "editor.panels.shapeChoice.rectangle" +msgstr "長方形" -# Source-Hash: 591087ea83a48ead +# Source-Hash: 5dc88f90e6aa4129 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete region" +#: packages/editor/src/components/ui/panels/wall-region-list.tsx #, fuzzy -msgid "editor.panels.referencePanel.hide" -msgstr "非表示" +msgid "editor.panels.wallRegionList.deleteRegion" +msgstr "領域を削除" -# Source-Hash: dd282ce13b9085ba +# Source-Hash: d81d8cbadf5d4f33 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint regions" +#: packages/editor/src/components/ui/panels/wall-region-list.tsx #, fuzzy -msgid "editor.panels.referencePanel.hideScale" -msgstr "縮尺を隠す" +msgid "editor.panels.wallRegionList.paintRegions" +msgstr "塗装領域" -# Source-Hash: fc6eaa65315f601d +# Source-Hash: 89ee318aad485f83 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Image" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Adjust design" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.panels.referencePanel.image" -msgstr "画像" +msgid "editor.proceduralItems.inspector.adjustDesign" +msgstr "デザインを調整" -# Source-Hash: 241399e11d93bd7b +# Source-Hash: 7ceade8f25b58fe9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lock" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.panels.referencePanel.lock" -msgstr "ロック" +msgid "editor.proceduralItems.inspector.back" +msgstr "戻る" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: ba9b68175315e177 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit parts" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.panels.referencePanel.move" -msgstr "移動" +msgid "editor.proceduralItems.inspector.editParts" +msgstr "パーツを編集" -# Source-Hash: 1c0b8a5503c5daeb +# Source-Hash: 07c62820f014ed6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opacity" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid attachment" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.panels.referencePanel.opacity" -msgstr "不透明度" +msgid "editor.proceduralItems.inspector.invalidAttachment" +msgstr "取り付けが無効です" -# Source-Hash: 6ca213a6b299f19f +# Source-Hash: f862aea8d7957c55 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overlay image unavailable. Replace the image to restore it." -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid edit" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.panels.referencePanel.overlayImageUnavailableReplaceTheImage" -msgstr "重ね合わせ画像が利用できません。画像を置き換えると復元されます。" +msgid "editor.proceduralItems.inspector.invalidEdit" +msgstr "編集が無効です" -# Source-Hash: 28fe6e9deddde6e8 +# Source-Hash: 190cf30b8edd8dd1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "pos" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid placement" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.panels.referencePanel.pos" -msgstr "位置" +msgid "editor.proceduralItems.inspector.invalidPlacement" +msgstr "配置が無効です" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: 45bd2ec690cc48dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid position" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.panels.referencePanel.position" -msgstr "位置" +msgid "editor.proceduralItems.inspector.invalidPosition" +msgstr "位置が無効です" -# Source-Hash: 8b003432b36230c4 +# Source-Hash: faccab895717c598 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Quick Actions" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid reset" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.panels.referencePanel.quickActions" -msgstr "クイック操作" +msgid "editor.proceduralItems.inspector.invalidReset" +msgstr "リセットが無効です" -# Source-Hash: dcd4728e9ca90181 +# Source-Hash: 28fe6e9deddde6e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reference Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "pos" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.panels.referencePanel.referenceScale" -msgstr "参照縮尺" +msgid "editor.proceduralItems.inspector.pos" +msgstr "位置" -# Source-Hash: 0cb87327b8076151 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.panels.referencePanel.replace" -msgstr "置き換え" +msgid "editor.proceduralItems.inspector.position" +msgstr "位置" -# Source-Hash: 08b45f9ba66eab3b +# Source-Hash: 3fce677837d5a876 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replacing..." -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset this part" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.panels.referencePanel.replacing" -msgstr "置き換え中..." +msgid "editor.proceduralItems.inspector.resetThisPart" +msgstr "このパーツをリセット" -# Source-Hash: 2714b5a81cedb625 +# Source-Hash: 5eab376947d29a50 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset Image Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reload editor" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.panels.referencePanel.resetImageScale" -msgstr "画像の縮尺をリセット" +msgid "editor.reloadEditor" +msgstr "エディターを再読み込み" -# Source-Hash: a05d3e429ae259ae +# Source-Hash: 1063f1e315258b20 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset Rotation" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close riser diagram" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.resetRotation" -msgstr "回転をリセット" +msgid "editor.riserDiagramPanel.close" +msgstr "立て管図を閉じる" -# Source-Hash: 5f433581c8f404fa +# Source-Hash: c2d59ee62035974c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "rot" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV plumbing isometric" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.rot" -msgstr "回転" +msgid "editor.riserDiagramPanel.dwvPlumbingIsometric" +msgstr "排水・通気配管のアイソメ図" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: 3501a7c8a93d3b19 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV riser diagram" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.rotation" -msgstr "回転" +msgid "editor.riserDiagramPanel.dwvRiserDiagram" +msgstr "排水・通気の立て管図" -# Source-Hash: 58fee802997c811c +# Source-Hash: 225e3e3dc3bb01ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No drain, waste, or vent pipes yet. Draw plumbing to see the riser diagram." +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.scale" -msgstr "縮尺" +msgid "editor.riserDiagramPanel.noDrainWasteOrVentPipes" +msgstr "排水・汚水・通気の配管はまだありません。配管を描くと立て管図が表示されます。" -# Source-Hash: e7d0e7d41a775fd8 +# Source-Hash: bc8e172ba55160ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scaled · {scale}" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Riser Diagram" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.scaled" -msgstr "縮尺設定済み · {scale}" +msgid "editor.riserDiagramPanel.riserDiagram" +msgstr "立て管図" -# Source-Hash: cd92eebfb30e708f +# Source-Hash: 6a1132961f17f320 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scaled (hidden) · {scale}" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{diameter}\" P-trap" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.scaledHidden" -msgstr "縮尺設定済み(非表示)· {scale}" +msgid "editor.riserDiagramPanel.trap" +msgstr "{diameter}\" Pトラップ" -# Source-Hash: bfd20999de7f216a +# Source-Hash: 04bc0909a133a7e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scale & Opacity" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vent" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.scaleOpacity" -msgstr "縮尺と不透明度" +msgid "editor.riserDiagramPanel.vent" +msgstr "換気口" -# Source-Hash: 8d8777505acdf78e +# Source-Hash: 02f3eef9f0fb6d9e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{diameter}\" VTR" +#. Vent through roof: where a plumbing vent stack exits the roof. +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.setScale" -msgstr "縮尺を設定" +msgid "editor.riserDiagramPanel.ventTermination" +msgstr "{diameter}\" 屋上通気口" -# Source-Hash: 827e0c6ac9936b69 +# Source-Hash: 29d8590334492601 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waste" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.show" -msgstr "表示" +msgid "editor.riserDiagramPanel.waste" +msgstr "排水" -# Source-Hash: 78be2337f0e81973 +# Source-Hash: 0f8d128255bf4afa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{current} · {distance} above {shared}" +#: packages/editor/src/lib/room-built-on.ts #, fuzzy -msgid "editor.panels.referencePanel.showScale" -msgstr "縮尺を表示" +msgid "editor.room.builtOn.above" +msgstr "{current} · {shared}より {distance} 上" -# Source-Hash: ad85a193442c8f76 +# Source-Hash: 8416f433385a2936 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Uncalibrated" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{current} · {distance} below {shared}" +#: packages/editor/src/lib/room-built-on.ts #, fuzzy -msgid "editor.panels.referencePanel.uncalibrated" -msgstr "未校正" +msgid "editor.room.builtOn.below" +msgstr "{current} · {shared}より {distance} 下" -# Source-Hash: 6c500cc253ab3fd4 +# Source-Hash: 6dc18e9fada391f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unlock" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{current} · level with {shared}" +#: packages/editor/src/lib/room-built-on.ts #, fuzzy -msgid "editor.panels.referencePanel.unlock" -msgstr "ロック解除" +msgid "editor.room.builtOn.levelWith" +msgstr "{current} · {shared}と同じ高さ" -# Source-Hash: 4b8d7e52013d1691 +# Source-Hash: 782bc47cb30d5c66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "XYZ" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cannot read \"{input}\"" +#: packages/editor/src/components/editor/room-handles.tsx #, fuzzy -msgid "editor.panels.referencePanel.xyz" -msgstr "XYZ" +msgid "editor.roomHandles.cannotReadInput" +msgstr "「{input}」を読み取れません" -# Source-Hash: e01549105012f8d2 +# Source-Hash: 70ca08939d758332 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "+ Add mezzanine" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimension value" +#: packages/editor/src/components/editor/room-handles.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.addMezzanine" -msgstr "+ 中二階を追加" +msgid "editor.roomHandles.dimensionValue" +msgstr "寸法値" -# Source-Hash: 167b0fe7fdbcd51d +# Source-Hash: d7148fa065bc709b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A drawn slab: set its thickness and finishes here. It has no footprint height or foundation." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/editor/src/components/editor/room-handles.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.aDrawnSlabSetItsThickness" -msgstr "描画されたスラブ:ここで厚さと仕上げを設定します。フットプリントの高さや基礎はありません。" +msgid "editor.roomHandles.floor" +msgstr "床" -# Source-Hash: 6cb0969b65fb60bf +# Source-Hash: de281c37906e7d14 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "At floor level" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type a size to move the wall" +#: packages/editor/src/components/editor/room-handles.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.atFloorLevel" -msgstr "床レベル" +msgid "editor.roomHandles.typeASizeToMoveThe" +msgstr "寸法を入力して壁を移動" -# Source-Hash: e8563d5ae1ee7390 +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Built on" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/editor/room-labels.tsx +#: packages/editor/src/lib/viewer-selection.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.builtOn" -msgstr "建築先" +msgid "editor.roomLabel.room" +msgstr "部屋" -# Source-Hash: 8e5ca7510677460c +# Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Built with" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone" +#: packages/editor/src/components/editor/room-labels.tsx +#: packages/editor/src/lib/viewer-selection.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.builtWith" -msgstr "構成" +msgid "editor.roomLabel.zone" +msgstr "ゾーン" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: 7da15e7c88dab485 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Attic" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.ceiling" -msgstr "天井" +msgid "editor.roomName.attic" +msgstr "屋根裏" -# Source-Hash: 9bf177f59f971033 +# Source-Hash: 52adf6ccf54fd772 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "At {height}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Balcony" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.ceilingAt" -msgstr "{height} の位置" +msgid "editor.roomName.balcony" +msgstr "バルコニー" -# Source-Hash: 48768dc0fc7b86a4 +# Source-Hash: 8caa959c0ae800c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close with walls" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Basement" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.closeWithWalls" -msgstr "壁で閉じる" +msgid "editor.roomName.basement" +msgstr "地下1階" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 75c84b4f21aefde4 +# Source-Hash: 0655333424a8b6fb # Review: required -# English: "{ambiguous, select, yes {Floor is several drawn slabs, mostly {name}} other {Floor is a drawn slab: {name}}}{shared, plural, =0 {} one { (shared with {sharedCount} room)} other { (shared with {sharedCount} rooms)}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bathroom" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.drawnFloor" -msgstr "{ambiguous, select, yes {床は複数の描画スラブで、主に{name}} other {床は描画スラブです:{name}}}{shared, plural, =0 {} other {({sharedCount} 部屋と共有)}}" +msgid "editor.roomName.bathroom" +msgstr "浴室" -# Source-Hash: 97e0fab8ffda6d6c +# Source-Hash: f25239fe3891ea8f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "This floor is a drawn slab: select it to edit or delete it." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bedroom" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.drawnFloorSwitchHint" -msgstr "この床は描画スラブです。選択して編集または削除してください。" +msgid "editor.roomName.bedroom" +msgstr "寝室" -# Source-Hash: ad5426620188242c +# Source-Hash: 77d15570e2eba719 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawn slab" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Boiler room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.drawnSlab" -msgstr "描画スラブ" +msgid "editor.roomName.boilerRoom" +msgstr "ボイラー室" -# Source-Hash: 0da0d104eaefbbad +# Source-Hash: 5fbe77592f8f0ca9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawn slab at {height}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Carport" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.drawnSlabAt" -msgstr "描画スラブ({height})" +msgid "editor.roomName.carport" +msgstr "カーポート" -# Source-Hash: 5dfead58503dbc86 +# Source-Hash: f31dc305ce3a803a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit shape" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cellar" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.editShape" -msgstr "形状を編集" +msgid "editor.roomName.cellar" +msgstr "地下貯蔵庫" -# Source-Hash: fadf264be55063e5 +# Source-Hash: e9af4141e3f8bdd1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat, at wall height" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Closet" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.flatAtWallHeight" -msgstr "平ら(壁の高さ)" +msgid "editor.roomName.closet" +msgstr "クローゼット" -# Source-Hash: d7148fa065bc709b +# Source-Hash: 388530b7b9c6647d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corridor" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.floor" -msgstr "階" +msgid "editor.roomName.corridor" +msgstr "廊下" -# Source-Hash: 996e8191c069e779 +# Source-Hash: 4d4a23b87e911d2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{distance} down" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Courtyard" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.floorDown" -msgstr "{distance} 下" +msgid "editor.roomName.courtyard" +msgstr "中庭" -# Source-Hash: 73614b8faa059cd6 +# Source-Hash: f3aa561772702108 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor thickness" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.floorThickness" -msgstr "床の厚さ" +msgid "editor.roomName.deck" +msgstr "デッキ" -# Source-Hash: 79cdde853c3e8f61 +# Source-Hash: 18d7f85ff03c43c9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{distance} up" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Den" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.floorUp" -msgstr "{distance} 上" +msgid "editor.roomName.den" +msgstr "書斎" -# Source-Hash: 77bc12b7aba0eb60 +# Source-Hash: 4424343cad1f08b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hand-drawn ceiling" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dining room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.handDrawnCeiling" -msgstr "手描きの天井" +msgid "editor.roomName.diningRoom" +msgstr "ダイニング" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: 5efd0185e89ee84e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dressing room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.height" -msgstr "高さ" +msgid "editor.roomName.dressingRoom" +msgstr "ドレッシングルーム" -# Source-Hash: 4d35023efe090b82 +# Source-Hash: f45768e27780dc72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Include floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "En-suite" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.includeFloor" -msgstr "床を含める" +msgid "editor.roomName.enSuite" +msgstr "専用浴室" -# Source-Hash: 6398ac77644eb5f6 +# Source-Hash: 51c664d19e5ea703 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{part, select, floor {Include floor} walls {Include walls} other {Include ceiling}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Entrance" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.includePart" -msgstr "{part, select, floor {床を含める} walls {壁を含める} other {天井を含める}}" +msgid "editor.roomName.entrance" +msgstr "玄関" -# Source-Hash: 3629e64a6e796ca9 +# Source-Hash: 4b32a81a5abf006a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Include walls" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Family room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.includeWalls" -msgstr "壁を含める" +msgid "editor.roomName.familyRoom" +msgstr "ファミリールーム" -# Source-Hash: f6d07fc7f239278b +# Source-Hash: e87e6bd9a7d6d667 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Keep outside dimensions" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gallery" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.keepOutsideDimensions" -msgstr "外形寸法を保つ" +msgid "editor.roomName.gallery" +msgstr "ギャラリー" -# Source-Hash: 544410e3cb0e0b07 +# Source-Hash: cf7cc0ba06d5eea1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lowered {lift}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Games room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.lowered" -msgstr "{lift} 下げる" +msgid "editor.roomName.gamesRoom" +msgstr "ゲームルーム" -# Source-Hash: c2daf78b740e4397 +# Source-Hash: 53aa825a4737190a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "+ New floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Garage" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.newFloor" -msgstr "+ 新しい床" +msgid "editor.roomName.garage" +msgstr "ガレージ" -# Source-Hash: ba9edc7910a60cea +# Source-Hash: 5073b3c2989a626d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Garden" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.noFloor" -msgstr "床なし" +msgid "editor.roomName.garden" +msgstr "庭" -# Source-Hash: ea2675041df74f40 +# Source-Hash: 52fe13434cdb7b27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Nothing to change." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Garden shed" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.nothingToChange" -msgstr "変更する内容はありません。" +msgid "editor.roomName.gardenShed" +msgstr "物置小屋" -# Source-Hash: ebe0d375d7938c93 +# Source-Hash: a2712156dcaec1ba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Not included" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guest room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.notIncluded" -msgstr "含まれていません" +msgid "editor.roomName.guestRoom" +msgstr "客室" -# Source-Hash: e9440fa9f770b7a4 +# Source-Hash: a1128cf188432bb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "On the ground" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gym" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.onTheGround" -msgstr "地面上" +msgid "editor.roomName.gym" +msgstr "ジム" -# Source-Hash: a5deb36c485d91bd +# Source-Hash: 18664ee5a1abd06d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "On the walls below" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hallway" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.onTheWallsBelow" -msgstr "下の壁の上" +msgid "editor.roomName.hallway" +msgstr "廊下" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 2256aec0d5bdc3ea +# Source-Hash: 7dd957fc73d4d73a # Review: required -# English: "{openSides, plural, one {{openSideCount} open side} other {{openSideCount} open sides}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Home cinema" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.openSides" -msgstr "{openSides, plural, other {{openSideCount} 個の開放辺}}" +msgid "editor.roomName.homeCinema" +msgstr "ホームシアター" -# Source-Hash: f704520c5e5b92b2 +# Source-Hash: e1579515f44233ca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Partial · {coverage, number, percent} covered" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kids' room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.partialCovered" -msgstr "部分 · {coverage, number, percent} を覆う" +msgid "editor.roomName.kidsRoom" +msgstr "子ども部屋" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: b648bee0231a41cd +# Source-Hash: 1176d2568d093bf1 # Review: required -# English: "Partial · {walls, plural, one {{wallCount} wall} other {{wallCount} walls}}, {openSides, plural, one {{openSideCount} open side} other {{openSideCount} open sides}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchen" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.partialWalls" -msgstr "部分 · {walls, plural, other {{wallCount} 枚の壁}}、{openSides, plural, other {{openSideCount} 個の開放辺}}" +msgid "editor.roomName.kitchen" +msgstr "キッチン" -# Source-Hash: e503250e8ecb0030 +# Source-Hash: 06eb4c431b9b09b6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised {lift}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchenette" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.raised" -msgstr "{lift} 上げ" +msgid "editor.roomName.kitchenette" +msgstr "簡易キッチン" -# Source-Hash: 0cb87327b8076151 +# Source-Hash: de9566487b17a73b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.replace" -msgstr "置き換え" +msgid "editor.roomName.landing" +msgstr "踊り場" -# Source-Hash: a4395168488bb476 +# Source-Hash: 558bcafa2ec70ded # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Laundry" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.select" -msgstr "選択" +msgid "editor.roomName.laundry" +msgstr "ランドリー" -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: 8d211c78417ed1b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Library" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.shape" -msgstr "形状" +msgid "editor.roomName.library" +msgstr "ライブラリ" -# Source-Hash: aafd84823715d698 +# Source-Hash: 2204538bab0e77ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Turning walls off keeps the ones shared with {rooms}." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Living room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.sharedWallsNote" -msgstr "壁をオフにしても、{rooms}と共有する壁は残ります。" +msgid "editor.roomName.livingRoom" +msgstr "リビングルーム" -# Source-Hash: c98df900d43f77bc +# Source-Hash: bb14c08f0c3db4ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sits on: {name} · {preset}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Loft" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.sitsOnPreset" -msgstr "設置先:{name} · {preset}" +msgid "editor.roomName.loft" +msgstr "ロフト" -# Source-Hash: a17a79e835fa2064 +# Source-Hash: a6a0e8bf816cbcb9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "the next room" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lounge" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.theNextRoom" -msgstr "隣の部屋" +msgid "editor.roomName.lounge" +msgstr "ラウンジ" -# Source-Hash: ebae699e0cb18ea6 +# Source-Hash: 194a147d4618a994 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use existing" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.useExisting" -msgstr "既存を使用" +msgid "editor.roomName.mezzanine" +msgstr "中二階" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 9976021d9162cd5e +# Source-Hash: 6b2c82e5fbccb28b # Review: required -# English: "{walls, plural, one {{wallCount} wall} other {{wallCount} walls}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mudroom" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.wallCount" -msgstr "{walls, plural, other {{wallCount} 枚の壁}}" +msgid "editor.roomName.mudroom" +msgstr "マッドルーム" -# Source-Hash: aac9a732d2159ccc +# Source-Hash: e3c3b9b917744680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Nursery" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.walls" -msgstr "壁" +msgid "editor.roomName.nursery" +msgstr "子供部屋(乳児)" -# Source-Hash: 6c69eb46a0c40d52 +# Source-Hash: c1f1fcd9cb418340 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls thicken inward, so the building's outer size stays the same." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Office" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomConstructionRows.wallsThickenInwardSoTheBuilding" -msgstr "壁は内側に厚くなるため、建物の外形寸法は変わりません。" +msgid "editor.roomName.office" +msgstr "オフィス" -# Source-Hash: 4e4f1a24e4a9d61e +# Source-Hash: 5d98d41ec10bd05e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut opening" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pantry" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomOpeningsField.cutOpening" -msgstr "開口を切る" +msgid "editor.roomName.pantry" +msgstr "パントリー" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: 78dbe13192c0894b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Patio" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomOpeningsField.done" -msgstr "完了" +msgid "editor.roomName.patio" +msgstr "パティオ" -# Source-Hash: 2c89abb1778a3f9b +# Source-Hash: c3cfcccc167b1c19 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit floor" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Playroom" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomOpeningsField.editFloor" -msgstr "床を編集" +msgid "editor.roomName.playroom" +msgstr "プレイルーム" -# Source-Hash: ca18a6c5398fc8ab +# Source-Hash: 2e6324beaed18dd5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevator opening" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pool area" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomOpeningsField.elevatorOpening" -msgstr "エレベーター開口" +msgid "editor.roomName.poolArea" +msgstr "プールエリア" -# Source-Hash: eafea43e795f3708 +# Source-Hash: 97d20e41044a3235 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No openings yet. Cut one for a stair void or a hatch." -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Porch" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomOpeningsField.noOpeningsYetCutOneFor" -msgstr "開口はまだありません。階段の吹き抜けやハッチ用に切り抜いてください。" +msgid "editor.roomName.porch" +msgstr "ポーチ" -# Source-Hash: 60fac94ffa614238 +# Source-Hash: 04cb81f4a4ae4ff3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening {number}" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Powder room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomOpeningsField.openingNumber" -msgstr "開口 {number}" +msgid "editor.roomName.powderRoom" +msgstr "パウダールーム" -# Source-Hash: 7aafbf90d659dcf6 +# Source-Hash: 599c44d857832cd0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, =0 {No openings} one {{number} opening} other {{number} openings}}" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Primary bedroom" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomOpeningsField.openings" -msgstr "{count, plural, =0 {開口なし} other {開口 {number} 個}}" +msgid "editor.roomName.primaryBedroom" +msgstr "主寝室" -# Source-Hash: c1a1794d31990f5a +# Source-Hash: 9a6ac3f1cdd8de2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair opening" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reading nook" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomOpeningsField.stairOpening" -msgstr "階段の開口" +msgid "editor.roomName.readingNook" +msgstr "読書スペース" -# Source-Hash: f0a46329fef44d94 +# Source-Hash: 01f8cc22989822c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add stairs" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bathrooms" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomPanel.addStairs" -msgstr "階段を追加" +msgid "editor.roomName.section.bathrooms" +msgstr "浴室" -# Source-Hash: 8a2ab34a61b9d181 +# Source-Hash: 9ec82561de8cb788 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add to a unit" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Circulation" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomPanel.addToAUnit" -msgstr "ユニットに追加" +msgid "editor.roomName.section.circulation" +msgstr "動線" -# Source-Hash: 8332ab41e22958f1 +# Source-Hash: f74a48b6b49644d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Area" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Living" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomPanel.area" -msgstr "面積" +msgid "editor.roomName.section.living" +msgstr "リビング" -# Source-Hash: 88f1a727e5528c10 +# Source-Hash: 194a147d4618a994 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Browse" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomPanel.browse" -msgstr "閲覧" +msgid "editor.roomName.section.mezzanine" +msgstr "中二階" -# Source-Hash: 8e5ca7510677460c +# Source-Hash: a5a7af5e5fff1c81 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Built with" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outdoor" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomPanel.builtWith" -msgstr "構成" +msgid "editor.roomName.section.outdoor" +msgstr "屋外" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: 5df703d5b5e6ef7e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sleeping" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomPanel.ceiling" -msgstr "天井" +msgid "editor.roomName.section.sleeping" +msgstr "寝室" -# Source-Hash: a5e4fe4960deced9 +# Source-Hash: c9d15ec19f814524 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete room" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Utility & storage" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomPanel.deleteRoom" -msgstr "部屋を削除" +msgid "editor.roomName.section.utility" +msgstr "ユーティリティと収納" -# Source-Hash: 5dfead58503dbc86 +# Source-Hash: fbe13f7ab45e4cca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit shape" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Work & hobbies" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomPanel.editShape" -msgstr "形状を編集" +msgid "editor.roomName.section.work" +msgstr "仕事と趣味" -# Source-Hash: d7148fa065bc709b +# Source-Hash: 10ccb6591f6ad207 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shower room" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.showerRoom" +msgstr "シャワールーム" + +# Source-Hash: 5254168cc5712cb2 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stairwell" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomPanel.floor" -msgstr "階" +msgid "editor.roomName.stairwell" +msgstr "階段室" -# Source-Hash: d17c3b63449c052b +# Source-Hash: d1596647cd84ade3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{height} headroom" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Storage" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomPanel.headroom" -msgstr "頭上空間 {height}" +msgid "editor.roomName.storage" +msgstr "収納" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: 7abc2dc6e39b1747 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Studio" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomPanel.height" -msgstr "高さ" +msgid "editor.roomName.studio" +msgstr "スタジオ" -# Source-Hash: 2d89c1638aa8dd7e +# Source-Hash: ebe68e83e73021ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide code" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Study" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomPanel.hideCode" -msgstr "コードを隠す" +msgid "editor.roomName.study" +msgstr "書斎" -# Source-Hash: e93969f5a7cbb140 +# Source-Hash: d69a0244649771ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room · {level}" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sunroom" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomPanel.kickerLevel" -msgstr "部屋 · {level}" +msgid "editor.roomName.sunroom" +msgstr "サンルーム" -# Source-Hash: f4ad56b4e0c014b3 +# Source-Hash: 96281876ce53ba08 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine · in {room}" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terrace" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomPanel.kickerMezzanineIn" -msgstr "中二階 · {room}内" +msgid "editor.roomName.terrace" +msgstr "テラス" -# Source-Hash: de37205633316011 +# Source-Hash: a0cb3e6f5cf4fbec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room · not enclosed" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Toilet" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomPanel.kickerNotEnclosed" -msgstr "部屋 · 囲まれていない" +msgid "editor.roomName.toilet" +msgstr "トイレ" -# Source-Hash: 9e84d6d7b9885c4f +# Source-Hash: 6c01526f89f3106b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Loading…" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Utility room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomPanel.loading" -msgstr "読み込み中…" +msgid "editor.roomName.utilityRoom" +msgstr "ユーティリティ" -# Source-Hash: 194a147d4618a994 +# Source-Hash: fc42d89621ae7bac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Veranda" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomPanel.mezzanine" -msgstr "中二階" +msgid "editor.roomName.veranda" +msgstr "ベランダ" -# Source-Hash: 97de3df03c4a0be6 +# Source-Hash: b45d7730e896fd99 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine name" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walk-in closet" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomPanel.mezzanineName" -msgstr "中二階の名前" +msgid "editor.roomName.walkInCloset" +msgstr "ウォークインクローゼット" -# Source-Hash: 42cfb1bcb80d09e7 +# Source-Hash: 399f27253ef956cb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine names" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Workshop" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.panels.roomPanel.mezzanineNames" -msgstr "中二階の名前" +msgid "editor.roomName.workshop" +msgstr "作業場" -# Source-Hash: 13b3e6a6afe319d1 +# Source-Hash: 83909f82446ee9c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "New unit" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Settings" +#: packages/editor/src/components/ui/sidebar/icon-rail.tsx #, fuzzy -msgid "editor.panels.roomPanel.newUnit" -msgstr "新規ユニット" +msgid "editor.sidebar.iconRail.settings" +msgstr "設定" -# Source-Hash: f2953d2931e36d0c +# Source-Hash: 91f90818d42a984e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Site" +#: packages/editor/src/components/ui/sidebar/icon-rail.tsx #, fuzzy -msgid "editor.panels.roomPanel.none" -msgstr "なし" +msgid "editor.sidebar.iconRail.site" +msgstr "敷地" -# Source-Hash: e92d6108b57df9e1 +# Source-Hash: 663175a9c461a96d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Not enough headroom" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx #, fuzzy -msgid "editor.panels.roomPanel.notEnoughHeadroom" -msgstr "頭上空間が不足" +msgid "editor.sidebar.panels.itemsPanel.all" +msgstr "すべて" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 81a6770092b05d48 +# Source-Hash: fce9814c289e6b71 # Review: required -# English: "{doors, plural, one {{doorCount} door} other {{doorCount} doors}} · {windows, plural, one {{windowCount} window} other {{windowCount} windows}}" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Community" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx #, fuzzy -msgid "editor.panels.roomPanel.openingCounts" -msgstr "{doors, plural, other {ドア {doorCount} 枚}} · {windows, plural, other {窓 {windowCount} 枚}}" +msgid "editor.sidebar.panels.itemsPanel.community" +msgstr "コミュニティ" -# Source-Hash: a8cd9507ce472a48 +# Source-Hash: 663175a9c461a96d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{area} · Close its walls to build its floor and ceiling." -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.openRoomArea" -msgstr "{area} · 壁を閉じると床と天井が作られます。" +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.all" +msgstr "すべて" -# Source-Hash: f8aa48ec39a15616 +# Source-Hash: fce9814c289e6b71 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Over the mezzanine" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Community" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.overTheMezzanine" -msgstr "中二階の上" +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.community" +msgstr "コミュニティ" -# Source-Hash: ac87e14dabd5a256 +# Source-Hash: 8d211c78417ed1b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Perimeter" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Library" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.perimeter" -msgstr "周長" +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.library" +msgstr "ライブラリ" -# Source-Hash: ed2aaf0a8d5a9b7b +# Source-Hash: a0b7adfdfdec7307 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mine" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.pick" -msgstr "選択" +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.mine" +msgstr "マイアイテム" -# Source-Hash: 7baaebbd411cc837 +# Source-Hash: 6024b7778b392ec3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picking it adds a number" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No results for “{search}”" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.pickingItAddsANumber" -msgstr "選ぶと番号が付きます" +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.noResultsForSearch" +msgstr "「{search}」の結果はありません" -# Source-Hash: 9469a102f04ea196 +# Source-Hash: 4ceb6dcb7827db7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Search..." +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.remove" -msgstr "削除" +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.search" +msgstr "検索..." -# Source-Hash: 41ac9dd23bb558d7 +# Source-Hash: 8d211c78417ed1b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove from unit" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Library" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx #, fuzzy -msgid "editor.panels.roomPanel.removeFromUnit" -msgstr "ユニットから外す" +msgid "editor.sidebar.panels.itemsPanel.library" +msgstr "ライブラリ" -# Source-Hash: a11d13b92b3cefdb +# Source-Hash: a0b7adfdfdec7307 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove from {unit}" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mine" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx #, fuzzy -msgid "editor.panels.roomPanel.removeFromUnitNamed" -msgstr "{unit}から外す" +msgid "editor.sidebar.panels.itemsPanel.mine" +msgstr "マイアイテム" -# Source-Hash: d6952b4e54d246dd +# Source-Hash: 6024b7778b392ec3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rename" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No results for “{search}”" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx #, fuzzy -msgid "editor.panels.roomPanel.rename" -msgstr "名前を変更" +msgid "editor.sidebar.panels.itemsPanel.noResultsForSearch" +msgstr "「{search}」の結果はありません" -# Source-Hash: 3562f9bea0a4a8f3 +# Source-Hash: 4ceb6dcb7827db7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{name} · Rename" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Search..." +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx #, fuzzy -msgid "editor.panels.roomPanel.renameNamed" -msgstr "{name} · 名前を変更" +msgid "editor.sidebar.panels.itemsPanel.search" +msgstr "検索..." -# Source-Hash: d0d4e919bb58a977 +# Source-Hash: fb66c49eee49a3bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Revert" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Build Tools" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.panels.roomPanel.revert" -msgstr "元に戻す" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.buildTools" +msgstr "建築ツール" -# Source-Hash: 612dcd5bf06a79c4 +# Source-Hash: 14622745dbf93f4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.panels.roomPanel.room" -msgstr "部屋" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.camera" +msgstr "カメラ" -# Source-Hash: 15ae260fae44f42f +# Source-Hash: 677783232bea72a2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room colour — used in the plan and labels" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Direct Manipulation" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.panels.roomPanel.roomColourUsedInThePlan" -msgstr "部屋の色 — 平面図とラベルで使用" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.directManipulation" +msgstr "直接操作" -# Source-Hash: bf75e739dd7e5877 +# Source-Hash: 8e67947d43b76596 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room name" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawing Tools" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.panels.roomPanel.roomName" -msgstr "部屋名" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.drawingTools" +msgstr "描画ツール" -# Source-Hash: 2ecf8c059646873b +# Source-Hash: 8cdda30f3be2bac2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room names" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Editor Navigation" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.panels.roomPanel.roomNames" -msgstr "部屋名" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.editorNavigation" +msgstr "エディターのナビゲーション" -# Source-Hash: e9a0a3688faba18b +# Source-Hash: 9a996e3570d615ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scripted finish" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Item Placement" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.panels.roomPanel.scriptedFinish" -msgstr "スクリプトの仕上げ" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.itemPlacement" +msgstr "アイテムの配置" -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: fc18926f9bd9eebd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keyboard shortcuts" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.panels.roomPanel.shape" -msgstr "形状" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.keyboardShortcuts" +msgstr "キーボードショートカット" -# Source-Hash: e51144ca1759a7bf +# Source-Hash: cbb4c3e007d70aa0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show mezzanine names" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modes & History" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.panels.roomPanel.showMezzanineNames" -msgstr "中二階の名前を表示" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.modesHistory" +msgstr "モードと履歴" -# Source-Hash: 875b7303c47df33f +# Source-Hash: 170b2049ef0f9131 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show room names" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selection" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.panels.roomPanel.showRoomNames" -msgstr "部屋名を表示" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.selection" +msgstr "選択" -# Source-Hash: f05bc67c57e4d530 +# Source-Hash: 0da1c4d163df2953 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stairs" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shortcuts are context-aware. Snapping is a visible mode: tap Shift to cycle it, hold Alt during a gesture to place freely." +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.panels.roomPanel.stairs" -msgstr "階段" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.shortcutsAreContextAwareGuidedConstraints" +msgstr "ショートカットは状況に応じて動作が変わります。スナップは表示されるモードです。Shift を軽く押すと切り替わり、操作中に Alt を押し続けると自由に配置できます。" -# Source-Hash: 062cc0f1afef0c52 +# Source-Hash: 3c67cde0578ac829 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unit" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.panels.roomPanel.unit" -msgstr "住戸" +msgid "editor.sidebar.panels.sitePanel.addLevel" +msgstr "階層を追加" -# Source-Hash: 91436d6b374e8263 +# Source-Hash: 9a56d90d461b4bca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add point" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.panels.roomPanel.use" -msgstr "使用" +msgid "editor.sidebar.panels.sitePanel.addPoint" +msgstr "点を追加" -# Source-Hash: 61880aff6cd698c9 +# Source-Hash: fedccec504a9ae33 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{used} on this level" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Area:" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.panels.roomPanel.usedOnThisLevel" -msgstr "この階層に {used} 個" +msgid "editor.sidebar.panels.sitePanel.area" +msgstr "面積:" -# Source-Hash: 611604740ed4549c +# Source-Hash: 87b6880f6de7a45a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{use} “{name}”" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base elevation" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.panels.roomPanel.useTyped" -msgstr "「{name}」を{use}" +msgid "editor.sidebar.panels.sitePanel.baseElevation" +msgstr "基準高さ" -# Source-Hash: 21242af83a2a6d17 +# Source-Hash: d42f7d29e3fc4af7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "View code" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Building" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.panels.roomPanel.viewCode" -msgstr "コードを表示" +msgid "editor.sidebar.panels.sitePanel.building" +msgstr "建物" -# Source-Hash: ba15840e60ce672b +# Source-Hash: 7c90f458259d5cd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The script could not be read." -#: packages/editor/src/components/ui/panels/room-panel.tsx -#: packages/nodes/src/wall/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add new level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx #, fuzzy -msgid "editor.panels.scriptUnreadable" -msgstr "スクリプトを読み込めませんでした。" +msgid "editor.sidebar.panels.sitePanel.buildingTreeNode.addNewLevel" +msgstr "新しい階層を追加" -# Source-Hash: 4e186fc057733162 +# Source-Hash: d42f7d29e3fc4af7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Polygon" -#: packages/editor/src/components/ui/panels/shape-choice.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Building" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx #, fuzzy -msgid "editor.panels.shapeChoice.polygon" -msgstr "多角形" +msgid "editor.sidebar.panels.sitePanel.buildingTreeNode.building" +msgstr "建物" -# Source-Hash: 2c2c20272b0370cc +# Source-Hash: bbc65c039ae86e11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangle" -#: packages/editor/src/components/ui/panels/shape-choice.tsx -#, fuzzy -msgid "editor.panels.shapeChoice.rectangle" -msgstr "長方形" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.cameraSnapshot" +msgstr "カメラスナップショット" -# Source-Hash: 5dc88f90e6aa4129 +# Source-Hash: 3a0701ebcb9f26cb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete region" -#: packages/editor/src/components/ui/panels/wall-region-list.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Capture" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.panels.wallRegionList.deleteRegion" -msgstr "領域を削除" +msgid "editor.sidebar.panels.sitePanel.capture" +msgstr "キャプチャ" -# Source-Hash: d81d8cbadf5d4f33 +# Source-Hash: 71f2343818c55e0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint regions" -#: packages/editor/src/components/ui/panels/wall-region-list.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear selection" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.panels.wallRegionList.paintRegions" -msgstr "塗装領域" +msgid "editor.sidebar.panels.sitePanel.clearSelection" +msgstr "選択を解除" +# Source-Hash: 67d29724469fa8d3 # Review: required -# Source-Hash: 89ee318aad485f83 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Adjust design" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.adjustDesign" -msgstr "デザインを調整" +msgid "editor.sidebar.panels.sitePanel.clearSnapshot" +msgstr "スナップショットを消去" +# Source-Hash: def517c77fda49ea # Review: required -# Source-Hash: 7ceade8f25b58fe9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close walls around a space to make a room." +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.back" -msgstr "戻る" +msgid "editor.sidebar.panels.sitePanel.closeWallsAroundASpaceTo" +msgstr "空間を壁で囲むと部屋になります。" +# Source-Hash: 2b9af8da4b34cbfa # Review: required -# Source-Hash: ba9b68175315e177 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit parts" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collection colour" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.editParts" -msgstr "パーツを編集" +msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.collectionColour" +msgstr "コレクションの色" +# Source-Hash: 135af27a14a4cda7 # Review: required -# Source-Hash: 07c62820f014ed6c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid attachment" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collections" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidAttachment" -msgstr "取り付けが無効です" +msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.collections" +msgstr "コレクション" +# Source-Hash: 6f4751c26f12aef9 # Review: required -# Source-Hash: f862aea8d7957c55 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid edit" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete collection" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidEdit" -msgstr "編集が無効です" +msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.deleteCollection" +msgstr "コレクションを削除" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: 190cf30b8edd8dd1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid placement" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidPlacement" -msgstr "配置が無効です" +msgid "editor.sidebar.panels.sitePanel.delete" +msgstr "削除" +# Source-Hash: 8e29375893d63408 # Review: required -# Source-Hash: 45bd2ec690cc48dc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid position" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidPosition" -msgstr "位置が無効です" +msgid "editor.sidebar.panels.sitePanel.deleteLevel" +msgstr "階層を削除" +# Source-Hash: 6552e45eecc0a227 # Review: required -# Source-Hash: faccab895717c598 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid reset" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw a zone" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidReset" -msgstr "リセットが無効です" +msgid "editor.sidebar.panels.sitePanel.drawAZone" +msgstr "ゾーンを描画" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: 28fe6e9deddde6e8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "pos" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.pos" -msgstr "位置" +msgid "editor.sidebar.panels.sitePanel.duplicate" +msgstr "複製" +# Source-Hash: 933177338f5a03ed # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.position" -msgstr "位置" +msgid "editor.sidebar.panels.sitePanel.duplicateLevel" +msgstr "階層を複製" +# Source-Hash: c038947f317cabba # Review: required -# Source-Hash: 3fce677837d5a876 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset this part" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate level with options" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.resetThisPart" -msgstr "このパーツをリセット" +msgid "editor.sidebar.panels.sitePanel.duplicateLevelWithOptions" +msgstr "オプションを指定して階層を複製" -# Source-Hash: 5eab376947d29a50 +# Source-Hash: 9614c6825a7c67bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reload editor" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate with options..." +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.reloadEditor" -msgstr "エディターを再読み込み" +msgid "editor.sidebar.panels.sitePanel.duplicateWithOptions" +msgstr "オプションを指定して複製..." +# Source-Hash: 7c4196b9e791c195 # Review: required -# Source-Hash: 1063f1e315258b20 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close riser diagram" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elements" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.riserDiagramPanel.close" -msgstr "立て管図を閉じる" +msgid "editor.sidebar.panels.sitePanel.elements" +msgstr "要素" +# Source-Hash: 1344ea2602e3aa9e # Review: required -# Source-Hash: c2d59ee62035974c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV plumbing isometric" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guide" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.riserDiagramPanel.dwvPlumbingIsometric" -msgstr "排水・通気配管のアイソメ図" +msgid "editor.sidebar.panels.sitePanel.guide" +msgstr "ガイド" +# Source-Hash: 591087ea83a48ead # Review: required -# Source-Hash: 3501a7c8a93d3b19 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV riser diagram" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.riserDiagramPanel.dwvRiserDiagram" -msgstr "排水・通気の立て管図" +msgid "editor.sidebar.panels.sitePanel.hide" +msgstr "非表示" +# Source-Hash: 0608743fc1736d86 # Review: required -# Source-Hash: 225e3e3dc3bb01ee -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No drain, waste, or vent pipes yet. Draw plumbing to see the riser diagram." -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.riserDiagramPanel.noDrainWasteOrVentPipes" -msgstr "排水・汚水・通気の配管はまだありません。配管を描くと立て管図が表示されます。" +msgid "editor.sidebar.panels.sitePanel.level" +msgstr "階層" +# Source-Hash: 13b3e6a6afe319d1 # Review: required -# Source-Hash: bc8e172ba55160ae -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Riser Diagram" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New unit" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.riserDiagramPanel.riserDiagram" -msgstr "立て管図" +msgid "editor.sidebar.panels.sitePanel.newUnit" +msgstr "新規ユニット" -# Review: required -# Source-Hash: 6a1132961f17f320 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{diameter}\" P-trap" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# Source-Hash: 0192748d50f0e5f7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No buildings yet" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.riserDiagramPanel.trap" -msgstr "{diameter}\" Pトラップ" +msgid "editor.sidebar.panels.sitePanel.noBuildingsYet" +msgstr "建物はまだありません" +# Source-Hash: 1be310702a12e433 # Review: required -# Source-Hash: 04bc0909a133a7e9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vent" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No elements on this level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.riserDiagramPanel.vent" -msgstr "換気口" +msgid "editor.sidebar.panels.sitePanel.noElementsOnThisLevel" +msgstr "この階層に要素はありません" +# Source-Hash: 0956af88ced36992 # Review: required -# Source-Hash: 02f3eef9f0fb6d9e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{diameter}\" VTR" -#. Vent through roof: where a plumbing vent stack exits the roof. -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No levels yet" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.riserDiagramPanel.ventTermination" -msgstr "{diameter}\" 屋上通気口" +msgid "editor.sidebar.panels.sitePanel.noLevelsYet" +msgstr "階層はまだありません" +# Source-Hash: 45c41bfb2ae19627 # Review: required -# Source-Hash: 29d8590334492601 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waste" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# object selected} other {# objects selected}}" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.riserDiagramPanel.waste" -msgstr "排水" +msgid "editor.sidebar.panels.sitePanel.objectsSelected" +msgstr "{count, plural, other {# 個のオブジェクトを選択中}}" -# Source-Hash: 0f8d128255bf4afa +# Source-Hash: a5434e26e5cb1b26 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{current} · {distance} above {shared}" -#: packages/editor/src/lib/room-built-on.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Other zones" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.room.builtOn.above" -msgstr "{current} · {shared}より {distance} 上" +msgid "editor.sidebar.panels.sitePanel.otherZones" +msgstr "その他のゾーン" -# Source-Hash: 8416f433385a2936 +# Source-Hash: 2aa38d84079d4dba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{current} · {distance} below {shared}" -#: packages/editor/src/lib/room-built-on.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Perimeter:" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.room.builtOn.below" -msgstr "{current} · {shared}より {distance} 下" +msgid "editor.sidebar.panels.sitePanel.perimeter" +msgstr "周長:" -# Source-Hash: 6dc18e9fada391f2 +# Source-Hash: 4004b9a8e4f8c9d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{current} · level with {shared}" -#: packages/editor/src/lib/room-built-on.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Property Line" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.room.builtOn.levelWith" -msgstr "{current} · {shared}と同じ高さ" +msgid "editor.sidebar.panels.sitePanel.propertyLine" +msgstr "敷地境界線" -# Source-Hash: 612dcd5bf06a79c4 +# Source-Hash: 3e7408ed44676176 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room" -#: packages/editor/src/components/editor/room-labels.tsx -#: packages/editor/src/lib/viewer-selection.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rooms" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomLabel.room" +msgid "editor.sidebar.panels.sitePanel.rooms" msgstr "部屋" -# Source-Hash: a107b4d76d6972e3 +# Source-Hash: ca39c0581c7318e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone" -#: packages/editor/src/components/editor/room-labels.tsx -#: packages/editor/src/lib/viewer-selection.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select a level to view content" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomLabel.zone" -msgstr "ゾーン" +msgid "editor.sidebar.panels.sitePanel.selectALevelToViewContent" +msgstr "階層を選択して内容を表示" -# Source-Hash: 7da15e7c88dab485 +# Source-Hash: 827e0c6ac9936b69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Attic" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomName.attic" -msgstr "屋根裏" +msgid "editor.sidebar.panels.sitePanel.show" +msgstr "表示" -# Source-Hash: 52adf6ccf54fd772 +# Source-Hash: 91f90818d42a984e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Balcony" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Site" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomName.balcony" -msgstr "バルコニー" +msgid "editor.sidebar.panels.sitePanel.site" +msgstr "敷地" -# Source-Hash: 8caa959c0ae800c3 +# Source-Hash: c40163620df24a76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Basement" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Take snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomName.basement" -msgstr "地下1階" +msgid "editor.sidebar.panels.sitePanel.takeSnapshot" +msgstr "スナップショットを撮る" -# Source-Hash: 0655333424a8b6fb +# Source-Hash: d6b381247066a7aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bathroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The ground level cannot be deleted" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomName.bathroom" -msgstr "浴室" +msgid "editor.sidebar.panels.sitePanel.theGroundLevelCannotBeDeleted" +msgstr "1階の階層は削除できません" -# Source-Hash: f25239fe3891ea8f +# Source-Hash: bbc65c039ae86e11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bedroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.roomName.bedroom" -msgstr "寝室" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.cameraSnapshot" +msgstr "カメラスナップショット" -# Source-Hash: 77d15570e2eba719 +# Source-Hash: 67d29724469fa8d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Boiler room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.roomName.boilerRoom" -msgstr "ボイラー室" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.clearSnapshot" +msgstr "スナップショットを消去" -# Source-Hash: 5fbe77592f8f0ca9 +# Source-Hash: 591087ea83a48ead # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Carport" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.roomName.carport" -msgstr "カーポート" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.hide" +msgstr "非表示" -# Source-Hash: f31dc305ce3a803a +# Source-Hash: 827e0c6ac9936b69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cellar" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.roomName.cellar" -msgstr "地下貯蔵庫" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.show" +msgstr "表示" -# Source-Hash: e9af4141e3f8bdd1 +# Source-Hash: c40163620df24a76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Closet" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Take snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.roomName.closet" -msgstr "クローゼット" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.takeSnapshot" +msgstr "スナップショットを撮る" -# Source-Hash: 388530b7b9c6647d +# Source-Hash: faecab10b69d4863 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corridor" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Update snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.roomName.corridor" -msgstr "廊下" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.updateSnapshot" +msgstr "スナップショットを更新" -# Source-Hash: 4d4a23b87e911d2b +# Source-Hash: 8a1fd8827a68f236 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Courtyard" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "View snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +#, fuzzy +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.viewSnapshot" +msgstr "スナップショットを表示" + +# Source-Hash: b404dded35241274 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Units" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomName.courtyard" -msgstr "中庭" +msgid "editor.sidebar.panels.sitePanel.units" +msgstr "単位" -# Source-Hash: f3aa561772702108 +# Source-Hash: 149fec3fd1f08042 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Deck" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete unit" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.roomName.deck" -msgstr "デッキ" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.deleteUnit" +msgstr "ユニットを削除" -# Source-Hash: 18d7f85ff03c43c9 +# Source-Hash: 930399d3fb247a7c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Den" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Focused" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.roomName.den" -msgstr "書斎" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.focused" +msgstr "フォーカス中" -# Source-Hash: 4424343cad1f08b0 +# Source-Hash: 41ac9dd23bb558d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dining room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove from unit" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.roomName.diningRoom" -msgstr "ダイニング" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.removeFromUnit" +msgstr "ユニットから削除" -# Source-Hash: 5efd0185e89ee84e +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dressing room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.roomName.dressingRoom" -msgstr "ドレッシングルーム" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.room" +msgstr "部屋" -# Source-Hash: f45768e27780dc72 +# Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "En-suite" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.roomName.enSuite" -msgstr "専用浴室" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.zone" +msgstr "ゾーン" -# Source-Hash: 51c664d19e5ea703 +# Source-Hash: faecab10b69d4863 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Entrance" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Update snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomName.entrance" -msgstr "玄関" +msgid "editor.sidebar.panels.sitePanel.updateSnapshot" +msgstr "スナップショットを更新" -# Source-Hash: 4b32a81a5abf006a +# Source-Hash: 28a12e6806c091b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Family room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{assetType, select, guide {Uploading guide... {progress}%} other {Uploading scan... {progress}%}}" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomName.familyRoom" -msgstr "ファミリールーム" +msgid "editor.sidebar.panels.sitePanel.uploadingProgress" +msgstr "{assetType, select, guide {ガイドをアップロード中... {progress}%} other {3Dスキャンをアップロード中... {progress}%}}" -# Source-Hash: e87e6bd9a7d6d667 +# Source-Hash: de389a2a46d53384 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gallery" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Upload scan/floorplan" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomName.gallery" -msgstr "ギャラリー" +msgid "editor.sidebar.panels.sitePanel.uploadScanFloorplan" +msgstr "3Dスキャン/平面図をアップロード" -# Source-Hash: cf7cc0ba06d5eea1 +# Source-Hash: 8a1fd8827a68f236 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Games room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "View snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.roomName.gamesRoom" -msgstr "ゲームルーム" +msgid "editor.sidebar.panels.sitePanel.viewSnapshot" +msgstr "スナップショットを表示" -# Source-Hash: 53aa825a4737190a +# Source-Hash: ba9f809cb032ee57 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Garage" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "In {unitName}" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/zone-membership-checkbox.tsx #, fuzzy -msgid "editor.roomName.garage" -msgstr "ガレージ" +msgid "editor.sidebar.panels.sitePanel.zoneMembershipCheckbox.inUnitname" +msgstr "{unitName}内" -# Source-Hash: 5073b3c2989a626d +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Garden" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.garden" -msgstr "庭" +msgid "editor.sidebar.panels.zonePanel.actions" +msgstr "操作" -# Source-Hash: 52fe13434cdb7b27 +# Source-Hash: fcc43f22937d1536 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Garden shed" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add one" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.gardenShed" -msgstr "物置小屋" +msgid "editor.sidebar.panels.zonePanel.addOne" +msgstr "追加する" -# Source-Hash: a2712156dcaec1ba +# Source-Hash: bbc65c039ae86e11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guest room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.guestRoom" -msgstr "客室" +msgid "editor.sidebar.panels.zonePanel.cameraSnapshot" +msgstr "カメラスナップショット" -# Source-Hash: a1128cf188432bb1 +# Source-Hash: 67d29724469fa8d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gym" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.gym" -msgstr "ジム" +msgid "editor.sidebar.panels.zonePanel.clearSnapshot" +msgstr "スナップショットを消去" -# Source-Hash: 18664ee5a1abd06d +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hallway" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.hallway" -msgstr "廊下" +msgid "editor.sidebar.panels.zonePanel.delete" +msgstr "削除" -# Source-Hash: 7dd957fc73d4d73a +# Source-Hash: e2411929697b7ed4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Home cinema" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete with contents" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.homeCinema" -msgstr "ホームシアター" +msgid "editor.sidebar.panels.zonePanel.deleteWithContents" +msgstr "内容ごと削除" -# Source-Hash: e1579515f44233ca +# Source-Hash: 22ca3935e8754072 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kids' room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No zones on this level." +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.kidsRoom" -msgstr "子ども部屋" +msgid "editor.sidebar.panels.zonePanel.noZonesOnThisLevel" +msgstr "この階層にゾーンはありません。" -# Source-Hash: 1176d2568d093bf1 +# Source-Hash: 941ea30f406dcfa2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchen" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Save to catalog" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.kitchen" -msgstr "キッチン" +msgid "editor.sidebar.panels.zonePanel.saveToCatalog" +msgstr "カタログに保存" -# Source-Hash: 06eb4c431b9b09b6 +# Source-Hash: 98662dfb371cac13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchenette" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select a level to view and create zones" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.kitchenette" -msgstr "簡易キッチン" +msgid "editor.sidebar.panels.zonePanel.selectALevelToViewAnd" +msgstr "階層を選択してゾーンを表示・作成" -# Source-Hash: de9566487b17a73b +# Source-Hash: c40163620df24a76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Take snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.landing" -msgstr "踊り場" +msgid "editor.sidebar.panels.zonePanel.takeSnapshot" +msgstr "スナップショットを撮る" -# Source-Hash: 558bcafa2ec70ded +# Source-Hash: faecab10b69d4863 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Laundry" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Update snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.laundry" -msgstr "ランドリー" +msgid "editor.sidebar.panels.zonePanel.updateSnapshot" +msgstr "スナップショットを更新" -# Source-Hash: 8d211c78417ed1b0 +# Source-Hash: 8a1fd8827a68f236 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Library" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "View snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.roomName.library" -msgstr "ライブラリ" +msgid "editor.sidebar.panels.zonePanel.viewSnapshot" +msgstr "スナップショットを表示" -# Source-Hash: 2204538bab0e77ac +# Source-Hash: 58b05af5b5724efb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Living room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "\"{label}\" plugin crashed" +#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx #, fuzzy -msgid "editor.roomName.livingRoom" -msgstr "リビングルーム" +msgid "editor.sidebar.usePluginPanels.labelPluginCrashed" +msgstr "プラグイン「{label}」がクラッシュしました" -# Source-Hash: bb14c08f0c3db4ad +# Source-Hash: 9e84d6d7b9885c4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Loft" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Loading…" +#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx #, fuzzy -msgid "editor.roomName.loft" -msgstr "ロフト" +msgid "editor.sidebar.usePluginPanels.loading" +msgstr "読み込み中…" -# Source-Hash: a6a0e8bf816cbcb9 +# Source-Hash: 9fc7a39bc32f287a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lounge" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plugins" +#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx #, fuzzy -msgid "editor.roomName.lounge" -msgstr "ラウンジ" +msgid "editor.sidebar.usePluginPanels.plugins" +msgstr "プラグイン" -# Source-Hash: 194a147d4618a994 +# Source-Hash: c6312309378aaaea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This panel hit an error and was unloaded for this session. The rest of the editor is unaffected — reload to try again." +#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx #, fuzzy -msgid "editor.roomName.mezzanine" -msgstr "中二階" +msgid "editor.sidebar.usePluginPanels.thisPanelHitAnErrorAnd" +msgstr "このパネルでエラーが発生したため、このセッションではアンロードされました。エディターの他の部分には影響ありません。再読み込みして再試行してください。" -# Source-Hash: 6b2c82e5fbccb28b +# Source-Hash: 2ab3b6983e384ecc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mudroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling attachment" +#: packages/editor/src/components/ui/snap-target-badge.tsx #, fuzzy -msgid "editor.roomName.mudroom" -msgstr "マッドルーム" +msgid "editor.snapTarget.ceiling" +msgstr "天井に取り付け" -# Source-Hash: e3c3b9b917744680 +# Source-Hash: 54a00bbb699e3778 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Nursery" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof attachment" +#: packages/editor/src/components/ui/snap-target-badge.tsx #, fuzzy -msgid "editor.roomName.nursery" -msgstr "子供部屋(乳児)" +msgid "editor.snapTarget.roof" +msgstr "屋根に取り付け" -# Source-Hash: c1f1fcd9cb418340 +# Source-Hash: e45fee9c27f6ae69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Office" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall attachment" +#: packages/editor/src/components/ui/snap-target-badge.tsx #, fuzzy -msgid "editor.roomName.office" -msgstr "オフィス" +msgid "editor.snapTarget.wall" +msgstr "壁に取り付け" -# Source-Hash: 5d98d41ec10bd05e +# Source-Hash: 834de1a7027c4da1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pantry" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The editor scene failed to render" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.roomName.pantry" -msgstr "パントリー" +msgid "editor.theEditorSceneFailedToRender" +msgstr "エディターのシーンを表示できませんでした" -# Source-Hash: 78dbe13192c0894b +# Source-Hash: 151f7c7e4110016f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Patio" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A curtain wall takes no corner window" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.patio" -msgstr "パティオ" +msgid "editor.toolHint.aCurtainWallTakesNoCorner.1qxjv5i" +msgstr "カーテンウォールにはコーナー窓を付けられません" -# Source-Hash: c3cfcccc167b1c19 +# Source-Hash: 97f5e044d46501fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Playroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A curved wall takes no corner window" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.playroom" -msgstr "プレイルーム" +msgid "editor.toolHint.aCurvedWallTakesNoCorner.1vdnaw5" +msgstr "曲面の壁にはコーナー窓を付けられません" -# Source-Hash: 2e6324beaed18dd5 +# Source-Hash: 776d8ebece7fe1bb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pool area" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add a corner · click the first to close" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.poolArea" -msgstr "プールエリア" +msgid "editor.toolHint.addACornerClickTheFirst.o4r67t" +msgstr "角を追加 · 最初の点をクリックして閉じる" -# Source-Hash: 97d20e41044a3235 +# Source-Hash: 6a0745dd047b149a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Porch" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Another opening is in the way at the corner" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.porch" -msgstr "ポーチ" +msgid "editor.toolHint.anotherOpeningIsInTheWay.11l9dd0" +msgstr "角に別の開口があります" -# Source-Hash: 04cb81f4a4ae4ff3 +# Source-Hash: 441124187e7da2fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Powder room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.powderRoom" -msgstr "パウダールーム" +msgid "editor.toolHint.autoHangers.10554ka" +msgstr "自動吊り金具" -# Source-Hash: 599c44d857832cd0 +# Source-Hash: 47a7f9a6a81156c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Primary bedroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers - click or press H to toggle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.primaryBedroom" -msgstr "主寝室" +msgid "editor.toolHint.autoHangersClickOrPressH.rwa3ka" +msgstr "自動吊り金具 - クリックまたは H で切り替え" -# Source-Hash: 9a6ac3f1cdd8de2b +# Source-Hash: d7944f31cba90e26 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reading nook" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers: Off" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.readingNook" -msgstr "読書スペース" +msgid "editor.toolHint.autoHangersOff.7yx01x" +msgstr "自動吊り金具: オフ" -# Source-Hash: 01f8cc22989822c4 +# Source-Hash: 295882d015d08742 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bathrooms" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers: On" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.section.bathrooms" -msgstr "浴室" +msgid "editor.toolHint.autoHangersOn.10b1umh" +msgstr "自動吊り金具: オン" -# Source-Hash: 9ec82561de8cb788 +# Source-Hash: 8c039e5182b01c4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Circulation" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bypass snapping" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.section.circulation" -msgstr "動線" +msgid "editor.toolHint.bypassSnapping.w5lmdv" +msgstr "スナップを無視" -# Source-Hash: f74a48b6b49644d7 +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Living" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.section.living" -msgstr "リビング" +msgid "editor.toolHint.cancel.ew9em3" +msgstr "キャンセル" -# Source-Hash: 194a147d4618a994 +# Source-Hash: 5b33b576fd30b74e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel move" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.section.mezzanine" -msgstr "中二階" +msgid "editor.toolHint.cancelMove.lvp31c" +msgstr "移動をキャンセル" -# Source-Hash: a5a7af5e5fff1c81 +# Source-Hash: 136fa29b9ae419bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Outdoor" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel run / exit" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.section.outdoor" -msgstr "屋外" +msgid "editor.toolHint.cancelRunExit.zqjf3h" +msgstr "経路をキャンセル / 終了" -# Source-Hash: 5df703d5b5e6ef7e +# Source-Hash: 75b406824be91ac2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sleeping" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel start point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.section.sleeping" -msgstr "寝室" +msgid "editor.toolHint.cancelStartPoint.1xbq2lh" +msgstr "始点をキャンセル" -# Source-Hash: c9d15ec19f814524 +# Source-Hash: ffa5aaa1746303c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Utility & storage" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner window" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.section.utility" -msgstr "ユーティリティと収納" +msgid "editor.toolHint.cornerWindow.1avkzpo" +msgstr "コーナー窓" -# Source-Hash: fbe13f7ab45e4cca +# Source-Hash: b0afdd855a02e4a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Work & hobbies" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cuts" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.section.work" -msgstr "仕事と趣味" +msgid "editor.toolHint.cuts.1y0axps" +msgstr "分割" -# Source-Hash: 10ccb6591f6ad207 +# Source-Hash: dc9fe7601cc525f8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shower room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cuts: {value}" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.showerRoom" -msgstr "シャワールーム" +msgid "editor.toolHint.cutsValue.ouzhvb" +msgstr "分割: {value}" -# Source-Hash: 5254168cc5712cb2 +# Source-Hash: a2e13bc4dc82624c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stairwell" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cuts: {value}, even" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.stairwell" -msgstr "階段室" +msgid "editor.toolHint.cutsValueEven.1ngsz3" +msgstr "分割: {value}、等分" -# Source-Hash: d1596647cd84ade3 +# Source-Hash: 04152b4cec726f34 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Storage" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cycle mono / gable / butterfly" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.storage" -msgstr "収納" +msgid "editor.toolHint.cycleMonoGableButterfly.1poga3m" +msgstr "片流れ / 切妻 / バタフライを切り替え" -# Source-Hash: 7abc2dc6e39b1747 +# Source-Hash: 4fb6c83edb6652b5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Studio" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cycle snapping mode" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.studio" -msgstr "スタジオ" +msgid "editor.toolHint.cycleSnappingMode.1ct0gn6" +msgstr "スナップモードを切り替え" -# Source-Hash: ebe68e83e73021ae +# Source-Hash: 5d550a3ac76279de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Study" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door style — click or press L to cycle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.study" -msgstr "書斎" +msgid "editor.toolHint.doorStyleClickOrPressL.33pe65" +msgstr "ドアのスタイル — クリックまたは L で切り替え" -# Source-Hash: d69a0244649771ef +# Source-Hash: 3272a7df5d7c6a9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sunroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door type — click or press O to cycle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.sunroom" -msgstr "サンルーム" +msgid "editor.toolHint.doorTypeClickOrPressO.1hhh8gt" +msgstr "ドアの種類 — クリックまたは O で切り替え" -# Source-Hash: 96281876ce53ba08 +# Source-Hash: 366222b4435eefda # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terrace" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drop downspout from outlet" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.terrace" -msgstr "テラス" +msgid "editor.toolHint.dropDownspoutFromOutlet.1k4h1m4" +msgstr "排水口から竪樋を下ろす" -# Source-Hash: a0cb3e6f5cf4fbec +# Source-Hash: 03f306371f345007 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Toilet" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct diameter down / up" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.toilet" -msgstr "トイレ" +msgid "editor.toolHint.ductDiameterDownUp.1wdz5vq" +msgstr "ダクト径を小さく / 大きく" -# Source-Hash: 6c01526f89f3106b +# Source-Hash: 7b4137e27f8327d9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Utility room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End run / cancel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.utilityRoom" -msgstr "ユーティリティ" +msgid "editor.toolHint.endRunCancel.59dh2w" +msgstr "経路を終了 / キャンセル" -# Source-Hash: fc42d89621ae7bac +# Source-Hash: b714e91c31108a71 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Veranda" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End the run" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.veranda" -msgstr "ベランダ" +msgid "editor.toolHint.endTheRun.1c1raig" +msgstr "連続描画を終了" -# Source-Hash: b45d7730e896fd99 +# Source-Hash: 938aacb119b29dc1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walk-in closet" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Exit" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.walkInCloset" -msgstr "ウォークインクローゼット" +msgid "editor.toolHint.exit.engmg5" +msgstr "終了" -# Source-Hash: 399f27253ef956cb +# Source-Hash: 7cb4e0688cabcb00 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Workshop" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Exit drawing" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.roomName.workshop" -msgstr "作業場" +msgid "editor.toolHint.exitDrawing.9noxyb" +msgstr "描画を終了" -# Source-Hash: 83909f82446ee9c3 +# Source-Hash: 47025a103c456125 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Settings" -#: packages/editor/src/components/ui/sidebar/icon-rail.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish and continue" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.iconRail.settings" -msgstr "設定" +msgid "editor.toolHint.finishAndContinue.1gpfsks" +msgstr "完了して続ける" -# Source-Hash: 91f90818d42a984e +# Source-Hash: 000918429b74128f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Site" -#: packages/editor/src/components/ui/sidebar/icon-rail.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish ceiling" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.iconRail.site" -msgstr "敷地" +msgid "editor.toolHint.finishCeiling.1c1lfel" +msgstr "天井を完了" -# Source-Hash: 663175a9c461a96d +# Source-Hash: 51a80a0dba5a6f30 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish grid axis" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.all" -msgstr "すべて" +msgid "editor.toolHint.finishGridAxis.1wvrfhr" +msgstr "通り芯を完了" -# Source-Hash: fce9814c289e6b71 +# Source-Hash: 87c7b98fc2e010e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Community" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish measurement" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.community" -msgstr "コミュニティ" +msgid "editor.toolHint.finishMeasurement.1e4gv16" +msgstr "計測を完了" -# Source-Hash: 663175a9c461a96d +# Source-Hash: 5e1a0af7dc506826 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish multi-point witnesses" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.all" -msgstr "すべて" +msgid "editor.toolHint.finishMultiPointWitnesses.8wzskz" +msgstr "複数点の参照を完了" -# Source-Hash: fce9814c289e6b71 +# Source-Hash: 30fc0862501ba2e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Community" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish slab" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.community" -msgstr "コミュニティ" +msgid "editor.toolHint.finishSlab.xmnm8e" +msgstr "スラブを完了" -# Source-Hash: 8d211c78417ed1b0 +# Source-Hash: 66ed7c7598d3aa29 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Library" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip side" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.library" -msgstr "ライブラリ" +msgid "editor.toolHint.flipSide.172xku9" +msgstr "向きを反転" -# Source-Hash: a0b7adfdfdec7307 +# Source-Hash: f5717f6a0905ffab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mine" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow: trace a lineset" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.mine" -msgstr "マイアイテム" +msgid "editor.toolHint.followTraceALineset.mgquwe" +msgstr "追従: 冷媒配管に沿って配管" -# Source-Hash: 6024b7778b392ec3 +# Source-Hash: ed7f3d8417a3e074 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No results for “{search}”" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Force place" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.noResultsForSearch" -msgstr "「{search}」の結果はありません" +msgid "editor.toolHint.forcePlace.1hq1nr" +msgstr "強制配置" -# Source-Hash: 4ceb6dcb7827db7f +# Source-Hash: 64b4ac6d3da25183 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Search..." -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free angle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.search" -msgstr "検索..." +msgid "editor.toolHint.freeAngle.1ptblho" +msgstr "自由角度" -# Source-Hash: 8d211c78417ed1b0 +# Source-Hash: 446b8aac1e5e8422 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Library" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free place" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.library" -msgstr "ライブラリ" +msgid "editor.toolHint.freePlace.1s1uusw" +msgstr "自由配置" -# Source-Hash: a0b7adfdfdec7307 +# Source-Hash: cc0c14065951444d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mine" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free placement" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.mine" -msgstr "マイアイテム" +msgid "editor.toolHint.freePlacement.1nztdac" +msgstr "自由配置" -# Source-Hash: 6024b7778b392ec3 +# Source-Hash: f098a27096a9c1ea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No results for “{search}”" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Go vertical ↕, click to place" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.noResultsForSearch" -msgstr "「{search}」の結果はありません" +msgid "editor.toolHint.goVerticalClickToPlace.dg8g6m" +msgstr "垂直に切り替え ↕、クリックで配置" -# Source-Hash: 4ceb6dcb7827db7f +# Source-Hash: fd47f1820d8799c8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Search..." -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Highlight outlet" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.search" -msgstr "検索..." +msgid "editor.toolHint.highlightOutlet.65hoq8" +msgstr "排水口を強調" -# Source-Hash: 3c67cde0578ac829 +# Source-Hash: eb90058d0f856f67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Join as a corner window" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.addLevel" -msgstr "階層を追加" +msgid "editor.toolHint.joinAsACornerWindow.jvdp4j" +msgstr "コーナー窓として結合" -# Source-Hash: 9a56d90d461b4bca +# Source-Hash: 225b3161f2e59757 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add point" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Alt + drag" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.addPoint" -msgstr "点を追加" +msgid "editor.toolHint.key.altDrag.ai3wn9" +msgstr "Alt + ドラッグ" -# Source-Hash: fedccec504a9ae33 +# Source-Hash: dd66f883b173fc72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Area:" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Backspace" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.area" -msgstr "面積:" +msgid "editor.toolHint.key.backspace.qy6qx8" +msgstr "Backspace" -# Source-Hash: 87b6880f6de7a45a +# Source-Hash: a18387bc0be54c32 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base elevation" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.baseElevation" -msgstr "基準高さ" +msgid "editor.toolHint.key.click.m8sun" +msgstr "クリック" -# Source-Hash: d42f7d29e3fc4af7 +# Source-Hash: db9e60c1d30b8499 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Building" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click again" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.building" -msgstr "建物" +msgid "editor.toolHint.key.clickAgain.190ws9j" +msgstr "もう一度クリック" -# Source-Hash: 7c90f458259d5cd8 +# Source-Hash: f400330b9c9c12e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add new level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Command" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.buildingTreeNode.addNewLevel" -msgstr "新しい階層を追加" +msgid "editor.toolHint.key.command.1j2mkia" +msgstr "Command" -# Source-Hash: d42f7d29e3fc4af7 +# Source-Hash: 976c63285a510b09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Building" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Control" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.buildingTreeNode.building" -msgstr "建物" +msgid "editor.toolHint.key.control.10fbl8e" +msgstr "Ctrl" -# Source-Hash: bbc65c039ae86e11 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Camera snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.cameraSnapshot" -msgstr "カメラスナップショット" +msgid "editor.toolHint.key.delete.oay2cq" +msgstr "削除" -# Source-Hash: 3a0701ebcb9f26cb +# Source-Hash: 88888c9d2719fa92 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Capture" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double click" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.capture" -msgstr "キャプチャ" +msgid "editor.toolHint.key.doubleClick.vlma6o" +msgstr "ダブルクリック" -# Source-Hash: 71f2343818c55e0c +# Source-Hash: dfb85b2addb7b9fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear selection" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.clearSelection" -msgstr "選択を解除" +msgid "editor.toolHint.key.drag.8pwtpf" +msgstr "ドラッグ" -# Source-Hash: 67d29724469fa8d3 +# Source-Hash: ed9140d42148c99b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Enter" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.clearSnapshot" -msgstr "スナップショットを消去" +msgid "editor.toolHint.key.enter.1ctpui5" +msgstr "Enter" -# Source-Hash: def517c77fda49ea +# Source-Hash: 9195fa8b9c8ebdfb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close walls around a space to make a room." -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.closeWallsAroundASpaceTo" -msgstr "空間を壁で囲むと部屋になります。" +msgid "editor.toolHint.key.hover.6xw79p" +msgstr "ホバー" -# Source-Hash: 2b9af8da4b34cbfa +# Source-Hash: 2d78441b741bc562 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collection colour" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a duct end" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.collectionColour" -msgstr "コレクションの色" +msgid "editor.toolHint.key.hoverADuctEnd.19axr3b" +msgstr "ダクトの端にホバー" -# Source-Hash: 135af27a14a4cda7 +# Source-Hash: 6083405086f61c76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collections" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a pipe end" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.collections" -msgstr "コレクション" +msgid "editor.toolHint.key.hoverAPipeEnd.1jbum5f" +msgstr "配管の端にホバー" -# Source-Hash: 6f4751c26f12aef9 +# Source-Hash: a5a337eb76fdb066 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete collection" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover gutter" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.deleteCollection" -msgstr "コレクションを削除" +msgid "editor.toolHint.key.hoverGutter.1dwcsno" +msgstr "雨樋にホバー" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: a58533594411e088 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left click" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.delete" -msgstr "削除" +msgid "editor.toolHint.key.leftClick.s4gwfc" +msgstr "左クリック" -# Source-Hash: 8e29375893d63408 +# Source-Hash: bc4ab608ec3d3b4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Middle click" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.deleteLevel" -msgstr "階層を削除" +msgid "editor.toolHint.key.middleClick.1jbaan4" +msgstr "中クリック" -# Source-Hash: 6552e45eecc0a227 +# Source-Hash: 6791879c651108c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw a zone" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right click" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.drawAZone" -msgstr "ゾーンを描画" +msgid "editor.toolHint.key.rightClick.1ovld0h" +msgstr "右クリック" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.duplicate" -msgstr "複製" +msgid "editor.toolHint.key.room.1f3jkpm" +msgstr "部屋" -# Source-Hash: 933177338f5a03ed +# Source-Hash: c836b21b42198868 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R / Shift+R" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.duplicateLevel" -msgstr "階層を複製" +msgid "editor.toolHint.key.rShiftR.13bnobh" +msgstr "R / Shift+R" -# Source-Hash: c038947f317cabba +# Source-Hash: 9812aa06d8bb7544 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate level with options" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scroll" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.duplicateLevelWithOptions" -msgstr "オプションを指定して階層を複製" +msgid "editor.toolHint.key.scroll.ai6wr0" +msgstr "スクロール" -# Source-Hash: 9614c6825a7c67bf +# Source-Hash: f2174536230657c8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate with options..." -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scroll wheel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.duplicateWithOptions" -msgstr "オプションを指定して複製..." +msgid "editor.toolHint.key.scrollWheel.18j0ix7" +msgstr "スクロールホイール" -# Source-Hash: 7c4196b9e791c195 +# Source-Hash: 82dd231086d87f3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elements" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Space" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.elements" -msgstr "要素" +msgid "editor.toolHint.key.space.1hrh82t" +msgstr "Space" -# Source-Hash: 1344ea2602e3aa9e +# Source-Hash: 9e68aa2f472cad56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guide" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tab" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.guide" -msgstr "ガイド" +msgid "editor.toolHint.key.tab.1xsal0s" +msgstr "Tab" -# Source-Hash: 591087ea83a48ead +# Source-Hash: 4b221b73f9496a49 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mount: floor / ceiling / wall" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.hide" -msgstr "非表示" +msgid "editor.toolHint.mountFloorCeilingWall.32dxpv" +msgstr "取付: 床 / 天井 / 壁" -# Source-Hash: 0608743fc1736d86 +# Source-Hash: 225edfb1e45aed95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No room for the matching window on the other wall" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.level" -msgstr "階層" +msgid "editor.toolHint.noRoomForTheMatchingWindow.1755948" +msgstr "もう一方の壁に対応する窓を置く余地がありません" -# Source-Hash: 13b3e6a6afe319d1 +# Source-Hash: e367d28a655f1cca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "New unit" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not a rectangle: draw this roof instead" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.newUnit" -msgstr "新規ユニット" +msgid "editor.toolHint.notARectangleDrawThisRoof.100pa5g" +msgstr "長方形ではありません: 代わりにこの屋根を描画" -# Source-Hash: 0192748d50f0e5f7 +# Source-Hash: a7045d6b678bcd13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No buildings yet" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx -#, fuzzy -msgid "editor.sidebar.panels.sitePanel.noBuildingsYet" -msgstr "建物はまだありません" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No wall meets here" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "editor.toolHint.noWallMeetsHere.19n99yc" +msgstr "ここで交わる壁はありません" -# Source-Hash: 1be310702a12e433 +# Source-Hash: a639341dc21fed2c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No elements on this level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Number of cuts — scroll or click to change" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.noElementsOnThisLevel" -msgstr "この階層に要素はありません" +msgid "editor.toolHint.numberOfCutsScrollOrClick.1kqe84b" +msgstr "分割数 — スクロールまたはクリックで変更" -# Source-Hash: 0956af88ced36992 +# Source-Hash: af01bde3ae4b7e59 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No levels yet" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick witness point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.noLevelsYet" -msgstr "階層はまだありません" +msgid "editor.toolHint.pickWitnessPoint.k3hgh1" +msgstr "参照点を選ぶ" -# Source-Hash: 45c41bfb2ae19627 +# Source-Hash: ecfd58576b28a9f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {# object selected} other {# objects selected}}" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pipe size down / up" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.objectsSelected" -msgstr "{count, plural, other {# 個のオブジェクトを選択中}}" +msgid "editor.toolHint.pipeSizeDownUp.wp04og" +msgstr "管径を小さく / 大きく" -# Source-Hash: a5434e26e5cb1b26 +# Source-Hash: 7a1eb7b64f06bad0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Other zones" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place and continue" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.otherZones" -msgstr "その他のゾーン" +msgid "editor.toolHint.placeAndContinue.qfwkrq" +msgstr "配置して続ける" -# Source-Hash: 2aa38d84079d4dba +# Source-Hash: c6cda39e2e4b5d3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Perimeter:" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place block" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.perimeter" -msgstr "周長:" +msgid "editor.toolHint.placeBlock.1aylwrx" +msgstr "ブロックを配置" -# Source-Hash: 4004b9a8e4f8c9d0 +# Source-Hash: 45a743c52a1d72de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Property Line" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place box vent on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.propertyLine" -msgstr "敷地境界線" +msgid "editor.toolHint.placeBoxVentOnRoof.kf88e5" +msgstr "屋根にボックス換気口を配置" -# Source-Hash: 3e7408ed44676176 +# Source-Hash: 75142dd1d557efe2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rooms" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place cabinet" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.rooms" -msgstr "部屋" +msgid "editor.toolHint.placeCabinet.b0ouyk" +msgstr "キャビネットを配置" -# Source-Hash: ca39c0581c7318e6 +# Source-Hash: da603a713d4c9909 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select a level to view content" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place canopy or set the next run point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.selectALevelToViewContent" -msgstr "階層を選択して内容を表示" +msgid "editor.toolHint.placeCanopyOrSetTheNext.12l7zf8" +msgstr "キャノピーを配置、または次の点を設定" -# Source-Hash: 827e0c6ac9936b69 +# Source-Hash: 8b3a30c6b7a5612d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place chimney on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.show" -msgstr "表示" +msgid "editor.toolHint.placeChimneyOnRoof.19dbqu" +msgstr "屋根に煙突を配置" -# Source-Hash: 91f90818d42a984e +# Source-Hash: 710d41e4e2f259fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Site" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place column" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.site" -msgstr "敷地" +msgid "editor.toolHint.placeColumn.1w2vq86" +msgstr "柱を配置" -# Source-Hash: c40163620df24a76 +# Source-Hash: ee1da4e12a71d9a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Take snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place cupola on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.takeSnapshot" -msgstr "スナップショットを撮る" +msgid "editor.toolHint.placeCupolaOnRoof.ofx3bn" +msgstr "屋根にキューポラを配置" -# Source-Hash: d6b381247066a7aa +# Source-Hash: 19c1fe8c46d213a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The ground level cannot be deleted" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place dimension line when needed" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.theGroundLevelCannotBeDeleted" -msgstr "1階の階層は削除できません" +msgid "editor.toolHint.placeDimensionLineWhenNeeded.bjw2cj" +msgstr "必要に応じて寸法線を配置" -# Source-Hash: bbc65c039ae86e11 +# Source-Hash: 58f3e7efb6ea120b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Camera snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place door on wall" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.cameraSnapshot" -msgstr "カメラスナップショット" +msgid "editor.toolHint.placeDoorOnWall.1jwadf" +msgstr "壁にドアを配置" -# Source-Hash: 67d29724469fa8d3 +# Source-Hash: de04e9d03d937c97 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place dormer on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.clearSnapshot" -msgstr "スナップショットを消去" +msgid "editor.toolHint.placeDormerOnRoof.1w518a6" +msgstr "屋根にドーマーを配置" -# Source-Hash: 591087ea83a48ead +# Source-Hash: c581645f2ee447c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place elevator" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.hide" -msgstr "非表示" +msgid "editor.toolHint.placeElevator.1f65zva" +msgstr "エレベーターを配置" -# Source-Hash: 827e0c6ac9936b69 +# Source-Hash: 096b8d6482717358 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place eyebrow vent on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.show" -msgstr "表示" +msgid "editor.toolHint.placeEyebrowVentOnRoof.1h1tqxn" +msgstr "屋根に眉型換気口を配置" -# Source-Hash: c40163620df24a76 +# Source-Hash: e8d42c1c8370773f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Take snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place fitting" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.takeSnapshot" -msgstr "スナップショットを撮る" +msgid "editor.toolHint.placeFitting.1pmx3vn" +msgstr "継手を配置" -# Source-Hash: faecab10b69d4863 +# Source-Hash: 2340a4b70cb0d9ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Update snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place gutter on roof eave" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.updateSnapshot" -msgstr "スナップショットを更新" +msgid "editor.toolHint.placeGutterOnRoofEave.llwzf9" +msgstr "軒に雨樋を配置" -# Source-Hash: 8a1fd8827a68f236 +# Source-Hash: 706a8eafb6212833 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "View snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place item" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.viewSnapshot" -msgstr "スナップショットを表示" +msgid "editor.toolHint.placeItem.teynf" +msgstr "アイテムを配置" -# Source-Hash: b404dded35241274 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Units" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# Source-Hash: 1815c482e249932e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place it (locked to 45°)" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.units" -msgstr "単位" +msgid "editor.toolHint.placeItLockedTo45.16e4csk" +msgstr "配置(45°に固定)" -# Source-Hash: 149fec3fd1f08042 +# Source-Hash: 4a14340657532838 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete unit" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place measurement point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.deleteUnit" -msgstr "ユニットを削除" +msgid "editor.toolHint.placeMeasurementPoint.bsatli" +msgstr "計測点を配置" -# Source-Hash: 930399d3fb247a7c +# Source-Hash: b3be684ac62fbf53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Focused" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.focused" -msgstr "フォーカス中" +msgid "editor.toolHint.placement.13lcvts" +msgstr "配置" -# Source-Hash: 41ac9dd23bb558d7 +# Source-Hash: 2bb2ce6276c69b1e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove from unit" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement: Auto" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.removeFromUnit" -msgstr "ユニットから削除" +msgid "editor.toolHint.placementAuto.1caa52d" +msgstr "配置: 自動" -# Source-Hash: 612dcd5bf06a79c4 +# Source-Hash: ed78ac5354a1dcd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement: Ground" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.room" -msgstr "部屋" +msgid "editor.toolHint.placementGround.1ruz145" +msgstr "配置: 地面" -# Source-Hash: a107b4d76d6972e3 +# Source-Hash: a066a2c9d5e65a1a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement: Roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.zone" -msgstr "ゾーン" +msgid "editor.toolHint.placementRoof.renkw8" +msgstr "配置: 屋根" -# Source-Hash: faecab10b69d4863 +# Source-Hash: 8f74dbe5064c4c66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Update snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement surface - click or press P to cycle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.updateSnapshot" -msgstr "スナップショットを更新" +msgid "editor.toolHint.placementSurfaceClickOrPressP.w56h19" +msgstr "配置面 - クリックまたは P で切り替え" -# Source-Hash: 28a12e6806c091b0 +# Source-Hash: fe119955c925feaf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{assetType, select, guide {Uploading guide... {progress}%} other {Uploading scan... {progress}%}}" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement type" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.uploadingProgress" -msgstr "{assetType, select, guide {ガイドをアップロード中... {progress}%} other {3Dスキャンをアップロード中... {progress}%}}" +msgid "editor.toolHint.placementType.1mdpl60" +msgstr "配置の種類" -# Source-Hash: de389a2a46d53384 +# Source-Hash: 33043a35500168f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Upload scan/floorplan" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement type — click or press I to toggle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.uploadScanFloorplan" -msgstr "3Dスキャン/平面図をアップロード" +msgid "editor.toolHint.placementTypeClickOrPressI.10cgxh2" +msgstr "配置の種類 — クリックまたは I で切り替え" -# Source-Hash: 8a1fd8827a68f236 +# Source-Hash: 9945f412e6a9a446 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "View snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place on a fence" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.viewSnapshot" -msgstr "スナップショットを表示" +msgid "editor.toolHint.placeOnAFence.1dptstr" +msgstr "フェンスに配置" -# Source-Hash: ba9f809cb032ee57 +# Source-Hash: 6708118775a7da7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "In {unitName}" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/zone-membership-checkbox.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place register" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.zoneMembershipCheckbox.inUnitname" -msgstr "{unitName}内" +msgid "editor.toolHint.placeRegister.1uebycd" +msgstr "吹出口を配置" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: ebd2731f5c79306e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place ridge vent on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.actions" -msgstr "操作" +msgid "editor.toolHint.placeRidgeVentOnRoof.2tpd8r" +msgstr "屋根に棟換気を配置" -# Source-Hash: fcc43f22937d1536 +# Source-Hash: 9b3c66a867c23326 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add one" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place shelf" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.addOne" -msgstr "追加する" +msgid "editor.toolHint.placeShelf.y4l3iw" +msgstr "棚を配置" -# Source-Hash: bbc65c039ae86e11 +# Source-Hash: f11cf5c1c9fe862d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Camera snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place skylight on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.cameraSnapshot" -msgstr "カメラスナップショット" +msgid "editor.toolHint.placeSkylightOnRoof.e215pe" +msgstr "屋根に天窓を配置" -# Source-Hash: 67d29724469fa8d3 +# Source-Hash: e989a58d6709cc16 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place solar panel array on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.clearSnapshot" -msgstr "スナップショットを消去" +msgid "editor.toolHint.placeSolarPanelArrayOnRoof.kk11fn" +msgstr "屋根に太陽光パネルを配置" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: b67f7036d5180cf5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place spawn point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.delete" -msgstr "削除" +msgid "editor.toolHint.placeSpawnPoint.205o25" +msgstr "スポーン地点を配置" -# Source-Hash: e2411929697b7ed4 +# Source-Hash: 6c7f32a17e5636c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete with contents" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place stairs" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.deleteWithContents" -msgstr "内容ごと削除" +msgid "editor.toolHint.placeStairs.zwxxu2" +msgstr "階段を配置" -# Source-Hash: 22ca3935e8754072 +# Source-Hash: 641c0d3debd798a8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No zones on this level." -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place trap" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.noZonesOnThisLevel" -msgstr "この階層にゾーンはありません。" +msgid "editor.toolHint.placeTrap.1gxemn3" +msgstr "トラップを配置" -# Source-Hash: 941ea30f406dcfa2 +# Source-Hash: 6f0a6f6c4b7588a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Save to catalog" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place turbine vent on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.saveToCatalog" -msgstr "カタログに保存" +msgid "editor.toolHint.placeTurbineVentOnRoof.1iqeluf" +msgstr "屋根にタービン換気扇を配置" -# Source-Hash: 98662dfb371cac13 +# Source-Hash: e65cf5edb4f51ed5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select a level to view and create zones" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place unit" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.selectALevelToViewAnd" -msgstr "階層を選択してゾーンを表示・作成" +msgid "editor.toolHint.placeUnit.8zkx4q" +msgstr "ユニットを配置" -# Source-Hash: c40163620df24a76 +# Source-Hash: 86ce1c730154f68b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Take snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place window on wall" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.takeSnapshot" -msgstr "スナップショットを撮る" +msgid "editor.toolHint.placeWindowOnWall.1k3qnfb" +msgstr "壁に窓を配置" -# Source-Hash: faecab10b69d4863 +# Source-Hash: 2b612180a7617901 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Update snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place without the corner snap" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.updateSnapshot" -msgstr "スナップショットを更新" +msgid "editor.toolHint.placeWithoutTheCornerSnap.1nifqew" +msgstr "角のスナップなしで配置" -# Source-Hash: 8a1fd8827a68f236 +# Source-Hash: dd2ea442152dca5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "View snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Point inside a room, porch or deck" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.viewSnapshot" -msgstr "スナップショットを表示" +msgid "editor.toolHint.pointInsideARoomPorchOr.58w64l" +msgstr "部屋・ポーチ・デッキの内側にカーソルを合わせる" -# Source-Hash: 58b05af5b5724efb +# Source-Hash: 0dc6d121791696f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "\"{label}\" plugin crashed" -#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove last point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.usePluginPanels.labelPluginCrashed" -msgstr "プラグイン「{label}」がクラッシュしました" +msgid "editor.toolHint.removeLastPoint.2dmdcx" +msgstr "最後の点を削除" -# Source-Hash: 9e84d6d7b9885c4f +# Source-Hash: 8b74b1d962be10fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Loading…" -#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove last witness" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.usePluginPanels.loading" -msgstr "読み込み中…" +msgid "editor.toolHint.removeLastWitness.1b6vvzw" +msgstr "最後の参照を削除" -# Source-Hash: 9fc7a39bc32f287a +# Source-Hash: 1185bd2407dd9172 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Plugins" -#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge direction" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.usePluginPanels.plugins" -msgstr "プラグイン" +msgid "editor.toolHint.ridgeDirection.5m1369" +msgstr "棟の向き" -# Source-Hash: c6312309378aaaea +# Source-Hash: 4352028e50450055 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "This panel hit an error and was unloaded for this session. The rest of the editor is unaffected — reload to try again." -#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge direction - click or press R to turn it 90°" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.sidebar.usePluginPanels.thisPanelHitAnErrorAnd" -msgstr "このパネルでエラーが発生したため、このセッションではアンロードされました。エディターの他の部分には影響ありません。再読み込みして再試行してください。" +msgid "editor.toolHint.ridgeDirectionClickOrPressR.1t14dyk" +msgstr "棟の向き - クリックまたは R で 90° 回転" +# Source-Hash: 96c889f047db9de5 # Review: required -# Source-Hash: 2ab3b6983e384ecc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling attachment" -#: packages/editor/src/components/ui/snap-target-badge.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge: Long side" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.snapTarget.ceiling" -msgstr "天井に取り付け" +msgid "editor.toolHint.ridgeLongSide.ew0euv" +msgstr "棟: 長辺" +# Source-Hash: 58143198d3f2a265 # Review: required -# Source-Hash: 54a00bbb699e3778 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof attachment" -#: packages/editor/src/components/ui/snap-target-badge.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge: Short side" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.snapTarget.roof" -msgstr "屋根に取り付け" +msgid "editor.toolHint.ridgeShortSide.gye8pb" +msgstr "棟: 短辺" +# Source-Hash: 306d409f8a1cf480 # Review: required -# Source-Hash: e45fee9c27f6ae69 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall attachment" -#: packages/editor/src/components/ui/snap-target-badge.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.snapTarget.wall" -msgstr "壁に取り付け" +msgid "editor.toolHint.rotate.1thqa0a" +msgstr "回転" -# Source-Hash: 834de1a7027c4da1 +# Source-Hash: 8a665ecaeffa9308 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The editor scene failed to render" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ±45°" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.theEditorSceneFailedToRender" -msgstr "エディターのシーンを表示できませんでした" +msgid "editor.toolHint.rotate45.9zq68u" +msgstr "±45°回転" -# Source-Hash: 151f7c7e4110016f +# Source-Hash: be2240289aa74df5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A curtain wall takes no corner window" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ±45° (floor / ceiling)" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.aCurtainWallTakesNoCorner.1qxjv5i" -msgstr "カーテンウォールにはコーナー窓を付けられません" +msgid "editor.toolHint.rotate45FloorCeiling.m9t57d" +msgstr "±45°回転(床 / 天井)" -# Source-Hash: 97f5e044d46501fb +# Source-Hash: d5fb78b07c0f8138 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A curved wall takes no corner window" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ghost ±15°" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.aCurvedWallTakesNoCorner.1vdnaw5" -msgstr "曲面の壁にはコーナー窓を付けられません" +msgid "editor.toolHint.rotateGhost15.rsa52c" +msgstr "プレビューを±15°回転" -# Source-Hash: 776d8ebece7fe1bb +# Source-Hash: 912d340cd16e27fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add a corner · click the first to close" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate or flip the run side" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.addACornerClickTheFirst.o4r67t" -msgstr "角を追加 · 最初の点をクリックして閉じる" +msgid "editor.toolHint.rotateOrFlipTheRunSide.t5ior7" +msgstr "配置側を回転または反転" -# Source-Hash: 6a0745dd047b149a +# Source-Hash: fa24651e9e5f595a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Another opening is in the way at the corner" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate spawn point" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.anotherOpeningIsInTheWay.11l9dd0" -msgstr "角に別の開口があります" +msgid "editor.toolHint.rotateSpawnPoint.1opcuu7" +msgstr "スポーン地点を回転" -# Source-Hash: 441124187e7da2fc +# Source-Hash: 2d693d87fe9b59e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round / rectangular / oval" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.autoHangers.10554ka" -msgstr "自動吊り金具" +msgid "editor.toolHint.roundRectangularOval.e4nh6x" +msgstr "円形 / 矩形 / 楕円" -# Source-Hash: 47a7f9a6a81156c3 +# Source-Hash: ee4ca2612f1ea085 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers - click or press H to toggle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set beam start / end; the next beam starts there" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.autoHangersClickOrPressH.rwa3ka" -msgstr "自動吊り金具 - クリックまたは H で切り替え" +msgid "editor.toolHint.setBeamStartEndTheNext.di3bzj" +msgstr "梁の始点 / 終点を設定、次の梁はそこから始まる" -# Source-Hash: d7944f31cba90e26 +# Source-Hash: f7d2c9cdcc637c97 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers: Off" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set fence start / end" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.autoHangersOff.7yx01x" -msgstr "自動吊り金具: オフ" +msgid "editor.toolHint.setFenceStartEnd.1phbwsq" +msgstr "フェンスの始点 / 終点を設定" -# Source-Hash: 295882d015d08742 +# Source-Hash: c93ae898b4d59f6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers: On" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set one corner, then the opposite" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.autoHangersOn.10b1umh" -msgstr "自動吊り金具: オン" +msgid "editor.toolHint.setOneCornerThenTheOpposite.8tsl49" +msgstr "1つの角、次に対角を設定" -# Source-Hash: 8c039e5182b01c4d +# Source-Hash: 4f55171f10c6ceeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bypass snapping" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set roof footprint" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.bypassSnapping.w5lmdv" -msgstr "スナップを無視" +msgid "editor.toolHint.setRoofFootprint.p50n0o" +msgstr "屋根の外形を設定" -# Source-Hash: c0774c185060fc13 +# Source-Hash: 0243859b1d64c21e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set wall start / end" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cancel.ew9em3" -msgstr "キャンセル" +msgid "editor.toolHint.setWallStartEnd.1r8ubcx" +msgstr "壁の始点 / 終点を設定" -# Source-Hash: 5b33b576fd30b74e +# Source-Hash: c2806cce9612fa50 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel move" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slope / level" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cancelMove.lvp31c" -msgstr "移動をキャンセル" +msgid "editor.toolHint.slopeLevel.ftqp67" +msgstr "勾配 / 水平" -# Source-Hash: 136fa29b9ae419bf +# Source-Hash: 06c0ec40606db679 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel run / exit" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snap onto the run" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cancelRunExit.zqjf3h" -msgstr "経路をキャンセル / 終了" +msgid "editor.toolHint.snapOntoTheRun.86yhmp" +msgstr "経路にスナップ" -# Source-Hash: 75b406824be91ac2 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel start point" +# Source-Hash: e214cccbac9c4fd2 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Split at the marks" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cancelStartPoint.1xbq2lh" -msgstr "始点をキャンセル" +msgid "editor.toolHint.splitAtTheMarks.x5tpdd" +msgstr "マークで分割" -# Source-Hash: ffa5aaa1746303c4 +# Source-Hash: 94455c35bfeac6b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner window" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start grid axis" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cornerWindow.1avkzpo" -msgstr "コーナー窓" +msgid "editor.toolHint.startGridAxis.k92yza" +msgstr "通り芯を開始" -# Source-Hash: b0afdd855a02e4a7 +# Source-Hash: 2edb4c29bbe7c513 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cuts" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start lineset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cuts.1y0axps" -msgstr "分割" +msgid "editor.toolHint.startLineset.23q8dh" +msgstr "冷媒配管を開始" -# Source-Hash: dc9fe7601cc525f8 +# Source-Hash: 9e50f1b30e325208 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cuts: {value}" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start liquid line" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cutsValue.ouzhvb" -msgstr "分割: {value}" +msgid "editor.toolHint.startLiquidLine.1rlxsgd" +msgstr "液管を開始" -# Source-Hash: a2e13bc4dc82624c +# Source-Hash: 877ddcb778c211cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cuts: {value}, even" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start run" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cutsValueEven.1ngsz3" -msgstr "分割: {value}、等分" +msgid "editor.toolHint.startRun.r6fc5u" +msgstr "経路を開始" -# Source-Hash: 04152b4cec726f34 +# Source-Hash: 8a62bee64174bbc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cycle mono / gable / butterfly" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start segment" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cycleMonoGableButterfly.1poga3m" -msgstr "片流れ / 切妻 / バタフライを切り替え" +msgid "editor.toolHint.startSegment.rolym6" +msgstr "セグメントを開始" -# Source-Hash: 4fb6c83edb6652b5 +# Source-Hash: 6cc5dc51a8e66779 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cycle snapping mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Step back or cancel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.cycleSnappingMode.1ct0gn6" -msgstr "スナップモードを切り替え" +msgid "editor.toolHint.stepBackOrCancel.zbfdkn" +msgstr "1つ戻る、またはキャンセル" -# Source-Hash: 5d550a3ac76279de +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door style — click or press L to cycle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.doorStyleClickOrPressL.33pe65" -msgstr "ドアのスタイル — クリックまたは L で切り替え" +msgid "editor.toolHint.style.nf3vcm" +msgstr "スタイル" -# Source-Hash: 3272a7df5d7c6a9a +# Source-Hash: 81f595b1c47c0080 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door type — click or press O to cycle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Barn" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.doorTypeClickOrPressO.1hhh8gt" -msgstr "ドアの種類 — クリックまたは O で切り替え" +msgid "editor.toolHint.styleBarn.k9n1x" +msgstr "スタイル: 納屋" -# Source-Hash: 366222b4435eefda +# Source-Hash: 3a82c718fe215273 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drop downspout from outlet" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Casement" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.dropDownspoutFromOutlet.1k4h1m4" -msgstr "排水口から竪樋を下ろす" +msgid "editor.toolHint.styleCasement.ziklec" +msgstr "スタイル: 開き" -# Source-Hash: 03f306371f345007 +# Source-Hash: 072e3331d1d105c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct diameter down / up" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Craftsman" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.ductDiameterDownUp.1wdz5vq" -msgstr "ダクト径を小さく / 大きく" +msgid "editor.toolHint.styleCraftsman.52e6a9" +msgstr "スタイル: クラフツマン" -# Source-Hash: 7b4137e27f8327d9 +# Source-Hash: b64d07557dec1714 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End run / cancel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Double-hung" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.endRunCancel.59dh2w" -msgstr "経路を終了 / キャンセル" +msgid "editor.toolHint.styleDoubleHung.1lg8pkg" +msgstr "スタイル: 上げ下げ(両側)" -# Source-Hash: 938aacb119b29dc1 +# Source-Hash: 55ef8761a537637f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Exit" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: French" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.exit.engmg5" -msgstr "終了" +msgid "editor.toolHint.styleFrench.1ue3j64" +msgstr "スタイル: フレンチ" -# Source-Hash: 7cb4e0688cabcb00 +# Source-Hash: bc8a751d87536dc3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Exit drawing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Glass" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.exitDrawing.9noxyb" -msgstr "描画を終了" +msgid "editor.toolHint.styleGlass.qudnb4" +msgstr "スタイル: ガラス" -# Source-Hash: 47025a103c456125 +# Source-Hash: 40c1eb0bc83e207d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish and continue" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Grid" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.finishAndContinue.1gpfsks" -msgstr "完了して続ける" +msgid "editor.toolHint.styleGrid.1vuq4po" +msgstr "スタイル: 格子" -# Source-Hash: 000918429b74128f +# Source-Hash: f516886bab2e7f10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish ceiling" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Half-louvered" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.finishCeiling.1c1lfel" -msgstr "天井を完了" +msgid "editor.toolHint.styleHalfLouvered.13b1few" +msgstr "スタイル: 半ルーバー" -# Source-Hash: 51a80a0dba5a6f30 +# Source-Hash: 64e4389a695371a2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish grid axis" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Horizontal bands" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.finishGridAxis.1wvrfhr" -msgstr "通り芯を完了" +msgid "editor.toolHint.styleHorizontalBands.12ethxk" +msgstr "スタイル: 横帯" -# Source-Hash: 87c7b98fc2e010e1 +# Source-Hash: ff6d226a425b00c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish measurement" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Modern" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.finishMeasurement.1e4gv16" -msgstr "計測を完了" +msgid "editor.toolHint.styleModern.1fh8hhn" +msgstr "スタイル: モダン" -# Source-Hash: 5e1a0af7dc506826 +# Source-Hash: c6d17ba078ff47e7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish multi-point witnesses" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Panel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.finishMultiPointWitnesses.8wzskz" -msgstr "複数点の参照を完了" +msgid "editor.toolHint.stylePanel.922jze" +msgstr "スタイル: パネル" -# Source-Hash: 30fc0862501ba2e8 +# Source-Hash: 5e6baad0d2ce3a62 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish slab" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Paneled glass" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.finishSlab.xmnm8e" -msgstr "スラブを完了" +msgid "editor.toolHint.stylePaneledGlass.17a17en" +msgstr "スタイル: パネルガラス" -# Source-Hash: 66ed7c7598d3aa29 +# Source-Hash: 6314388e6832c252 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip side" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Shaker" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.flipSide.172xku9" -msgstr "向きを反転" +msgid "editor.toolHint.styleShaker.49z17k" +msgstr "スタイル: シェーカー" -# Source-Hash: f5717f6a0905ffab +# Source-Hash: a0f8e524f3ca121f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follow: trace a lineset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Single" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.followTraceALineset.mgquwe" -msgstr "追従: 冷媒配管に沿って配管" +msgid "editor.toolHint.styleSingle.6f3cm0" +msgstr "スタイル: 単体" -# Source-Hash: ed7f3d8417a3e074 +# Source-Hash: 368279df3a472c86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Force place" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Six-panel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.forcePlace.1hq1nr" -msgstr "強制配置" +msgid "editor.toolHint.styleSixPanel.u49laj" +msgstr "スタイル: 6パネル" -# Source-Hash: cc0c14065951444d +# Source-Hash: 8f3c2571d8168fee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Free placement" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Sliding" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.freePlacement.1nztdac" -msgstr "自由配置" +msgid "editor.toolHint.styleSliding.q81s0i" +msgstr "スタイル: 引き違い" -# Source-Hash: f098a27096a9c1ea +# Source-Hash: aa9d9eb137ca38d4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Go vertical ↕, click to place" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Tall grid" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.goVerticalClickToPlace.dg8g6m" -msgstr "垂直に切り替え ↕、クリックで配置" +msgid "editor.toolHint.styleTallGrid.1eotg3x" +msgstr "スタイル: 縦長格子" -# Source-Hash: fd47f1820d8799c8 +# Source-Hash: bc164648722b63e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Highlight outlet" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Transom" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.highlightOutlet.65hoq8" -msgstr "排水口を強調" +msgid "editor.toolHint.styleTransom.kb9bh6" +msgstr "スタイル: 欄間" -# Source-Hash: eb90058d0f856f67 +# Source-Hash: 9a218f0c9ceb4697 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Join as a corner window" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Triple-hung" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.joinAsACornerWindow.jvdp4j" -msgstr "コーナー窓として結合" +msgid "editor.toolHint.styleTripleHung.pxnqi3" +msgstr "スタイル: 3段上げ下げ" -# Source-Hash: 225b3161f2e59757 +# Source-Hash: 9f6df1344bd3d694 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Alt + drag" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Wide grid" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.altDrag.ai3wn9" -msgstr "Alt + ドラッグ" +msgid "editor.toolHint.styleWideGrid.12n27et" +msgstr "スタイル: 横長格子" -# Source-Hash: dd66f883b173fc72 +# Source-Hash: 711d4050c0cb95d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Backspace" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Switch rotation axis (Y → X → Z)" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.backspace.qy6qx8" -msgstr "Backspace" +msgid "editor.toolHint.switchRotationAxisYXZ.15lohm6" +msgstr "回転軸を切り替え(Y → X → Z)" -# Source-Hash: a18387bc0be54c32 +# Source-Hash: d650c71e042c2598 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The walls meet at too sharp or too flat an angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.click.m8sun" -msgstr "クリック" +msgid "editor.toolHint.theWallsMeetAtTooSharp.kh3wi3" +msgstr "壁の交わる角度が鋭すぎるか浅すぎます" -# Source-Hash: db9e60c1d30b8499 +# Source-Hash: ab206ac56e65f190 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click again" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The window waiting there is taller than this wall" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.clickAgain.190ws9j" -msgstr "もう一度クリック" +msgid "editor.toolHint.theWindowWaitingThereIsTaller.1tqwez4" +msgstr "そこにある窓はこの壁より高いです" -# Source-Hash: f400330b9c9c12e8 +# Source-Hash: 9c1f47138ed5c7ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Command" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Three or more walls meet here" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.command.1j2mkia" -msgstr "Command" +msgid "editor.toolHint.threeOrMoreWallsMeetHere.rgifif" +msgstr "ここで3枚以上の壁が交わります" -# Source-Hash: 976c63285a510b09 +# Source-Hash: c3ca56fa28e15f07 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Control" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trace ceiling outline" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.control.10fbl8e" -msgstr "Ctrl" +msgid "editor.toolHint.traceCeilingOutline.1b639wv" +msgstr "天井の輪郭をなぞる" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: bdf71499d30a29de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trace slab outline" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.delete.oay2cq" -msgstr "削除" +msgid "editor.toolHint.traceSlabOutline.z0j2lc" +msgstr "スラブの輪郭をなぞる" -# Source-Hash: 88888c9d2719fa92 +# Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double click" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.doubleClick.vlma6o" -msgstr "ダブルクリック" +msgid "editor.toolHint.type.1m2zofh" +msgstr "種類" -# Source-Hash: dfb85b2addb7b9fa +# Source-Hash: b54eaaff3349dcb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Awning" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.drag.8pwtpf" -msgstr "ドラッグ" +msgid "editor.toolHint.typeAwning.1cj59al" +msgstr "種類: 突き出し" -# Source-Hash: ed9140d42148c99b +# Source-Hash: f399572a27417c66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Enter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Barn" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.enter.1ctpui5" -msgstr "Enter" +msgid "editor.toolHint.typeBarn.sbnygq" +msgstr "種類: 納屋" -# Source-Hash: 9195fa8b9c8ebdfb +# Source-Hash: a1df9782200b5f1e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Bay" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.hover.6xw79p" -msgstr "ホバー" +msgid "editor.toolHint.typeBay.1200hc1" +msgstr "種類: 出窓" -# Source-Hash: 2d78441b741bc562 +# Source-Hash: ff069a390e8e3f66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a duct end" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Bow" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.hoverADuctEnd.19axr3b" -msgstr "ダクトの端にホバー" +msgid "editor.toolHint.typeBow.14s2t9p" +msgstr "種類: 弓形出窓" -# Source-Hash: 6083405086f61c76 +# Source-Hash: bdac5f3f2ea70fff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a pipe end" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Cabinet" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.hoverAPipeEnd.1jbum5f" -msgstr "配管の端にホバー" +msgid "editor.toolHint.typeCabinet.1r68je5" +msgstr "種類: キャビネット" -# Source-Hash: a5a337eb76fdb066 +# Source-Hash: e0754fc03997cbf9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover gutter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Casement" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.hoverGutter.1dwcsno" -msgstr "雨樋にホバー" +msgid "editor.toolHint.typeCasement.176uo9j" +msgstr "種類: 開き" -# Source-Hash: a58533594411e088 +# Source-Hash: 47d873446d6e173b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left click" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Double" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.leftClick.s4gwfc" -msgstr "左クリック" +msgid "editor.toolHint.typeDouble.af7w4i" +msgstr "種類: 両開き" -# Source-Hash: bc4ab608ec3d3b4f +# Source-Hash: 5942e484513aaab5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Middle click" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Double Hung" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.middleClick.1jbaan4" -msgstr "中クリック" +msgid "editor.toolHint.typeDoubleHung.t482fu" +msgstr "種類: 上げ下げ(両側)" -# Source-Hash: 6791879c651108c7 +# Source-Hash: f9497fbfceefda27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right click" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Fixed" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.rightClick.1ovld0h" -msgstr "右クリック" +msgid "editor.toolHint.typeFixed.v1cjez" +msgstr "種類: はめ殺し" -# Source-Hash: c836b21b42198868 +# Source-Hash: 0dcf07acc9cbf000 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R / Shift+R" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Folding" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.rShiftR.13bnobh" -msgstr "R / Shift+R" +msgid "editor.toolHint.typeFolding.sxxyng" +msgstr "種類: 折れ戸" -# Source-Hash: 9812aa06d8bb7544 +# Source-Hash: bff7331f87f279aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scroll" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: French" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.scroll.ai6wr0" -msgstr "スクロール" +msgid "editor.toolHint.typeFrench.1y57z1b" +msgstr "種類: フレンチ" -# Source-Hash: f2174536230657c8 +# Source-Hash: 9d2c3b82079eb769 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scroll wheel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Hinged" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.scrollWheel.18j0ix7" -msgstr "スクロールホイール" +msgid "editor.toolHint.typeHinged.1xrcfju" +msgstr "種類: 開き戸" -# Source-Hash: 82dd231086d87f3b +# Source-Hash: b8001b90ff522838 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Space" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Island" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.space.1hrh82t" -msgstr "Space" +msgid "editor.toolHint.typeIsland.ufr3ce" +msgstr "種類: アイランド" -# Source-Hash: 9e68aa2f472cad56 +# Source-Hash: 516833c5160d412e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tab" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Louvered" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.key.tab.1xsal0s" -msgstr "Tab" +msgid "editor.toolHint.typeLouvered.oxl1cz" +msgstr "種類: ルーバー" -# Source-Hash: 4b221b73f9496a49 +# Source-Hash: 291272bf848ad6ab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mount: floor / ceiling / wall" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Pocket" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.mountFloorCeilingWall.32dxpv" -msgstr "取付: 床 / 天井 / 壁" +msgid "editor.toolHint.typePocket.hc65x9" +msgstr "種類: 引き込み" -# Source-Hash: 225edfb1e45aed95 +# Source-Hash: 46d0e53d6ae07c72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No room for the matching window on the other wall" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Single Hung" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.noRoomForTheMatchingWindow.1755948" -msgstr "もう一方の壁に対応する窓を置く余地がありません" +msgid "editor.toolHint.typeSingleHung.p53pyl" +msgstr "種類: 上げ下げ(片側)" -# Source-Hash: a7045d6b678bcd13 +# Source-Hash: b11115b50df8faac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No wall meets here" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Sliding" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.noWallMeetsHere.19n99yc" -msgstr "ここで交わる壁はありません" +msgid "editor.toolHint.typeSliding.nwmr3f" +msgstr "種類: 引き戸" -# Source-Hash: a639341dc21fed2c +# Source-Hash: bff0c1694ee0a37e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Number of cuts — scroll or click to change" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical stack ↕, click to place" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.numberOfCutsScrollOrClick.1kqe84b" -msgstr "分割数 — スクロールまたはクリックで変更" +msgid "editor.toolHint.verticalStackClickToPlace.ijcn4q" +msgstr "立て管 ↕、クリックで配置" -# Source-Hash: af01bde3ae4b7e59 +# Source-Hash: bac471ee67af6412 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick witness point" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waste / vent" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.pickWitnessPoint.k3hgh1" -msgstr "参照点を選ぶ" +msgid "editor.toolHint.wasteVent.1hvi3vj" +msgstr "排水 / 通気" -# Source-Hash: ecfd58576b28a9f6 +# Source-Hash: 1c744b7e24fc786e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pipe size down / up" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Window style — click or press L to cycle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.pipeSizeDownUp.wp04og" -msgstr "管径を小さく / 大きく" +msgid "editor.toolHint.windowStyleClickOrPressL.ah7qm9" +msgstr "窓のスタイル — クリックまたは L で切り替え" -# Source-Hash: 7a1eb7b64f06bad0 +# Source-Hash: dd6f0ab314fea26c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place and continue" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Window type — click or press O to cycle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeAndContinue.qfwkrq" -msgstr "配置して続ける" +msgid "editor.toolHint.windowTypeClickOrPressO.wv4x35" +msgstr "窓の種類 — クリックまたは O で切り替え" -# Source-Hash: c6cda39e2e4b5d3a +# Source-Hash: a48c4b2e4d71b08d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place block" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length: {field} m" +#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx #, fuzzy -msgid "editor.toolHint.placeBlock.1aylwrx" -msgstr "ブロックを配置" +msgid "editor.tools.distribution.distributionRunTool.lengthField" +msgstr "長さ:{field} m" -# Source-Hash: 45a743c52a1d72de +# Source-Hash: e53695d6669245c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place box vent on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tab: direction" +#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx #, fuzzy -msgid "editor.toolHint.placeBoxVentOnRoof.kf88e5" -msgstr "屋根にボックス換気口を配置" +msgid "editor.tools.distribution.distributionRunTool.tabDirection" +msgstr "Tab:方向" -# Source-Hash: 75142dd1d557efe2 +# Source-Hash: abb1d8c8bfb41acf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place cabinet" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "type a length" +#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx #, fuzzy -msgid "editor.toolHint.placeCabinet.b0ouyk" -msgstr "キャビネットを配置" +msgid "editor.tools.distribution.distributionRunTool.typeALength" +msgstr "長さを入力" -# Source-Hash: da603a713d4c9909 +# Source-Hash: 9fc7a39bc32f287a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place canopy or set the next run point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plugins" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeCanopyOrSetTheNext.12l7zf8" -msgstr "キャノピーを配置、または次の点を設定" +msgid "editor.views.plugins" +msgstr "プラグイン" -# Source-Hash: 8b3a30c6b7a5612d +# Source-Hash: c54f9bac358893d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place chimney on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "2D" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeChimneyOnRoof.19dbqu" -msgstr "屋根に煙突を配置" +msgid "editor.views.view2d" +msgstr "2D" -# Source-Hash: 710d41e4e2f259fa +# Source-Hash: f78f2fa035f25f85 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place column" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "3D" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeColumn.1w2vq86" -msgstr "柱を配置" +msgid "editor.views.view3d" +msgstr "3D" -# Source-Hash: ee1da4e12a71d9a9 +# Source-Hash: 05b65242d8c48791 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place cupola on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeCupolaOnRoof.ofx3bn" -msgstr "屋根にキューポラを配置" +msgid "editor.views.viewBar.auto" +msgstr "自動" -# Source-Hash: 19c1fe8c46d213a5 +# Source-Hash: 7890c110650ad1e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place dimension line when needed" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Browse plugins" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeDimensionLineWhenNeeded.bjw2cj" -msgstr "必要に応じて寸法線を配置" +msgid "editor.views.viewBar.browsePlugins" +msgstr "プラグインを探す" -# Source-Hash: 58f3e7efb6ea120b +# Source-Hash: 3b11e7af681a9dcd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place door on wall" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close {label}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeDoorOnWall.1jwadf" -msgstr "壁にドアを配置" +msgid "editor.views.viewBar.closeLabel" +msgstr "{label}を閉じる" -# Source-Hash: de04e9d03d937c97 +# Source-Hash: 3f00e92517e3f4a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place dormer on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close split (\\)" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeDormerOnRoof.1w518a6" -msgstr "屋根にドーマーを配置" +msgid "editor.views.viewBar.closeSplit" +msgstr "分割を閉じる (\\)" -# Source-Hash: c581645f2ee447c2 +# Source-Hash: 94cc8e9f1ee16edb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place elevator" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeElevator.1f65zva" -msgstr "エレベーターを配置" +msgid "editor.views.viewBar.ground" +msgstr "地面" -# Source-Hash: 096b8d6482717358 +# Source-Hash: 0d472502a4d36e86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place eyebrow vent on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{standing, select, partly {Partly below grade · ground solid} below {Below grade · ground solid} other {Ground solid}}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeEyebrowVentOnRoof.1h1tqxn" -msgstr "屋根に眉型換気口を配置" +msgid "editor.views.viewBar.groundSolid" +msgstr "{standing, select, partly {一部地盤面下 · 地面ソリッド} below {地盤面下 · 地面ソリッド} other {地面ソリッド}}" -# Source-Hash: e8d42c1c8370773f +# Source-Hash: 1b6798c307ac1b96 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place fitting" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{standing, select, partly {Partly below grade · ground veiled} below {Below grade · ground veiled} other {Ground veiled}}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeFitting.1pmx3vn" -msgstr "継手を配置" +msgid "editor.views.viewBar.groundVeiled" +msgstr "{standing, select, partly {一部地盤面下 · 地面を透過} below {地盤面下 · 地面を透過} other {地面を透過}}" -# Source-Hash: 2340a4b70cb0d9ad +# Source-Hash: ebdc976a98e82626 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place gutter on roof eave" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keep the ground solid" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeGutterOnRoofEave.llwzf9" -msgstr "軒に雨樋を配置" +msgid "editor.views.viewBar.keepTheGroundSolid" +msgstr "地面をソリッドのままにする" -# Source-Hash: 706a8eafb6212833 +# Source-Hash: 5f827686a006d88c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place item" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "More views" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeItem.teynf" -msgstr "アイテムを配置" +msgid "editor.views.viewBar.moreViews" +msgstr "その他のビュー" -# Source-Hash: 1815c482e249932e +# Source-Hash: f175bbcf457ab73c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place it (locked to 45°)" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pane {pane} views" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeItLockedTo45.16e4csk" -msgstr "配置(45°に固定)" +msgid "editor.views.viewBar.paneViews" +msgstr "ペイン {pane} のビュー" -# Source-Hash: 4a14340657532838 +# Source-Hash: 33c20cc33dce9a9b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place measurement point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pin {label}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeMeasurementPoint.bsatli" -msgstr "計測点を配置" +msgid "editor.views.viewBar.pinLabel" +msgstr "{label}をピン留め" -# Source-Hash: b3be684ac62fbf53 +# Source-Hash: 3f7231b1eb2f93f3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pin to the view bar" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placement.13lcvts" -msgstr "配置" +msgid "editor.views.viewBar.pinToTheViewBar" +msgstr "ビューバーにピン留め" -# Source-Hash: 2bb2ce6276c69b1e +# Source-Hash: ef3e765e692faf4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement: Auto" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placementAuto.1caa52d" -msgstr "配置: 自動" +msgid "editor.views.viewBar.solid" +msgstr "ソリッド" -# Source-Hash: ed78ac5354a1dcd8 +# Source-Hash: 98f22f3f89f17686 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement: Ground" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Split (\\)" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placementGround.1ruz145" -msgstr "配置: 地面" +msgid "editor.views.viewBar.split" +msgstr "分割 (\\)" -# Source-Hash: a066a2c9d5e65a1a +# Source-Hash: e4cd64b1680ac0d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement: Roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Split" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placementRoof.renkw8" -msgstr "配置: 屋根" +msgid "editor.views.viewBar.split2" +msgstr "分割" -# Source-Hash: 8f74dbe5064c4c66 +# Source-Hash: 15b0adc705923a27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement surface - click or press P to cycle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap panes" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placementSurfaceClickOrPressP.w56h19" -msgstr "配置面 - クリックまたは P で切り替え" +msgid "editor.views.viewBar.swapPanes" +msgstr "ペインを入れ替え" -# Source-Hash: fe119955c925feaf +# Source-Hash: 9781bcdb7a8549e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement type" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unpin from the view bar" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placementType.1mdpl60" -msgstr "配置の種類" +msgid "editor.views.viewBar.unpinFromTheViewBar" +msgstr "ビューバーからピン留めを外す" -# Source-Hash: 33043a35500168f5 +# Source-Hash: f667358dec4abdea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement type — click or press I to toggle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unpin {label}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placementTypeClickOrPressI.10cgxh2" -msgstr "配置の種類 — クリックまたは I で切り替え" +msgid "editor.views.viewBar.unpinLabel" +msgstr "{label}のピン留めを外す" -# Source-Hash: 9945f412e6a9a446 +# Source-Hash: e96581f0bbf9fa91 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place on a fence" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Veil the ground over a level below grade" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeOnAFence.1dptstr" -msgstr "フェンスに配置" +msgid "editor.views.viewBar.veilTheGroundOverALevel" +msgstr "地盤面下の階層の上で地面を透過" -# Source-Hash: 6708118775a7da7f +# Source-Hash: fb82f09f8ed3059e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place register" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Views" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "editor.toolHint.placeRegister.1uebycd" -msgstr "吹出口を配置" +msgid "editor.views.viewBar.views" +msgstr "ビュー" -# Source-Hash: ebd2731f5c79306e +# Source-Hash: 57c1428fe2d28745 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place ridge vent on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "List the layers from the outside in, around one framing core. The type is saved with the project and applied to this wall; other walls keep their layers." +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.toolHint.placeRidgeVentOnRoof.2tpd8r" -msgstr "屋根に棟換気を配置" +msgid "editor.wallTypeEditorDialog.listTheLayersAppliedToThisWall" +msgstr "1つの躯体を中心に、外側から内側へ層を並べます。種類はプロジェクトに保存され、この壁に適用されます。他の壁は現在の層のままです。" -# Source-Hash: 9b3c66a867c23326 +# Source-Hash: 9e9715d52410c86f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place shelf" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.toolHint.placeShelf.y4l3iw" -msgstr "棚を配置" +msgid "editor.wallTypeMenu.custom" +msgstr "カスタム" -# Source-Hash: f11cf5c1c9fe862d +# Source-Hash: 0e2a2a8b90ba9c7e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place skylight on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall types: new, edit or duplicate {label}" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.toolHint.placeSkylightOnRoof.e215pe" -msgstr "屋根に天窓を配置" +msgid "editor.wallTypeMenu.wallTypesOf" +msgstr "壁の種類:{label} の新規作成・編集・複製" -# Source-Hash: e989a58d6709cc16 +# Source-Hash: fdece5c2158dfe88 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place solar panel array on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "You can retry the scene or return home without reloading the whole app shell." +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.toolHint.placeSolarPanelArrayOnRoof.kk11fn" -msgstr "屋根に太陽光パネルを配置" +msgid "editor.youCanRetryTheSceneOr" +msgstr "アプリ全体を再読み込みせずに、シーンを再試行するかホームに戻れます。" -# Source-Hash: b67f7036d5180cf5 +# Source-Hash: bafa390e07160f3c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place spawn point" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A framing beam drawn end to end: a porch header, a deck beam, a girder." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeSpawnPoint.205o25" -msgstr "スポーン地点を配置" +msgid "node.beam.description" +msgstr "端から端まで描く構造用の梁:ポーチの桁、デッキの梁、大梁など。" -# Source-Hash: 6c7f32a17e5636c3 +# Source-Hash: e14858b33b6e2623 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place stairs" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeStairs.zwxxu2" -msgstr "階段を配置" +msgid "node.beam.label" +msgstr "梁" -# Source-Hash: 641c0d3debd798a8 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place trap" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.placeTrap.1gxemn3" -msgstr "トラップを配置" +msgid "node.beam.panel.actions" +msgstr "操作" -# Source-Hash: 6f0a6f6c4b7588a0 +# Source-Hash: 59f845b250e0df6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place turbine vent on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add posts" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.placeTurbineVentOnRoof.1iqeluf" -msgstr "屋根にタービン換気扇を配置" +msgid "node.beam.panel.addPosts" +msgstr "支柱を追加" -# Source-Hash: e65cf5edb4f51ed5 +# Source-Hash: e14858b33b6e2623 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place unit" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.placeUnit.8zkx4q" -msgstr "ユニットを配置" +msgid "node.beam.panel.beam" +msgstr "梁" -# Source-Hash: 86ce1c730154f68b +# Source-Hash: 26e977da636cc882 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place window on wall" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam {size}" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.placeWindowOnWall.1k3qnfb" -msgstr "壁に窓を配置" +msgid "node.beam.panel.beamSize" +msgstr "梁 {size}" -# Source-Hash: 2b612180a7617901 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place without the corner snap" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.placeWithoutTheCornerSnap.1nifqew" -msgstr "角のスナップなしで配置" +msgid "node.beam.panel.delete" +msgstr "削除" -# Source-Hash: 0dc6d121791696f7 +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove last point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.removeLastPoint.2dmdcx" -msgstr "最後の点を削除" +msgid "node.beam.panel.depth" +msgstr "せい" -# Source-Hash: 8b74b1d962be10fc +# Source-Hash: 73694f3f45cf2ee1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove last witness" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dropped" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.removeLastWitness.1b6vvzw" -msgstr "最後の参照を削除" +msgid "node.beam.panel.dropped" +msgstr "下がり" -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: eaaa20f3b603140f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flush" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.rotate.1thqa0a" -msgstr "回転" +msgid "node.beam.panel.flush" +msgstr "面一" -# Source-Hash: 8a665ecaeffa9308 +# Source-Hash: 0ee3edea19fd153e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ±45°" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow the ceiling plane" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.rotate45.9zq68u" -msgstr "±45°回転" +msgid "node.beam.panel.followTheCeilingPlane" +msgstr "天井面に合わせる" -# Source-Hash: be2240289aa74df5 +# Source-Hash: 193b75ac869c251d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ±45° (floor / ceiling)" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{length} long; its underside {underside} over the floor, the ceiling plane {plane}." +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.rotate45FloorCeiling.m9t57d" -msgstr "±45°回転(床 / 天井)" +msgid "node.beam.panel.lengthLongItsUnderside" +msgstr "長さ {length}。下端は床から {underside}、天井面は {plane}。" -# Source-Hash: d5fb78b07c0f8138 +# Source-Hash: 964b86ae1474ff98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ghost ±15°" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Material" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.rotateGhost15.rsa52c" -msgstr "プレビューを±15°回転" +msgid "node.beam.panel.material" +msgstr "材料" -# Source-Hash: 912d340cd16e27fa +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate or flip the run side" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.rotateOrFlipTheRunSide.t5ior7" -msgstr "配置側を回転または反転" +msgid "node.beam.panel.move" +msgstr "移動" -# Source-Hash: ad1dc0b5536cceef +# Source-Hash: fa876c632c284d81 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate roof direction 90°" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "1 ply" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.rotateRoofDirection90.tvbji2" -msgstr "屋根の向きを90°回転" +msgid "node.beam.panel.n1Ply" +msgstr "1 枚" -# Source-Hash: fa24651e9e5f595a +# Source-Hash: b3be684ac62fbf53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate spawn point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.rotateSpawnPoint.1opcuu7" -msgstr "スポーン地点を回転" +msgid "node.beam.panel.placement" +msgstr "配置" -# Source-Hash: 2d693d87fe9b59e6 +# Source-Hash: 6ac7987d650b9742 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round / rectangular / oval" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{plies} plies" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.roundRectangularOval.e4nh6x" -msgstr "円形 / 矩形 / 楕円" +msgid "node.beam.panel.pliesPlies" +msgstr "{plies} 枚" -# Source-Hash: f7d2c9cdcc637c97 +# Source-Hash: 60bb3338e0ad558c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set fence start / end" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Size" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.setFenceStartEnd.1phbwsq" -msgstr "フェンスの始点 / 終点を設定" +msgid "node.beam.panel.size" +msgstr "サイズ" -# Source-Hash: c93ae898b4d59f6f +# Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set one corner, then the opposite" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.setOneCornerThenTheOpposite.8tsl49" -msgstr "1つの角、次に対角を設定" +msgid "node.beam.panel.top" +msgstr "天端" -# Source-Hash: 4f55171f10c6ceeb +# Source-Hash: 5b4c960036b3d05b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set roof footprint" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top elevation" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.setRoofFootprint.p50n0o" -msgstr "屋根の外形を設定" +msgid "node.beam.panel.topElevation" +msgstr "天端高さ" -# Source-Hash: 0243859b1d64c21e +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set wall start / end" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "editor.toolHint.setWallStartEnd.1r8ubcx" -msgstr "壁の始点 / 終点を設定" +msgid "node.beam.panel.width" +msgstr "幅" -# Source-Hash: c2806cce9612fa50 +# Source-Hash: a273dacdf51b26f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slope / level" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A topology-backed solid edited directly in the canvas." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.slopeLevel.ftqp67" -msgstr "勾配 / 水平" +msgid "node.block.description" +msgstr "キャンバス上で直接編集できる、トポロジーを持つソリッド。" -# Source-Hash: 06c0ec40606db679 +# Source-Hash: 279f456ebb2f5da0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snap onto the run" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Block" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.snapOntoTheRun.86yhmp" -msgstr "経路にスナップ" +msgid "node.block.label" +msgstr "ブロック" -# Source-Hash: e214cccbac9c4fd2 +# Source-Hash: b2a371b4041b5e38 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Split at the marks" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Small louvered exhaust vent that sits on a roof slope." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.splitAtTheMarks.x5tpdd" -msgstr "マークで分割" +msgid "node.boxVent.description" +msgstr "屋根勾配に載る小型のルーバー付き排気口。" -# Source-Hash: 94455c35bfeac6b4 +# Source-Hash: f736ca24e84825c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start grid axis" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box Vent" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.startGridAxis.k92yza" -msgstr "通り芯を開始" +msgid "node.boxVent.label" +msgstr "ボックス換気口" -# Source-Hash: 2edb4c29bbe7c513 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start lineset" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.startLineset.23q8dh" -msgstr "冷媒配管を開始" +msgid "node.boxVent.panel.actions" +msgstr "操作" -# Source-Hash: 9e50f1b30e325208 +# Source-Hash: c0e9837e67038e92 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start liquid line" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base Flange" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.startLiquidLine.1rlxsgd" -msgstr "液管を開始" +msgid "node.boxVent.panel.baseFlange" +msgstr "ベースフランジ" -# Source-Hash: 877ddcb778c211cc +# Source-Hash: fa9118f6f4f020d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start run" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base Height" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.startRun.r6fc5u" -msgstr "経路を開始" +msgid "node.boxVent.panel.baseHeight" +msgstr "ベースの高さ" -# Source-Hash: 8a62bee64174bbc0 +# Source-Hash: 0869f5a92dabb4e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start segment" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base Inset" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.startSegment.rolym6" -msgstr "セグメントを開始" +msgid "node.boxVent.panel.baseInset" +msgstr "ベースの内寄せ" + +# Source-Hash: e9a89a5e4ac8cd61 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box" +#: packages/nodes/src/box-vent/panel.tsx +#, fuzzy +msgid "node.boxVent.panel.box" +msgstr "ボックス" -# Source-Hash: 6cc5dc51a8e66779 +# Source-Hash: f736ca24e84825c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Step back or cancel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box Vent" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.stepBackOrCancel.zbfdkn" -msgstr "1つ戻る、またはキャンセル" +msgid "node.boxVent.panel.boxVent" +msgstr "ボックス換気口" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: d52b53241789ee63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.style.nf3vcm" -msgstr "スタイル" +msgid "node.boxVent.panel.cap" +msgstr "キャップ" -# Source-Hash: 81f595b1c47c0080 +# Source-Hash: 0ce3b53766b550e7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Barn" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap Height" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleBarn.k9n1x" -msgstr "スタイル: 納屋" +msgid "node.boxVent.panel.capHeight" +msgstr "キャップの高さ" -# Source-Hash: 3a82c718fe215273 +# Source-Hash: 89eba9f077fba348 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Casement" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner Bevel" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleCasement.ziklec" -msgstr "スタイル: 開き" +msgid "node.boxVent.panel.cornerBevel" +msgstr "角の面取り" -# Source-Hash: 072e3331d1d105c0 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Craftsman" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleCraftsman.52e6a9" -msgstr "スタイル: クラフツマン" +msgid "node.boxVent.panel.delete" +msgstr "削除" -# Source-Hash: b64d07557dec1714 +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Double-hung" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleDoubleHung.1lg8pkg" -msgstr "スタイル: 上げ下げ(両側)" +msgid "node.boxVent.panel.depth" +msgstr "奥行き" -# Source-Hash: 55ef8761a537637f +# Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: French" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleFrench.1ue3j64" -msgstr "スタイル: フレンチ" +msgid "node.boxVent.panel.dimensions" +msgstr "寸法" -# Source-Hash: bc8a751d87536dc3 +# Source-Hash: de47e23eb81efe02 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Glass" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dome" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleGlass.qudnb4" -msgstr "スタイル: ガラス" +msgid "node.boxVent.panel.dome" +msgstr "ドーム" -# Source-Hash: 40c1eb0bc83e207d +# Source-Hash: 1c5c81aa21193d07 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Grid" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dome Curvature" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleGrid.1vuq4po" -msgstr "スタイル: 格子" +msgid "node.boxVent.panel.domeCurvature" +msgstr "ドームの曲率" -# Source-Hash: f516886bab2e7f10 +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Half-louvered" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleHalfLouvered.13b1few" -msgstr "スタイル: 半ルーバー" +msgid "node.boxVent.panel.duplicate" +msgstr "複製" -# Source-Hash: 64e4389a695371a2 +# Source-Hash: 8cac057f7ae6804d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Horizontal bands" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap Height" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleHorizontalBands.12ethxk" -msgstr "スタイル: 横帯" +msgid "node.boxVent.panel.gapHeight" +msgstr "隙間の高さ" -# Source-Hash: ff6d226a425b00c0 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Modern" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleModern.1fh8hhn" -msgstr "スタイル: モダン" +msgid "node.boxVent.panel.height" +msgstr "高さ" -# Source-Hash: c6d17ba078ff47e7 +# Source-Hash: 8a9c2ea0783a0e53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Panel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hood Overhang" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.stylePanel.922jze" -msgstr "スタイル: パネル" +msgid "node.boxVent.panel.hoodOverhang" +msgstr "フードの張り出し" -# Source-Hash: 5e6baad0d2ce3a62 +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Paneled glass" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.stylePaneledGlass.17a17en" -msgstr "スタイル: パネルガラス" +msgid "node.boxVent.panel.move" +msgstr "移動" -# Source-Hash: 6314388e6832c252 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Shaker" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleShaker.49z17k" -msgstr "スタイル: シェーカー" +msgid "node.boxVent.panel.position" +msgstr "位置" -# Source-Hash: a0f8e524f3ca121f +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Single" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleSingle.6f3cm0" -msgstr "スタイル: 単体" +msgid "node.boxVent.panel.rotation" +msgstr "回転" -# Source-Hash: 368279df3a472c86 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Six-panel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleSixPanel.u49laj" -msgstr "スタイル: 6パネル" +msgid "node.boxVent.panel.style" +msgstr "スタイル" -# Source-Hash: 8f3c2571d8168fee +# Source-Hash: 71d82d47e11d2564 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Sliding" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Taper" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleSliding.q81s0i" -msgstr "スタイル: 引き違い" +msgid "node.boxVent.panel.topTaper" +msgstr "上部のテーパー" -# Source-Hash: aa9d9eb137ca38d4 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Tall grid" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "editor.toolHint.styleTallGrid.1eotg3x" -msgstr "スタイル: 縦長格子" +msgid "node.boxVent.panel.width" +msgstr "幅" -# Source-Hash: bc164648722b63e5 +# Source-Hash: f49d8836ae037dde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Transom" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A building container holding one or more levels." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleTransom.kb9bh6" -msgstr "スタイル: 欄間" +msgid "node.building.description" +msgstr "1つ以上の階層を含む建物コンテナ。" -# Source-Hash: 9a218f0c9ceb4697 +# Source-Hash: d42f7d29e3fc4af7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Triple-hung" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Building" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleTripleHung.pxnqi3" -msgstr "スタイル: 3段上げ下げ" +msgid "node.building.label" +msgstr "建物" -# Source-Hash: 9f6df1344bd3d694 +# Source-Hash: 5a8274cbe3034558 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Wide grid" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Baskets" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.styleWideGrid.12n27et" -msgstr "スタイル: 横長格子" +msgid "node.cabinet.compartmentCard.baskets" +msgstr "バスケット" -# Source-Hash: 711d4050c0cb95d7 +# Source-Hash: b3a163b453896bef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Switch rotation axis (Y → X → Z)" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.switchRotationAxisYXZ.15lohm6" -msgstr "回転軸を切り替え(Y → X → Z)" +msgid "node.cabinet.compartmentCard.bottom" +msgstr "下" -# Source-Hash: d650c71e042c2598 +# Source-Hash: 486501f027037732 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The walls meet at too sharp or too flat an angle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Freezer" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.theWallsMeetAtTooSharp.kh3wi3" -msgstr "壁の交わる角度が鋭すぎるか浅すぎます" +msgid "node.cabinet.compartmentCard.bottomFreezer" +msgstr "下段冷凍" -# Source-Hash: ab206ac56e65f190 +# Source-Hash: 375acc0016b3aa14 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The window waiting there is taller than this wall" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bowls" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.theWindowWaitingThereIsTaller.1tqwez4" -msgstr "そこにある窓はこの壁より高いです" +msgid "node.cabinet.compartmentCard.bowls" +msgstr "シンク槽" -# Source-Hash: 9c1f47138ed5c7ee +# Source-Hash: 8449b59bf054c27d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Three or more walls meet here" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Burners on" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.threeOrMoreWallsMeetHere.rgifif" -msgstr "ここで3枚以上の壁が交わります" +msgid "node.cabinet.compartmentCard.burnersOn" +msgstr "点火" -# Source-Hash: c3ca56fa28e15f07 +# Source-Hash: 95169058fec6db14 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trace ceiling outline" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Chimney" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.traceCeilingOutline.1b639wv" -msgstr "天井の輪郭をなぞる" +msgid "node.cabinet.compartmentCard.chimney" +msgstr "煙突" -# Source-Hash: bdf71499d30a29de +# Source-Hash: a6b76187db231ae7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trace slab outline" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Decrease {label}" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.traceSlabOutline.z0j2lc" -msgstr "スラブの輪郭をなぞる" +msgid "node.cabinet.compartmentCard.decrease" +msgstr "{label}を減らす" -# Source-Hash: c44f7ab8bbd24858 +# Source-Hash: 787e10f5db16904e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.type.1m2zofh" -msgstr "種類" +msgid "node.cabinet.compartmentCard.door" +msgstr "ドア" -# Source-Hash: b54eaaff3349dcb1 +# Source-Hash: 3cd71355956a1821 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Awning" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeAwning.1cj59al" -msgstr "種類: 突き出し" +msgid "node.cabinet.compartmentCard.double" +msgstr "両開き" -# Source-Hash: f399572a27417c66 +# Source-Hash: 63fe49d73892aac8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Barn" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawer" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeBarn.sbnygq" -msgstr "種類: 納屋" +msgid "node.cabinet.compartmentCard.drawer" +msgstr "引き出し" -# Source-Hash: a1df9782200b5f1e +# Source-Hash: f98242a5dacd33f3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Bay" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawers" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeBay.1200hc1" -msgstr "種類: 出窓" +msgid "node.cabinet.compartmentCard.drawers" +msgstr "引き出し" -# Source-Hash: ff069a390e8e3f66 +# Source-Hash: 3af5347c94ae6443 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Bow" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip hinge" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeBow.14s2t9p" -msgstr "種類: 弓形出窓" +msgid "node.cabinet.compartmentCard.flipHinge" +msgstr "丁番を反転" -# Source-Hash: bdac5f3f2ea70fff +# Source-Hash: c930f681e61c029c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Cabinet" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip the door hinge to the opposite side" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeCabinet.1r68je5" -msgstr "種類: キャビネット" +msgid "node.cabinet.compartmentCard.flipTheDoorHingeToThe" +msgstr "扉の丁番を反対側にする" -# Source-Hash: e0754fc03997cbf9 +# Source-Hash: 85724031c91952a3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Casement" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fridge" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeCasement.176uo9j" -msgstr "種類: 開き" +msgid "node.cabinet.compartmentCard.fridge" +msgstr "冷蔵庫" -# Source-Hash: 47d873446d6e173b +# Source-Hash: e67f11024d683ea9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Double" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gas" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeDouble.af7w4i" -msgstr "種類: 両開き" +msgid "node.cabinet.compartmentCard.gas" +msgstr "ガス" -# Source-Hash: 5942e484513aaab5 +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Double Hung" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeDoubleHung.t482fu" -msgstr "種類: 上げ下げ(両側)" +msgid "node.cabinet.compartmentCard.glass" +msgstr "ガラス" -# Source-Hash: f9497fbfceefda27 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Fixed" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeFixed.v1cjez" -msgstr "種類: はめ殺し" +msgid "node.cabinet.compartmentCard.height" +msgstr "高さ" -# Source-Hash: 0dcf07acc9cbf000 +# Source-Hash: 6f434b84c8b59b8c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Folding" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hob" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeFolding.sxxyng" -msgstr "種類: 折れ戸" +msgid "node.cabinet.compartmentCard.hob" +msgstr "コンロ" + +# Source-Hash: d52570d41b4df776 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Increase {label}" +#: packages/nodes/src/cabinet/compartment-card.tsx +#, fuzzy +msgid "node.cabinet.compartmentCard.increase" +msgstr "{label}を増やす" -# Source-Hash: bff7331f87f279aa +# Source-Hash: d298f259163e868e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: French" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Induction" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeFrench.1y57z1b" -msgstr "種類: フレンチ" +msgid "node.cabinet.compartmentCard.induction" +msgstr "IH" -# Source-Hash: 9d2c3b82079eb769 +# Source-Hash: 54800340a0eeab23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Hinged" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layout" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeHinged.1xrcfju" -msgstr "種類: 開き戸" +msgid "node.cabinet.compartmentCard.layout" +msgstr "レイアウト" -# Source-Hash: b8001b90ff522838 +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Island" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeIsland.ufr3ce" -msgstr "種類: アイランド" +msgid "node.cabinet.compartmentCard.left" +msgstr "左" -# Source-Hash: 516833c5160d412e +# Source-Hash: 12ade82be3830a0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Louvered" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Micro" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeLouvered.oxl1cz" -msgstr "種類: ルーバー" +msgid "node.cabinet.compartmentCard.micro" +msgstr "電子レンジ" -# Source-Hash: 291272bf848ad6ab +# Source-Hash: a06a50e63f0c240e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Pocket" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move down" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typePocket.hc65x9" -msgstr "種類: 引き込み" +msgid "node.cabinet.compartmentCard.moveDown" +msgstr "下へ移動" -# Source-Hash: 46d0e53d6ae07c72 +# Source-Hash: d49ea60a2312df2f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Single Hung" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move up" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeSingleHung.p53pyl" -msgstr "種類: 上げ下げ(片側)" +msgid "node.cabinet.compartmentCard.moveUp" +msgstr "上へ移動" -# Source-Hash: b11115b50df8faac +# Source-Hash: 596023c8b9a8f2e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Sliding" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Oven" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.typeSliding.nwmr3f" -msgstr "種類: 引き戸" +msgid "node.cabinet.compartmentCard.oven" +msgstr "オーブン" -# Source-Hash: bff0c1694ee0a37e +# Source-Hash: 83b20797fb0a01a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical stack ↕, click to place" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pullout" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.verticalStackClickToPlace.ijcn4q" -msgstr "立て管 ↕、クリックで配置" +msgid "node.cabinet.compartmentCard.pullout" +msgstr "引き出し式" -# Source-Hash: bac471ee67af6412 +# Source-Hash: 43c251f465b647ce # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waste / vent" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rack" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.wasteVent.1hvi3vj" -msgstr "排水 / 通気" +msgid "node.cabinet.compartmentCard.rack" +msgstr "ラック" -# Source-Hash: 1c744b7e24fc786e +# Source-Hash: 3c2b3026d37cbcc2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Window style — click or press L to cycle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove compartment" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.windowStyleClickOrPressL.ah7qm9" -msgstr "窓のスタイル — クリックまたは L で切り替え" +msgid "node.cabinet.compartmentCard.removeCompartment" +msgstr "区画を削除" -# Source-Hash: dd6f0ab314fea26c +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Window type — click or press O to cycle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.toolHint.windowTypeClickOrPressO.wv4x35" -msgstr "窓の種類 — クリックまたは O で切り替え" +msgid "node.cabinet.compartmentCard.right" +msgstr "右" +# Source-Hash: d7145f84f8e0e3fe # Review: required -# Source-Hash: a48c4b2e4d71b08d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length: {field} m" -#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shelf" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.tools.distribution.distributionRunTool.lengthField" -msgstr "長さ:{field} m" +msgid "node.cabinet.compartmentCard.shelf" +msgstr "棚" +# Source-Hash: 5fbb88f1f079b6db # Review: required -# Source-Hash: e53695d6669245c7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tab: direction" -#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shelves" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.tools.distribution.distributionRunTool.tabDirection" -msgstr "Tab:方向" +msgid "node.cabinet.compartmentCard.shelves" +msgstr "棚板" +# Source-Hash: 47173085127029f0 # Review: required -# Source-Hash: abb1d8c8bfb41acf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "type a length" -#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shelves inside" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.tools.distribution.distributionRunTool.typeALength" -msgstr "長さを入力" +msgid "node.cabinet.compartmentCard.shelvesInside" +msgstr "内部の棚板" -# Source-Hash: 9fc7a39bc32f287a +# Source-Hash: 62ab2eb3c775da95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Plugins" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.plugins" -msgstr "プラグイン" +msgid "node.cabinet.compartmentCard.single" +msgstr "片開き" -# Source-Hash: c54f9bac358893d8 +# Source-Hash: 522a7535fc93fb4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "2D" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sink" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.view2d" -msgstr "2D" +msgid "node.cabinet.compartmentCard.sink" +msgstr "シンク" -# Source-Hash: f78f2fa035f25f85 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "3D" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.view3d" -msgstr "3D" +msgid "node.cabinet.compartmentCard.style" +msgstr "スタイル" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: 78a454b7ac7a3cd9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.viewBar.auto" -msgstr "自動" +msgid "node.cabinet.compartmentCard.surface" +msgstr "面" -# Source-Hash: 7890c110650ad1e5 +# Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Browse plugins" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.viewBar.browsePlugins" -msgstr "プラグインを探す" +msgid "node.cabinet.compartmentCard.top" +msgstr "上" -# Source-Hash: 3b11e7af681a9dcd -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close {label}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# Source-Hash: eaadfd2d19b27d87 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Freezer" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.viewBar.closeLabel" -msgstr "{label}を閉じる" +msgid "node.cabinet.compartmentCard.topFreezer" +msgstr "上段冷凍" -# Source-Hash: 3f00e92517e3f4a5 +# Source-Hash: 04f3a3462ef5d247 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close split (\\)" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top grate" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.viewBar.closeSplit" -msgstr "分割を閉じる (\\)" +msgid "node.cabinet.compartmentCard.topGrate" +msgstr "上部ごとく" -# Source-Hash: 94cc8e9f1ee16edb +# Source-Hash: 4a616e1d2ca55bd5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tray" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.viewBar.ground" -msgstr "地面" +msgid "node.cabinet.compartmentCard.tray" +msgstr "トレー" -# Source-Hash: 0d472502a4d36e86 +# Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{standing, select, partly {Partly below grade · ground solid} below {Below grade · ground solid} other {Ground solid}}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.viewBar.groundSolid" -msgstr "{standing, select, partly {一部地盤面下 · 地面ソリッド} below {地盤面下 · 地面ソリッド} other {地面ソリッド}}" +msgid "node.cabinet.compartmentCard.type" +msgstr "種類" -# Source-Hash: 1b6798c307ac1b96 +# Source-Hash: 6c4de540d19316ab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{standing, select, partly {Partly below grade · ground veiled} below {Below grade · ground veiled} other {Ground veiled}}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Washer" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.viewBar.groundVeiled" -msgstr "{standing, select, partly {一部地盤面下 · 地面を透過} below {地盤面下 · 地面を透過} other {地面を透過}}" +msgid "node.cabinet.compartmentCard.washer" +msgstr "食洗機" -# Source-Hash: ebdc976a98e82626 +# Source-Hash: 5211a0caf3518125 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Keep the ground solid" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wire" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "editor.views.viewBar.keepTheGroundSolid" -msgstr "地面をソリッドのままにする" +msgid "node.cabinet.compartmentCard.wire" +msgstr "ワイヤー" -# Source-Hash: 5f827686a006d88c +# Source-Hash: 693a0d8896f5cc43 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "More views" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A configurable parametric base cabinet." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.moreViews" -msgstr "その他のビュー" +msgid "node.cabinet.description" +msgstr "設定可能なパラメトリックのベースキャビネット。" -# Source-Hash: f175bbcf457ab73c +# Source-Hash: b0568ea943addd5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pane {pane} views" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom freezer" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.paneViews" -msgstr "ペイン {pane} のビュー" +msgid "node.cabinet.essentialControls.bottomFreezer" +msgstr "下段冷凍" -# Source-Hash: 33c20cc33dce9a9b +# Source-Hash: da78819903ae0863 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pin {label}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cooktop type" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.pinLabel" -msgstr "{label}をピン留め" +msgid "node.cabinet.essentialControls.cooktopType" +msgstr "コンロの種類" -# Source-Hash: 3f7231b1eb2f93f3 +# Source-Hash: c608188f58ed1cfc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pin to the view bar" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door direction" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.pinToTheViewBar" -msgstr "ビューバーにピン留め" +msgid "node.cabinet.essentialControls.doorDirection" +msgstr "扉の開き方向" -# Source-Hash: ef3e765e692faf4c +# Source-Hash: 3cd71355956a1821 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.solid" -msgstr "ソリッド" +msgid "node.cabinet.essentialControls.double" +msgstr "両開き" -# Source-Hash: 98f22f3f89f17686 +# Source-Hash: f7fb8f6393cc4cfc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Split (\\)" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fridge type" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.split" -msgstr "分割 (\\)" +msgid "node.cabinet.essentialControls.fridgeType" +msgstr "冷蔵庫の種類" -# Source-Hash: e4cd64b1680ac0d2 +# Source-Hash: e67f11024d683ea9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Split" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gas" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.split2" -msgstr "分割" +msgid "node.cabinet.essentialControls.gas" +msgstr "ガス" -# Source-Hash: 15b0adc705923a27 +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swap panes" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.swapPanes" -msgstr "ペインを入れ替え" +msgid "node.cabinet.essentialControls.glass" +msgstr "ガラス" -# Source-Hash: 9781bcdb7a8549e2 +# Source-Hash: d298f259163e868e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unpin from the view bar" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Induction" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.unpinFromTheViewBar" -msgstr "ビューバーからピン留めを外す" +msgid "node.cabinet.essentialControls.induction" +msgstr "IH" -# Source-Hash: f667358dec4abdea +# Source-Hash: 76df477d42cec629 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unpin {label}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Item options" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.unpinLabel" -msgstr "{label}のピン留めを外す" +msgid "node.cabinet.essentialControls.itemOptions" +msgstr "アイテムのオプション" -# Source-Hash: e96581f0bbf9fa91 +# Source-Hash: bca1b184af1c0c4b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Veil the ground over a level below grade" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left hinge" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.veilTheGroundOverALevel" -msgstr "地盤面下の階層の上で地面を透過" +msgid "node.cabinet.essentialControls.leftHinge" +msgstr "左丁番" -# Source-Hash: fb82f09f8ed3059e +# Source-Hash: e32da7429c85f1a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Views" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right hinge" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.views.viewBar.views" -msgstr "ビュー" +msgid "node.cabinet.essentialControls.rightHinge" +msgstr "右丁番" -# Source-Hash: fdece5c2158dfe88 +# Source-Hash: 62ab2eb3c775da95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "You can retry the scene or return home without reloading the whole app shell." -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "editor.youCanRetryTheSceneOr" -msgstr "アプリ全体を再読み込みせずに、シーンを再試行するかホームに戻れます。" +msgid "node.cabinet.essentialControls.single" +msgstr "片開き" -# Source-Hash: a273dacdf51b26f2 +# Source-Hash: 4bc3042055df1e85 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A topology-backed solid edited directly in the canvas." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sink layout" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.block.description" -msgstr "キャンバス上で直接編集できる、トポロジーを持つソリッド。" +msgid "node.cabinet.essentialControls.sinkLayout" +msgstr "シンクの構成" -# Source-Hash: 279f456ebb2f5da0 +# Source-Hash: 29cffe75281dbea6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Block" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top freezer" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.block.label" -msgstr "ブロック" +msgid "node.cabinet.essentialControls.topFreezer" +msgstr "上段冷凍" -# Source-Hash: b2a371b4041b5e38 +# Source-Hash: 09c2cb2ea7b1be3c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Small louvered exhaust vent that sits on a roof slope." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose {label}" +#: packages/nodes/src/cabinet/kitchen-collection.tsx #, fuzzy -msgid "node.boxVent.description" -msgstr "屋根勾配に載る小型のルーバー付き排気口。" +msgid "node.cabinet.kitchenCollection.chooseLabel" +msgstr "{label}を選択" -# Source-Hash: f736ca24e84825c3 +# Source-Hash: 1dd2cac6488ddc30 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box Vent" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No kitchen items match. Try “fridge”, “sink”, or “cabinet”." +#: packages/nodes/src/cabinet/kitchen-collection.tsx #, fuzzy -msgid "node.boxVent.label" -msgstr "ボックス換気口" +msgid "node.cabinet.kitchenCollection.noKitchenItemsMatchTryFridge" +msgstr "一致するキッチンアイテムはありません。「冷蔵庫」「シンク」「キャビネット」で試してください。" +# Source-Hash: 6752675ca6280ddd # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Search fridge, sink, cabinets…" +#: packages/nodes/src/cabinet/kitchen-collection.tsx #, fuzzy -msgid "node.boxVent.panel.actions" -msgstr "操作" +msgid "node.cabinet.kitchenCollection.searchFridgeSinkCabinets" +msgstr "冷蔵庫、シンク、キャビネットを検索…" +# Source-Hash: fe3c6d57a07c323d # Review: required -# Source-Hash: c0e9837e67038e92 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base Flange" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Search kitchen items" +#: packages/nodes/src/cabinet/kitchen-collection.tsx #, fuzzy -msgid "node.boxVent.panel.baseFlange" -msgstr "ベースフランジ" +msgid "node.cabinet.kitchenCollection.searchKitchenItems" +msgstr "キッチンアイテムを検索" +# Source-Hash: d44a46146db2e44c # Review: required -# Source-Hash: fa9118f6f4f020d7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base Height" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Appliances & fixtures" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.boxVent.panel.baseHeight" -msgstr "ベースの高さ" +msgid "node.cabinet.kitchenGroup.appliances" +msgstr "家電・設備" +# Source-Hash: d4d3ad7c099b6513 # Review: required -# Source-Hash: 0869f5a92dabb4e1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base Inset" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinets" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.boxVent.panel.baseInset" -msgstr "ベースの内寄せ" +msgid "node.cabinet.kitchenGroup.cabinets" +msgstr "キャビネット" +# Source-Hash: 465db52f98c2d94f # Review: required -# Source-Hash: e9a89a5e4ac8cd61 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add beside" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.box" -msgstr "ボックス" +msgid "node.cabinet.kitchenModuleActions.addBeside" +msgstr "横に追加" +# Source-Hash: 9733e2ad85deb6d5 # Review: required -# Source-Hash: f736ca24e84825c3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box Vent" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add beside selected item" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.boxVent" -msgstr "ボックス換気口" +msgid "node.cabinet.kitchenModuleActions.addBesideSelectedItem" +msgstr "選択したアイテムの横に追加" +# Source-Hash: 4b2f676fb4c9ec63 # Review: required -# Source-Hash: d52b53241789ee63 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add {label}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.cap" -msgstr "キャップ" +msgid "node.cabinet.kitchenModuleActions.addLabel" +msgstr "{label}を追加" +# Source-Hash: 5122b8e9b4ec6a00 # Review: required -# Source-Hash: 0ce3b53766b550e7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap Height" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An upper cabinet attached to this item will be removed to make room." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.capHeight" -msgstr "キャップの高さ" +msgid "node.cabinet.kitchenModuleActions.anUpperCabinetAttachedToThis" +msgstr "スペースを空けるため、このアイテムに付いている吊り戸棚は削除されます。" +# Source-Hash: 5737c4567e0f6863 # Review: required -# Source-Hash: 89eba9f077fba348 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner Bevel" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.cornerBevel" -msgstr "角の面取り" +msgid "node.cabinet.kitchenModuleActions.cabinet" +msgstr "キャビネット" +# Source-Hash: c0774c185060fc13 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.delete" -msgstr "削除" +msgid "node.cabinet.kitchenModuleActions.cancel" +msgstr "キャンセル" +# Source-Hash: f42912b116015f58 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This {width} item cannot fit within the current run and its wall or corner limits. Move an end cabinet or free space, then try again." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.depth" -msgstr "奥行き" +msgid "node.cabinet.kitchenModuleActions.cannotFit" +msgstr "この {width} のアイテムは、現在のキャビネット列と壁・コーナーの制限内に収まりません。端のキャビネットを動かすか空きを作ってから、もう一度お試しください。" +# Source-Hash: b7eeb26a356d03c3 # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{side, select, left {Inserts on the left of the selected item.} other {Inserts on the right of the selected item.}}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.dimensions" -msgstr "寸法" +msgid "node.cabinet.kitchenModuleActions.insertsBeside" +msgstr "{side, select, left {選択したアイテムの左側に挿入します。} other {選択したアイテムの右側に挿入します。}}" +# Source-Hash: f65332177316d11d # Review: required -# Source-Hash: de47e23eb81efe02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dome" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The kitchen changed. Select an item again to refresh the preview." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.dome" -msgstr "ドーム" +msgid "node.cabinet.kitchenModuleActions.kitchenChanged" +msgstr "キッチンが変更されました。プレビューを更新するにはアイテムを選び直してください。" +# Source-Hash: 5b6990b17111fd6b # Review: required -# Source-Hash: 1c5c81aa21193d07 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dome Curvature" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchen run preview, highlighted item is the proposed change" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.domeCurvature" -msgstr "ドームの曲率" +msgid "node.cabinet.kitchenModuleActions.kitchenRunPreviewHighlightedItemIs" +msgstr "キッチン列のプレビュー。ハイライトされたアイテムが変更案です" +# Source-Hash: cb59562ba7eb1d25 # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left side" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.duplicate" -msgstr "複製" +msgid "node.cabinet.kitchenModuleActions.leftSide" +msgstr "左側" +# Source-Hash: 766354d53f17d78c # Review: required -# Source-Hash: 8cac057f7ae6804d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap Height" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{name}: moves {distance}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.gapHeight" -msgstr "隙間の高さ" +msgid "node.cabinet.kitchenModuleActions.moved" +msgstr "{name}:{distance} 移動" +# Source-Hash: df1083d9ffc2c59d # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{name}: {width}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.height" -msgstr "高さ" +msgid "node.cabinet.kitchenModuleActions.previewItem" +msgstr "{name}:{width}" +# Source-Hash: ada7fbece9ca9e3c # Review: required -# Source-Hash: 8a9c2ea0783a0e53 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hood Overhang" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace selected item" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.hoodOverhang" -msgstr "フードの張り出し" +msgid "node.cabinet.kitchenModuleActions.replaceSelectedItem" +msgstr "選択したアイテムを置き換え" +# Source-Hash: ab8b52d2704537d2 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replaces only the selected item." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.move" -msgstr "移動" +msgid "node.cabinet.kitchenModuleActions.replacesOnlyTheSelectedItem" +msgstr "選択したアイテムだけを置き換えます。" +# Source-Hash: 03cb6dea6e4a4c5e # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace with…" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.position" -msgstr "位置" +msgid "node.cabinet.kitchenModuleActions.replaceWith" +msgstr "置き換え…" +# Source-Hash: 948fe657641f298c # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace with {label}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.rotation" -msgstr "回転" +msgid "node.cabinet.kitchenModuleActions.replaceWithLabel" +msgstr "{label}に置き換え" +# Source-Hash: 154f9fa86b7670ba # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{name}: {before} → {after}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.style" -msgstr "スタイル" +msgid "node.cabinet.kitchenModuleActions.resized" +msgstr "{name}:{before} → {after}" +# Source-Hash: 4ecc493400fb6aa2 # Review: required -# Source-Hash: 71d82d47e11d2564 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Taper" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right side" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.topTaper" -msgstr "上部のテーパー" +msgid "node.cabinet.kitchenModuleActions.rightSide" +msgstr "右側" +# Source-Hash: f2c30e7e21cf27e6 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unable to update this kitchen." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.boxVent.panel.width" -msgstr "幅" +msgid "node.cabinet.kitchenModuleActions.unableToUpdateThisKitchen" +msgstr "このキッチンを更新できません。" -# Source-Hash: f49d8836ae037dde +# Source-Hash: 2e6d8cda361c648d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A building container holding one or more levels." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modular Cabinet" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.building.description" -msgstr "1つ以上の階層を含む建物コンテナ。" +msgid "node.cabinet.label" +msgstr "モジュール式キャビネット" -# Source-Hash: d42f7d29e3fc4af7 +# Source-Hash: 740e0a4e4afa78ea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Building" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finished height extends {overflow} mm above the ceiling." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.building.label" -msgstr "建物" +msgid "node.cabinet.panel.aboveCeiling" +msgstr "仕上がり高さが天井を {overflow} mm 超えています。" +# Source-Hash: e3b4d2ed4f6f5efb # Review: required -# Source-Hash: 5a8274cbe3034558 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Baskets" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add chimney" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.baskets" -msgstr "バスケット" +msgid "node.cabinet.panel.addChimney" +msgstr "レンジフードを追加" +# Source-Hash: 90bdc92c0a91d060 # Review: required -# Source-Hash: b3a163b453896bef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add compartment" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.bottom" -msgstr "下" +msgid "node.cabinet.panel.addCompartment" +msgstr "区画を追加" +# Source-Hash: ece05d9b6f4b616d # Review: required -# Source-Hash: 486501f027037732 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Freezer" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add wall cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.bottomFreezer" -msgstr "下段冷凍" +msgid "node.cabinet.panel.addWallCabinet" +msgstr "吊り戸棚を追加" +# Source-Hash: f571cb2d06ae01ae # Review: required -# Source-Hash: 375acc0016b3aa14 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bowls" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Advanced" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.bowls" -msgstr "シンク槽" +msgid "node.cabinet.panel.advanced" +msgstr "詳細" +# Source-Hash: 7f4dcb90defe1ac2 # Review: required -# Source-Hash: 8449b59bf054c27d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Burners on" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Appliance" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.burnersOn" -msgstr "点火" +msgid "node.cabinet.panel.appliance" +msgstr "家電" +# Source-Hash: bd5e3f533412ff6a # Review: required -# Source-Hash: 95169058fec6db14 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Chimney" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Appliance front" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.chimney" -msgstr "煙突" +msgid "node.cabinet.panel.applianceFront" +msgstr "家電の前面" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: a6b76187db231ae7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Decrease {label}" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.decrease" -msgstr "{label}を減らす" +msgid "node.cabinet.panel.auto" +msgstr "自動" +# Source-Hash: 9cf3754f15467c50 # Review: required -# Source-Hash: 787e10f5db16904e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.door" -msgstr "ドア" +msgid "node.cabinet.panel.bar" +msgstr "バー" + +# Source-Hash: 133893b177bd05d6 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base Cabinet" +#: packages/nodes/src/cabinet/panel.tsx +#, fuzzy +msgid "node.cabinet.panel.baseCabinet" +msgstr "ベースキャビネット" +# Source-Hash: d63f16df2c754126 # Review: required -# Source-Hash: 3cd71355956a1821 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet construction, compartments, and opening preview." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.double" -msgstr "両開き" +msgid "node.cabinet.panel.cabinetConstructionCompartmentsAndOpeningPreview" +msgstr "キャビネットの構造、区画、開閉プレビュー。" +# Source-Hash: d62dc35dac835228 # Review: required -# Source-Hash: 63fe49d73892aac8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawer" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet panel" +#: packages/nodes/src/cabinet/panel.tsx +#, fuzzy +msgid "node.cabinet.panel.cabinetPanel" +msgstr "キャビネットパネル" + +# Source-Hash: 81caf4809d58b5f5 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet Type" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.drawer" -msgstr "引き出し" +msgid "node.cabinet.panel.cabinetType" +msgstr "キャビネットの種類" +# Source-Hash: 5211341ed18f33f6 # Review: required -# Source-Hash: f98242a5dacd33f3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawers" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.drawers" -msgstr "引き出し" +msgid "node.cabinet.panel.center" +msgstr "中央" +# Source-Hash: d7cf5045c01b2eb9 # Review: required -# Source-Hash: 3af5347c94ae6443 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip hinge" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.flipHinge" -msgstr "丁番を反転" +msgid "node.cabinet.panel.close" +msgstr "閉じる" +# Source-Hash: cf29134333e47184 # Review: required -# Source-Hash: c930f681e61c029c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip the door hinge to the opposite side" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.flipTheDoorHingeToThe" -msgstr "扉の丁番を反対側にする" +msgid "node.cabinet.panel.closeCabinet" +msgstr "キャビネットを閉じる" +# Source-Hash: b1ab1ba948bb77b0 # Review: required -# Source-Hash: 85724031c91952a3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fridge" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Common wall-cabinet heights. Use the slider below for a custom height." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.fridge" -msgstr "冷蔵庫" +msgid "node.cabinet.panel.commonWallCabinetHeightsUseThe" +msgstr "一般的な吊り戸棚の高さです。任意の高さには下のスライダーを使います。" +# Source-Hash: fe9e63d5c5087386 # Review: required -# Source-Hash: e67f11024d683ea9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gas" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Compartments" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.gas" -msgstr "ガス" +msgid "node.cabinet.panel.compartments" +msgstr "区画" +# Source-Hash: 7984b1c42abd9c02 # Review: required -# Source-Hash: 8ab91094cf650204 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cutout" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.glass" -msgstr "ガラス" +msgid "node.cabinet.panel.cutout" +msgstr "切り欠き" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.height" -msgstr "高さ" +msgid "node.cabinet.panel.depth" +msgstr "奥行き" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: 6f434b84c8b59b8c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hob" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.hob" -msgstr "コンロ" +msgid "node.cabinet.panel.dimensions" +msgstr "寸法" +# Source-Hash: 82c9ea6f403fc934 # Review: required -# Source-Hash: d52570d41b4df776 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Increase {label}" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit kitchen run" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.increase" -msgstr "{label}を増やす" +msgid "node.cabinet.panel.editKitchenRun" +msgstr "キッチン列を編集" +# Source-Hash: 7e9bbeb035fc73e2 # Review: required -# Source-Hash: d298f259163e868e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Induction" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fill to ceiling" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.induction" -msgstr "IH" +msgid "node.cabinet.panel.fillToCeiling" +msgstr "天井まで" +# Source-Hash: b3907da0ad234f10 # Review: required -# Source-Hash: 54800340a0eeab23 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Layout" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.layout" -msgstr "レイアウト" +msgid "node.cabinet.panel.finish" +msgstr "完了" +# Source-Hash: c1796152935221ef # Review: required -# Source-Hash: f365c6b6dd9ebab9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front construction" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.left" -msgstr "左" +msgid "node.cabinet.panel.frontConstruction" +msgstr "前面の構造" +# Source-Hash: 58884f99d64e6d00 # Review: required -# Source-Hash: 12ade82be3830a0b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Micro" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handles" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.micro" -msgstr "電子レンジ" +msgid "node.cabinet.panel.handles" +msgstr "取っ手" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: a06a50e63f0c240e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move down" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.moveDown" -msgstr "下へ移動" +msgid "node.cabinet.panel.height" +msgstr "高さ" +# Source-Hash: d73589d7c04b1121 # Review: required -# Source-Hash: d49ea60a2312df2f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move up" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height preset" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.moveUp" -msgstr "上へ移動" +msgid "node.cabinet.panel.heightPreset" +msgstr "高さプリセット" +# Source-Hash: 590bfdd02dcdb857 # Review: required -# Source-Hash: 596023c8b9a8f2e4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Oven" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hole" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.oven" -msgstr "オーブン" +msgid "node.cabinet.panel.hole" +msgstr "穴" +# Source-Hash: 3db1dea825785a30 # Review: required -# Source-Hash: 83b20797fb0a01a0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pullout" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inset" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.pullout" -msgstr "引き出し式" +msgid "node.cabinet.panel.inset" +msgstr "埋め込み" +# Source-Hash: 1176d2568d093bf1 # Review: required -# Source-Hash: 43c251f465b647ce -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rack" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchen" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.rack" -msgstr "ラック" +msgid "node.cabinet.panel.kitchen" +msgstr "キッチン" +# Source-Hash: a74f10dadc92c8bb # Review: required -# Source-Hash: 3c2b3026d37cbcc2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove compartment" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchen run" +#: packages/nodes/src/cabinet/panel.tsx +#, fuzzy +msgid "node.cabinet.panel.kitchenRun" +msgstr "キッチン列" + +# Source-Hash: 103e15b39c909210 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Knob" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.removeCompartment" -msgstr "区画を削除" +msgid "node.cabinet.panel.knob" +msgstr "つまみ" +# Source-Hash: 81d365ccef73068c # Review: required -# Source-Hash: b34d5ee0f218221d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.right" -msgstr "右" +msgid "node.cabinet.panel.mounting" +msgstr "取り付け方法" +# Source-Hash: f2953d2931e36d0c # Review: required -# Source-Hash: d7145f84f8e0e3fe -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shelf" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.shelf" -msgstr "棚" +msgid "node.cabinet.panel.none" +msgstr "なし" +# Source-Hash: 3e52f04f92e08070 # Review: required -# Source-Hash: 5fbb88f1f079b6db -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shelves" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.shelves" -msgstr "棚板" +msgid "node.cabinet.panel.open" +msgstr "開く" +# Source-Hash: b8ecc16c07d66f42 # Review: required -# Source-Hash: 47173085127029f0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shelves inside" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open Animation" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.shelvesInside" -msgstr "内部の棚板" +msgid "node.cabinet.panel.openAnimation" +msgstr "開閉アニメーション" +# Source-Hash: 2d4adbbd70c3ae6a # Review: required -# Source-Hash: 62ab2eb3c775da95 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.single" -msgstr "片開き" +msgid "node.cabinet.panel.openCabinet" +msgstr "キャビネットを開く" +# Source-Hash: 9c215dc512e57fa4 # Review: required -# Source-Hash: 522a7535fc93fb4f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sink" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overlay" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.sink" -msgstr "シンク" +msgid "node.cabinet.panel.overlay" +msgstr "かぶせ" +# Source-Hash: a35b7357943a5cae # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel-ready" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.style" -msgstr "スタイル" +msgid "node.cabinet.panel.panelReady" +msgstr "パネル対応" +# Source-Hash: 3d0d4eee59177824 # Review: required -# Source-Hash: 78a454b7ac7a3cd9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Planning checks" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.surface" -msgstr "面" +msgid "node.cabinet.panel.planningChecks" +msgstr "プランのチェック" +# Source-Hash: c7b10382e01914ad # Review: required -# Source-Hash: 27644f0497fd9849 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Play" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.top" -msgstr "上" +msgid "node.cabinet.panel.play" +msgstr "再生" +# Source-Hash: c530f8af9dfd846f # Review: required -# Source-Hash: eaadfd2d19b27d87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Freezer" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Play animation" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.topFreezer" -msgstr "上段冷凍" +msgid "node.cabinet.panel.playAnimation" +msgstr "アニメーションを再生" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: 04f3a3462ef5d247 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top grate" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.topGrate" -msgstr "上部ごとく" +msgid "node.cabinet.panel.position" +msgstr "位置" +# Source-Hash: efca749fc4463623 # Review: required -# Source-Hash: 4a616e1d2ca55bd5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tray" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised Arch" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.tray" -msgstr "トレー" +msgid "node.cabinet.panel.raisedArch" +msgstr "アーチ型" +# Source-Hash: a8639a97ab07cd59 # Review: required -# Source-Hash: c44f7ab8bbd24858 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove wall cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.type" -msgstr "種類" +msgid "node.cabinet.panel.removeWallCabinet" +msgstr "吊り戸棚を削除" +# Source-Hash: 03cb6dea6e4a4c5e # Review: required -# Source-Hash: 6c4de540d19316ab -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Washer" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace with…" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.washer" -msgstr "食洗機" +msgid "node.cabinet.panel.replaceWith" +msgstr "置き換え…" +# Source-Hash: 5d6956c21fde6418 # Review: required -# Source-Hash: 5211a0caf3518125 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wire" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reveal gap" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.compartmentCard.wire" -msgstr "ワイヤー" +msgid "node.cabinet.panel.revealGap" +msgstr "目地幅" -# Source-Hash: 693a0d8896f5cc43 +# Source-Hash: 5b68e435b7210876 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A configurable parametric base cabinet." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaker" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.description" -msgstr "設定可能なパラメトリックのベースキャビネット。" +msgid "node.cabinet.panel.shaker" +msgstr "シェーカー" +# Source-Hash: c378ed346bf83375 # Review: required -# Source-Hash: b0568ea943addd5b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom freezer" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shared countertop, plinth, and finishes" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.bottomFreezer" -msgstr "下段冷凍" +msgid "node.cabinet.panel.sharedCountertopPlinthAndFinishes" +msgstr "共通のカウンター・台輪・仕上げ" +# Source-Hash: 8775bc8dc9593964 # Review: required -# Source-Hash: da78819903ae0863 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cooktop type" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.cooktopType" -msgstr "コンロの種類" +msgid "node.cabinet.panel.slab" +msgstr "スラブ" +# Source-Hash: 8606fe2c60764a95 # Review: required -# Source-Hash: c608188f58ed1cfc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door direction" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid matching front between the cabinet and wall. Countertop and toe-kick continue across this filler." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.doorDirection" -msgstr "扉の開き方向" +msgid "node.cabinet.panel.solidMatchingFrontBetweenTheCabinet" +msgstr "キャビネットと壁の間をふさぐ同じ仕上げの前板です。カウンターと台輪はこのフィラーの上にも続きます。" +# Source-Hash: 5a4d5353cc496a63 # Review: required -# Source-Hash: 3cd71355956a1821 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard width" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.double" -msgstr "両開き" +msgid "node.cabinet.panel.standardWidth" +msgstr "標準幅" +# Source-Hash: 4a784e3e95a08715 # Review: required -# Source-Hash: f7fb8f6393cc4cfc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fridge type" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stop" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.fridgeType" -msgstr "冷蔵庫の種類" +msgid "node.cabinet.panel.stop" +msgstr "停止" +# Source-Hash: 72c9fcd7a0eb5380 # Review: required -# Source-Hash: e67f11024d683ea9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gas" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stop animation" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.gas" -msgstr "ガス" +msgid "node.cabinet.panel.stopAnimation" +msgstr "アニメーションを停止" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: 8ab91094cf650204 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.glass" -msgstr "ガラス" +msgid "node.cabinet.panel.style" +msgstr "スタイル" +# Source-Hash: bfd618690e0c2f24 # Review: required -# Source-Hash: d298f259163e868e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Induction" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tall Cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.induction" -msgstr "IH" +msgid "node.cabinet.panel.tallCabinet" +msgstr "トールキャビネット" +# Source-Hash: 27644f0497fd9849 # Review: required -# Source-Hash: 76df477d42cec629 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Item options" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.itemOptions" -msgstr "アイテムのオプション" +msgid "node.cabinet.panel.top" +msgstr "上" +# Source-Hash: d09654ebd12a538a # Review: required -# Source-Hash: bca1b184af1c0c4b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left hinge" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.leftHinge" -msgstr "左丁番" +msgid "node.cabinet.panel.topCabinet" +msgstr "上部キャビネット" +# Source-Hash: bc19e7805b3e3703 # Review: required -# Source-Hash: e32da7429c85f1a5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right hinge" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top / Ceiling" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.rightHinge" -msgstr "右丁番" +msgid "node.cabinet.panel.topCeiling" +msgstr "上部 / 天井" +# Source-Hash: 29ea8a68eed99925 # Review: required -# Source-Hash: 62ab2eb3c775da95 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top depth" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.single" -msgstr "片開き" +msgid "node.cabinet.panel.topDepth" +msgstr "上部の奥行き" +# Source-Hash: 2d40f591e7dcbf5a # Review: required -# Source-Hash: 4bc3042055df1e85 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sink layout" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top height" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.sinkLayout" -msgstr "シンクの構成" +msgid "node.cabinet.panel.topHeight" +msgstr "上部の高さ" +# Source-Hash: 3b878d6015c03945 # Review: required -# Source-Hash: 29cffe75281dbea6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top freezer" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trim / Soffit" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.essentialControls.topFreezer" -msgstr "上段冷凍" +msgid "node.cabinet.panel.trimSoffit" +msgstr "幕板 / 下がり天井" +# Source-Hash: a6e5be20001e8d26 # Review: required -# Source-Hash: 09c2cb2ea7b1be3c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose {label}" -#: packages/nodes/src/cabinet/kitchen-collection.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Uses the cabinet front style, reveal, handle, and front material settings below." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.kitchenCollection.chooseLabel" -msgstr "{label}を選択" +msgid "node.cabinet.panel.usesTheCabinetFrontStyleReveal" +msgstr "下の前面スタイル、目地、取っ手、前面材質の設定を使います。" +# Source-Hash: cd55643590c64a42 # Review: required -# Source-Hash: 1dd2cac6488ddc30 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No kitchen items match. Try “fridge”, “sink”, or “cabinet”." -#: packages/nodes/src/cabinet/kitchen-collection.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall filler" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.kitchenCollection.noKitchenItemsMatchTryFridge" -msgstr "一致するキッチンアイテムはありません。「冷蔵庫」「シンク」「キャビネット」で試してください。" +msgid "node.cabinet.panel.wallFiller" +msgstr "壁側フィラー" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: 6752675ca6280ddd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Search fridge, sink, cabinets…" -#: packages/nodes/src/cabinet/kitchen-collection.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.kitchenCollection.searchFridgeSinkCabinets" -msgstr "冷蔵庫、シンク、キャビネットを検索…" +msgid "node.cabinet.panel.width" +msgstr "幅" +# Source-Hash: 4ef03cfd6782316b # Review: required -# Source-Hash: fe3c6d57a07c323d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Search kitchen items" -#: packages/nodes/src/cabinet/kitchen-collection.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base cabinet" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.kitchenCollection.searchKitchenItems" -msgstr "キッチンアイテムを検索" +msgid "node.cabinet.preset.baseCabinet" +msgstr "ベースキャビネット" +# Source-Hash: d353fff221a78228 # Review: required -# Source-Hash: d44a46146db2e44c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Appliances & fixtures" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dishwasher" #: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.kitchenGroup.appliances" -msgstr "家電・設備" +msgid "node.cabinet.preset.dishwasher" +msgstr "食洗機" +# Source-Hash: ecb596567b8b7179 # Review: required -# Source-Hash: d4d3ad7c099b6513 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinets" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawer cabinet" #: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.kitchenGroup.cabinets" -msgstr "キャビネット" +msgid "node.cabinet.preset.drawerCabinet" +msgstr "引き出しキャビネット" +# Source-Hash: 85724031c91952a3 # Review: required -# Source-Hash: 465db52f98c2d94f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add beside" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fridge" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.kitchenModuleActions.addBeside" -msgstr "横に追加" +msgid "node.cabinet.preset.fridge" +msgstr "冷蔵庫" +# Source-Hash: 72d587d58b645a81 # Review: required -# Source-Hash: 9733e2ad85deb6d5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add beside selected item" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gas cooktop" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.kitchenModuleActions.addBesideSelectedItem" -msgstr "選択したアイテムの横に追加" +msgid "node.cabinet.preset.gasCooktop" +msgstr "ガスコンロ" +# Source-Hash: 6b02c36e6aac2cd6 # Review: required -# Source-Hash: 4b2f676fb4c9ec63 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add {label}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Induction cooktop" +#: packages/nodes/src/cabinet/kitchen-catalog.ts +#, fuzzy +msgid "node.cabinet.preset.inductionCooktop" +msgstr "IHコンロ" + +# Source-Hash: d5fcb790aef707bf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Oven Tower" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.kitchenModuleActions.addLabel" -msgstr "{label}を追加" +msgid "node.cabinet.preset.ovenTower" +msgstr "オーブントール" +# Source-Hash: edd4d1ab7525dcaa # Review: required -# Source-Hash: 5122b8e9b4ec6a00 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "An upper cabinet attached to this item will be removed to make room." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sink cabinet" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.kitchenModuleActions.anUpperCabinetAttachedToThis" -msgstr "スペースを空けるため、このアイテムに付いている吊り戸棚は削除されます。" +msgid "node.cabinet.preset.sinkCabinet" +msgstr "シンクキャビネット" +# Source-Hash: 9b7427a8954f618b # Review: required -# Source-Hash: 5737c4567e0f6863 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tall Pantry" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.kitchenModuleActions.cabinet" -msgstr "キャビネット" +msgid "node.cabinet.preset.tallPantry" +msgstr "トールパントリー" +# Source-Hash: 3bd9629eb17cc572 # Review: required -# Source-Hash: c0774c185060fc13 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall cabinet" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.kitchenModuleActions.cancel" -msgstr "キャンセル" +msgid "node.cabinet.preset.wallCabinet" +msgstr "吊り戸棚" +# Source-Hash: 7c40d26770eede82 # Review: required -# Source-Hash: f42912b116015f58 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "This {width} item cannot fit within the current run and its wall or corner limits. Move an end cabinet or free space, then try again." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add left" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.cannotFit" -msgstr "この {width} のアイテムは、現在のキャビネット列と壁・コーナーの制限内に収まりません。端のキャビネットを動かすか空きを作ってから、もう一度お試しください。" +msgid "node.cabinet.runPanel.addLeft" +msgstr "左に追加" +# Source-Hash: 25082cdf77e219c3 # Review: required -# Source-Hash: b7eeb26a356d03c3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{side, select, left {Inserts on the left of the selected item.} other {Inserts on the right of the selected item.}}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add right" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.insertsBeside" -msgstr "{side, select, left {選択したアイテムの左側に挿入します。} other {選択したアイテムの右側に挿入します。}}" +msgid "node.cabinet.runPanel.addRight" +msgstr "右に追加" +# Source-Hash: 4b1204c1b706f618 # Review: required -# Source-Hash: f65332177316d11d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The kitchen changed. Select an item again to refresh the preview." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Align cabinets & handles" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.kitchenChanged" -msgstr "キッチンが変更されました。プレビューを更新するにはアイテムを選び直してください。" +msgid "node.cabinet.runPanel.alignCabinetsHandles" +msgstr "キャビネットと取っ手を揃える" +# Source-Hash: 8c73c7a9406db5ad # Review: required -# Source-Hash: 5b6990b17111fd6b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchen run preview, highlighted item is the proposed change" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Applies depth, carcass, plinth, and countertop thickness to this run." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.kitchenRunPreviewHighlightedItemIs" -msgstr "キッチン列のプレビュー。ハイライトされたアイテムが変更案です" +msgid "node.cabinet.runPanel.appliesDepthCarcassPlinthAndCountertop" +msgstr "この列に奥行き・本体・台輪・カウンター厚さを適用します。" +# Source-Hash: ef576e6c8f9ebe5f # Review: required -# Source-Hash: cb59562ba7eb1d25 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left side" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {Create {number} module copy} other {Create {number} module copies}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.leftSide" -msgstr "左側" +msgid "node.cabinet.runPanel.arrayCreate" +msgstr "{count, plural, other {モジュールのコピーを {number} 個作成}}" +# Source-Hash: 0eec3888096306a1 # Review: required -# Source-Hash: 766354d53f17d78c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{name}: moves {distance}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {Create {number} {name} copy} other {Create {number} {name} copies}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.moved" -msgstr "{name}:{distance} 移動" +msgid "node.cabinet.runPanel.arrayCreateNamed" +msgstr "{count, plural, other {{name} のコピーを {number} 個作成}}" +# Source-Hash: 8cdc0b808b551d3a # Review: required -# Source-Hash: df1083d9ffc2c59d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{name}: {width}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a copy count from 1 to 20 and spacing from 0 to 2 m" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.previewItem" -msgstr "{name}:{width}" +msgid "node.cabinet.runPanel.arrayInvalidOptions" +msgstr "コピー数は 1〜20、間隔は 0〜2 m で選んでください" +# Source-Hash: cb89fe4161e87d68 # Review: required -# Source-Hash: ada7fbece9ca9e3c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace selected item" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "There is not enough room in this run for the requested array" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.replaceSelectedItem" -msgstr "選択したアイテムを置き換え" +msgid "node.cabinet.runPanel.arrayNoRoom" +msgstr "この列には指定した配列を置くだけのスペースがありません" +# Source-Hash: 075d027345689724 # Review: required -# Source-Hash: ab8b52d2704537d2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replaces only the selected item." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a standard or appliance module as the source" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.replacesOnlyTheSelectedItem" -msgstr "選択したアイテムだけを置き換えます。" +msgid "node.cabinet.runPanel.arrayNoSource" +msgstr "標準モジュールか家電モジュールを元として選んでください" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: 03cb6dea6e4a4c5e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace with…" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.replaceWith" -msgstr "置き換え…" +msgid "node.cabinet.runPanel.auto" +msgstr "自動" +# Source-Hash: 7ceade8f25b58fe9 # Review: required -# Source-Hash: 948fe657641f298c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace with {label}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.replaceWithLabel" -msgstr "{label}に置き換え" +msgid "node.cabinet.runPanel.back" +msgstr "戻る" +# Source-Hash: b2c3a03bf67a97a7 # Review: required -# Source-Hash: 154f9fa86b7670ba -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{name}: {before} → {after}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Balances standard base cabinets while keeping appliance and corner-filler widths fixed." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.resized" -msgstr "{name}:{before} → {after}" +msgid "node.cabinet.runPanel.balancesStandardBaseCabinetsWhileKeeping" +msgstr "家電とコーナーフィラーの幅は固定したまま、標準ベースキャビネットの幅を均等にします。" +# Source-Hash: 9cf3754f15467c50 # Review: required -# Source-Hash: 4ecc493400fb6aa2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right side" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.rightSide" -msgstr "右側" +msgid "node.cabinet.runPanel.bar" +msgstr "バー" +# Source-Hash: ccec5da17ca39eee # Review: required -# Source-Hash: f2c30e7e21cf27e6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unable to update this kitchen." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar counter" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.unableToUpdateThisKitchen" -msgstr "このキッチンを更新できません。" +msgid "node.cabinet.runPanel.barCounter" +msgstr "バーカウンター" -# Source-Hash: 2e6d8cda361c648d +# Source-Hash: 97c1605fff221752 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Modular Cabinet" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar depth" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.label" -msgstr "モジュール式キャビネット" +msgid "node.cabinet.runPanel.barDepth" +msgstr "バーの奥行き" +# Source-Hash: 9514a6ddebdca34e # Review: required -# Source-Hash: 740e0a4e4afa78ea -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finished height extends {overflow} mm above the ceiling." -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar height" +#: packages/nodes/src/cabinet/run-panel.tsx +#, fuzzy +msgid "node.cabinet.runPanel.barHeight" +msgstr "バーの高さ" + +# Source-Hash: 7af3b69b4b5aeb19 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Carcass height" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.aboveCeiling" -msgstr "仕上がり高さが天井を {overflow} mm 超えています。" +msgid "node.cabinet.runPanel.carcassHeight" +msgstr "本体の高さ" +# Source-Hash: 5211341ed18f33f6 # Review: required -# Source-Hash: e3b4d2ed4f6f5efb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add chimney" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.addChimney" -msgstr "レンジフードを追加" +msgid "node.cabinet.runPanel.center" +msgstr "中央" +# Source-Hash: b1ab1ba948bb77b0 # Review: required -# Source-Hash: 90bdc92c0a91d060 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add compartment" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Common wall-cabinet heights. Use the slider below for a custom height." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.addCompartment" -msgstr "区画を追加" +msgid "node.cabinet.runPanel.commonWallCabinetHeightsUseThe" +msgstr "一般的な吊り戸棚の高さです。任意の高さには下のスライダーを使います。" +# Source-Hash: 88ccc87b9b45a464 # Review: required -# Source-Hash: ece05d9b6f4b616d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add wall cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Copies" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.addWallCabinet" -msgstr "吊り戸棚を追加" +msgid "node.cabinet.runPanel.copies" +msgstr "コピー" +# Source-Hash: d215c489b8385d9f # Review: required -# Source-Hash: f571cb2d06ae01ae -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Advanced" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Copies include the source cabinet structure and any attached wall cabinet. Existing modules stay fixed; the requested array must fit in the available run space." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.advanced" -msgstr "詳細" +msgid "node.cabinet.runPanel.copiesIncludeTheSourceCabinetStructure" +msgstr "コピーには元のキャビネットの構造と付属の吊り戸棚が含まれます。既存のモジュールは動かず、指定した配列は列の空きスペースに収まる必要があります。" +# Source-Hash: 221d1b64649b08f8 # Review: required -# Source-Hash: 7f4dcb90defe1ac2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Appliance" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner fillers cannot be used as array sources" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.appliance" -msgstr "家電" +msgid "node.cabinet.runPanel.cornerFillersCannotBeUsedAs" +msgstr "コーナーフィラーは配列の元にできません" +# Source-Hash: d8d1bc5a0f9fa0cd # Review: required -# Source-Hash: bd5e3f533412ff6a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Appliance front" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Countertop depth" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.applianceFront" -msgstr "家電の前面" +msgid "node.cabinet.runPanel.countertopDepth" +msgstr "カウンターの奥行き" +# Source-Hash: 10bba4a11996c84b # Review: required -# Source-Hash: 05b65242d8c48791 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Countertop height" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.auto" -msgstr "自動" +msgid "node.cabinet.runPanel.countertopHeight" +msgstr "カウンターの高さ" +# Source-Hash: 8abdfbc1798d9eaa # Review: required -# Source-Hash: 9cf3754f15467c50 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Create array" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.bar" -msgstr "バー" +msgid "node.cabinet.runPanel.createArray" +msgstr "配列を作成" +# Source-Hash: 7984b1c42abd9c02 # Review: required -# Source-Hash: 133893b177bd05d6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base Cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cutout" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.baseCabinet" -msgstr "ベースキャビネット" +msgid "node.cabinet.runPanel.cutout" +msgstr "切り欠き" +# Source-Hash: 555240ffcca44233 # Review: required -# Source-Hash: d63f16df2c754126 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet construction, compartments, and opening preview." -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete {name}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.cabinetConstructionCompartmentsAndOpeningPreview" -msgstr "キャビネットの構造、区画、開閉プレビュー。" +msgid "node.cabinet.runPanel.deleteModule" +msgstr "{name}を削除" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: d62dc35dac835228 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet panel" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.cabinetPanel" -msgstr "キャビネットパネル" +msgid "node.cabinet.runPanel.depth" +msgstr "奥行き" +# Source-Hash: 76cd03300faa9b2b # Review: required -# Source-Hash: 81caf4809d58b5f5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet Type" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Direction" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.cabinetType" -msgstr "キャビネットの種類" +msgid "node.cabinet.runPanel.direction" +msgstr "方向" +# Source-Hash: 5ca5884d3ff7edf4 # Review: required -# Source-Hash: 5211341ed18f33f6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate along run" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.center" -msgstr "中央" +msgid "node.cabinet.runPanel.duplicateAlongRun" +msgstr "列に沿って複製" +# Source-Hash: a834f687290afc10 # Review: required -# Source-Hash: d7cf5045c01b2eb9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equalize all resizeable standard base cabinets in this run" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.close" -msgstr "閉じる" +msgid "node.cabinet.runPanel.equalizeAll" +msgstr "この列のサイズ変更できる標準ベースキャビネットをすべて均等にする" +# Source-Hash: 24da8a2de2c6e345 # Review: required -# Source-Hash: cf29134333e47184 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The resizeable cabinet widths are already equal" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.closeCabinet" -msgstr "キャビネットを閉じる" +msgid "node.cabinet.runPanel.equalizeAlreadyEqual" +msgstr "サイズ変更できるキャビネットの幅はすでに揃っています" +# Source-Hash: c38a4faef2097b73 # Review: required -# Source-Hash: b1ab1ba948bb77b0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Common wall-cabinet heights. Use the slider below for a custom height." -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "At least two standard base cabinets are required" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.commonWallCabinetHeightsUseThe" -msgstr "一般的な吊り戸棚の高さです。任意の高さには下のスライダーを使います。" +msgid "node.cabinet.runPanel.equalizeNeedsTwo" +msgstr "標準ベースキャビネットが 2 つ以上必要です" +# Source-Hash: 61f15ae24419430c # Review: required -# Source-Hash: fe9e63d5c5087386 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Compartments" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The available run width cannot satisfy the cabinet width limits" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.compartments" -msgstr "区画" +msgid "node.cabinet.runPanel.equalizeNoFit" +msgstr "列の空き幅ではキャビネットの幅の制限を満たせません" +# Source-Hash: 7617bb3b455dcdda # Review: required -# Source-Hash: 7984b1c42abd9c02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cutout" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equalize widths" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.cutout" -msgstr "切り欠き" +msgid "node.cabinet.runPanel.equalizeWidths" +msgstr "幅を揃える" +# Source-Hash: ad8c948d883a0c9d # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{side, select, left {Left: {width} mm} other {Right: {width} mm}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.depth" -msgstr "奥行き" +msgid "node.cabinet.runPanel.fillerPlanSide" +msgstr "{side, select, left {左:{width} mm} other {右:{width} mm}}" +# Source-Hash: 47ccd8c8b04475cd # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish & align" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.dimensions" -msgstr "寸法" +msgid "node.cabinet.runPanel.finishAlign" +msgstr "仕上げと整列" +# Source-Hash: 855892e18c74153a # Review: required -# Source-Hash: 82c9ea6f403fc934 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit kitchen run" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finished back" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.editKitchenRun" -msgstr "キッチン列を編集" +msgid "node.cabinet.runPanel.finishedBack" +msgstr "背面仕上げ" +# Source-Hash: 7ab47aea30c73663 # Review: required -# Source-Hash: 7e9bbeb035fc73e2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fill to ceiling" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finished exposed ends" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.fillToCeiling" -msgstr "天井まで" +msgid "node.cabinet.runPanel.finishedExposedEnds" +msgstr "見える側面の仕上げ" +# Source-Hash: c9356f25caf33eec # Review: required -# Source-Hash: b3907da0ad234f10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fits 50–150 mm gaps at run ends beside perpendicular walls." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.finish" -msgstr "完了" +msgid "node.cabinet.runPanel.fits50150MmGapsAt" +msgstr "直交する壁際の列端にある 50〜150 mm の隙間を埋めます。" +# Source-Hash: b6f541bc28e38d2f # Review: required -# Source-Hash: c1796152935221ef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front construction" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit wall fillers" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.frontConstruction" -msgstr "前面の構造" +msgid "node.cabinet.runPanel.fitWallFillers" +msgstr "壁側フィラーを合わせる" +# Source-Hash: 2af738f010ce28f0 # Review: required -# Source-Hash: 58884f99d64e6d00 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handles" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fronts" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.handles" -msgstr "取っ手" +msgid "node.cabinet.runPanel.fronts" +msgstr "前面" +# Source-Hash: 58884f99d64e6d00 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handles" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.height" -msgstr "高さ" +msgid "node.cabinet.runPanel.handles" +msgstr "取っ手" -# Review: required # Source-Hash: d73589d7c04b1121 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Height preset" -#: packages/nodes/src/cabinet/panel.tsx +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.heightPreset" +msgid "node.cabinet.runPanel.heightPreset" msgstr "高さプリセット" -# Review: required # Source-Hash: 590bfdd02dcdb857 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hole" -#: packages/nodes/src/cabinet/panel.tsx +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.hole" +msgid "node.cabinet.runPanel.hole" msgstr "穴" -# Review: required # Source-Hash: 3db1dea825785a30 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Inset" -#: packages/nodes/src/cabinet/panel.tsx +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.inset" +msgid "node.cabinet.runPanel.inset" msgstr "埋め込み" +# Source-Hash: 2997c230c529590d # Review: required -# Source-Hash: 1176d2568d093bf1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchen" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Island & Bar" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.kitchen" -msgstr "キッチン" +msgid "node.cabinet.runPanel.islandBar" +msgstr "アイランドとバー" -# Review: required # Source-Hash: a74f10dadc92c8bb -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen run" -#: packages/nodes/src/cabinet/panel.tsx +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.kitchenRun" +msgid "node.cabinet.runPanel.kitchenRun" msgstr "キッチン列" -# Review: required # Source-Hash: 103e15b39c909210 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Knob" -#: packages/nodes/src/cabinet/panel.tsx +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.knob" +msgid "node.cabinet.runPanel.knob" msgstr "つまみ" +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# Source-Hash: 81d365ccef73068c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting" -#: packages/nodes/src/cabinet/panel.tsx -#, fuzzy -msgid "node.cabinet.panel.mounting" -msgstr "取り付け方法" - -# Review: required -# Source-Hash: f2953d2931e36d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/nodes/src/cabinet/panel.tsx -#, fuzzy -msgid "node.cabinet.panel.none" -msgstr "なし" - -# Review: required -# Source-Hash: 3e52f04f92e08070 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/cabinet/panel.tsx -#, fuzzy -msgid "node.cabinet.panel.open" -msgstr "開く" - -# Review: required -# Source-Hash: b8ecc16c07d66f42 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open Animation" -#: packages/nodes/src/cabinet/panel.tsx -#, fuzzy -msgid "node.cabinet.panel.openAnimation" -msgstr "開閉アニメーション" - -# Review: required -# Source-Hash: 2d4adbbd70c3ae6a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.openCabinet" -msgstr "キャビネットを開く" +msgid "node.cabinet.runPanel.left" +msgstr "左" +# Source-Hash: 3c88a1840043e15a # Review: required -# Source-Hash: 9c215dc512e57fa4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overlay" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match base heights, backs, reveals and handles. Align upper cabinets; preserve tall appliances and custom compartments." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.overlay" -msgstr "かぶせ" +msgid "node.cabinet.runPanel.matchBaseHeightsBacksRevealsAnd" +msgstr "ベースの高さ・背面・目地・取っ手を揃え、上部キャビネットを整列します。背の高い家電とカスタム区画はそのまま残します。" +# Source-Hash: b112e31fe44cc94b # Review: required -# Source-Hash: a35b7357943a5cae -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel-ready" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Metric · 600 mm" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.panelReady" -msgstr "パネル対応" +msgid "node.cabinet.runPanel.metricProfile" +msgstr "メートル法 · 600 mm" +# Source-Hash: 4739f6315c5e8680 # Review: required -# Source-Hash: 3d0d4eee59177824 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Planning checks" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Module {number}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.planningChecks" -msgstr "プランのチェック" +msgid "node.cabinet.runPanel.moduleNumber" +msgstr "モジュール {number}" +# Source-Hash: b8801184e07e4815 # Review: required -# Source-Hash: c7b10382e01914ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Play" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modules" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.play" -msgstr "再生" +msgid "node.cabinet.runPanel.modules" +msgstr "モジュール" +# Source-Hash: 81d365ccef73068c # Review: required -# Source-Hash: c530f8af9dfd846f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Play animation" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.playAnimation" -msgstr "アニメーションを再生" +msgid "node.cabinet.runPanel.mounting" +msgstr "取り付け方法" +# Source-Hash: a3914bd96488175c # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No eligible module" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.position" -msgstr "位置" +msgid "node.cabinet.runPanel.noEligibleModule" +msgstr "対象のモジュールがありません" +# Source-Hash: f2953d2931e36d0c # Review: required -# Source-Hash: efca749fc4463623 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised Arch" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.raisedArch" -msgstr "アーチ型" +msgid "node.cabinet.runPanel.none" +msgstr "なし" +# Source-Hash: 9c215dc512e57fa4 # Review: required -# Source-Hash: a8639a97ab07cd59 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove wall cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overlay" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.removeWallCabinet" -msgstr "吊り戸棚を削除" +msgid "node.cabinet.runPanel.overlay" +msgstr "かぶせ" +# Source-Hash: 49fb05dfafd6001d # Review: required -# Source-Hash: 03cb6dea6e4a4c5e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace with…" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plinth height" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.replaceWith" -msgstr "置き換え…" +msgid "node.cabinet.runPanel.plinthHeight" +msgstr "台輪の高さ" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: 5d6956c21fde6418 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reveal gap" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.revealGap" -msgstr "目地幅" +msgid "node.cabinet.runPanel.position" +msgstr "位置" +# Source-Hash: efca749fc4463623 # Review: required -# Source-Hash: 5b68e435b7210876 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaker" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised Arch" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.shaker" -msgstr "シェーカー" +msgid "node.cabinet.runPanel.raisedArch" +msgstr "アーチ型" +# Source-Hash: 5d6956c21fde6418 # Review: required -# Source-Hash: c378ed346bf83375 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shared countertop, plinth, and finishes" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reveal gap" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.sharedCountertopPlinthAndFinishes" -msgstr "共通のカウンター・台輪・仕上げ" +msgid "node.cabinet.runPanel.revealGap" +msgstr "目地幅" +# Source-Hash: b34d5ee0f218221d # Review: required -# Source-Hash: 8775bc8dc9593964 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.slab" -msgstr "スラブ" +msgid "node.cabinet.runPanel.right" +msgstr "右" +# Source-Hash: e022da49ae8b4aef # Review: required -# Source-Hash: 8606fe2c60764a95 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid matching front between the cabinet and wall. Countertop and toe-kick continue across this filler." -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Seating overhang" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.solidMatchingFrontBetweenTheCabinet" -msgstr "キャビネットと壁の間をふさぐ同じ仕上げの前板です。カウンターと台輪はこのフィラーの上にも続きます。" +msgid "node.cabinet.runPanel.seatingOverhang" +msgstr "座席側の張り出し" +# Source-Hash: 5b68e435b7210876 # Review: required -# Source-Hash: 5a4d5353cc496a63 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard width" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaker" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.standardWidth" -msgstr "標準幅" +msgid "node.cabinet.runPanel.shaker" +msgstr "シェーカー" +# Source-Hash: cba29b18ce666b0a # Review: required -# Source-Hash: 4a784e3e95a08715 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stop" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shared Plinth & Countertop" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.stop" -msgstr "停止" +msgid "node.cabinet.runPanel.sharedPlinthCountertop" +msgstr "共通の台輪とカウンター" +# Source-Hash: f7d577c4064c16ff # Review: required -# Source-Hash: 72c9fcd7a0eb5380 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stop animation" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show countertop" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.stopAnimation" -msgstr "アニメーションを停止" +msgid "node.cabinet.runPanel.showCountertop" +msgstr "カウンターを表示" +# Source-Hash: 5d98e04dfd2e0a83 # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show plinth" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.style" -msgstr "スタイル" +msgid "node.cabinet.runPanel.showPlinth" +msgstr "台輪を表示" +# Source-Hash: 8775bc8dc9593964 # Review: required -# Source-Hash: bfd618690e0c2f24 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tall Cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.tallCabinet" -msgstr "トールキャビネット" +msgid "node.cabinet.runPanel.slab" +msgstr "スラブ" +# Source-Hash: 5bdc0a959203c52e # Review: required -# Source-Hash: 27644f0497fd9849 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Source module" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.top" -msgstr "上" +msgid "node.cabinet.runPanel.sourceModule" +msgstr "元のモジュール" +# Source-Hash: e4698e83d02beb6c # Review: required -# Source-Hash: d09654ebd12a538a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spacing" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.topCabinet" -msgstr "上部キャビネット" +msgid "node.cabinet.runPanel.spacing" +msgstr "間隔" +# Source-Hash: 40e3105cbe68d163 # Review: required -# Source-Hash: bc19e7805b3e3703 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top / Ceiling" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard dimensions" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.topCeiling" -msgstr "上部 / 天井" +msgid "node.cabinet.runPanel.standardDimensions" +msgstr "標準寸法" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: 29ea8a68eed99925 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top depth" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.topDepth" -msgstr "上部の奥行き" +msgid "node.cabinet.runPanel.style" +msgstr "スタイル" +# Source-Hash: e9d7ad9851d476d9 # Review: required -# Source-Hash: 2d40f591e7dcbf5a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top height" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{type, select, shelf {Shelf} drawer {Drawer} door {Door} oven {Oven} microwave {Microwave} dishwasher {Dishwasher} sink {Sink} cooktop_gas {Gas cooktop} cooktop_induction {Induction cooktop} pull_out_pantry {Pull-out pantry} fridge_single {Fridge} fridge_double {Double fridge} fridge_top_freezer {Top-freezer fridge} fridge_bottom_freezer {Bottom-freezer fridge} hood_pyramid {Pyramid hood} hood_curved_glass {Curved glass hood} other {{raw}}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.topHeight" -msgstr "上部の高さ" +msgid "node.cabinet.runPanel.summaryCompartment" +msgstr "{type, select, shelf {棚板} drawer {引き出し} door {扉} oven {オーブン} microwave {電子レンジ} dishwasher {食洗機} sink {シンク} cooktop_gas {ガスコンロ} cooktop_induction {IHコンロ} pull_out_pantry {引き出し式パントリー} fridge_single {冷蔵庫} fridge_double {両開き冷蔵庫} fridge_top_freezer {上段冷凍冷蔵庫} fridge_bottom_freezer {下段冷凍冷蔵庫} hood_pyramid {ピラミッド型フード} hood_curved_glass {曲面ガラスフード} other {{raw}}}" +# Source-Hash: 98582c257f149d44 # Review: required -# Source-Hash: 3b878d6015c03945 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trim / Soffit" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {{number} compartment} other {{number} compartments}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.trimSoffit" -msgstr "幕板 / 下がり天井" +msgid "node.cabinet.runPanel.summaryCompartments" +msgstr "{count, plural, other {{number} 区画}}" +# Source-Hash: 65b1cbba3b92c5b2 # Review: required -# Source-Hash: a6e5be20001e8d26 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Uses the cabinet front style, reveal, handle, and front material settings below." -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Empty" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.usesTheCabinetFrontStyleReveal" -msgstr "下の前面スタイル、目地、取っ手、前面材質の設定を使います。" +msgid "node.cabinet.runPanel.summaryEmpty" +msgstr "空" +# Source-Hash: 5db8b868684cf9f3 # Review: required -# Source-Hash: cd55643590c64a42 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall filler" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tall cabinet" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.wallFiller" -msgstr "壁側フィラー" +msgid "node.cabinet.runPanel.summaryTall" +msgstr "トールキャビネット" +# Source-Hash: 27644f0497fd9849 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.panel.width" -msgstr "幅" +msgid "node.cabinet.runPanel.top" +msgstr "上" +# Source-Hash: 88c85283afe0c0bc # Review: required -# Source-Hash: 4ef03cfd6782316b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base cabinet" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unable to finish this kitchen run." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.preset.baseCabinet" -msgstr "ベースキャビネット" +msgid "node.cabinet.runPanel.unableToFinish" +msgstr "このキッチン列を仕上げられません。" +# Source-Hash: 8f668fb3e1a1696a # Review: required -# Source-Hash: d353fff221a78228 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dishwasher" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use {name} as array source" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.preset.dishwasher" -msgstr "食洗機" +msgid "node.cabinet.runPanel.useAsArraySource" +msgstr "{name}を配列の元にする" +# Source-Hash: 9308a109d017dcd6 # Review: required -# Source-Hash: ecb596567b8b7179 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawer cabinet" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use this module as the array source" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.preset.drawerCabinet" -msgstr "引き出しキャビネット" +msgid "node.cabinet.runPanel.useThisModuleAsTheArray" +msgstr "このモジュールを配列の元にする" +# Source-Hash: 1ce253a4d11bfa68 # Review: required -# Source-Hash: 85724031c91952a3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fridge" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "US · 24 in" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.preset.fridge" -msgstr "冷蔵庫" +msgid "node.cabinet.runPanel.usProfile" +msgstr "米国 · 24 in" +# Source-Hash: a2d852b2c5629796 # Review: required -# Source-Hash: 72d587d58b645a81 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gas cooktop" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waterfall ends" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.cabinet.preset.gasCooktop" -msgstr "ガスコンロ" +msgid "node.cabinet.runPanel.waterfallEnds" +msgstr "ウォーターフォールエンド" +# Source-Hash: ffc8d80e438f40b7 # Review: required -# Source-Hash: 6b02c36e6aac2cd6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Induction cooktop" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An editable module inside a modular cabinet run." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.preset.inductionCooktop" -msgstr "IHコンロ" +msgid "node.cabinetModule.description" +msgstr "モジュール式キャビネットの列の中にある編集可能なモジュール。" +# Source-Hash: d5c19ec529e26a98 # Review: required -# Source-Hash: d5fcb790aef707bf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Oven Tower" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet Module" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.preset.ovenTower" -msgstr "オーブントール" +msgid "node.cabinetModule.label" +msgstr "キャビネットモジュール" +# Source-Hash: 25be6d614ec09df9 # Review: required -# Source-Hash: edd4d1ab7525dcaa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sink cabinet" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom chord" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.preset.sinkCabinet" -msgstr "シンクキャビネット" +msgid "node.ceiling.buildUpSection.bottomChord" +msgstr "下弦材" +# Source-Hash: a0c71abc0f146a2b # Review: required -# Source-Hash: 9b7427a8954f618b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tall Pantry" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling joists" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.preset.tallPantry" -msgstr "トールパントリー" +msgid "node.ceiling.buildUpSection.ceilingJoists" +msgstr "天井根太" +# Source-Hash: 7d286c87375d417e # Review: required -# Source-Hash: 3bd9629eb17cc572 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall cabinet" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Decking" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.preset.wallCabinet" -msgstr "吊り戸棚" +msgid "node.ceiling.buildUpSection.decking" +msgstr "小屋裏床板" +# Source-Hash: b3907da0ad234f10 # Review: required -# Source-Hash: 7c40d26770eede82 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add left" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.runPanel.addLeft" -msgstr "左に追加" +msgid "node.ceiling.buildUpSection.finish" +msgstr "仕上げ" +# Source-Hash: c7e72beff9fe4b37 # Review: required -# Source-Hash: 25082cdf77e219c3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add right" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framing" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.runPanel.addRight" -msgstr "右に追加" +msgid "node.ceiling.buildUpSection.framing" +msgstr "下地" +# Source-Hash: c7aa596536ceeecb # Review: required -# Source-Hash: 4b1204c1b706f618 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Align cabinets & handles" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Joists" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.runPanel.alignCabinetsHandles" -msgstr "キャビネットと取っ手を揃える" +msgid "node.ceiling.buildUpSection.joists" +msgstr "根太" +# Source-Hash: 4ccd2fc1a471fca5 # Review: required -# Source-Hash: 8c73c7a9406db5ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Applies depth, carcass, plinth, and countertop thickness to this run." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layers" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.runPanel.appliesDepthCarcassPlinthAndCountertop" -msgstr "この列に奥行き・本体・台輪・カウンター厚さを適用します。" +msgid "node.ceiling.buildUpSection.layers" +msgstr "層" +# Source-Hash: f2953d2931e36d0c # Review: required -# Source-Hash: ef576e6c8f9ebe5f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {Create {number} module copy} other {Create {number} module copies}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.runPanel.arrayCreate" -msgstr "{count, plural, other {モジュールのコピーを {number} 個作成}}" +msgid "node.ceiling.buildUpSection.none" +msgstr "なし" +# Source-Hash: 441f7f652ea6a0d8 # Review: required -# Source-Hash: 0eec3888096306a1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {Create {number} {name} copy} other {Create {number} {name} copies}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preset" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.runPanel.arrayCreateNamed" -msgstr "{count, plural, other {{name} のコピーを {number} 個作成}}" +msgid "node.ceiling.buildUpSection.preset" +msgstr "プリセット" +# Source-Hash: 2bc7b44c217cb8fb # Review: required -# Source-Hash: 8cdc0b808b551d3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a copy count from 1 to 20 and spacing from 0 to 2 m" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The height is the finished underside; the layers rise from it." +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.runPanel.arrayInvalidOptions" -msgstr "コピー数は 1〜20、間隔は 0〜2 m で選んでください" +msgid "node.ceiling.buildUpSection.theHeightIsTheFinishedUnderside" +msgstr "高さは仕上げ下面の位置です。層はそこから上へ重なります。" +# Source-Hash: fdbb503f0941bd56 # Review: required -# Source-Hash: cb89fe4161e87d68 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "There is not enough room in this run for the requested array" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.cabinet.runPanel.arrayNoRoom" -msgstr "この列には指定した配列を置くだけのスペースがありません" +msgid "node.ceiling.buildUpSection.thickness" +msgstr "厚さ" +# Source-Hash: 2cf52770d658d006 # Review: required -# Source-Hash: 075d027345689724 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a standard or appliance module as the source" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Truss bottom chords" +#: packages/nodes/src/ceiling/build-up-section.tsx +#, fuzzy +msgid "node.ceiling.buildUpSection.trussBottomChords" +msgstr "トラス下弦材" + +# Source-Hash: 4d6d5e9439f40e9b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A polygon-bounded ceiling surface that hosts ceiling-mounted items." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.runPanel.arrayNoSource" -msgstr "標準モジュールか家電モジュールを元として選んでください" +msgid "node.ceiling.description" +msgstr "多角形で囲まれた天井面。天井付けのアイテムを取り付けられます。" +# Source-Hash: 4275c05172abd7fb # Review: required -# Source-Hash: 05b65242d8c48791 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.runPanel.auto" -msgstr "自動" +msgid "node.ceiling.label" +msgstr "天井" +# Source-Hash: 659e6b799ad7c27d # Review: required -# Source-Hash: 7ceade8f25b58fe9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Hole" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.back" -msgstr "戻る" +msgid "node.ceiling.panel.addHole" +msgstr "開口を追加" +# Source-Hash: 8332ab41e22958f1 # Review: required -# Source-Hash: b2c3a03bf67a97a7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Balances standard base cabinets while keeping appliance and corner-filler widths fixed." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Area" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.balancesStandardBaseCabinetsWhileKeeping" -msgstr "家電とコーナーフィラーの幅は固定したまま、標準ベースキャビネットの幅を均等にします。" +msgid "node.ceiling.panel.area" +msgstr "面積" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: 9cf3754f15467c50 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.bar" -msgstr "バー" +msgid "node.ceiling.panel.auto" +msgstr "自動" +# Source-Hash: 4275c05172abd7fb # Review: required -# Source-Hash: ccec5da17ca39eee -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar counter" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.barCounter" -msgstr "バーカウンター" +msgid "node.ceiling.panel.ceiling" +msgstr "天井" +# Source-Hash: b2a1b3bc9676fe05 # Review: required -# Source-Hash: 97c1605fff221752 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar depth" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom height" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.barDepth" -msgstr "バーの奥行き" +msgid "node.ceiling.panel.customHeight" +msgstr "カスタムの高さ" +# Source-Hash: 4e4f1a24e4a9d61e # Review: required -# Source-Hash: 9514a6ddebdca34e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar height" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut opening" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.barHeight" -msgstr "バーの高さ" +msgid "node.ceiling.panel.cutOpening" +msgstr "開口を切る" +# Source-Hash: 16552c2580bbe8b8 # Review: required -# Source-Hash: 7af3b69b4b5aeb19 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Carcass height" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.carcassHeight" -msgstr "本体の高さ" +msgid "node.ceiling.panel.done" +msgstr "完了" +# Source-Hash: a5c2353769b603d5 # Review: required -# Source-Hash: 5211341ed18f33f6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows level" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.center" -msgstr "中央" +msgid "node.ceiling.panel.followsLevel" +msgstr "階層に従う" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: b1ab1ba948bb77b0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Common wall-cabinet heights. Use the slider below for a custom height." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.commonWallCabinetHeightsUseThe" -msgstr "一般的な吊り戸棚の高さです。任意の高さには下のスライダーを使います。" +msgid "node.ceiling.panel.height" +msgstr "高さ" +# Source-Hash: 703f56131ac45e60 # Review: required -# Source-Hash: 88ccc87b9b45a464 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Copies" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High (3.0m)" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.copies" -msgstr "コピー" +msgid "node.ceiling.panel.high30m" +msgstr "高(3.0m)" +# Source-Hash: 4ed40bdab397fe22 # Review: required -# Source-Hash: d215c489b8385d9f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Copies include the source cabinet structure and any attached wall cabinet. Existing modules stay fixed; the requested array must fit in the available run space." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High (9'0\")" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.copiesIncludeTheSourceCabinetStructure" -msgstr "コピーには元のキャビネットの構造と付属の吊り戸棚が含まれます。既存のモジュールは動かず、指定した配列は列の空きスペースに収まる必要があります。" +msgid "node.ceiling.panel.high90" +msgstr "高(9'0\")" +# Source-Hash: 34504c6ca6445e76 # Review: required -# Source-Hash: 221d1b64649b08f8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner fillers cannot be used as array sources" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Holes" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.cornerFillersCannotBeUsedAs" -msgstr "コーナーフィラーは配列の元にできません" +msgid "node.ceiling.panel.holes" +msgstr "開口" +# Source-Hash: 6e68b62d2aa611a4 # Review: required -# Source-Hash: d8d1bc5a0f9fa0cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Countertop depth" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Info" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.countertopDepth" -msgstr "カウンターの奥行き" +msgid "node.ceiling.panel.info" +msgstr "情報" +# Source-Hash: 6925a008b1924062 # Review: required -# Source-Hash: 10bba4a11996c84b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Countertop height" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Limited by the level to {height} — raise the level height for a taller ceiling." +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.countertopHeight" -msgstr "カウンターの高さ" +msgid "node.ceiling.panel.limitedByLevel" +msgstr "階層により {height} までに制限されます。天井を高くするには階層の高さを上げてください。" +# Source-Hash: c7410ff087be3a61 # Review: required -# Source-Hash: 8abdfbc1798d9eaa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Create array" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low (2.4m)" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.createArray" -msgstr "配列を作成" +msgid "node.ceiling.panel.low24m" +msgstr "低(2.4m)" +# Source-Hash: a59425761b7c9084 # Review: required -# Source-Hash: 7984b1c42abd9c02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cutout" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low (8'0\")" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.cutout" -msgstr "切り欠き" +msgid "node.ceiling.panel.low80" +msgstr "低(8'0\")" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: 555240ffcca44233 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete {name}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.deleteModule" -msgstr "{name}を削除" +msgid "node.ceiling.panel.move" +msgstr "移動" +# Source-Hash: 1d2dafb0d8f26ed5 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No holes" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.depth" -msgstr "奥行き" +msgid "node.ceiling.panel.noHoles" +msgstr "開口なし" +# Source-Hash: 24f5fbd158798197 # Review: required -# Source-Hash: 76cd03300faa9b2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Direction" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard (2.5m)" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.direction" -msgstr "方向" +msgid "node.ceiling.panel.standard25m" +msgstr "標準(2.5m)" +# Source-Hash: 73cf00cf1900c22b # Review: required -# Source-Hash: 5ca5884d3ff7edf4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate along run" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard (8'6\")" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.duplicateAlongRun" -msgstr "列に沿って複製" +msgid "node.ceiling.panel.standard86" +msgstr "標準(8'6\")" +# Source-Hash: 065626498678bc5d # Review: required -# Source-Hash: a834f687290afc10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equalize all resizeable standard base cabinets in this run" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Taller than this level ({available} available). Raise the level height first." +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.equalizeAll" -msgstr "この列のサイズ変更できる標準ベースキャビネットをすべて均等にする" +msgid "node.ceiling.panel.tallerThanLevel" +msgstr "この階層より高すぎます(使用可能 {available})。先に階層の高さを上げてください。" +# Source-Hash: ea12ce3c2b3588e7 # Review: required -# Source-Hash: 24da8a2de2c6e345 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The resizeable cabinet widths are already equal" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical masonry stack on a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.runPanel.equalizeAlreadyEqual" -msgstr "サイズ変更できるキャビネットの幅はすでに揃っています" +msgid "node.chimney.description" +msgstr "屋根面上の組積造の煙突。" +# Source-Hash: 95169058fec6db14 # Review: required -# Source-Hash: c38a4faef2097b73 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "At least two standard base cabinets are required" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Chimney" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.runPanel.equalizeNeedsTwo" -msgstr "標準ベースキャビネットが 2 つ以上必要です" +msgid "node.chimney.label" +msgstr "煙突" +# Source-Hash: dc393661f0038c2d # Review: required -# Source-Hash: 61f15ae24419430c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The available run width cannot satisfy the cabinet width limits" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Above Ridge" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.equalizeNoFit" -msgstr "列の空き幅ではキャビネットの幅の制限を満たせません" +msgid "node.chimney.panel.aboveRidge" +msgstr "棟上の高さ" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 7617bb3b455dcdda -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equalize widths" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.equalizeWidths" -msgstr "幅を揃える" +msgid "node.chimney.panel.actions" +msgstr "操作" +# Source-Hash: 7ceade8f25b58fe9 # Review: required -# Source-Hash: ad8c948d883a0c9d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{side, select, left {Left: {width} mm} other {Right: {width} mm}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.fillerPlanSide" -msgstr "{side, select, left {左:{width} mm} other {右:{width} mm}}" +msgid "node.chimney.panel.back" +msgstr "戻る" +# Source-Hash: 0d42509b34b05dec # Review: required -# Source-Hash: 47ccd8c8b04475cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish & align" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bands" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.finishAlign" -msgstr "仕上げと整列" +msgid "node.chimney.panel.bands" +msgstr "帯" +# Source-Hash: d52b53241789ee63 # Review: required -# Source-Hash: 855892e18c74153a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finished back" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.finishedBack" -msgstr "背面仕上げ" +msgid "node.chimney.panel.cap" +msgstr "キャップ" +# Source-Hash: 95169058fec6db14 # Review: required -# Source-Hash: 7ab47aea30c73663 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finished exposed ends" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Chimney" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.finishedExposedEnds" -msgstr "見える側面の仕上げ" +msgid "node.chimney.panel.chimney" +msgstr "煙突" +# Source-Hash: b619f366d2a1dfda # Review: required -# Source-Hash: c9356f25caf33eec -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fits 50–150 mm gaps at run ends beside perpendicular walls." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Chimney Type" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.fits50150MmGapsAt" -msgstr "直交する壁際の列端にある 50〜150 mm の隙間を埋めます。" +msgid "node.chimney.panel.chimneyType" +msgstr "煙突の種類" +# Source-Hash: 6786ac75cbe9af57 # Review: required -# Source-Hash: b6f541bc28e38d2f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fit wall fillers" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corbeled" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.fitWallFillers" -msgstr "壁側フィラーを合わせる" +msgid "node.chimney.panel.corbeled" +msgstr "持ち送り" +# Source-Hash: 89eba9f077fba348 # Review: required -# Source-Hash: 2af738f010ce28f0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fronts" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner Bevel" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.fronts" -msgstr "前面" +msgid "node.chimney.panel.cornerBevel" +msgstr "角の面取り" +# Source-Hash: 8a4beb9a57edc26e # Review: required -# Source-Hash: 58884f99d64e6d00 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handles" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Count" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.handles" -msgstr "取っ手" +msgid "node.chimney.panel.count" +msgstr "数" +# Source-Hash: f8ba7d73d3006d57 # Review: required -# Source-Hash: d73589d7c04b1121 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height preset" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.heightPreset" -msgstr "高さプリセット" +msgid "node.chimney.panel.cricket" +msgstr "クリケット" +# Source-Hash: 14144df9e1364eea # Review: required -# Source-Hash: 590bfdd02dcdb857 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hole" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cutout Offset" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.hole" -msgstr "穴" +msgid "node.chimney.panel.cutoutOffset" +msgstr "開口のオフセット" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: 3db1dea825785a30 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inset" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.inset" -msgstr "埋め込み" +msgid "node.chimney.panel.delete" +msgstr "削除" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: 2997c230c529590d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Island & Bar" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.islandBar" -msgstr "アイランドとバー" +msgid "node.chimney.panel.depth" +msgstr "奥行き" +# Source-Hash: 016d8e70618916d4 # Review: required -# Source-Hash: a74f10dadc92c8bb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchen run" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diameter" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.kitchenRun" -msgstr "キッチン列" +msgid "node.chimney.panel.diameter" +msgstr "直径" +# Source-Hash: 3cd71355956a1821 # Review: required -# Source-Hash: 103e15b39c909210 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Knob" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.knob" -msgstr "つまみ" +msgid "node.chimney.panel.double" +msgstr "両開き" +# Source-Hash: 150340cd05f4a6dd # Review: required -# Source-Hash: f365c6b6dd9ebab9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Extent" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.left" -msgstr "左" +msgid "node.chimney.panel.extent" +msgstr "範囲" +# Source-Hash: 9cab4d4c95f63cdd # Review: required -# Source-Hash: 3c88a1840043e15a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match base heights, backs, reveals and handles. Align upper cabinets; preserve tall appliances and custom compartments." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.matchBaseHeightsBacksRevealsAnd" -msgstr "ベースの高さ・背面・目地・取っ手を揃え、上部キャビネットを整列します。背の高い家電とカスタム区画はそのまま残します。" +msgid "node.chimney.panel.flat" +msgstr "陸屋根" +# Source-Hash: f817c09ef0bb6d69 # Review: required -# Source-Hash: b112e31fe44cc94b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Metric · 600 mm" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flues" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.metricProfile" -msgstr "メートル法 · 600 mm" +msgid "node.chimney.panel.flues" +msgstr "煙道" +# Source-Hash: a3c10560fa3c1612 # Review: required -# Source-Hash: 4739f6315c5e8680 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Module {number}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Footprint" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.moduleNumber" -msgstr "モジュール {number}" +msgid "node.chimney.panel.footprint" +msgstr "フットプリント" +# Source-Hash: e360f89d3c0ec456 # Review: required -# Source-Hash: b8801184e07e4815 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Modules" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.modules" -msgstr "モジュール" +msgid "node.chimney.panel.front" +msgstr "前面" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 81d365ccef73068c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.mounting" -msgstr "取り付け方法" +msgid "node.chimney.panel.height" +msgstr "高さ" +# Source-Hash: 5b490bc19dddf201 # Review: required -# Source-Hash: a3914bd96488175c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No eligible module" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hollow Depth" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.noEligibleModule" -msgstr "対象のモジュールがありません" +msgid "node.chimney.panel.hollowDepth" +msgstr "くぼみの深さ" +# Source-Hash: 643687bc3adaac76 # Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" +#: packages/nodes/src/chimney/panel.tsx +#, fuzzy +msgid "node.chimney.panel.length" +msgstr "長さ" + # Source-Hash: f2953d2931e36d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "None" -#: packages/nodes/src/cabinet/run-panel.tsx +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.none" +msgid "node.chimney.panel.none" msgstr "なし" +# Source-Hash: 0f0e13abf9b2bb67 # Review: required -# Source-Hash: 9c215dc512e57fa4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overlay" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Offset" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.overlay" -msgstr "かぶせ" +msgid "node.chimney.panel.offset" +msgstr "オフセット" +# Source-Hash: 88540def2ce16ac5 # Review: required -# Source-Hash: 49fb05dfafd6001d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Plinth height" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overhang" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.plinthHeight" -msgstr "台輪の高さ" +msgid "node.chimney.panel.overhang" +msgstr "張り出し" +# Source-Hash: 6ce059aee1386f72 # Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panels" +#: packages/nodes/src/chimney/panel.tsx +#, fuzzy +msgid "node.chimney.panel.panels" +msgstr "パネル" + # Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Position" -#: packages/nodes/src/cabinet/run-panel.tsx +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.position" +msgid "node.chimney.panel.position" msgstr "位置" +# Source-Hash: f29fef1beeb25f22 # Review: required -# Source-Hash: efca749fc4463623 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised Arch" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangular" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.raisedArch" -msgstr "アーチ型" +msgid "node.chimney.panel.rectangular" +msgstr "長方形" +# Source-Hash: 01989595ee7c1dc0 # Review: required -# Source-Hash: 5d6956c21fde6418 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reveal gap" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.revealGap" -msgstr "目地幅" +msgid "node.chimney.panel.rotation" +msgstr "回転" +# Source-Hash: ad0457800a1f0eb4 # Review: required -# Source-Hash: b34d5ee0f218221d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.right" -msgstr "右" +msgid "node.chimney.panel.round" +msgstr "丸" +# Source-Hash: 8c6e3985459dacf9 # Review: required -# Source-Hash: e022da49ae8b4aef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Seating overhang" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.seatingOverhang" -msgstr "座席側の張り出し" +msgid "node.chimney.panel.shoulder" +msgstr "ショルダー" +# Source-Hash: 84b9195c73dd7a67 # Review: required -# Source-Hash: 5b68e435b7210876 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaker" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Side Margin" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.shaker" -msgstr "シェーカー" +msgid "node.chimney.panel.sideMargin" +msgstr "側面の余白" + +# Source-Hash: a05a390ae205fdd8 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Simple" +#: packages/nodes/src/chimney/panel.tsx +#, fuzzy +msgid "node.chimney.panel.simple" +msgstr "シンプル" + +# Source-Hash: 62ab2eb3c775da95 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single" +#: packages/nodes/src/chimney/panel.tsx +#, fuzzy +msgid "node.chimney.panel.single" +msgstr "片開き" + +# Source-Hash: f6998707123fe72d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sloped" +#: packages/nodes/src/chimney/panel.tsx +#, fuzzy +msgid "node.chimney.panel.sloped" +msgstr "傾斜" +# Source-Hash: e4698e83d02beb6c # Review: required -# Source-Hash: cba29b18ce666b0a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shared Plinth & Countertop" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spacing" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.sharedPlinthCountertop" -msgstr "共通の台輪とカウンター" +msgid "node.chimney.panel.spacing" +msgstr "間隔" +# Source-Hash: 39287346366fc206 # Review: required -# Source-Hash: f7d577c4064c16ff -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show countertop" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.showCountertop" -msgstr "カウンターを表示" +msgid "node.chimney.panel.square" +msgstr "正方形" +# Source-Hash: 2c6b1cf17a973d67 # Review: required -# Source-Hash: 5d98e04dfd2e0a83 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show plinth" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stepped" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.showPlinth" -msgstr "台輪を表示" +msgid "node.chimney.panel.stepped" +msgstr "段状" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: 8775bc8dc9593964 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.slab" -msgstr "スラブ" +msgid "node.chimney.panel.style" +msgstr "スタイル" +# Source-Hash: f86f1f22230596b7 # Review: required -# Source-Hash: 5bdc0a959203c52e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Source module" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tapered" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.sourceModule" -msgstr "元のモジュール" +msgid "node.chimney.panel.tapered" +msgstr "テーパー" +# Source-Hash: fdbb503f0941bd56 # Review: required -# Source-Hash: e4698e83d02beb6c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spacing" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.spacing" -msgstr "間隔" +msgid "node.chimney.panel.thickness" +msgstr "厚さ" +# Source-Hash: 14b162761ce18fe9 # Review: required -# Source-Hash: 40e3105cbe68d163 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard dimensions" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Offset" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.standardDimensions" -msgstr "標準寸法" +msgid "node.chimney.panel.topOffset" +msgstr "上部のオフセット" +# Source-Hash: 1a5ccd607c400d76 # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall Thickness" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.style" -msgstr "スタイル" +msgid "node.chimney.panel.wallThickness" +msgstr "壁厚" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: e9d7ad9851d476d9 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# English: "{type, select, shelf {Shelf} drawer {Drawer} door {Door} oven {Oven} microwave {Microwave} dishwasher {Dishwasher} sink {Sink} cooktop_gas {Gas cooktop} cooktop_induction {Induction cooktop} pull_out_pantry {Pull-out pantry} fridge_single {Fridge} fridge_double {Double fridge} fridge_top_freezer {Top-freezer fridge} fridge_bottom_freezer {Bottom-freezer fridge} hood_pyramid {Pyramid hood} hood_curved_glass {Curved glass hood} other {{raw}}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.summaryCompartment" -msgstr "{type, select, shelf {棚板} drawer {引き出し} door {扉} oven {オーブン} microwave {電子レンジ} dishwasher {食洗機} sink {シンク} cooktop_gas {ガスコンロ} cooktop_induction {IHコンロ} pull_out_pantry {引き出し式パントリー} fridge_single {冷蔵庫} fridge_double {両開き冷蔵庫} fridge_top_freezer {上段冷凍冷蔵庫} fridge_bottom_freezer {下段冷凍冷蔵庫} hood_pyramid {ピラミッド型フード} hood_curved_glass {曲面ガラスフード} other {{raw}}}" +msgid "node.chimney.panel.width" +msgstr "幅" +# Source-Hash: abff67400a76e5eb # Review: required -# Source-Hash: 98582c257f149d44 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {{number} compartment} other {{number} compartments}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brick" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.summaryCompartments" -msgstr "{count, plural, other {{number} 区画}}" +msgid "node.chimney.preset.brick" +msgstr "レンガ" +# Source-Hash: f6cbdaa17e989b91 # Review: required -# Source-Hash: 65b1cbba3b92c5b2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Empty" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modern" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.summaryEmpty" -msgstr "空" +msgid "node.chimney.preset.modern" +msgstr "モダン" +# Source-Hash: ad0457800a1f0eb4 # Review: required -# Source-Hash: 5db8b868684cf9f3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tall cabinet" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.summaryTall" -msgstr "トールキャビネット" +msgid "node.chimney.preset.round" +msgstr "丸" +# Source-Hash: 6a06e628257f3393 # Review: required -# Source-Hash: 27644f0497fd9849 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A parametric column with configurable cross-section, base, and capital." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.runPanel.top" -msgstr "上" +msgid "node.column.description" +msgstr "断面、柱脚、柱頭を設定できるパラメトリックな柱。" +# Source-Hash: 3530ac1f4046cd22 # Review: required -# Source-Hash: 88c85283afe0c0bc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unable to finish this kitchen run." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Column" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.runPanel.unableToFinish" -msgstr "このキッチン列を仕上げられません。" +msgid "node.column.label" +msgstr "柱" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 8f668fb3e1a1696a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use {name} as array source" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.useAsArraySource" -msgstr "{name}を配列の元にする" +msgid "node.column.panel.actions" +msgstr "操作" +# Source-Hash: 14b21685d375581a # Review: required -# Source-Hash: 9308a109d017dcd6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use this module as the array source" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A-Frame" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.useThisModuleAsTheArray" -msgstr "このモジュールを配列の元にする" +msgid "node.column.panel.aFrame" +msgstr "A フレーム" +# Source-Hash: 4007d88108e25c2b # Review: required -# Source-Hash: 1ce253a4d11bfa68 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "US · 24 in" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Apply preset..." +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.usProfile" -msgstr "米国 · 24 in" +msgid "node.column.panel.applyPreset" +msgstr "プリセットを適用…" +# Source-Hash: dbfe7c561383c964 # Review: required -# Source-Hash: a2d852b2c5629796 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waterfall ends" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Apply proportion..." +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.waterfallEnds" -msgstr "ウォーターフォールエンド" +msgid "node.column.panel.applyProportion" +msgstr "比率を適用…" -# Source-Hash: ffc8d80e438f40b7 +# Source-Hash: 1f3fd938f0b26c9f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "An editable module inside a modular cabinet run." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Depth" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.cabinetModule.description" -msgstr "モジュール式キャビネットの列の中にある編集可能なモジュール。" +msgid "node.column.panel.bottomDepth" +msgstr "下部の奥行き" + +# Source-Hash: 85576e19cd3da914 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Height" +#: packages/nodes/src/column/panel.tsx +#, fuzzy +msgid "node.column.panel.bottomHeight" +msgstr "下部の高さ" -# Source-Hash: d5c19ec529e26a98 +# Source-Hash: 4df0bbb04744a810 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet Module" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.cabinetModule.label" -msgstr "キャビネットモジュール" +msgid "node.column.panel.bottomSpread" +msgstr "下部の開き" -# Source-Hash: 4d6d5e9439f40e9b +# Source-Hash: 67479fecb980a441 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A polygon-bounded ceiling surface that hosts ceiling-mounted items." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Step Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.description" -msgstr "多角形で囲まれた天井面。天井付けのアイテムを取り付けられます。" +msgid "node.column.panel.bottomStepSpread" +msgstr "下部段の広がり" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: 6ea977c42202ca24 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Tiers" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.label" -msgstr "天井" +msgid "node.column.panel.bottomTiers" +msgstr "下部の段数" -# Source-Hash: 659e6b799ad7c27d +# Source-Hash: 709ca788827f8a94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Hole" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.addHole" -msgstr "開口を追加" +msgid "node.column.panel.bottomWidth" +msgstr "下部の幅" -# Source-Hash: 8332ab41e22958f1 +# Source-Hash: 39d33008c81fc075 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Area" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box Frame" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.area" -msgstr "面積" +msgid "node.column.panel.boxFrame" +msgstr "ボックスフレーム" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: 381b1f481f747677 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brace Depth" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.auto" -msgstr "自動" +msgid "node.column.panel.braceDepth" +msgstr "ブレースの奥行き" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: 8509b09b4ecdd6b6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brace Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.ceiling" -msgstr "天井" +msgid "node.column.panel.braceWidth" +msgstr "ブレースの幅" -# Source-Hash: b2a1b3bc9676fe05 +# Source-Hash: 08558dd786f45281 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom height" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bulge" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.customHeight" -msgstr "カスタムの高さ" +msgid "node.column.panel.bulge" +msgstr "ふくらみ" -# Source-Hash: 4e4f1a24e4a9d61e +# Source-Hash: 663b9a9e6a469b02 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut opening" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bulged" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.cutOpening" -msgstr "開口を切る" +msgid "node.column.panel.bulged" +msgstr "ふくらみ型" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Column" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.done" -msgstr "完了" +msgid "node.column.panel.column" +msgstr "柱" -# Source-Hash: a5c2353769b603d5 +# Source-Hash: ca0a856f04460bd5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows level" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connector Plates" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.followsLevel" -msgstr "階層に従う" +msgid "node.column.panel.connectorPlates" +msgstr "接合プレート" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.height" -msgstr "高さ" +msgid "node.column.panel.delete" +msgstr "削除" -# Source-Hash: 703f56131ac45e60 +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High (3.0m)" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.high30m" -msgstr "高(3.0m)" +msgid "node.column.panel.depth" +msgstr "奥行き" -# Source-Hash: 4ed40bdab397fe22 +# Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High (9'0\")" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.high90" -msgstr "高(9'0\")" +msgid "node.column.panel.dimensions" +msgstr "寸法" -# Source-Hash: 34504c6ca6445e76 +# Source-Hash: b963a08f0d540014 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Holes" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edge Softness" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.holes" -msgstr "開口" +msgid "node.column.panel.edgeSoftness" +msgstr "角の丸み" -# Source-Hash: 6e68b62d2aa611a4 +# Source-Hash: 82b3db356639ef92 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Info" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ends" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.info" -msgstr "情報" +msgid "node.column.panel.ends" +msgstr "端部" -# Source-Hash: 6925a008b1924062 +# Source-Hash: 646c3cd99df3e285 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Limited by the level to {height} — raise the level height for a taller ceiling." -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.limitedByLevel" -msgstr "階層により {height} までに制限されます。天井を高くするには階層の高さを上げてください。" +msgid "node.column.panel.endWidth" +msgstr "端部の幅" -# Source-Hash: c7410ff087be3a61 +# Source-Hash: 02e229bca2a2b5f1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low (2.4m)" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fork Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.low24m" -msgstr "低(2.4m)" +msgid "node.column.panel.forkSpread" +msgstr "分岐の開き" -# Source-Hash: a59425761b7c9084 +# Source-Hash: fdebfac05413abcf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low (8'0\")" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Heavy" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.low80" -msgstr "低(8'0\")" +msgid "node.column.panel.heavy" +msgstr "重厚" + +# Source-Hash: 646ef0fbcbc58edf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/column/panel.tsx +#, fuzzy +msgid "node.column.panel.height" +msgstr "高さ" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 957fae84ed52a2e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height and footprint are controlled by the lean-to extension. Rotate or change the support style here; resize from the parent lean-to." +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.move" -msgstr "移動" +msgid "node.column.panel.heightAndFootprintAreControlledBy" +msgstr "高さと設置面積は片流れ増築で決まります。ここでは回転と支柱スタイルの変更ができ、サイズは親の片流れ増築で変更します。" -# Source-Hash: 1d2dafb0d8f26ed5 +# Source-Hash: bb851e93088b73a2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No holes" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hourglass" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.noHoles" -msgstr "開口なし" +msgid "node.column.panel.hourglass" +msgstr "砂時計型" -# Source-Hash: 24f5fbd158798197 +# Source-Hash: 9cc75129edee59ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard (2.5m)" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "K Brace" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.standard25m" -msgstr "標準(2.5m)" +msgid "node.column.panel.kBrace" +msgstr "K ブレース" -# Source-Hash: 73cf00cf1900c22b +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard (8'6\")" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.standard86" -msgstr "標準(8'6\")" +msgid "node.column.panel.move" +msgstr "移動" -# Source-Hash: 065626498678bc5d +# Source-Hash: 6dc190abd3f22787 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Taller than this level ({available} available). Raise the level height first." -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Neck Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.ceiling.panel.tallerThanLevel" -msgstr "この階層より高すぎます(使用可能 {available})。先に階層の高さを上げてください。" +msgid "node.column.panel.neckWidth" +msgstr "くびれの幅" -# Source-Hash: ea12ce3c2b3588e7 +# Source-Hash: 7dba7ed55eeba18f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical masonry stack on a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.description" -msgstr "屋根面上の組積造の煙突。" +msgid "node.column.panel.noBottom" +msgstr "下部なし" -# Source-Hash: 95169058fec6db14 +# Source-Hash: 682d71815bb20e94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Chimney" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No Top" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.label" -msgstr "煙突" +msgid "node.column.panel.noTop" +msgstr "上部なし" +# Source-Hash: 4da8688437f64db8 # Review: required -# Source-Hash: dc393661f0038c2d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Above Ridge" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plinth Thickness" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.aboveRidge" -msgstr "棟上の高さ" +msgid "node.column.panel.plinthThickness" +msgstr "台座の厚さ" +# Source-Hash: 0bf453b4882c663c # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Portal Frame" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.actions" -msgstr "操作" +msgid "node.column.panel.portalFrame" +msgstr "門型フレーム" +# Source-Hash: 441f7f652ea6a0d8 # Review: required -# Source-Hash: 7ceade8f25b58fe9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preset" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.back" -msgstr "戻る" +msgid "node.column.panel.preset" +msgstr "プリセット" +# Source-Hash: f29fef1beeb25f22 # Review: required -# Source-Hash: 0d42509b34b05dec -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bands" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangular" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.bands" -msgstr "帯" +msgid "node.column.panel.rectangular" +msgstr "長方形" +# Source-Hash: 23b9d290b165cd49 # Review: required -# Source-Hash: d52b53241789ee63 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ring Pairs" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.cap" -msgstr "キャップ" +msgid "node.column.panel.ringPairs" +msgstr "リングの対数" +# Source-Hash: 8db82d731a19651e # Review: required -# Source-Hash: 95169058fec6db14 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Chimney" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ring Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.chimney" -msgstr "煙突" +msgid "node.column.panel.ringSpread" +msgstr "リングの間隔" +# Source-Hash: bdb524a15d9e1509 # Review: required -# Source-Hash: b619f366d2a1dfda -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Chimney Type" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ring Thickness" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.chimneyType" -msgstr "煙突の種類" +msgid "node.column.panel.ringThickness" +msgstr "リングの厚さ" +# Source-Hash: ad0457800a1f0eb4 # Review: required -# Source-Hash: 6786ac75cbe9af57 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corbeled" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.corbeled" -msgstr "持ち送り" +msgid "node.column.panel.round" +msgstr "丸" +# Source-Hash: baa84a2d17095dcf # Review: required -# Source-Hash: 89eba9f077fba348 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner Bevel" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round Band Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.cornerBevel" -msgstr "角の面取り" +msgid "node.column.panel.roundBandWidth" +msgstr "丸帯の幅" +# Source-Hash: 5f1f67fb0ca59a6d # Review: required -# Source-Hash: 8a4beb9a57edc26e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Count" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rounded Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.count" -msgstr "数" +msgid "node.column.panel.roundedBottom" +msgstr "丸い下部" +# Source-Hash: 446816980ed0da27 # Review: required -# Source-Hash: f8ba7d73d3006d57 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rounded Top" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.cricket" -msgstr "クリケット" +msgid "node.column.panel.roundedTop" +msgstr "丸い上部" +# Source-Hash: 9e554c26be80f0d0 # Review: required -# Source-Hash: 14144df9e1364eea -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cutout Offset" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segment Twist" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.cutoutOffset" -msgstr "開口のオフセット" +msgid "node.column.panel.segmentTwist" +msgstr "セグメントのねじれ" + +# Source-Hash: 4fc63ad21de30103 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft" +#: packages/nodes/src/column/panel.tsx +#, fuzzy +msgid "node.column.panel.shaft" +msgstr "シャフト" +# Source-Hash: 9bc3a704a9a96b3a # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Corner Radius" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.delete" -msgstr "削除" +msgid "node.column.panel.shaftCornerRadius" +msgstr "柱身の角半径" +# Source-Hash: 3dab61aeb47e504d # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.depth" -msgstr "奥行き" +msgid "node.column.panel.shaftWidth" +msgstr "柱身の幅" +# Source-Hash: 85ea1d3c8b749680 # Review: required -# Source-Hash: 016d8e70618916d4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diameter" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.diameter" -msgstr "直径" +msgid "node.column.panel.shape" +msgstr "形状" +# Source-Hash: 49a2ce13016d4073 # Review: required -# Source-Hash: 3cd71355956a1821 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Short / Stout" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.double" -msgstr "両開き" +msgid "node.column.panel.shortStout" +msgstr "短く太い" +# Source-Hash: 4637a9a61638cc66 # Review: required -# Source-Hash: 150340cd05f4a6dd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Extent" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Simple Block Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.extent" -msgstr "範囲" +msgid "node.column.panel.simpleBlockBottom" +msgstr "シンプルなブロック下部" +# Source-Hash: 9278f9b4a48208b0 # Review: required -# Source-Hash: 9cab4d4c95f63cdd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Simple Top" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.flat" -msgstr "陸屋根" +msgid "node.column.panel.simpleTop" +msgstr "シンプルな上部" +# Source-Hash: 9099890734ae1238 # Review: required -# Source-Hash: f817c09ef0bb6d69 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flues" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single Strut" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.flues" -msgstr "煙道" +msgid "node.column.panel.singleStrut" +msgstr "単一支柱" +# Source-Hash: d87ce271009ce063 # Review: required -# Source-Hash: a3c10560fa3c1612 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Footprint" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slender" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.footprint" -msgstr "フットプリント" +msgid "node.column.panel.slender" +msgstr "細身" +# Source-Hash: 39287346366fc206 # Review: required -# Source-Hash: e360f89d3c0ec456 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.front" -msgstr "前面" +msgid "node.column.panel.square" +msgstr "正方形" +# Source-Hash: 2dc84759d8df709d # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square Plinth Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.height" -msgstr "高さ" +msgid "node.column.panel.squarePlinthBottom" +msgstr "角台座の下部" +# Source-Hash: d998c212030bc7c2 # Review: required -# Source-Hash: 5b490bc19dddf201 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hollow Depth" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.hollowDepth" -msgstr "くぼみの深さ" +msgid "node.column.panel.standard" +msgstr "標準" +# Source-Hash: 01a6393135e0fb10 # Review: required -# Source-Hash: 643687bc3adaac76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stepped Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.length" -msgstr "長さ" +msgid "node.column.panel.steppedBottom" +msgstr "段付き下部" +# Source-Hash: 3d7e443797d4146e # Review: required -# Source-Hash: f2953d2931e36d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stepped Top" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.none" -msgstr "なし" +msgid "node.column.panel.steppedTop" +msgstr "段付き上部" +# Source-Hash: 4ee35f740730ae87 # Review: required -# Source-Hash: 0f0e13abf9b2bb67 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Offset" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.offset" -msgstr "オフセット" +msgid "node.column.panel.straight" +msgstr "直進" +# Source-Hash: 6063ae2877faa35d # Review: required -# Source-Hash: 88540def2ce16ac5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overhang" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Taper" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.overhang" -msgstr "張り出し" +msgid "node.column.panel.taper" +msgstr "テーパー" +# Source-Hash: f86f1f22230596b7 # Review: required -# Source-Hash: 6ce059aee1386f72 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panels" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tapered" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.panels" -msgstr "パネル" +msgid "node.column.panel.tapered" +msgstr "テーパー" +# Source-Hash: 3e7ec47626ee3f22 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Depth" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.position" -msgstr "位置" +msgid "node.column.panel.topDepth" +msgstr "上部の奥行き" +# Source-Hash: 0ca9047731784f56 # Review: required -# Source-Hash: f29fef1beeb25f22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangular" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Height" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.rectangular" -msgstr "長方形" +msgid "node.column.panel.topHeight" +msgstr "上部の高さ" +# Source-Hash: 3d8a2be83b5b536a # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.rotation" -msgstr "回転" +msgid "node.column.panel.topSpread" +msgstr "上部の開き" + +# Source-Hash: f4ae0dc639dbc220 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Step Spread" +#: packages/nodes/src/column/panel.tsx +#, fuzzy +msgid "node.column.panel.topStepSpread" +msgstr "上部段の広がり" +# Source-Hash: 8acc4e843934b086 # Review: required -# Source-Hash: ad0457800a1f0eb4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Tiers" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.round" -msgstr "丸" +msgid "node.column.panel.topTiers" +msgstr "上部の段数" +# Source-Hash: a50eb6400611a57c # Review: required -# Source-Hash: 8c6e3985459dacf9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.shoulder" -msgstr "ショルダー" +msgid "node.column.panel.topWidth" +msgstr "上部の幅" +# Source-Hash: f425799b82e085ed # Review: required -# Source-Hash: 84b9195c73dd7a67 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Side Margin" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transform" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.sideMargin" -msgstr "側面の余白" +msgid "node.column.panel.transform" +msgstr "変形" +# Source-Hash: 952fd1ef187c6646 # Review: required -# Source-Hash: a05a390ae205fdd8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Simple" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trestle" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.simple" -msgstr "シンプル" +msgid "node.column.panel.trestle" +msgstr "架台" +# Source-Hash: 7430dad59aaf98f4 # Review: required -# Source-Hash: 62ab2eb3c775da95 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tripod" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.single" -msgstr "片開き" +msgid "node.column.panel.tripod" +msgstr "三脚" +# Source-Hash: 0db559f22647ec73 # Review: required -# Source-Hash: f6998707123fe72d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sloped" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Twist Segments" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.sloped" -msgstr "傾斜" +msgid "node.column.panel.twistSegments" +msgstr "ねじれのセグメント数" +# Source-Hash: 8038a34ffebf4932 # Review: required -# Source-Hash: e4698e83d02beb6c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spacing" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.spacing" -msgstr "間隔" +msgid "node.column.panel.vertical" +msgstr "垂直" +# Source-Hash: f24cc343d79acc10 # Review: required -# Source-Hash: 39287346366fc206 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "V Support" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.square" -msgstr "正方形" +msgid "node.column.panel.vSupport" +msgstr "V 字支柱" +# Source-Hash: 44dda7136b93c8ee # Review: required -# Source-Hash: 2c6b1cf17a973d67 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stepped" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.stepped" -msgstr "段状" +msgid "node.column.panel.waist" +msgstr "スラブ式" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.style" -msgstr "スタイル" +msgid "node.column.panel.width" +msgstr "幅" +# Source-Hash: 4e6640dfff42cea4 # Review: required -# Source-Hash: f86f1f22230596b7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tapered" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "X Brace" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.tapered" -msgstr "テーパー" +msgid "node.column.panel.xBrace" +msgstr "X ブレース" +# Source-Hash: fefc9b1cfb26b5a8 # Review: required -# Source-Hash: fdbb503f0941bd56 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Yaw" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.thickness" -msgstr "厚さ" +msgid "node.column.panel.yaw" +msgstr "ヨー" +# Source-Hash: 86259690e332b66d # Review: required -# Source-Hash: 14b162761ce18fe9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Offset" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Y Support" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.chimney.panel.topOffset" -msgstr "上部のオフセット" +msgid "node.column.panel.ySupport" +msgstr "Y 字支柱" +# Source-Hash: 4d3a89de7073d38d # Review: required -# Source-Hash: 1a5ccd607c400d76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Thickness" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A {size} deck post stands no taller than {limit} (IRC Table R507.4, by species and the area it carries): check it, or use the next size up." +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.chimney.panel.wallThickness" -msgstr "壁厚" +msgid "node.column.postSection.aSizeDeckPostStandsNo" +msgstr "{size} のデッキ支柱の高さは最大 {limit} です(IRC Table R507.4、樹種と負担面積による)。確認するか、1 つ上のサイズを使ってください。" +# Source-Hash: 9e9715d52410c86f # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.chimney.panel.width" -msgstr "幅" +msgid "node.column.postSection.custom" +msgstr "カスタム" +# Source-Hash: 31f74f6b8e7f077e # Review: required -# Source-Hash: abff67400a76e5eb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Brick" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit to the beam over it ({height})" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.chimney.preset.brick" -msgstr "レンガ" +msgid "node.column.postSection.fitToTheBeamOverIt" +msgstr "上の梁に合わせる({height})" +# Source-Hash: f09c0bf0ea50fc47 # Review: required -# Source-Hash: f6cbdaa17e989b91 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Modern" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit to the ceiling plane ({height})" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.chimney.preset.modern" -msgstr "モダン" +msgid "node.column.postSection.fitToTheCeilingPlane" +msgstr "天井面に合わせる({height})" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: ad0457800a1f0eb4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.chimney.preset.round" -msgstr "丸" +msgid "node.column.postSection.height" +msgstr "高さ" -# Source-Hash: 6a06e628257f3393 +# Source-Hash: b1778491849d76d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A parametric column with configurable cross-section, base, and capital." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keep its shape and style it as a column" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.column.description" -msgstr "断面、柱脚、柱頭を設定できるパラメトリックな柱。" +msgid "node.column.postSection.keepItsShapeAndStyleIt" +msgstr "形状を保ったまま柱としてスタイルを設定" -# Source-Hash: 3530ac1f4046cd22 +# Source-Hash: 151f47e85cf7cc8b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Column" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Make it a column" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.column.label" -msgstr "柱" +msgid "node.column.postSection.makeItAColumn" +msgstr "柱にする" +# Source-Hash: 5cc981e79d737694 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.column.panel.actions" -msgstr "操作" +msgid "node.column.postSection.post" +msgstr "支柱" +# Source-Hash: 64ed304f3773f93d # Review: required -# Source-Hash: 14b21685d375581a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A-Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Treated" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.column.panel.aFrame" -msgstr "A フレーム" +msgid "node.column.postSection.treated" +msgstr "防腐処理" +# Source-Hash: 5c362de43a2cbac1 # Review: required -# Source-Hash: 4007d88108e25c2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Apply preset..." -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Untreated" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.column.panel.applyPreset" -msgstr "プリセットを適用…" +msgid "node.column.postSection.untreated" +msgstr "未処理" +# Source-Hash: bf2baf3d7b55f0df # Review: required -# Source-Hash: dbfe7c561383c964 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Apply proportion..." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A-Frame Support" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.applyProportion" -msgstr "比率を適用…" +msgid "node.column.preset.aFrameSupport" +msgstr "A フレーム支柱" +# Source-Hash: 51cf77bb359cee43 # Review: required -# Source-Hash: 1f3fd938f0b26c9f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight Round" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.bottomDepth" -msgstr "下部の奥行き" +msgid "node.column.preset.basicPillar" +msgstr "円柱" +# Source-Hash: 39d33008c81fc075 # Review: required -# Source-Hash: 85576e19cd3da914 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box Frame" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.bottomHeight" -msgstr "下部の高さ" +msgid "node.column.preset.boxFrameSupport" +msgstr "ボックスフレーム" +# Source-Hash: 4f22058e862d1f81 # Review: required -# Source-Hash: 4df0bbb04744a810 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Spread" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Soft Bulged" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.bottomSpread" -msgstr "下部の開き" +msgid "node.column.preset.bulgedPillar" +msgstr "ゆるいふくらみ" +# Source-Hash: bb851e93088b73a2 # Review: required -# Source-Hash: 67479fecb980a441 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Step Spread" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hourglass" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.bottomStepSpread" -msgstr "下部段の広がり" +msgid "node.column.preset.hourglassPillar" +msgstr "砂時計型" +# Source-Hash: 9cc75129edee59ad # Review: required -# Source-Hash: 6ea977c42202ca24 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Tiers" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "K Brace" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.bottomTiers" -msgstr "下部の段数" +msgid "node.column.preset.kBraceSupport" +msgstr "K ブレース" +# Source-Hash: 0bf453b4882c663c # Review: required -# Source-Hash: 709ca788827f8a94 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Portal Frame" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.bottomWidth" -msgstr "下部の幅" +msgid "node.column.preset.portalFrameSupport" +msgstr "門型フレーム" +# Source-Hash: 9099890734ae1238 # Review: required -# Source-Hash: 39d33008c81fc075 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box Frame" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single Strut" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.boxFrame" -msgstr "ボックスフレーム" +msgid "node.column.preset.singleStrutSupport" +msgstr "単一支柱" +# Source-Hash: 0c13af329b9b57cd # Review: required -# Source-Hash: 381b1f481f747677 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Brace Depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square Block" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.braceDepth" -msgstr "ブレースの奥行き" +msgid "node.column.preset.squarePillar" +msgstr "角柱" +# Source-Hash: 4c294bad84924665 # Review: required -# Source-Hash: 8509b09b4ecdd6b6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Brace Width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tapered Round" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.braceWidth" -msgstr "ブレースの幅" +msgid "node.column.preset.taperedPillar" +msgstr "テーパー円柱" +# Source-Hash: 360e405bfd74a379 # Review: required -# Source-Hash: 08558dd786f45281 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bulge" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trestle Frame" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.bulge" -msgstr "ふくらみ" +msgid "node.column.preset.trestleSupport" +msgstr "架台フレーム" +# Source-Hash: 4589103259b4fc4d # Review: required -# Source-Hash: 663b9a9e6a469b02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bulged" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tripod Support" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.bulged" -msgstr "ふくらみ型" +msgid "node.column.preset.tripodSupport" +msgstr "三脚支柱" +# Source-Hash: f24cc343d79acc10 # Review: required -# Source-Hash: 3530ac1f4046cd22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Column" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "V Support" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.column" -msgstr "柱" +msgid "node.column.preset.vFrameSupport" +msgstr "V 字支柱" +# Source-Hash: 4e6640dfff42cea4 # Review: required -# Source-Hash: ca0a856f04460bd5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connector Plates" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "X Brace" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.connectorPlates" -msgstr "接合プレート" +msgid "node.column.preset.xBraceSupport" +msgstr "X ブレース" +# Source-Hash: 86259690e332b66d # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Y Support" #: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.column.panel.delete" -msgstr "削除" +msgid "node.column.preset.yFrameSupport" +msgstr "Y 字支柱" +# Source-Hash: 895766ad1b766c2e # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Associative linear, curved, circular, angular, or coordinate plan dimension." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.panel.depth" -msgstr "奥行き" +msgid "node.constructionDimension.description" +msgstr "連動する直線・曲線・円・角度・座標の平面寸法。" +# Source-Hash: 6875b60ee8a7cc3b # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Construction Dimension" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.panel.dimensions" -msgstr "寸法" +msgid "node.constructionDimension.label" +msgstr "施工寸法" +# Source-Hash: 61a6c6b9bc29c4f8 # Review: required -# Source-Hash: b963a08f0d540014 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edge Softness" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Left" +#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.column.panel.edgeSoftness" -msgstr "角の丸み" +msgid "node.cornerRadius.bottomLeft" +msgstr "左下" +# Source-Hash: c5368accab136fa6 # Review: required -# Source-Hash: 82b3db356639ef92 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ends" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Right" +#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.column.panel.ends" -msgstr "端部" +msgid "node.cornerRadius.bottomRight" +msgstr "右下" +# Source-Hash: c8f86af3f03af6c7 # Review: required -# Source-Hash: 646c3cd99df3e285 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Left" +#: packages/nodes/src/door/panel.tsx +#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.column.panel.endWidth" -msgstr "端部の幅" +msgid "node.cornerRadius.topLeft" +msgstr "左上" +# Source-Hash: 0ead7f1ffdbbd892 # Review: required -# Source-Hash: 02e229bca2a2b5f1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fork Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Right" +#: packages/nodes/src/door/panel.tsx +#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.column.panel.forkSpread" -msgstr "分岐の開き" +msgid "node.cornerRadius.topRight" +msgstr "右上" + +# Source-Hash: a276c9693f01dec7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Louvered roof lantern with a dome or pyramid cap and optional finial." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.cupola.description" +msgstr "ドームまたはピラミッドの笠と任意の頂華を持つルーバー付き屋根ランタン。" +# Source-Hash: e679dd19f96eba0a # Review: required -# Source-Hash: fdebfac05413abcf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Heavy" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cupola" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.panel.heavy" -msgstr "重厚" +msgid "node.cupola.label" +msgstr "キューポラ" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.height" -msgstr "高さ" +msgid "node.cupola.panel.actions" +msgstr "操作" +# Source-Hash: e679dd19f96eba0a # Review: required -# Source-Hash: 957fae84ed52a2e3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height and footprint are controlled by the lean-to extension. Rotate or change the support style here; resize from the parent lean-to." -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cupola" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.heightAndFootprintAreControlledBy" -msgstr "高さと設置面積は片流れ増築で決まります。ここでは回転と支柱スタイルの変更ができ、サイズは親の片流れ増築で変更します。" +msgid "node.cupola.panel.cupola" +msgstr "キューポラ" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: bb851e93088b73a2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hourglass" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.hourglass" -msgstr "砂時計型" +msgid "node.cupola.panel.delete" +msgstr "削除" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: 9cc75129edee59ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "K Brace" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.kBrace" -msgstr "K ブレース" +msgid "node.cupola.panel.depth" +msgstr "奥行き" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.move" -msgstr "移動" +msgid "node.cupola.panel.dimensions" +msgstr "寸法" +# Source-Hash: de47e23eb81efe02 # Review: required -# Source-Hash: 6dc190abd3f22787 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Neck Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dome" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.neckWidth" -msgstr "くびれの幅" +msgid "node.cupola.panel.dome" +msgstr "ドーム" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: 7dba7ed55eeba18f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.noBottom" -msgstr "下部なし" +msgid "node.cupola.panel.duplicate" +msgstr "複製" +# Source-Hash: 1cfe33235b30b1d8 # Review: required -# Source-Hash: 682d71815bb20e94 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No Top" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finial" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.noTop" -msgstr "上部なし" +msgid "node.cupola.panel.finial" +msgstr "フィニアル" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 4da8688437f64db8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Plinth Thickness" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.plinthThickness" -msgstr "台座の厚さ" +msgid "node.cupola.panel.height" +msgstr "高さ" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: 0bf453b4882c663c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Portal Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.portalFrame" -msgstr "門型フレーム" +msgid "node.cupola.panel.move" +msgstr "移動" +# Source-Hash: b5e0cb318d484d0c # Review: required -# Source-Hash: 441f7f652ea6a0d8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preset" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No Finial" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.preset" -msgstr "プリセット" +msgid "node.cupola.panel.noFinial" +msgstr "頂華なし" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: f29fef1beeb25f22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangular" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.rectangular" -msgstr "長方形" +msgid "node.cupola.panel.position" +msgstr "位置" +# Source-Hash: 47587b825e9a696b # Review: required -# Source-Hash: 23b9d290b165cd49 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ring Pairs" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pyramid" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.ringPairs" -msgstr "リングの対数" +msgid "node.cupola.panel.pyramid" +msgstr "ピラミッド" +# Source-Hash: 01989595ee7c1dc0 # Review: required -# Source-Hash: 8db82d731a19651e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ring Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.ringSpread" -msgstr "リングの間隔" +msgid "node.cupola.panel.rotation" +msgstr "回転" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: bdb524a15d9e1509 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ring Thickness" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.ringThickness" -msgstr "リングの厚さ" +msgid "node.cupola.panel.style" +msgstr "スタイル" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: ad0457800a1f0eb4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.column.panel.round" -msgstr "丸" +msgid "node.cupola.panel.width" +msgstr "幅" +# Source-Hash: 5d4ccdf13668fab4 # Review: required -# Source-Hash: baa84a2d17095dcf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round Band Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto elevator cutout" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.column.panel.roundBandWidth" -msgstr "丸帯の幅" +msgid "node.cutout.autoElevator" +msgstr "エレベーターの自動切り抜き" +# Source-Hash: 78aa03576e02dda7 # Review: required -# Source-Hash: 5f1f67fb0ca59a6d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rounded Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto stair cutout" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.column.panel.roundedBottom" -msgstr "丸い下部" +msgid "node.cutout.autoStair" +msgstr "階段の自動切り抜き" +# Source-Hash: e04298381837252f # Review: required -# Source-Hash: 446816980ed0da27 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rounded Top" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.column.panel.roundedTop" -msgstr "丸い上部" +msgid "node.cutout.opening" +msgstr "開口" +# Source-Hash: ce37dbd7a309940b # Review: required -# Source-Hash: 9e554c26be80f0d0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segment Twist" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room cutout" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.column.panel.segmentTwist" -msgstr "セグメントのねじれ" +msgid "node.cutout.room" +msgstr "部屋の切り抜き" +# Source-Hash: b1757d76048706b7 # Review: required -# Source-Hash: 4fc63ad21de30103 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap hinge side" +#: packages/nodes/src/door/actions.tsx #, fuzzy -msgid "node.column.panel.shaft" -msgstr "シャフト" +msgid "node.door.actions.swapHingeSide" +msgstr "丁番側を入れ替え" +# Source-Hash: d8bbb9fdf69726ca # Review: required -# Source-Hash: 9bc3a704a9a96b3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Corner Radius" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap swing side" +#: packages/nodes/src/door/actions.tsx #, fuzzy -msgid "node.column.panel.shaftCornerRadius" -msgstr "柱身の角半径" +msgid "node.door.actions.swapSwingSide" +msgstr "開く向きを入れ替え" +# Source-Hash: 6123b20edb9569de # Review: required -# Source-Hash: 3dab61aeb47e504d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A door cut into a wall. Animated open/close state." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.panel.shaftWidth" -msgstr "柱身の幅" +msgid "node.door.description" +msgstr "壁に設けたドア。開閉アニメーション付き。" +# Source-Hash: 787e10f5db16904e # Review: required -# Source-Hash: 85ea1d3c8b749680 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.panel.shape" -msgstr "形状" +msgid "node.door.label" +msgstr "ドア" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 49a2ce13016d4073 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Short / Stout" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.shortStout" -msgstr "短く太い" +msgid "node.door.panel.actions" +msgstr "操作" +# Source-Hash: 8337b3213849faca # Review: required -# Source-Hash: 4637a9a61638cc66 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Simple Block Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "+ Add Segment" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.simpleBlockBottom" -msgstr "シンプルなブロック下部" +msgid "node.door.panel.addSegment" +msgstr "+ セグメントを追加" +# Source-Hash: 663175a9c461a96d # Review: required -# Source-Hash: 9278f9b4a48208b0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Simple Top" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.simpleTop" -msgstr "シンプルな上部" +msgid "node.door.panel.all" +msgstr "すべて" +# Source-Hash: 710261f5ffb32617 # Review: required -# Source-Hash: 9099890734ae1238 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single Strut" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arch" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.singleStrut" -msgstr "単一支柱" +msgid "node.door.panel.arch" +msgstr "アーチ" +# Source-Hash: 3715cd54e4775087 # Review: required -# Source-Hash: d87ce271009ce063 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slender" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arch Height" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.slender" -msgstr "細身" +msgid "node.door.panel.archHeight" +msgstr "アーチの高さ" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: 39287346366fc206 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.square" -msgstr "正方形" +msgid "node.door.panel.auto" +msgstr "自動" +# Source-Hash: 8a04486ba122ea7d # Review: required -# Source-Hash: 2dc84759d8df709d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square Plinth Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto follows the wall" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.squarePlinthBottom" -msgstr "角台座の下部" +msgid "node.door.panel.autoFollowsTheWall" +msgstr "自動は壁に合わせます" +# Source-Hash: 387773c8aa2820a4 # Review: required -# Source-Hash: d998c212030bc7c2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar Height" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.standard" -msgstr "標準" +msgid "node.door.panel.barHeight" +msgstr "バーの高さ" +# Source-Hash: 30edd1c180aac9b4 # Review: required -# Source-Hash: 01a6393135e0fb10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stepped Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Columns" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.steppedBottom" -msgstr "段付き下部" +msgid "node.door.panel.columns" +msgstr "列" +# Source-Hash: f533584833a4a7bb # Review: required -# Source-Hash: 3d7e443797d4146e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stepped Top" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Content Padding" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.steppedTop" -msgstr "段付き上部" +msgid "node.door.panel.contentPadding" +msgstr "内側余白" +# Source-Hash: 7a90a42b578f2435 # Review: required -# Source-Hash: 4ee35f740730ae87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner Radius" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.straight" -msgstr "直進" +msgid "node.door.panel.cornerRadius" +msgstr "角の半径" +# Source-Hash: aa0e8e02212091e4 # Review: required -# Source-Hash: 6063ae2877faa35d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Taper" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom: the segments match no style." +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.taper" -msgstr "テーパー" +msgid "node.door.panel.customTheSegmentsMatchNoStyle" +msgstr "カスタム:セグメントがどのスタイルとも一致しません。" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: f86f1f22230596b7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tapered" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.tapered" -msgstr "テーパー" +msgid "node.door.panel.delete" +msgstr "削除" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: 3e7ec47626ee3f22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Depth" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.topDepth" -msgstr "上部の奥行き" +msgid "node.door.panel.depth" +msgstr "奥行き" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: 0ca9047731784f56 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Height" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.topHeight" -msgstr "上部の高さ" +msgid "node.door.panel.dimensions" +msgstr "寸法" +# Source-Hash: 76cd03300faa9b2b # Review: required -# Source-Hash: 3d8a2be83b5b536a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Direction" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.topSpread" -msgstr "上部の開き" +msgid "node.door.panel.direction" +msgstr "方向" +# Source-Hash: c53c3307e2a2a32a # Review: required -# Source-Hash: f4ae0dc639dbc220 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Step Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divider" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.topStepSpread" -msgstr "上部段の広がり" +msgid "node.door.panel.divider" +msgstr "仕切り" +# Source-Hash: 787e10f5db16904e # Review: required -# Source-Hash: 8acc4e843934b086 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Tiers" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.topTiers" -msgstr "上部の段数" +msgid "node.door.panel.door" +msgstr "ドア" +# Source-Hash: 4a0aa7f647e6461b # Review: required -# Source-Hash: a50eb6400611a57c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Closer" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.topWidth" -msgstr "上部の幅" +msgid "node.door.panel.doorCloser" +msgstr "ドアクローザー" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: f425799b82e085ed -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transform" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.transform" -msgstr "変形" +msgid "node.door.panel.duplicate" +msgstr "複製" +# Source-Hash: 65b1cbba3b92c5b2 # Review: required -# Source-Hash: 952fd1ef187c6646 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trestle" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Empty" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.trestle" -msgstr "架台" +msgid "node.door.panel.empty" +msgstr "空" +# Source-Hash: 6982301da2dbe186 # Review: required -# Source-Hash: 7430dad59aaf98f4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tripod" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Enable Handle" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.tripod" -msgstr "三脚" +msgid "node.door.panel.enableHandle" +msgstr "ハンドルを有効化" +# Source-Hash: 2e96ebf9c6e7fe49 # Review: required -# Source-Hash: 0db559f22647ec73 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Twist Segments" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Enable Threshold" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.twistSegments" -msgstr "ねじれのセグメント数" +msgid "node.door.panel.enableThreshold" +msgstr "敷居を有効化" +# Source-Hash: 61f9413d3bbabde7 # Review: required -# Source-Hash: 8038a34ffebf4932 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip Side" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.vertical" -msgstr "垂直" +msgid "node.door.panel.flipSide" +msgstr "向きを反転" +# Source-Hash: 7e8fdd28f9d54d1f # Review: required -# Source-Hash: f24cc343d79acc10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "V Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fold" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.vSupport" -msgstr "V 字支柱" +msgid "node.door.panel.fold" +msgstr "折り" +# Source-Hash: ce3a6c03765dbbd8 # Review: required -# Source-Hash: 44dda7136b93c8ee -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.waist" -msgstr "スラブ式" +msgid "node.door.panel.frame" +msgstr "枠" +# Source-Hash: 0cce8ae784f78478 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth (auto)" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.width" -msgstr "幅" +msgid "node.door.panel.frameDepthAuto" +msgstr "奥行き(自動)" +# Source-Hash: 53aa825a4737190a # Review: required -# Source-Hash: 4e6640dfff42cea4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "X Brace" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Garage" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.xBrace" -msgstr "X ブレース" +msgid "node.door.panel.garage" +msgstr "ガレージ" +# Source-Hash: 8ab91094cf650204 # Review: required -# Source-Hash: fefc9b1cfb26b5a8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Yaw" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.yaw" -msgstr "ヨー" +msgid "node.door.panel.glass" +msgstr "ガラス" +# Source-Hash: 41483b645efc0c65 # Review: required -# Source-Hash: 86259690e332b66d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Y Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handle" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.panel.ySupport" -msgstr "Y 字支柱" +msgid "node.door.panel.handle" +msgstr "ハンドル" +# Source-Hash: b4a496a904640583 # Review: required -# Source-Hash: bf2baf3d7b55f0df -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A-Frame Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handle Side" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.aFrameSupport" -msgstr "A フレーム支柱" +msgid "node.door.panel.handleSide" +msgstr "ハンドルの側" +# Source-Hash: 8c1bc3a078056ff7 # Review: required -# Source-Hash: 51cf77bb359cee43 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight Round" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hardware" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.basicPillar" -msgstr "円柱" +msgid "node.door.panel.hardware" +msgstr "金物" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 39d33008c81fc075 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.boxFrameSupport" -msgstr "ボックスフレーム" +msgid "node.door.panel.height" +msgstr "高さ" +# Source-Hash: 7c8f079bbefe86c9 # Review: required -# Source-Hash: 4f22058e862d1f81 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Soft Bulged" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hinges Side" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.bulgedPillar" -msgstr "ゆるいふくらみ" +msgid "node.door.panel.hingesSide" +msgstr "蝶番の側" +# Source-Hash: ac9c79f08ef130a1 # Review: required -# Source-Hash: bb851e93088b73a2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hourglass" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Horizontal" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.hourglassPillar" -msgstr "砂時計型" +msgid "node.door.panel.horizontal" +msgstr "水平" +# Source-Hash: 42824e50de26bc14 # Review: required -# Source-Hash: 9cc75129edee59ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "K Brace" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Individual" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.kBraceSupport" -msgstr "K ブレース" +msgid "node.door.panel.individual" +msgstr "個別" +# Source-Hash: 3db1dea825785a30 # Review: required -# Source-Hash: 0bf453b4882c663c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Portal Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inset" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.portalFrameSupport" -msgstr "門型フレーム" +msgid "node.door.panel.inset" +msgstr "埋め込み" +# Source-Hash: 1f4ad5ad3e1be222 # Review: required -# Source-Hash: 9099890734ae1238 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single Strut" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inward" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.singleStrutSupport" -msgstr "単一支柱" +msgid "node.door.panel.inward" +msgstr "内開き" +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# Source-Hash: 0c13af329b9b57cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square Block" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.squarePillar" -msgstr "角柱" +msgid "node.door.panel.left" +msgstr "左" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: 4c294bad84924665 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tapered Round" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.taperedPillar" -msgstr "テーパー円柱" +msgid "node.door.panel.move" +msgstr "移動" +# Source-Hash: 3e52f04f92e08070 # Review: required -# Source-Hash: 360e405bfd74a379 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trestle Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.trestleSupport" -msgstr "架台フレーム" +msgid "node.door.panel.open" +msgstr "開く" +# Source-Hash: e04298381837252f # Review: required -# Source-Hash: 4589103259b4fc4d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tripod Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.tripodSupport" -msgstr "三脚支柱" +msgid "node.door.panel.opening" +msgstr "開口" +# Source-Hash: ecb81bd3eefa6a47 # Review: required -# Source-Hash: f24cc343d79acc10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "V Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening Shape" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.vFrameSupport" -msgstr "V 字支柱" +msgid "node.door.panel.openingShape" +msgstr "開口の形状" +# Source-Hash: ccd8f06b8f8d27c9 # Review: required -# Source-Hash: 4e6640dfff42cea4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "X Brace" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outward" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.xBraceSupport" -msgstr "X ブレース" +msgid "node.door.panel.outward" +msgstr "外開き" +# Source-Hash: 482469f5a0873f73 # Review: required -# Source-Hash: 86259690e332b66d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Y Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.column.preset.yFrameSupport" -msgstr "Y 字支柱" +msgid "node.door.panel.panel" +msgstr "パネル" -# Source-Hash: 895766ad1b766c2e +# Source-Hash: 6ce059aee1386f72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Associative linear, curved, circular, angular, or coordinate plan dimension." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panels" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.constructionDimension.description" -msgstr "連動する直線・曲線・円・角度・座標の平面寸法。" +msgid "node.door.panel.panels" +msgstr "パネル" -# Source-Hash: 6875b60ee8a7cc3b +# Source-Hash: ad56a8ab82ff1a77 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Construction Dimension" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panic Bar" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.constructionDimension.label" -msgstr "施工寸法" +msgid "node.door.panel.panicBar" +msgstr "パニックバー" -# Source-Hash: 61a6c6b9bc29c4f8 +# Source-Hash: ade6246634d93054 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Left" -#: packages/nodes/src/window/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pocket" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cornerRadius.bottomLeft" -msgstr "左下" +msgid "node.door.panel.pocket" +msgstr "引き込み戸" -# Source-Hash: c5368accab136fa6 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Right" -#: packages/nodes/src/window/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cornerRadius.bottomRight" -msgstr "右下" +msgid "node.door.panel.position" +msgstr "位置" -# Source-Hash: c8f86af3f03af6c7 +# Source-Hash: 947eacd2689daced # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Left" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rail" #: packages/nodes/src/door/panel.tsx -#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.cornerRadius.topLeft" -msgstr "左上" +msgid "node.door.panel.rail" +msgstr "レール" -# Source-Hash: 0ead7f1ffdbbd892 +# Source-Hash: 3b6f225112035fde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Right" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rect" #: packages/nodes/src/door/panel.tsx -#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.cornerRadius.topRight" -msgstr "右上" +msgid "node.door.panel.rect" +msgstr "矩形" -# Source-Hash: a276c9693f01dec7 +# Source-Hash: c05172113af5a2b8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Louvered roof lantern with a dome or pyramid cap and optional finial." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "- Remove" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.description" -msgstr "ドームまたはピラミッドの笠と任意の頂華を持つルーバー付き屋根ランタン。" +msgid "node.door.panel.remove" +msgstr "- 削除" -# Source-Hash: e679dd19f96eba0a +# Source-Hash: 59236bd016c6b904 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cupola" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reveal Radius" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.label" -msgstr "キューポラ" +msgid "node.door.panel.revealRadius" +msgstr "見込みの半径" +# Source-Hash: b34d5ee0f218221d # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.actions" -msgstr "操作" +msgid "node.door.panel.right" +msgstr "右" -# Review: required -# Source-Hash: e679dd19f96eba0a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cupola" -#: packages/nodes/src/cupola/panel.tsx +# Source-Hash: fc826da6c99303e6 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rounded" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.cupola" -msgstr "キューポラ" +msgid "node.door.panel.rounded" +msgstr "角丸" +# Source-Hash: 505d8419cf4cc5e1 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segments" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.delete" -msgstr "削除" +msgid "node.door.panel.segments" +msgstr "セグメント" +# Source-Hash: a8096eb4beaadeef # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Size is limited to the wall, including clearance for the opening frame." +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.depth" -msgstr "奥行き" +msgid "node.door.panel.sizeIsLimitedToTheWall" +msgstr "サイズは開口枠のクリアランスを含めて壁の範囲に制限されます。" +# Source-Hash: c00de0e2c9b0ddcb # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slide" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.dimensions" -msgstr "寸法" +msgid "node.door.panel.slide" +msgstr "スライド" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: de47e23eb81efe02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dome" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.dome" -msgstr "ドーム" +msgid "node.door.panel.style" +msgstr "スタイル" +# Source-Hash: e48604b5f7b2a5f4 # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swing" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.duplicate" -msgstr "複製" +msgid "node.door.panel.swing" +msgstr "開き" +# Source-Hash: fdbb503f0941bd56 # Review: required -# Source-Hash: 1cfe33235b30b1d8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finial" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.finial" -msgstr "フィニアル" +msgid "node.door.panel.thickness" +msgstr "厚さ" +# Source-Hash: f165d6c05be2b651 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Threshold" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.height" -msgstr "高さ" +msgid "node.door.panel.threshold" +msgstr "敷居" +# Source-Hash: 7e2505dd1d5e3513 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Shape" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.move" -msgstr "移動" +msgid "node.door.panel.topShape" +msgstr "上部の形状" +# Source-Hash: c44f7ab8bbd24858 # Review: required -# Source-Hash: b5e0cb318d484d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No Finial" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.noFinial" -msgstr "頂華なし" +msgid "node.door.panel.type" +msgstr "種類" +# Source-Hash: 8038a34ffebf4932 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.position" -msgstr "位置" +msgid "node.door.panel.vertical" +msgstr "垂直" +# Source-Hash: 63d6b766151965f9 # Review: required -# Source-Hash: 47587b825e9a696b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pyramid" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "wall" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.pyramid" -msgstr "ピラミッド" +msgid "node.door.panel.wall" +msgstr "壁" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.cupola.panel.rotation" -msgstr "回転" +msgid "node.door.panel.width" +msgstr "幅" +# Source-Hash: 8421deea35cb5afc # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Barn" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.cupola.panel.style" -msgstr "スタイル" +msgid "node.door.style.barn" +msgstr "納屋ドア" +# Source-Hash: f747fbe71717772e # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Craftsman" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.cupola.panel.width" -msgstr "幅" +msgid "node.door.style.craftsman" +msgstr "クラフツマン" -# Source-Hash: 5d4ccdf13668fab4 +# Source-Hash: 092033938ca2debb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto elevator cutout" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "French" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.cutout.autoElevator" -msgstr "エレベーターの自動切り抜き" +msgid "node.door.style.french" +msgstr "フレンチドア" -# Source-Hash: 78aa03576e02dda7 +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto stair cutout" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.cutout.autoStair" -msgstr "階段の自動切り抜き" +msgid "node.door.style.glass" +msgstr "ガラス" -# Source-Hash: e04298381837252f +# Source-Hash: 6ab8b98b38eb2e65 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Half-louvered" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.cutout.opening" -msgstr "開口" +msgid "node.door.style.halfLouvered" +msgstr "半ルーバー" -# Source-Hash: ce37dbd7a309940b +# Source-Hash: f6cbdaa17e989b91 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room cutout" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modern" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.cutout.room" -msgstr "部屋の切り抜き" +msgid "node.door.style.modern" +msgstr "モダン" -# Source-Hash: 6123b20edb9569de +# Source-Hash: 482469f5a0873f73 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A door cut into a wall. Animated open/close state." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel" +#: packages/nodes/src/shared/opening-labels.ts +#, fuzzy +msgid "node.door.style.panel" +msgstr "パネル" + +# Source-Hash: ac42c328610a0edd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paneled glass" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.door.description" -msgstr "壁に設けたドア。開閉アニメーション付き。" +msgid "node.door.style.paneledGlass" +msgstr "パネルガラス" -# Source-Hash: 787e10f5db16904e +# Source-Hash: 5b68e435b7210876 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaker" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.door.label" -msgstr "ドア" +msgid "node.door.style.shaker" +msgstr "シェーカー" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 9ad6ac42b4152b64 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Six-panel" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.door.panel.actions" -msgstr "操作" +msgid "node.door.style.sixPanel" +msgstr "6枚パネル" -# Source-Hash: 8337b3213849faca +# Source-Hash: 8421deea35cb5afc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "+ Add Segment" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Barn" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.addSegment" -msgstr "+ セグメントを追加" +msgid "node.door.type.barn" +msgstr "納屋ドア" -# Source-Hash: 663175a9c461a96d +# Source-Hash: 3cd71355956a1821 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.all" -msgstr "すべて" +msgid "node.door.type.double" +msgstr "両開き" -# Source-Hash: 710261f5ffb32617 +# Source-Hash: 29ff60e662b789fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arch" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Folding" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.arch" -msgstr "アーチ" +msgid "node.door.type.folding" +msgstr "折れ戸" -# Source-Hash: 3715cd54e4775087 +# Source-Hash: 092033938ca2debb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arch Height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "French" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.archHeight" -msgstr "アーチの高さ" +msgid "node.door.type.french" +msgstr "フレンチドア" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: c86309fefe89699b # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 -# English: "Auto" +# AI-Model: claude-opus-5-5 +# English: "Roll-up" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.auto" -msgstr "自動" +msgid "node.door.type.garageRollup" +msgstr "巻き上げ" -# Source-Hash: 8a04486ba122ea7d +# Source-Hash: fb6a868430547544 # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 -# English: "Auto follows the wall" +# AI-Model: claude-opus-5-5 +# English: "Sectional" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.autoFollowsTheWall" -msgstr "自動は壁に合わせます" +msgid "node.door.type.garageSectional" +msgstr "セクショナル" -# Source-Hash: 387773c8aa2820a4 +# Source-Hash: 0b5eb64b569db837 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar Height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilt-up" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.barHeight" -msgstr "バーの高さ" +msgid "node.door.type.garageTiltup" +msgstr "跳ね上げ" -# Source-Hash: 30edd1c180aac9b4 +# Source-Hash: e744be60baad6abc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Columns" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hinged" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.columns" -msgstr "列" +msgid "node.door.type.hinged" +msgstr "開き戸" -# Source-Hash: f533584833a4a7bb +# Source-Hash: ade6246634d93054 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Content Padding" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pocket" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.contentPadding" -msgstr "内側余白" +msgid "node.door.type.pocket" +msgstr "引き込み戸" -# Source-Hash: 7a90a42b578f2435 +# Source-Hash: 18cbc73c5e1590aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner Radius" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sliding" #: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.door.panel.cornerRadius" -msgstr "角の半径" +msgid "node.door.type.sliding" +msgstr "引き戸" -# Source-Hash: aa0e8e02212091e4 +# Source-Hash: 387e57242c8d110a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom: the segments match no style." -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "House-shaped protrusion on a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.customTheSegmentsMatchNoStyle" -msgstr "カスタム:セグメントがどのスタイルとも一致しません。" +msgid "node.dormer.description" +msgstr "屋根面の家形の突出部。" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 6b6f8068bbc4c902 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dormer" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.delete" -msgstr "削除" +msgid "node.dormer.label" +msgstr "ドーマー" # Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Depth" -#: packages/nodes/src/door/panel.tsx +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.depth" +msgid "node.dormer.panel.depth" msgstr "奥行き" # Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dimensions" -#: packages/nodes/src/door/panel.tsx +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.dimensions" +msgid "node.dormer.panel.dimensions" msgstr "寸法" -# Source-Hash: 76cd03300faa9b2b -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Direction" -#: packages/nodes/src/door/panel.tsx -#, fuzzy -msgid "node.door.panel.direction" -msgstr "方向" - -# Source-Hash: c53c3307e2a2a32a -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Divider" -#: packages/nodes/src/door/panel.tsx -#, fuzzy -msgid "node.door.panel.divider" -msgstr "仕切り" - -# Source-Hash: 787e10f5db16904e -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door" -#: packages/nodes/src/door/panel.tsx -#, fuzzy -msgid "node.door.panel.door" -msgstr "ドア" - -# Source-Hash: 4a0aa7f647e6461b +# Source-Hash: 6b6f8068bbc4c902 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Closer" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dormer" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.doorCloser" -msgstr "ドアクローザー" +msgid "node.dormer.panel.dormer" +msgstr "ドーマー" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 6949d667043bee0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.duplicate" -msgstr "複製" +msgid "node.dormer.panel.dutch" +msgstr "入母屋" -# Source-Hash: 65b1cbba3b92c5b2 +# Source-Hash: 9cab4d4c95f63cdd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Empty" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.empty" -msgstr "空" +msgid "node.dormer.panel.flat" +msgstr "陸屋根" -# Source-Hash: 6982301da2dbe186 +# Source-Hash: deaffa095d126dfe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Enable Handle" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.enableHandle" -msgstr "ハンドルを有効化" +msgid "node.dormer.panel.gable" +msgstr "切妻" -# Source-Hash: 2e96ebf9c6e7fe49 +# Source-Hash: 7f53d9ffca39984a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Enable Threshold" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.enableThreshold" -msgstr "敷居を有効化" +msgid "node.dormer.panel.gambrel" +msgstr "腰折れ" -# Source-Hash: 61f9413d3bbabde7 +# Source-Hash: 9eda0ea8d447066d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip Side" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hip" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.flipSide" -msgstr "向きを反転" +msgid "node.dormer.panel.hip" +msgstr "寄棟" -# Source-Hash: 7e8fdd28f9d54d1f +# Source-Hash: 7f7bb0e875af3260 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fold" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.fold" -msgstr "折り" +msgid "node.dormer.panel.mansard" +msgstr "マンサード" -# Source-Hash: ce3a6c03765dbbd8 +# Source-Hash: 53af9efc7eca6594 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pitch Direction" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.frame" -msgstr "枠" +msgid "node.dormer.panel.pitchDirection" +msgstr "勾配の向き" -# Source-Hash: 0cce8ae784f78478 +# Source-Hash: 6c39ef7125494c4a # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 -# English: "Depth (auto)" -#: packages/nodes/src/door/panel.tsx +# AI-Model: claude-opus-5-5 +# English: "Pitch Rise" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.frameDepthAuto" -msgstr "奥行き(自動)" +msgid "node.dormer.panel.pitchRise" +msgstr "勾配の立ち上がり" -# Source-Hash: 53aa825a4737190a +# Source-Hash: 96336d4b0820b977 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Garage" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rise Back" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.garage" -msgstr "ガレージ" +msgid "node.dormer.panel.riseBack" +msgstr "後ろ上がり" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: ee3d45f8b756d029 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rise Front" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.glass" -msgstr "ガラス" +msgid "node.dormer.panel.riseFront" +msgstr "前上がり" -# Source-Hash: 41483b645efc0c65 +# Source-Hash: 5e0622f3b09c9326 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handle" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Height" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.handle" -msgstr "ハンドル" +msgid "node.dormer.panel.roofHeight" +msgstr "屋根の高さ" -# Source-Hash: b4a496a904640583 +# Source-Hash: 19ab9527ae7889f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handle Side" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Type" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.handleSide" -msgstr "ハンドルの側" +msgid "node.dormer.panel.roofType" +msgstr "屋根の種類" -# Source-Hash: 8c1bc3a078056ff7 +# Source-Hash: dba6a7b56cf7083f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hardware" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Section" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.hardware" -msgstr "金物" +msgid "node.dormer.panel.section" +msgstr "セクション" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: c8d0df27faa3feaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.height" -msgstr "高さ" +msgid "node.dormer.panel.shed" +msgstr "片流れ" -# Source-Hash: 7c8f079bbefe86c9 +# Source-Hash: e0f973edce3e4ca8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hinges Side" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall Height" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.hingesSide" -msgstr "蝶番の側" +msgid "node.dormer.panel.wallHeight" +msgstr "壁の高さ" -# Source-Hash: ac9c79f08ef130a1 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Horizontal" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.horizontal" -msgstr "水平" +msgid "node.dormer.panel.width" +msgstr "幅" -# Source-Hash: 42824e50de26bc14 +# Source-Hash: 0b1d1e9a36456a50 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Individual" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Windows" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.door.panel.individual" -msgstr "個別" +msgid "node.dormer.panel.windows" +msgstr "窓" -# Source-Hash: 3db1dea825785a30 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inset" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/dormer/panel-actions-section.tsx #, fuzzy -msgid "node.door.panel.inset" -msgstr "埋め込み" +msgid "node.dormer.panelActionsSection.actions" +msgstr "操作" -# Source-Hash: 1f4ad5ad3e1be222 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inward" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/dormer/panel-actions-section.tsx #, fuzzy -msgid "node.door.panel.inward" -msgstr "内開き" +msgid "node.dormer.panelActionsSection.delete" +msgstr "削除" -# Source-Hash: f365c6b6dd9ebab9 +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/dormer/panel-actions-section.tsx #, fuzzy -msgid "node.door.panel.left" -msgstr "左" +msgid "node.dormer.panelActionsSection.duplicate" +msgstr "複製" # Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Move" -#: packages/nodes/src/door/panel.tsx +#: packages/nodes/src/dormer/panel-actions-section.tsx #, fuzzy -msgid "node.door.panel.move" +msgid "node.dormer.panelActionsSection.move" msgstr "移動" -# Source-Hash: 3e52f04f92e08070 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/door/panel.tsx -#, fuzzy -msgid "node.door.panel.open" -msgstr "開く" - -# Source-Hash: e04298381837252f +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/dormer/panel-position-section.tsx #, fuzzy -msgid "node.door.panel.opening" -msgstr "開口" +msgid "node.dormer.panelPositionSection.position" +msgstr "位置" -# Source-Hash: ecb81bd3eefa6a47 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening Shape" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/dormer/panel-position-section.tsx #, fuzzy -msgid "node.door.panel.openingShape" -msgstr "開口の形状" +msgid "node.dormer.panelPositionSection.rotation" +msgstr "回転" -# Source-Hash: ccd8f06b8f8d27c9 +# Source-Hash: 7b19d21b9ad868c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Outward" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Window" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.outward" -msgstr "外開き" +msgid "node.dormer.panelWindowsSection.addWindow" +msgstr "窓を追加" -# Source-Hash: 482469f5a0873f73 +# Source-Hash: 70d7cc5a6422feaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit {name}" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.panel" -msgstr "パネル" +msgid "node.dormer.panelWindowsSection.editNamed" +msgstr "{name}を編集" -# Source-Hash: 6ce059aee1386f72 +# Source-Hash: b6648f023e6c83dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panels" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit window" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.panels" -msgstr "パネル" +msgid "node.dormer.panelWindowsSection.editWindow" +msgstr "窓を編集" -# Source-Hash: ad56a8ab82ff1a77 +# Source-Hash: 4649baf9753aeb74 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panic Bar" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Increase the dormer width to add another window." +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.panicBar" -msgstr "パニックバー" +msgid "node.dormer.panelWindowsSection.increaseTheDormerWidthToAdd" +msgstr "窓をもう 1 つ追加するにはドーマーの幅を広げてください。" -# Source-Hash: ade6246634d93054 +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pocket" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.pocket" -msgstr "引き込み戸" +msgid "node.dormer.panelWindowsSection.move" +msgstr "移動" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: c24226954309d83e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move {name}" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.position" -msgstr "位置" +msgid "node.dormer.panelWindowsSection.moveNamed" +msgstr "{name}を移動" -# Source-Hash: 947eacd2689daced +# Source-Hash: f07faaf0d5e43eef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rail" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move window" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.rail" -msgstr "レール" +msgid "node.dormer.panelWindowsSection.moveWindow" +msgstr "窓を移動" -# Source-Hash: 3b6f225112035fde +# Source-Hash: d2816490ea93d363 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rect" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No windows" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.rect" -msgstr "矩形" +msgid "node.dormer.panelWindowsSection.noWindows" +msgstr "窓はありません" -# Source-Hash: c05172113af5a2b8 +# Source-Hash: 5cbb24f8b1ce7fb7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "- Remove" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Window {number}" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.remove" -msgstr "- 削除" +msgid "node.dormer.panelWindowsSection.windowNumber" +msgstr "窓 {number}" -# Source-Hash: 59236bd016c6b904 +# Source-Hash: 9ca7d951240907cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reveal Radius" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Windows ({length})" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.revealRadius" -msgstr "見込みの半径" +msgid "node.dormer.panelWindowsSection.windowsLength" +msgstr "窓({length})" -# Source-Hash: b34d5ee0f218221d +# Source-Hash: f975c4759607806a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{face, select, back {Back} left {Left} right {Right} other {Front}} · {width} × {height} m" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.door.panel.right" -msgstr "右" +msgid "node.dormer.panelWindowsSection.windowSummary" +msgstr "{face, select, back {背面} left {左面} right {右面} other {正面}} · {width} × {height} m" -# Source-Hash: fc826da6c99303e6 +# Source-Hash: b46392d2ea865760 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rounded" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical drop pipe from a gutter outlet to the ground." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.rounded" -msgstr "角丸" +msgid "node.downspout.description" +msgstr "雨樋の排水口から地面までの竪樋。" -# Source-Hash: 505d8419cf4cc5e1 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segments" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/downspout/inspector-editors.tsx #, fuzzy -msgid "node.door.panel.segments" -msgstr "セグメント" +msgid "node.downspout.inspectorEditors.position" +msgstr "位置" -# Source-Hash: a8096eb4beaadeef +# Source-Hash: 1a1ec08a311f1b35 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Size is limited to the wall, including clearance for the opening frame." -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspout" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.sizeIsLimitedToTheWall" -msgstr "サイズは開口枠のクリアランスを含めて壁の範囲に制限されます。" +msgid "node.downspout.label" +msgstr "竪樋" -# Source-Hash: c00de0e2c9b0ddcb +# Source-Hash: 29eadb8c84ae9632 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slide" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elbow, tee, reducer, or square-to-round transition connecting duct runs." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.slide" -msgstr "スライド" +msgid "node.ductFitting.description" +msgstr "ダクトをつなぐエルボ、T、レデューサー、角丸変換。" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: 7323a0fc9efb077f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap W/H" +#: packages/nodes/src/duct-fitting/inspector-editors.tsx #, fuzzy -msgid "node.door.panel.style" -msgstr "スタイル" +msgid "node.ductFitting.inspectorEditors.swapWH" +msgstr "幅/高さを入れ替え" -# Source-Hash: e48604b5f7b2a5f4 +# Source-Hash: 064b36c4fc5deb87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swing" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap width and height" +#: packages/nodes/src/duct-fitting/inspector-editors.tsx #, fuzzy -msgid "node.door.panel.swing" -msgstr "開き" +msgid "node.ductFitting.inspectorEditors.swapWidthAndHeight" +msgstr "幅と高さを入れ替え" -# Source-Hash: fdbb503f0941bd56 +# Source-Hash: 6d0c3833d87535e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct Fitting" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.thickness" -msgstr "厚さ" +msgid "node.ductFitting.label" +msgstr "ダクト継手" -# Source-Hash: f165d6c05be2b651 +# Source-Hash: dd86efcab72fc5c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Threshold" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Axis" +#: packages/nodes/src/duct-fitting/tool.tsx #, fuzzy -msgid "node.door.panel.threshold" -msgstr "敷居" +msgid "node.ductFitting.tool.axis" +msgstr "軸" -# Source-Hash: 7e2505dd1d5e3513 +# Source-Hash: 5232a826549f915e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Shape" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "⌥ axis" +#: packages/nodes/src/duct-fitting/tool.tsx #, fuzzy -msgid "node.door.panel.topShape" -msgstr "上部の形状" +msgid "node.ductFitting.tool.axis2" +msgstr "⌥ 軸" -# Source-Hash: c44f7ab8bbd24858 +# Source-Hash: 880b34f6fc0ae854 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a duct face that fits the door" +#: packages/nodes/src/duct-fitting/tool.tsx #, fuzzy -msgid "node.door.panel.type" -msgstr "種類" +msgid "node.ductFitting.tool.hoverADuctFaceThatFits" +msgstr "点検口が収まるダクト面にカーソルを合わせてください" -# Source-Hash: 8038a34ffebf4932 +# Source-Hash: 706f5b43a1d4a84a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place access door" +#: packages/nodes/src/duct-fitting/tool.tsx #, fuzzy -msgid "node.door.panel.vertical" -msgstr "垂直" +msgid "node.ductFitting.tool.placeAccessDoor" +msgstr "点検口を配置" -# Source-Hash: 63d6b766151965f9 +# Source-Hash: 8fb180251a321cef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "wall" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/duct-fitting/tool.tsx #, fuzzy -msgid "node.door.panel.wall" -msgstr "壁" +msgid "node.ductFitting.tool.rTRotate" +msgstr "R/T で回転" -# Source-Hash: 3a0ccd6c46877a87 +# Source-Hash: 09eb45a9b35d1a9f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "HVAC duct run — polyline of round, rect, or flat-oval sections." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.width" -msgstr "幅" +msgid "node.ductSegment.description" +msgstr "空調ダクト — 円形・矩形・扁平楕円断面のポリライン。" -# Source-Hash: 8421deea35cb5afc +# Source-Hash: e971d82044e2f48e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Barn" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.style.barn" -msgstr "納屋ドア" +msgid "node.ductSegment.label" +msgstr "ダクト" -# Source-Hash: f747fbe71717772e +# Source-Hash: 33181d0f42421013 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Craftsman" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct terminal — supply register, ceiling diffuser, or return grille. Duct runs end at its collar." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.style.craftsman" -msgstr "クラフツマン" +msgid "node.ductTerminal.description" +msgstr "吹出口 — 給気口、天井ディフューザー、還気グリル。ダクトはそのカラーで終わります。" -# Source-Hash: 092033938ca2debb +# Source-Hash: 161e5386b939e1bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "French" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Register" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.style.french" -msgstr "フレンチドア" +msgid "node.ductTerminal.label" +msgstr "吹出口" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: 83c665eafcf43a68 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{mount, select, floor {Mount Floor} ceiling {Mount Ceiling} wall {Mount Wall} other {Mount {label}}}" +#: packages/nodes/src/duct-terminal/tool.tsx #, fuzzy -msgid "node.door.style.glass" -msgstr "ガラス" +msgid "node.ductTerminal.tool.mount" +msgstr "{mount, select, floor {取付:床} ceiling {取付:天井} wall {取付:壁} other {取付:{label}}}" -# Source-Hash: 6ab8b98b38eb2e65 +# Source-Hash: f067dd52ea051385 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Half-louvered" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "M surface" +#. Key hint: pressing M switches the mounting surface. +#: packages/nodes/src/duct-terminal/tool.tsx #, fuzzy -msgid "node.door.style.halfLouvered" -msgstr "半ルーバー" +msgid "node.ductTerminal.tool.mSurface" +msgstr "M 面" -# Source-Hash: f6cbdaa17e989b91 +# Source-Hash: 8fb180251a321cef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Modern" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/duct-terminal/tool.tsx #, fuzzy -msgid "node.door.style.modern" -msgstr "モダン" +msgid "node.ductTerminal.tool.rTRotate" +msgstr "R/T で回転" -# Source-Hash: 482469f5a0873f73 +# Source-Hash: 98446855908ee71d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapped to duct" +#: packages/nodes/src/duct-terminal/tool.tsx #, fuzzy -msgid "node.door.style.panel" -msgstr "パネル" +msgid "node.ductTerminal.tool.snappedToDuct" +msgstr "ダクトにスナップ" -# Source-Hash: ac42c328610a0edd +# Source-Hash: d0afa386e65cd3a4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paneled glass" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A multi-level elevator shaft with configurable openings per level." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.style.paneledGlass" -msgstr "パネルガラス" +msgid "node.elevator.description" +msgstr "階層ごとに開口を設定できる複数階のエレベーターシャフト。" -# Source-Hash: 5b68e435b7210876 +# Source-Hash: ab5cbab7be160a1c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaker" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevator" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.style.shaker" -msgstr "シェーカー" +msgid "node.elevator.label" +msgstr "エレベーター" -# Source-Hash: 9ad6ac42b4152b64 +# Source-Hash: 7e6d5f138e315bdb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Six-panel" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Access" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.style.sixPanel" -msgstr "6枚パネル" +msgid "node.elevator.panel.access" +msgstr "アクセス" -# Source-Hash: 8421deea35cb5afc +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Barn" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.barn" -msgstr "納屋ドア" +msgid "node.elevator.panel.actions" +msgstr "操作" -# Source-Hash: 3cd71355956a1821 +# Source-Hash: fdf7108a011bd94b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cab" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.double" -msgstr "両開き" +msgid "node.elevator.panel.cab" +msgstr "かご" -# Source-Hash: 29ff60e662b789fb +# Source-Hash: 2d0ab44f3820f22c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Folding" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cab Height" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.folding" -msgstr "折れ戸" +msgid "node.elevator.panel.cabHeight" +msgstr "かごの高さ" -# Source-Hash: 092033938ca2debb +# Source-Hash: 65f410261609060b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "French" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center opening" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.french" -msgstr "フレンチドア" +msgid "node.elevator.panel.centerOpening" +msgstr "中央開き" + +# Source-Hash: c5433f4d3ea8a8a7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default Floor" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.defaultFloor" +msgstr "既定の階" -# Source-Hash: c86309fefe89699b +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roll-up" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.garageRollup" -msgstr "巻き上げ" +msgid "node.elevator.panel.delete" +msgstr "削除" -# Source-Hash: fb6a868430547544 +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sectional" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.garageSectional" -msgstr "セクショナル" +msgid "node.elevator.panel.depth" +msgstr "奥行き" -# Source-Hash: 0b5eb64b569db837 +# Source-Hash: 748877ae309c313c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilt-up" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Destination" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.garageTiltup" -msgstr "跳ね上げ" +msgid "node.elevator.panel.destination" +msgstr "接続先" -# Source-Hash: e744be60baad6abc +# Source-Hash: 3bff69bd74544339 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hinged" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Disabled" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.hinged" -msgstr "開き戸" +msgid "node.elevator.panel.disabled" +msgstr "無効" -# Source-Hash: ade6246634d93054 +# Source-Hash: d8baf402fa9c52f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pocket" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Height" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.pocket" -msgstr "引き込み戸" +msgid "node.elevator.panel.doorHeight" +msgstr "扉の高さ" -# Source-Hash: 18cbc73c5e1590aa +# Source-Hash: 20f60b98de67849b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sliding" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Doors" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.door.type.sliding" -msgstr "引き戸" +msgid "node.elevator.panel.doors" +msgstr "ドア" -# Source-Hash: 387e57242c8d110a +# Source-Hash: eb0d4023a513b16c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "House-shaped protrusion on a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Time" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.description" -msgstr "屋根面の家形の突出部。" +msgid "node.elevator.panel.doorTime" +msgstr "扉の開閉時間" -# Source-Hash: 6b6f8068bbc4c902 +# Source-Hash: b3e001acdb1f869d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dormer" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Type" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.label" -msgstr "ドーマー" +msgid "node.elevator.panel.doorType" +msgstr "扉の種類" +# Source-Hash: c6203a69fdf44065 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Width" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.depth" -msgstr "奥行き" +msgid "node.elevator.panel.doorWidth" +msgstr "扉の幅" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.dimensions" -msgstr "寸法" +msgid "node.elevator.panel.duplicate" +msgstr "複製" +# Source-Hash: eb3abe5340b26138 # Review: required -# Source-Hash: 6b6f8068bbc4c902 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dormer" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dwell" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.dormer" -msgstr "ドーマー" +msgid "node.elevator.panel.dwell" +msgstr "停止時間" +# Source-Hash: ab5cbab7be160a1c # Review: required -# Source-Hash: 6949d667043bee0b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevator" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.dutch" -msgstr "入母屋" +msgid "node.elevator.panel.elevator" +msgstr "エレベーター" +# Source-Hash: 702140636ff3977a # Review: required -# Source-Hash: 9cab4d4c95f63cdd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "From" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.flat" -msgstr "陸屋根" +msgid "node.elevator.panel.from" +msgstr "出発階" +# Source-Hash: 8ab91094cf650204 # Review: required -# Source-Hash: deaffa095d126dfe -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.gable" -msgstr "切妻" +msgid "node.elevator.panel.glass" +msgstr "ガラス" +# Source-Hash: 88810658a2b97bc6 # Review: required -# Source-Hash: 7f53d9ffca39984a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass frame" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.gambrel" -msgstr "腰折れ" +msgid "node.elevator.panel.glassFrame" +msgstr "ガラス枠" +# Source-Hash: c0ff16d77ebc9593 # Review: required -# Source-Hash: 9eda0ea8d447066d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hip" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Motion" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.hip" -msgstr "寄棟" +msgid "node.elevator.panel.motion" +msgstr "動き" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: 7f7bb0e875af3260 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.mansard" -msgstr "マンサード" +msgid "node.elevator.panel.move" +msgstr "移動" +# Source-Hash: 825ac8855353a4e1 # Review: required -# Source-Hash: 53af9efc7eca6594 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pitch Direction" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening Style" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.pitchDirection" -msgstr "勾配の向き" +msgid "node.elevator.panel.openingStyle" +msgstr "開き方" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: 6c39ef7125494c4a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pitch Rise" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.pitchRise" -msgstr "勾配の立ち上がり" +msgid "node.elevator.panel.position" +msgstr "位置" + +# Source-Hash: 01989595ee7c1dc0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.rotation" +msgstr "回転" +# Source-Hash: f9a95d8407fafda4 # Review: required -# Source-Hash: 96336d4b0820b977 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rise Back" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segmented panel" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.riseBack" -msgstr "後ろ上がり" +msgid "node.elevator.panel.segmentedPanel" +msgstr "分割パネル" +# Source-Hash: aa7b49b13f96057f # Review: required -# Source-Hash: ee3d45f8b756d029 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rise Front" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Service" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.riseFront" -msgstr "前上がり" +msgid "node.elevator.panel.service" +msgstr "サービス" +# Source-Hash: 4fc63ad21de30103 # Review: required -# Source-Hash: 5e0622f3b09c9326 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Height" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.roofHeight" -msgstr "屋根の高さ" +msgid "node.elevator.panel.shaft" +msgstr "シャフト" +# Source-Hash: 6605ade39317cd42 # Review: required -# Source-Hash: 19ab9527ae7889f4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Type" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Depth" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.roofType" -msgstr "屋根の種類" +msgid "node.elevator.panel.shaftDepth" +msgstr "昇降路の奥行き" +# Source-Hash: b28db5a3a48fe52e # Review: required -# Source-Hash: dba6a7b56cf7083f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Section" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Style" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.section" -msgstr "セクション" +msgid "node.elevator.panel.shaftStyle" +msgstr "昇降路のスタイル" +# Source-Hash: 3dab61aeb47e504d # Review: required -# Source-Hash: c8d0df27faa3feaa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Width" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.shed" -msgstr "片流れ" +msgid "node.elevator.panel.shaftWidth" +msgstr "昇降路の幅" +# Source-Hash: aee3b2bd78c87d0b # Review: required -# Source-Hash: e0f973edce3e4ca8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Height" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single left" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.wallHeight" -msgstr "壁の高さ" +msgid "node.elevator.panel.singleLeft" +msgstr "片開き(左)" +# Source-Hash: cc43ffbef4ac7ae0 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single right" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.width" -msgstr "幅" +msgid "node.elevator.panel.singleRight" +msgstr "片開き(右)" +# Source-Hash: ef3e765e692faf4c # Review: required -# Source-Hash: 0b1d1e9a36456a50 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Windows" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panel.windows" -msgstr "窓" +msgid "node.elevator.panel.solid" +msgstr "ソリッド" +# Source-Hash: 8008b6f17089beaf # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/dormer/panel-actions-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid panel" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panelActionsSection.actions" -msgstr "操作" +msgid "node.elevator.panel.solidPanel" +msgstr "不透明パネル" +# Source-Hash: 3b006be0b1f0493f # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/dormer/panel-actions-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Speed" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panelActionsSection.delete" -msgstr "削除" +msgid "node.elevator.panel.speed" +msgstr "速度" +# Source-Hash: 6d37a1679fa3708e # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/dormer/panel-actions-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stop {stopOrder}" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panelActionsSection.duplicate" -msgstr "複製" +msgid "node.elevator.panel.stopStoporder" +msgstr "停止階 {stopOrder}" +# Source-Hash: b3214a20e45a7aed # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/dormer/panel-actions-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "To" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panelActionsSection.move" -msgstr "移動" +msgid "node.elevator.panel.to" +msgstr "終点" +# Source-Hash: 1a5ccd607c400d76 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/dormer/panel-position-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall Thickness" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panelPositionSection.position" -msgstr "位置" +msgid "node.elevator.panel.wallThickness" +msgstr "壁厚" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/dormer/panel-position-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panelPositionSection.rotation" -msgstr "回転" +msgid "node.elevator.panel.width" +msgstr "幅" +# Source-Hash: fefc9b1cfb26b5a8 # Review: required -# Source-Hash: 7b19d21b9ad868c7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Window" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Yaw" +#: packages/nodes/src/elevator/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.addWindow" -msgstr "窓を追加" +msgid "node.elevator.panel.yaw" +msgstr "ヨー" +# Source-Hash: 7b22c91cf520e161 # Review: required -# Source-Hash: 70d7cc5a6422feaa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit {name}" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low curved lens-shaped roof vent with a louvered front." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.dormer.panelWindowsSection.editNamed" -msgstr "{name}を編集" +msgid "node.eyebrowVent.description" +msgstr "正面にルーバーのある、低く湾曲したレンズ形の屋根換気口。" +# Source-Hash: 654b29319185ac66 # Review: required -# Source-Hash: b6648f023e6c83dc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit window" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eyebrow Vent" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.dormer.panelWindowsSection.editWindow" -msgstr "窓を編集" +msgid "node.eyebrowVent.label" +msgstr "眉型換気口" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 4649baf9753aeb74 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Increase the dormer width to add another window." -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.increaseTheDormerWidthToAdd" -msgstr "窓をもう 1 つ追加するにはドーマーの幅を広げてください。" +msgid "node.eyebrowVent.panel.actions" +msgstr "操作" + +# Source-Hash: abc97377800a8333 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back height" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.backHeight" +msgstr "背面の高さ" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.move" -msgstr "移動" +msgid "node.eyebrowVent.panel.delete" +msgstr "削除" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: c24226954309d83e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move {name}" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.moveNamed" -msgstr "{name}を移動" +msgid "node.eyebrowVent.panel.depth" +msgstr "奥行き" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: f07faaf0d5e43eef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move window" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.moveWindow" -msgstr "窓を移動" +msgid "node.eyebrowVent.panel.dimensions" +msgstr "寸法" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: d2816490ea93d363 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No windows" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.noWindows" -msgstr "窓はありません" +msgid "node.eyebrowVent.panel.duplicate" +msgstr "複製" +# Source-Hash: 654b29319185ac66 # Review: required -# Source-Hash: 5cbb24f8b1ce7fb7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Window {number}" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eyebrow Vent" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.windowNumber" -msgstr "窓 {number}" +msgid "node.eyebrowVent.panel.eyebrowVent" +msgstr "眉型換気口" +# Source-Hash: a2d107a5deaa01f4 # Review: required -# Source-Hash: 9ca7d951240907cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Windows ({length})" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Half-round" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.windowsLength" -msgstr "窓({length})" +msgid "node.eyebrowVent.panel.halfRound" +msgstr "半円" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: f975c4759607806a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{face, select, back {Back} left {Left} right {Right} other {Front}} · {width} × {height} m" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.windowSummary" -msgstr "{face, select, back {背面} left {左面} right {右面} other {正面}} · {width} × {height} m" +msgid "node.eyebrowVent.panel.height" +msgstr "高さ" -# Source-Hash: b46392d2ea865760 +# Source-Hash: 318192f27a774fb7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical drop pipe from a gutter outlet to the ground." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Louvers" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.downspout.description" -msgstr "雨樋の排水口から地面までの竪樋。" +msgid "node.eyebrowVent.panel.louvers" +msgstr "ルーバー" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/downspout/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.downspout.inspectorEditors.position" -msgstr "位置" +msgid "node.eyebrowVent.panel.move" +msgstr "移動" -# Source-Hash: 1a1ec08a311f1b35 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspout" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.downspout.label" -msgstr "竪樋" +msgid "node.eyebrowVent.panel.position" +msgstr "位置" -# Source-Hash: 29eadb8c84ae9632 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elbow, tee, reducer, or square-to-round transition connecting duct runs." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.ductFitting.description" -msgstr "ダクトをつなぐエルボ、T、レデューサー、角丸変換。" +msgid "node.eyebrowVent.panel.rotation" +msgstr "回転" +# Source-Hash: e16f85e4bebfefb1 # Review: required -# Source-Hash: 7323a0fc9efb077f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swap W/H" -#: packages/nodes/src/duct-fitting/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scoop" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.ductFitting.inspectorEditors.swapWH" -msgstr "幅/高さを入れ替え" +msgid "node.eyebrowVent.panel.scoop" +msgstr "スクープ" +# Source-Hash: ec53d40877e11b62 # Review: required -# Source-Hash: 064b36c4fc5deb87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swap width and height" -#: packages/nodes/src/duct-fitting/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slant-box" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.ductFitting.inspectorEditors.swapWidthAndHeight" -msgstr "幅と高さを入れ替え" +msgid "node.eyebrowVent.panel.slantBox" +msgstr "傾斜ボックス" -# Source-Hash: 6d0c3833d87535e4 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct Fitting" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.ductFitting.label" -msgstr "ダクト継手" +msgid "node.eyebrowVent.panel.style" +msgstr "スタイル" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: dd86efcab72fc5c7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Axis" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/eyebrow-vent/panel.tsx #, fuzzy -msgid "node.ductFitting.tool.axis" -msgstr "軸" +msgid "node.eyebrowVent.panel.width" +msgstr "幅" +# Source-Hash: 20032fe9430f610d # Review: required -# Source-Hash: 5232a826549f915e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "⌥ axis" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A straight or curved fence segment with configurable posts and infill." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.ductFitting.tool.axis2" -msgstr "⌥ 軸" +msgid "node.fence.description" +msgstr "支柱と面材を設定できる直線または曲線のフェンス区間。" +# Source-Hash: 6f84b85097bc1ffc # Review: required -# Source-Hash: 880b34f6fc0ae854 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a duct face that fits the door" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add point after" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductFitting.tool.hoverADuctFaceThatFits" -msgstr "点検口が収まるダクト面にカーソルを合わせてください" +msgid "node.fence.inspectorEditors.addPointAfter" +msgstr "後ろに点を追加" +# Source-Hash: 1a15ab3101e2d166 # Review: required -# Source-Hash: 706f5b43a1d4a84a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place access door" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a slab or shaped surface on this level." +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductFitting.tool.placeAccessDoor" -msgstr "点検口を配置" +msgid "node.fence.inspectorEditors.chooseASlabOrShapedSurface" +msgstr "この階のスラブか成形面を選んでください。" +# Source-Hash: 78a5625401384000 # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a surface" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductFitting.tool.rTRotate" -msgstr "R/T で回転" +msgid "node.fence.inspectorEditors.chooseASurface" +msgstr "面を選択" -# Source-Hash: 09eb45a9b35d1a9f -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "HVAC duct run — polyline of round, rect, or flat-oval sections." -#: packages/nodes/src/i18n/definition-messages.ts +# Source-Hash: 2ee121dca87bb64a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductSegment.description" -msgstr "空調ダクト — 円形・矩形・扁平楕円断面のポリライン。" +msgid "node.fence.inspectorEditors.corner" +msgstr "コーナー" -# Source-Hash: e971d82044e2f48e +# Source-Hash: f08fbb462e9afc0e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curve" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductSegment.label" -msgstr "ダクト" +msgid "node.fence.inspectorEditors.curve" +msgstr "曲線" -# Source-Hash: 33181d0f42421013 +# Source-Hash: a028e08962c388e0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct terminal — supply register, ceiling diffuser, or return grille. Duct runs end at its collar." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curved" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductTerminal.description" -msgstr "吹出口 — 給気口、天井ディフューザー、還気グリル。ダクトはそのカラーで終わります。" +msgid "node.fence.inspectorEditors.curved" +msgstr "曲線" -# Source-Hash: 161e5386b939e1bc +# Source-Hash: 81b75058b7843a0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Register" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{style, select, picket {Distribution controls pickets in each bay between posts.} horizontal {Distribution controls posts along the full fence.} other {Distribution controls infill pieces between the two end posts.}} Spacing is measured between centers. The available width limits the count so pieces do not overlap." +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductTerminal.label" -msgstr "吹出口" +msgid "node.fence.inspectorEditors.distributionInfo" +msgstr "{style, select, picket {配置は支柱間の各スパンのピケットを制御します。} horizontal {配置はフェンス全体の支柱を制御します。} other {配置は両端の支柱間の充填材を制御します。}}間隔は中心間で測ります。重ならないよう、使える幅によって数が制限されます。" +# Source-Hash: fbc8f54b0e3fdeb1 # Review: required -# Source-Hash: 83c665eafcf43a68 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{mount, select, floor {Mount Floor} ceiling {Mount Ceiling} wall {Mount Wall} other {Mount {label}}}" -#: packages/nodes/src/duct-terminal/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit path" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductTerminal.tool.mount" -msgstr "{mount, select, floor {取付:床} ceiling {取付:天井} wall {取付:壁} other {取付:{label}}}" +msgid "node.fence.inspectorEditors.editPath" +msgstr "パスを編集" +# Source-Hash: 55686db44529c013 # Review: required -# Source-Hash: f067dd52ea051385 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "M surface" -#. Key hint: pressing M switches the mounting surface. -#: packages/nodes/src/duct-terminal/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Extend path" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductTerminal.tool.mSurface" -msgstr "M 面" +msgid "node.fence.inspectorEditors.extendPath" +msgstr "パスを延長" +# Source-Hash: 0bf0f27e631aa98d # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/duct-terminal/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow highest surface" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductTerminal.tool.rTRotate" -msgstr "R/T で回転" +msgid "node.fence.inspectorEditors.followHighestSurface" +msgstr "最も高い面に沿う" +# Source-Hash: e0b381fcb05a65c4 # Review: required -# Source-Hash: 98446855908ee71d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapped to duct" -#: packages/nodes/src/duct-terminal/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow selected surface" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.ductTerminal.tool.snappedToDuct" -msgstr "ダクトにスナップ" +msgid "node.fence.inspectorEditors.followSelectedSurface" +msgstr "選択した面に沿う" -# Source-Hash: d0afa386e65cd3a4 +# Source-Hash: c418d97f803af8dd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A multi-level elevator shaft with configurable openings per level." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hold starting height" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.elevator.description" -msgstr "階層ごとに開口を設定できる複数階のエレベーターシャフト。" +msgid "node.fence.inspectorEditors.holdStartingHeight" +msgstr "開始時の高さを保つ" -# Source-Hash: ab5cbab7be160a1c +# Source-Hash: 295ca9336dc1935b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevator" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Join" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.elevator.label" -msgstr "エレベーター" +msgid "node.fence.inspectorEditors.join" +msgstr "結合" +# Source-Hash: 643687bc3adaac76 # Review: required -# Source-Hash: 7e6d5f138e315bdb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Access" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.elevator.panel.access" -msgstr "アクセス" +msgid "node.fence.inspectorEditors.length" +msgstr "長さ" +# Source-Hash: 1fedc8a2f2ea6887 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {{number} point} other {{number} points}} · {length} m" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.elevator.panel.actions" -msgstr "操作" +msgid "node.fence.inspectorEditors.pathSummary" +msgstr "{count, plural, other {{number} 点}} · {length} m" +# Source-Hash: c96d499e11181429 # Review: required -# Source-Hash: fdf7108a011bd94b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cab" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket rail projection" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.elevator.panel.cab" -msgstr "かご" +msgid "node.fence.inspectorEditors.picketRailProjection" +msgstr "ピケットのレール突出" +# Source-Hash: a1880fca8372d06f # Review: required -# Source-Hash: 2d0ab44f3820f22c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cab Height" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Point" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.elevator.panel.cabHeight" -msgstr "かごの高さ" +msgid "node.fence.inspectorEditors.point" +msgstr "点" +# Source-Hash: 39bc6254b5307f53 # Review: required -# Source-Hash: 65f410261609060b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center opening" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove point" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.elevator.panel.centerOpening" -msgstr "中央開き" +msgid "node.fence.inspectorEditors.removePoint" +msgstr "点を削除" +# Source-Hash: ea56af3a0d7a65e4 # Review: required -# Source-Hash: c5433f4d3ea8a8a7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default Floor" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set each span to straight or curved, then drag its points and curve handles in either view." +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.elevator.panel.defaultFloor" -msgstr "既定の階" +msgid "node.fence.inspectorEditors.setEachSpanToStraightOr" +msgstr "各スパンを直線か曲線にしてから、どちらのビューでも点と曲線ハンドルをドラッグします。" +# Source-Hash: 354c8bc5c8da5a6e # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Smooth" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.elevator.panel.delete" -msgstr "削除" +msgid "node.fence.inspectorEditors.smooth" +msgstr "スムーズ" +# Source-Hash: 3c700cc1299a150f # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Span to point {number}" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.elevator.panel.depth" -msgstr "奥行き" +msgid "node.fence.inspectorEditors.spanToPointNumber" +msgstr "点 {number} までのスパン" +# Source-Hash: 4ee35f740730ae87 # Review: required -# Source-Hash: 748877ae309c313c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Destination" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.elevator.panel.destination" -msgstr "接続先" +msgid "node.fence.inspectorEditors.straight" +msgstr "直進" +# Source-Hash: 78a454b7ac7a3cd9 # Review: required -# Source-Hash: 3bff69bd74544339 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Disabled" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.surface" +msgstr "面" + +# Source-Hash: ab2de0428c093018 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface behavior" +#: packages/nodes/src/fence/inspector-editors.tsx #, fuzzy -msgid "node.elevator.panel.disabled" -msgstr "無効" +msgid "node.fence.inspectorEditors.surfaceBehavior" +msgstr "面への追従" +# Source-Hash: 02042fde61b5aa11 # Review: required -# Source-Hash: d8baf402fa9c52f0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Height" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fence" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.elevator.panel.doorHeight" -msgstr "扉の高さ" +msgid "node.fence.label" +msgstr "フェンス" +# Source-Hash: 3e07a9889c1bd7f9 # Review: required -# Source-Hash: 20f60b98de67849b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Doors" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Detach endpoint" +#: packages/nodes/src/fence/move-endpoint-tool.tsx #, fuzzy -msgid "node.elevator.panel.doors" -msgstr "ドア" +msgid "node.fence.moveEndpointTool.detachEndpoint" +msgstr "端点を切り離す" +# Source-Hash: 7a3ce9fec6370e3e # Review: required -# Source-Hash: eb0d4023a513b16c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Time" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag endpoint" +#: packages/nodes/src/fence/move-endpoint-tool.tsx #, fuzzy -msgid "node.elevator.panel.doorTime" -msgstr "扉の開閉時間" +msgid "node.fence.moveEndpointTool.dragEndpoint" +msgstr "端点をドラッグ" +# Source-Hash: d7cf5045c01b2eb9 # Review: required -# Source-Hash: b3e001acdb1f869d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Type" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close" +#: packages/nodes/src/fence-feature/actions.tsx #, fuzzy -msgid "node.elevator.panel.doorType" -msgstr "扉の種類" +msgid "node.fenceFeature.actions.close" +msgstr "閉じる" +# Source-Hash: 3e52f04f92e08070 # Review: required -# Source-Hash: c6203a69fdf44065 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Width" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/fence-feature/actions.tsx #, fuzzy -msgid "node.elevator.panel.doorWidth" -msgstr "扉の幅" +msgid "node.fenceFeature.actions.open" +msgstr "開く" +# Source-Hash: fc4cf2bc034fc547 # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Board width" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.duplicate" -msgstr "複製" +msgid "node.fenceFeature.inspector.boardWidth" +msgstr "板幅" +# Source-Hash: f3b11e5b2dd3b25f # Review: required -# Source-Hash: eb3abe5340b26138 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dwell" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bracing" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.dwell" -msgstr "停止時間" +msgid "node.fenceFeature.inspector.bracing" +msgstr "筋交い" +# Source-Hash: d09ec3d9565734c3 # Review: required -# Source-Hash: ab5cbab7be160a1c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevator" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Distance from start" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.elevator" -msgstr "エレベーター" +msgid "node.fenceFeature.inspector.distanceFromStart" +msgstr "始点からの距離" +# Source-Hash: dcd803eaf3796298 # Review: required -# Source-Hash: 702140636ff3977a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "From" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fence unavailable." +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.from" -msgstr "出発階" +msgid "node.fenceFeature.inspector.fenceUnavailable" +msgstr "フェンスを利用できません。" +# Source-Hash: 3519d91b7bda18a5 # Review: required -# Source-Hash: 8ab91094cf650204 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame width" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.glass" -msgstr "ガラス" +msgid "node.fenceFeature.inspector.frameWidth" +msgstr "枠の幅" +# Source-Hash: cb18554b2420e700 # Review: required -# Source-Hash: 88810658a2b97bc6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass frame" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gate height" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.glassFrame" -msgstr "ガラス枠" +msgid "node.fenceFeature.inspector.gateHeight" +msgstr "門扉の高さ" +# Source-Hash: 54098b5ee574737a # Review: required -# Source-Hash: c0ff16d77ebc9593 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Motion" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gate style" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.motion" -msgstr "動き" +msgid "node.fenceFeature.inspector.gateStyle" +msgstr "門のスタイル" +# Source-Hash: 4fc3e60be28f60d5 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground clearance" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.move" -msgstr "移動" +msgid "node.fenceFeature.inspector.groundClearance" +msgstr "地面とのクリアランス" +# Source-Hash: 916f2e07bf082795 # Review: required -# Source-Hash: 825ac8855353a4e1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening Style" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hinges and latch" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.openingStyle" -msgstr "開き方" +msgid "node.fenceFeature.inspector.hingesAndLatch" +msgstr "丁番とラッチ" +# Source-Hash: 5bd2e597fbb2a2c9 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hinge side" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.position" -msgstr "位置" +msgid "node.fenceFeature.inspector.hingeSide" +msgstr "丁番側" +# Source-Hash: 8fec7e969045a8e7 # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Horizontal boards" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.rotation" -msgstr "回転" +msgid "node.fenceFeature.inspector.horizontalBoards" +msgstr "横板" +# Source-Hash: f4addad87cc4223e # Review: required -# Source-Hash: f9a95d8407fafda4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segmented panel" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Infill spacing" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.segmentedPanel" -msgstr "分割パネル" +msgid "node.fenceFeature.inspector.infillSpacing" +msgstr "充填材の間隔" +# Source-Hash: cdec08b292742b20 # Review: required -# Source-Hash: aa7b49b13f96057f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Service" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Jamb posts" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.service" -msgstr "サービス" +msgid "node.fenceFeature.inspector.jambPosts" +msgstr "門柱" +# Source-Hash: ef88410453ee7414 # Review: required -# Source-Hash: 4fc63ad21de30103 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keep the opening inside the fence and clear of other gates or passages." +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.keepTheOpeningInsideTheFence" +msgstr "開口はフェンス内に収め、ほかの門扉や通路と重ならないようにしてください。" + +# Source-Hash: 67cd0171b226fedb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Leaf thickness" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.shaft" -msgstr "シャフト" +msgid "node.fenceFeature.inspector.leafThickness" +msgstr "扉の厚さ" +# Source-Hash: c390ba248e629b9e # Review: required -# Source-Hash: 6605ade39317cd42 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Depth" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Leaves" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.shaftDepth" -msgstr "昇降路の奥行き" +msgid "node.fenceFeature.inspector.leaves" +msgstr "扉" +# Source-Hash: d7bb934589475512 # Review: required -# Source-Hash: b28db5a3a48fe52e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Style" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left leaf proportion" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.shaftStyle" -msgstr "昇降路のスタイル" +msgid "node.fenceFeature.inspector.leftLeafProportion" +msgstr "左扉の比率" +# Source-Hash: aa9fe0ebace8957d # Review: required -# Source-Hash: 3dab61aeb47e504d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Width" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match fence height" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.shaftWidth" -msgstr "昇降路の幅" +msgid "node.fenceFeature.inspector.matchFenceHeight" +msgstr "フェンスの高さに合わせる" +# Source-Hash: c15c1af69ec5c1eb # Review: required -# Source-Hash: aee3b2bd78c87d0b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single left" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match fence style" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.singleLeft" -msgstr "片開き(左)" +msgid "node.fenceFeature.inspector.matchFenceStyle" +msgstr "フェンスのスタイルに合わせる" +# Source-Hash: 51b7ab6a0a78d90a # Review: required -# Source-Hash: cc43ffbef4ac7ae0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single right" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening angle" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.singleRight" -msgstr "片開き(右)" +msgid "node.fenceFeature.inspector.openingAngle" +msgstr "開き角度" +# Source-Hash: d2e20300c07aa722 # Review: required -# Source-Hash: ef3e765e692faf4c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening width" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.solid" -msgstr "ソリッド" +msgid "node.fenceFeature.inspector.openingWidth" +msgstr "開口幅" +# Source-Hash: 6b108fb1d0eb8f9d # Review: required -# Source-Hash: 8008b6f17089beaf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid panel" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open rails" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.solidPanel" -msgstr "不透明パネル" +msgid "node.fenceFeature.inspector.openRails" +msgstr "横桟" +# Source-Hash: d500c4b7827d3390 # Review: required -# Source-Hash: 3b006be0b1f0493f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Speed" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cross" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.speed" -msgstr "速度" +msgid "node.fenceFeature.inspector.option.cross" +msgstr "クロス" +# Source-Hash: 7420c0d2caee1c22 # Review: required -# Source-Hash: 6d37a1679fa3708e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stop {stopOrder}" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diagonal" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.stopStoporder" -msgstr "停止階 {stopOrder}" +msgid "node.fenceFeature.inspector.option.diagonal" +msgstr "斜め" +# Source-Hash: 7308869944020839 # Review: required -# Source-Hash: b3214a20e45a7aed -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "To" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double gate" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.to" -msgstr "終点" +msgid "node.fenceFeature.inspector.option.doubleGate" +msgstr "両開き門" +# Source-Hash: 1f4ad5ad3e1be222 # Review: required -# Source-Hash: 1a5ccd607c400d76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Thickness" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inward" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.wallThickness" -msgstr "壁厚" +msgid "node.fenceFeature.inspector.option.inward" +msgstr "内開き" +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.width" -msgstr "幅" +msgid "node.fenceFeature.inspector.option.left" +msgstr "左" +# Source-Hash: f2953d2931e36d0c # Review: required -# Source-Hash: fefc9b1cfb26b5a8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Yaw" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.elevator.panel.yaw" -msgstr "ヨー" +msgid "node.fenceFeature.inspector.option.none" +msgstr "なし" -# Source-Hash: 7b22c91cf520e161 +# Source-Hash: ccd8f06b8f8d27c9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low curved lens-shaped roof vent with a louvered front." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outward" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.eyebrowVent.description" -msgstr "正面にルーバーのある、低く湾曲したレンズ形の屋根換気口。" +msgid "node.fenceFeature.inspector.option.outward" +msgstr "外開き" -# Source-Hash: 654b29319185ac66 +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Eyebrow Vent" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.eyebrowVent.label" -msgstr "眉型換気口" +msgid "node.fenceFeature.inspector.option.right" +msgstr "右" +# Source-Hash: d327097d9ac1099f # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single gate" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.eyebrowVent.panel.actions" -msgstr "操作" +msgid "node.fenceFeature.inspector.option.singleGate" +msgstr "片開き門" +# Source-Hash: 9295ddc2805b21e2 # Review: required -# Source-Hash: abc97377800a8333 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back height" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.eyebrowVent.panel.backHeight" -msgstr "背面の高さ" +msgid "node.fenceFeature.inspector.picket" +msgstr "ピケット" +# Source-Hash: 8dd5999b235f60ab # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post height" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.eyebrowVent.panel.delete" -msgstr "削除" +msgid "node.fenceFeature.inspector.postHeight" +msgstr "支柱の高さ" +# Source-Hash: 90bcd7a8123ec343 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove gate" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.removeGate" +msgstr "門扉を削除" + +# Source-Hash: 7e3505710613543f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove opening" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.eyebrowVent.panel.depth" -msgstr "奥行き" +msgid "node.fenceFeature.inspector.removeOpening" +msgstr "開口を削除" +# Source-Hash: af6f8885fe0fa4e9 # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid privacy" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.eyebrowVent.panel.dimensions" -msgstr "寸法" +msgid "node.fenceFeature.inspector.solidPrivacy" +msgstr "目隠し" +# Source-Hash: 1a7048255c3bdfcb # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swing direction" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.eyebrowVent.panel.duplicate" -msgstr "複製" +msgid "node.fenceFeature.inspector.swingDirection" +msgstr "開く向き" +# Source-Hash: eba3df14a2de0812 # Review: required -# Source-Hash: 654b29319185ac66 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Eyebrow Vent" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical slats" +#: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.eyebrowVent.panel.eyebrowVent" -msgstr "眉型換気口" +msgid "node.fenceFeature.inspector.verticalSlats" +msgstr "縦板" +# Source-Hash: df61821ed00852d8 # Review: required -# Source-Hash: a2d107a5deaa01f4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Half-round" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A gate hosted by a fence." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.halfRound" -msgstr "半円" +msgid "node.fenceGate.description" +msgstr "フェンスに取り付けた門。" +# Source-Hash: 4a479aa23542d766 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gate" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.height" -msgstr "高さ" +msgid "node.fenceGate.label" +msgstr "門" +# Source-Hash: 8f9c927d79796c26 # Review: required -# Source-Hash: 318192f27a774fb7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Louvers" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An intentional opening in a fence." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.louvers" -msgstr "ルーバー" +msgid "node.fenceOpening.description" +msgstr "フェンスに設けた開口。" +# Source-Hash: ab67bb47e647d594 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open Passage" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.move" -msgstr "移動" +msgid "node.fenceOpening.label" +msgstr "通路" +# Source-Hash: dc3adf0c2d50dba6 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor opening" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.position" -msgstr "位置" +msgid "node.floorOpening.label" +msgstr "床開口" +# Source-Hash: 2f4fac2b1d39fdb1 # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A measurement / reference annotation (linear, area, or arc)." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.rotation" -msgstr "回転" +msgid "node.guide.description" +msgstr "計測・参照の注記(直線、面積、円弧)。" +# Source-Hash: 1344ea2602e3aa9e # Review: required -# Source-Hash: e16f85e4bebfefb1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scoop" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guide" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.scoop" -msgstr "スクープ" +msgid "node.guide.label" +msgstr "ガイド" +# Source-Hash: 5402d634f40b2f97 # Review: required -# Source-Hash: ec53d40877e11b62 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slant-box" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rain-water channel running along the eave of a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.eyebrowVent.panel.slantBox" -msgstr "傾斜ボックス" +msgid "node.gutter.description" +msgstr "屋根面の軒に沿う雨水の樋。" +# Source-Hash: fc7d4ecf973db135 # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Downspout" +#: packages/nodes/src/gutter/downspouts-panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.style" -msgstr "スタイル" +msgid "node.gutter.downspoutsPanel.addDownspout" +msgstr "縦樋を追加" +# Source-Hash: 9b9929bac2c39bca # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspout {number}" +#: packages/nodes/src/gutter/downspouts-panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.width" -msgstr "幅" +msgid "node.gutter.downspoutsPanel.downspoutNumber" +msgstr "縦樋 {number}" -# Source-Hash: 20032fe9430f610d +# Source-Hash: fc34d45725838141 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A straight or curved fence segment with configurable posts and infill." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspouts" +#: packages/nodes/src/gutter/downspouts-panel.tsx #, fuzzy -msgid "node.fence.description" -msgstr "支柱と面材を設定できる直線または曲線のフェンス区間。" +msgid "node.gutter.downspoutsPanel.downspouts" +msgstr "縦樋" +# Source-Hash: ac329c74056f0616 # Review: required -# Source-Hash: 6f84b85097bc1ffc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add point after" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove downspout" +#: packages/nodes/src/gutter/downspouts-panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.addPointAfter" -msgstr "後ろに点を追加" +msgid "node.gutter.downspoutsPanel.removeDownspout" +msgstr "縦樋を削除" +# Source-Hash: 14ba981da3627ae2 # Review: required -# Source-Hash: 1a15ab3101e2d166 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a slab or shaped surface on this level." -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gutter" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fence.inspectorEditors.chooseASlabOrShapedSurface" -msgstr "この階のスラブか成形面を選んでください。" +msgid "node.gutter.label" +msgstr "雨樋" +# Source-Hash: 387082cd5f118bed # Review: required -# Source-Hash: 78a5625401384000 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a surface" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Manual" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.chooseASurface" -msgstr "面を選択" +msgid "node.hole.manual" +msgstr "手動" +# Source-Hash: fffde6fa82e65ffc # Review: required -# Source-Hash: 2ee121dca87bb64a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hole {number} (Editing)" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.corner" -msgstr "コーナー" +msgid "node.holeEditing" +msgstr "開口 {number}(編集中)" +# Source-Hash: 0fe446c72451e4a5 # Review: required -# Source-Hash: f08fbb462e9afc0e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curve" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hole {number}" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.curve" -msgstr "曲線" +msgid "node.holeNumber" +msgstr "開口 {number}" +# Source-Hash: 8eeeb79ff4221939 # Review: required -# Source-Hash: a028e08962c388e0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curved" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} {unit} · {count, plural, one {{points} pt} other {{points} pts}} · {source}" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.curved" -msgstr "曲線" +msgid "node.holeSummary" +msgstr "{area} {unit} · {count, plural, other {{points} 点}} · {source}" +# Source-Hash: 50e9252d30f3fb4d # Review: required -# Source-Hash: 81b75058b7843a0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{style, select, picket {Distribution controls pickets in each bay between posts.} horizontal {Distribution controls posts along the full fence.} other {Distribution controls infill pieces between the two end posts.}} Spacing is measured between centers. The available width limits the count so pieces do not overlap." -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Furnace, air handler, or condenser — duct runs connect to its supply/return collars." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fence.inspectorEditors.distributionInfo" -msgstr "{style, select, picket {配置は支柱間の各スパンのピケットを制御します。} horizontal {配置はフェンス全体の支柱を制御します。} other {配置は両端の支柱間の充填材を制御します。}}間隔は中心間で測ります。重ならないよう、使える幅によって数が制限されます。" +msgid "node.hvacEquipment.description" +msgstr "炉、空調機、室外機 — ダクトは給気・還気カラーに接続します。" +# Source-Hash: 3bf1c1a8dbb93743 # Review: required -# Source-Hash: fbc8f54b0e3fdeb1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit path" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "HVAC Unit" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fence.inspectorEditors.editPath" -msgstr "パスを編集" +msgid "node.hvacEquipment.label" +msgstr "空調機" +# Source-Hash: 8fb180251a321cef # Review: required -# Source-Hash: 55686db44529c013 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Extend path" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/hvac-equipment/tool.tsx #, fuzzy -msgid "node.fence.inspectorEditors.extendPath" -msgstr "パスを延長" +msgid "node.hvacEquipment.tool.rTRotate" +msgstr "R/T で回転" +# Source-Hash: f24a1089d9256460 # Review: required -# Source-Hash: 0bf0f27e631aa98d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follow highest surface" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Geometry preserved from an imported model when no native Pascal shape exists." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fence.inspectorEditors.followHighestSurface" -msgstr "最も高い面に沿う" +msgid "node.importedMesh.description" +msgstr "Pascal のネイティブ形状がない場合に、インポートしたモデルから保持されるジオメトリ。" +# Source-Hash: 9f9d11f287f722d7 # Review: required -# Source-Hash: e0b381fcb05a65c4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follow selected surface" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Imported Mesh" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fence.inspectorEditors.followSelectedSurface" -msgstr "選択した面に沿う" +msgid "node.importedMesh.label" +msgstr "インポートメッシュ" +# Source-Hash: 9cce89f94c673821 # Review: required -# Source-Hash: c418d97f803af8dd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hold starting height" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Couldn't rebuild with these values." +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.holdStartingHeight" -msgstr "開始時の高さを保つ" +msgid "node.item.authoredParams.couldnTRebuildWithTheseValues" +msgstr "この値では再構築できませんでした。" +# Source-Hash: 373b929318436fe3 # Review: required -# Source-Hash: 295ca9336dc1935b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Join" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Parameters" +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.join" -msgstr "結合" +msgid "node.item.authoredParams.parameters" +msgstr "パラメーター" +# Source-Hash: 558cb886dbe0babe # Review: required -# Source-Hash: 643687bc3adaac76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rebuilding…" +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.length" -msgstr "長さ" +msgid "node.item.authoredParams.rebuilding" +msgstr "再構築中…" +# Source-Hash: a094c99dc8ad29a3 # Review: required -# Source-Hash: 1fedc8a2f2ea6887 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {{number} point} other {{number} points}} · {length} m" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rebuilding in Blender…" +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.pathSummary" -msgstr "{count, plural, other {{number} 点}} · {length} m" +msgid "node.item.authoredParams.rebuildingInBlender" +msgstr "Blender で再構築中…" +# Source-Hash: 1778f93ee143cd95 # Review: required -# Source-Hash: c96d499e11181429 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket rail projection" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset {param}" +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.picketRailProjection" -msgstr "ピケットのレール突出" +msgid "node.item.authoredParams.resetParam" +msgstr "{param}をリセット" +# Source-Hash: 5a28cf5f2402dd7a # Review: required -# Source-Hash: a1880fca8372d06f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Point" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset parameters" +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.point" -msgstr "点" +msgid "node.item.authoredParams.resetParameters" +msgstr "パラメーターをリセット" +# Source-Hash: 6eb8025c60d6d3ca # Review: required -# Source-Hash: 39bc6254b5307f53 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove point" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset to default" +#: packages/nodes/src/item/authored-params.tsx #, fuzzy -msgid "node.fence.inspectorEditors.removePoint" -msgstr "点を削除" +msgid "node.item.authoredParams.resetToDefault" +msgstr "既定に戻す" +# Source-Hash: 63f79b3c467177b3 # Review: required -# Source-Hash: ea56af3a0d7a65e4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set each span to straight or curved, then drag its points and curve handles in either view." -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A catalog-backed item (furniture, fixtures, decorations)." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fence.inspectorEditors.setEachSpanToStraightOr" -msgstr "各スパンを直線か曲線にしてから、どちらのビューでも点と曲線ハンドルをドラッグします。" +msgid "node.item.description" +msgstr "カタログのアイテム(家具、設備、装飾)。" +# Source-Hash: 2743a0e9d2743807 # Review: required -# Source-Hash: 354c8bc5c8da5a6e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Smooth" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Item" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fence.inspectorEditors.smooth" -msgstr "スムーズ" +msgid "node.item.label" +msgstr "アイテム" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 3c700cc1299a150f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Span to point {number}" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.spanToPointNumber" -msgstr "点 {number} までのスパン" +msgid "node.item.panel.actions" +msgstr "操作" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: 4ee35f740730ae87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.straight" -msgstr "直進" +msgid "node.item.panel.delete" +msgstr "削除" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: 78a454b7ac7a3cd9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.surface" -msgstr "面" +msgid "node.item.panel.dimensions" +msgstr "寸法" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: ab2de0428c093018 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface behavior" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.surfaceBehavior" -msgstr "面への追従" +msgid "node.item.panel.duplicate" +msgstr "複製" -# Source-Hash: 02042fde61b5aa11 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fence" -#: packages/nodes/src/i18n/definition-messages.ts +# Source-Hash: 6e68b62d2aa611a4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Info" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.label" -msgstr "フェンス" +msgid "node.item.panel.info" +msgstr "情報" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: 3e07a9889c1bd7f9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Detach endpoint" -#: packages/nodes/src/fence/move-endpoint-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.moveEndpointTool.detachEndpoint" -msgstr "端点を切り離す" +msgid "node.item.panel.move" +msgstr "移動" +# Source-Hash: 28fe6e9deddde6e8 # Review: required -# Source-Hash: 7a3ce9fec6370e3e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag endpoint" -#: packages/nodes/src/fence/move-endpoint-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "pos" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fence.moveEndpointTool.dragEndpoint" -msgstr "端点をドラッグ" +msgid "node.item.panel.pos" +msgstr "位置" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: d7cf5045c01b2eb9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close" -#: packages/nodes/src/fence-feature/actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fenceFeature.actions.close" -msgstr "閉じる" +msgid "node.item.panel.position" +msgstr "位置" +# Source-Hash: 5f433581c8f404fa # Review: required -# Source-Hash: 3e52f04f92e08070 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/fence-feature/actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "rot" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fenceFeature.actions.open" -msgstr "開く" +msgid "node.item.panel.rot" +msgstr "回転" +# Source-Hash: 01989595ee7c1dc0 # Review: required -# Source-Hash: fc4cf2bc034fc547 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Board width" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.boardWidth" -msgstr "板幅" +msgid "node.item.panel.rotation" +msgstr "回転" +# Source-Hash: 8210f376c0d29acc # Review: required -# Source-Hash: f3b11e5b2dd3b25f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bracing" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scale" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.bracing" -msgstr "筋交い" +msgid "node.item.panel.scale" +msgstr "縮尺" +# Source-Hash: 58fee802997c811c # Review: required -# Source-Hash: d09ec3d9565734c3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Distance from start" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "scale" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.distanceFromStart" -msgstr "始点からの距離" +msgid "node.item.panel.scale2" +msgstr "縮尺" +# Source-Hash: b0d264950558d50e # Review: required -# Source-Hash: dcd803eaf3796298 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fence unavailable." -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Uniform Scale" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.fenceUnavailable" -msgstr "フェンスを利用できません。" +msgid "node.item.panel.uniformScale" +msgstr "均等スケール" +# Source-Hash: 4b8d7e52013d1691 # Review: required -# Source-Hash: 3519d91b7bda18a5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame width" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "XYZ" +#: packages/nodes/src/item/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.frameWidth" -msgstr "枠の幅" +msgid "node.item.panel.xyz" +msgstr "XYZ" +# Source-Hash: a9e2d7b215696e2a # Review: required -# Source-Hash: cb18554b2420e700 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gate height" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An attached mono-pitch or freestanding mono, gable, or butterfly canopy with managed structure and drainage." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.gateHeight" -msgstr "門扉の高さ" +msgid "node.leanToExtension.description" +msgstr "構造と排水を自動処理する、付属の片流れまたは独立型の片流れ・切妻・バタフライのキャノピー。" +# Source-Hash: 8503bedfbafde9a3 # Review: required -# Source-Hash: 54098b5ee574737a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gate style" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Canopy" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.gateStyle" -msgstr "門のスタイル" +msgid "node.leanToExtension.label" +msgstr "キャノピー" +# Source-Hash: 45673462f914d3df # Review: required -# Source-Hash: 4fc3e60be28f60d5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground clearance" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A single floor of a building, holding walls / slabs / ceilings / items." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.groundClearance" -msgstr "地面とのクリアランス" +msgid "node.level.description" +msgstr "建物の1つの階。壁・スラブ・天井・アイテムを含みます。" +# Source-Hash: 0608743fc1736d86 # Review: required -# Source-Hash: 916f2e07bf082795 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hinges and latch" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.hingesAndLatch" -msgstr "丁番とラッチ" +msgid "node.level.label" +msgstr "階層" +# Source-Hash: 156bdee8fee5bec6 # Review: required -# Source-Hash: 5bd2e597fbb2a2c9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hinge side" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Refrigerant lineset — copper suction + liquid pair joining a condenser to the indoor coil." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.hingeSide" -msgstr "丁番側" +msgid "node.lineset.description" +msgstr "冷媒配管 — 室外機と室内コイルを結ぶ銅製の吸入管と液管。" +# Source-Hash: 362b03eba9d8234c # Review: required -# Source-Hash: 8fec7e969045a8e7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Horizontal boards" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lineset" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.horizontalBoards" -msgstr "横板" +msgid "node.lineset.label" +msgstr "冷媒配管" +# Source-Hash: 2bd4a85bed158269 # Review: required -# Source-Hash: f4addad87cc4223e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Infill spacing" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standalone refrigerant liquid line — a thin bare-copper run; Follow mode traces an existing lineset." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.infillSpacing" -msgstr "充填材の間隔" +msgid "node.liquidLine.description" +msgstr "単独の冷媒液管 — 細い裸銅管。追従モードは既存の冷媒配管に沿います。" +# Source-Hash: c34c9b36492c6e21 # Review: required -# Source-Hash: cdec08b292742b20 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Jamb posts" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Liquid Line" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.jambPosts" -msgstr "門柱" +msgid "node.liquidLine.label" +msgstr "液管" +# Source-Hash: 601aaf23ce5a9279 # Review: required -# Source-Hash: ef88410453ee7414 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Keep the opening inside the fence and clear of other gates or passages." -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click to trace this lineset run" +#: packages/nodes/src/liquid-line/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.keepTheOpeningInsideTheFence" -msgstr "開口はフェンス内に収め、ほかの門扉や通路と重ならないようにしてください。" +msgid "node.liquidLine.tool.clickToTraceThisLinesetRun" +msgstr "クリックしてこの冷媒配管をたどる" +# Source-Hash: 77df017af9260468 # Review: required -# Source-Hash: 67cd0171b226fedb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Leaf thickness" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow: hover a lineset" +#: packages/nodes/src/liquid-line/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.leafThickness" -msgstr "扉の厚さ" +msgid "node.liquidLine.tool.followHoverALineset" +msgstr "フォロー:冷媒配管にカーソルを合わせる" +# Source-Hash: ff4e3bb72267859e # Review: required -# Source-Hash: c390ba248e629b9e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Leaves" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A persistent distance, angle, area, perimeter, or volume annotation." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.leaves" -msgstr "扉" +msgid "node.measurement.description" +msgstr "距離、角度、面積、周長、体積の常設注記。" +# Source-Hash: ec3567fd058bab7c # Review: required -# Source-Hash: d7bb934589475512 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left leaf proportion" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Measurement" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.leftLeafProportion" -msgstr "左扉の比率" +msgid "node.measurement.label" +msgstr "計測" +# Source-Hash: d71b38e990539364 # Review: required -# Source-Hash: aa9fe0ebace8957d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match fence height" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{kind} {number}" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.matchFenceHeight" -msgstr "フェンスの高さに合わせる" +msgid "node.numberedName" +msgstr "{kind} {number}" +# Source-Hash: 09865d8781ef8699 # Review: required -# Source-Hash: c15c1af69ec5c1eb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match fence style" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Currently {value}" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/roof/panel.tsx +#: packages/nodes/src/stair/panel.tsx +#: packages/nodes/src/wall/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.matchFenceStyle" -msgstr "フェンスのスタイルに合わせる" +msgid "node.panel.currently" +msgstr "現在 {value}" +# Source-Hash: 7764b50334e9f71d # Review: required -# Source-Hash: 51b7ab6a0a78d90a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening angle" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV joint — elbow bend, 45° wye, or sanitary tee." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.openingAngle" -msgstr "開き角度" +msgid "node.pipeFitting.description" +msgstr "排水継手 — エルボ、45°Y、衛生T。" +# Source-Hash: c040baa6ed4c7aa5 # Review: required -# Source-Hash: d2e20300c07aa722 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening width" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pipe Fitting" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.openingWidth" -msgstr "開口幅" +msgid "node.pipeFitting.label" +msgstr "配管継手" +# Source-Hash: dd86efcab72fc5c7 # Review: required -# Source-Hash: 6b108fb1d0eb8f9d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open rails" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Axis" +#: packages/nodes/src/pipe-fitting/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.openRails" -msgstr "横桟" +msgid "node.pipeFitting.tool.axis" +msgstr "軸" +# Source-Hash: 5232a826549f915e # Review: required -# Source-Hash: d500c4b7827d3390 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cross" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "⌥ axis" +#: packages/nodes/src/pipe-fitting/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.cross" -msgstr "クロス" +msgid "node.pipeFitting.tool.axis2" +msgstr "⌥ 軸" +# Source-Hash: 8fb180251a321cef # Review: required -# Source-Hash: 7420c0d2caee1c22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diagonal" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/pipe-fitting/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.diagonal" -msgstr "斜め" +msgid "node.pipeFitting.tool.rTRotate" +msgstr "R/T で回転" +# Source-Hash: a0bb4762aa66fa3e # Review: required -# Source-Hash: 7308869944020839 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double gate" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drain / waste / vent pipe run — draw level or toggle a ¼″ per foot fall with S." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.option.doubleGate" -msgstr "両開き門" +msgid "node.pipeSegment.description" +msgstr "排水・汚水・通気管 — 水平に描くか、S で1フィートあたり¼″の勾配を切り替え。" +# Source-Hash: 457155657704f7cc # Review: required -# Source-Hash: 1f4ad5ad3e1be222 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inward" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV Pipe" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.option.inward" -msgstr "内開き" +msgid "node.pipeSegment.label" +msgstr "排水管" +# Source-Hash: 6d0cdd14d0675e05 # Review: required -# Source-Hash: f365c6b6dd9ebab9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV P-trap — water seal on the waste line. The trap arm runs to the vent." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.option.left" -msgstr "左" +msgid "node.pipeTrap.description" +msgstr "Pトラップ — 排水管の封水。トラップアームは通気管へ伸びます。" +# Source-Hash: b778a315e82065a0 # Review: required -# Source-Hash: f2953d2931e36d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trap" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.option.none" -msgstr "なし" +msgid "node.pipeTrap.label" +msgstr "トラップ" +# Source-Hash: 73078bc0f5d686fa # Review: required -# Source-Hash: ccd8f06b8f8d27c9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Outward" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{diameter}\" Trap" +#: packages/nodes/src/pipe-trap/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.outward" -msgstr "外開き" +msgid "node.pipeTrap.tool.diameterTrap" +msgstr "{diameter}\" トラップ" +# Source-Hash: 8fb180251a321cef # Review: required -# Source-Hash: b34d5ee0f218221d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/pipe-trap/tool.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.right" -msgstr "右" +msgid "node.pipeTrap.tool.rTRotate" +msgstr "R/T で回転" +# Source-Hash: 0efe82436b915f6d # Review: required -# Source-Hash: d327097d9ac1099f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single gate" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Experimental editable recipe" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.option.singleGate" -msgstr "片開き門" +msgid "node.proceduralItem.description" +msgstr "実験的な編集可能レシピ" +# Source-Hash: c8bbcc888cce7b8a # Review: required -# Source-Hash: 9295ddc2805b21e2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Procedural item" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.picket" -msgstr "ピケット" +msgid "node.proceduralItem.label" +msgstr "プロシージャルアイテム" +# Source-Hash: 356aa0ed69cb8ec5 # Review: required -# Source-Hash: 8dd5999b235f60ab -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post height" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ventilation strip running along the ridge of a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.postHeight" -msgstr "支柱の高さ" +msgid "node.ridgeVent.description" +msgstr "屋根面の棟に沿う換気帯。" +# Source-Hash: 54b74080f33c8c4e # Review: required -# Source-Hash: 90bcd7a8123ec343 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove gate" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge Vent" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.removeGate" -msgstr "門扉を削除" +msgid "node.ridgeVent.label" +msgstr "棟換気" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 7e3505710613543f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove opening" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.removeOpening" -msgstr "開口を削除" +msgid "node.ridgeVent.panel.actions" +msgstr "操作" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: af6f8885fe0fa4e9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid privacy" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.solidPrivacy" -msgstr "目隠し" +msgid "node.ridgeVent.panel.delete" +msgstr "削除" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: 1a7048255c3bdfcb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swing direction" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.swingDirection" -msgstr "開く向き" +msgid "node.ridgeVent.panel.dimensions" +msgstr "寸法" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: eba3df14a2de0812 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical slats" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.verticalSlats" -msgstr "縦板" +msgid "node.ridgeVent.panel.duplicate" +msgstr "複製" -# Source-Hash: df61821ed00852d8 +# Source-Hash: 18bf817325c1c537 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A gate hosted by a fence." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End Caps" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceGate.description" -msgstr "フェンスに取り付けた門。" +msgid "node.ridgeVent.panel.endCaps" +msgstr "エンドキャップ" -# Source-Hash: 4a479aa23542d766 +# Source-Hash: 466f817a0102d4a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gate" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flanged" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceGate.label" -msgstr "門" +msgid "node.ridgeVent.panel.flanged" +msgstr "フランジ付き" -# Source-Hash: 8f9c927d79796c26 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "An intentional opening in a fence." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceOpening.description" -msgstr "フェンスに設けた開口。" +msgid "node.ridgeVent.panel.height" +msgstr "高さ" -# Source-Hash: ab67bb47e647d594 +# Source-Hash: 643687bc3adaac76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open Passage" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceOpening.label" -msgstr "通路" +msgid "node.ridgeVent.panel.length" +msgstr "長さ" -# Source-Hash: dc3adf0c2d50dba6 +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor opening" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.floorOpening.label" -msgstr "床開口" +msgid "node.ridgeVent.panel.move" +msgstr "移動" -# Source-Hash: 2f4fac2b1d39fdb1 +# Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A measurement / reference annotation (linear, area, or arc)." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.guide.description" -msgstr "計測・参照の注記(直線、面積、円弧)。" +msgid "node.ridgeVent.panel.open" +msgstr "開く" -# Source-Hash: 1344ea2602e3aa9e +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guide" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.guide.label" -msgstr "ガイド" +msgid "node.ridgeVent.panel.position" +msgstr "位置" -# Source-Hash: 5402d634f40b2f97 +# Source-Hash: 54b74080f33c8c4e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rain-water channel running along the eave of a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge Vent" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.gutter.description" -msgstr "屋根面の軒に沿う雨水の樋。" +msgid "node.ridgeVent.panel.ridgeVent" +msgstr "棟換気" +# Source-Hash: 01989595ee7c1dc0 # Review: required -# Source-Hash: fc7d4ecf973db135 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Downspout" -#: packages/nodes/src/gutter/downspouts-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.gutter.downspoutsPanel.addDownspout" -msgstr "縦樋を追加" +msgid "node.ridgeVent.panel.rotation" +msgstr "回転" +# Source-Hash: e9046e9823b400a0 # Review: required -# Source-Hash: 9b9929bac2c39bca -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspout {number}" -#: packages/nodes/src/gutter/downspouts-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingled" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.gutter.downspoutsPanel.downspoutNumber" -msgstr "縦樋 {number}" +msgid "node.ridgeVent.panel.shingled" +msgstr "シングル葺き" +# Source-Hash: d998c212030bc7c2 # Review: required -# Source-Hash: fc34d45725838141 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspouts" -#: packages/nodes/src/gutter/downspouts-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.gutter.downspoutsPanel.downspouts" -msgstr "縦樋" +msgid "node.ridgeVent.panel.standard" +msgstr "標準" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: ac329c74056f0616 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove downspout" -#: packages/nodes/src/gutter/downspouts-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.gutter.downspoutsPanel.removeDownspout" -msgstr "縦樋を削除" +msgid "node.ridgeVent.panel.style" +msgstr "スタイル" -# Source-Hash: 14ba981da3627ae2 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gutter" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.gutter.label" -msgstr "雨樋" +msgid "node.ridgeVent.panel.width" +msgstr "幅" -# Source-Hash: 387082cd5f118bed +# Source-Hash: c6d3976b4eb80586 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Manual" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arch bays" +#: packages/nodes/src/roof/barrel-panel.tsx #, fuzzy -msgid "node.hole.manual" -msgstr "手動" +msgid "node.roof.barrelPanel.archBays" +msgstr "アーチベイ" -# Source-Hash: fffde6fa82e65ffc +# Source-Hash: 1cfdd5affedf153c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hole {number} (Editing)" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Barrel arch" +#: packages/nodes/src/roof/barrel-panel.tsx #, fuzzy -msgid "node.holeEditing" -msgstr "開口 {number}(編集中)" +msgid "node.roof.barrelPanel.barrelArch" +msgstr "かまぼこアーチ" -# Source-Hash: 0fe446c72451e4a5 +# Source-Hash: b3e8929750d18f7b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hole {number}" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat panes follow a circular arch. Rise is measured from the eaves." +#: packages/nodes/src/roof/barrel-panel.tsx #, fuzzy -msgid "node.holeNumber" -msgstr "開口 {number}" +msgid "node.roof.barrelPanel.flatPanesFollowACircularArch" +msgstr "平らなガラスが円弧に沿います。ライズは軒から測ります。" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: fd26f8df9d087c6b +# Source-Hash: fe8c5b735495eb00 # Review: required -# English: "{area} m² · {count, plural, one {{points} pt} other {{points} pts}} · {source}" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rise" +#: packages/nodes/src/roof/barrel-panel.tsx #, fuzzy -msgid "node.holeSummary" -msgstr "{area} m² · {count, plural, other {{points} 点}} · {source}" +msgid "node.roof.barrelPanel.rise" +msgstr "高さ" -# Source-Hash: 50e9252d30f3fb4d +# Source-Hash: 6afeec8de7ed618d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Furnace, air handler, or condenser — duct runs connect to its supply/return collars." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A pitched / hip / gable roof composed of one or more segments." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.hvacEquipment.description" -msgstr "炉、空調機、室外機 — ダクトは給気・還気カラーに接続します。" +msgid "node.roof.description" +msgstr "1つ以上の面で構成される勾配・寄棟・切妻屋根。" -# Source-Hash: 3bf1c1a8dbb93743 +# Source-Hash: b5be04471fd3fb7a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "HVAC Unit" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arch bay {number}" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.hvacEquipment.label" -msgstr "空調機" +msgid "node.roof.glazing.face.archBay" +msgstr "アーチベイ {number}" +# Source-Hash: 93381b9024a75a99 # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/hvac-equipment/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back slope" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.hvacEquipment.tool.rTRotate" -msgstr "R/T で回転" +msgid "node.roof.glazing.face.back" +msgstr "背面の勾配" -# Source-Hash: f24a1089d9256460 +# Source-Hash: 08b00107b635e11d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Geometry preserved from an imported model when no native Pascal shape exists." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left end" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.importedMesh.description" -msgstr "Pascal のネイティブ形状がない場合に、インポートしたモデルから保持されるジオメトリ。" +msgid "node.roof.glazing.face.endLeft" +msgstr "左端" -# Source-Hash: 9f9d11f287f722d7 +# Source-Hash: 821734ea5d17a693 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Imported Mesh" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right end" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.importedMesh.label" -msgstr "インポートメッシュ" +msgid "node.roof.glazing.face.endRight" +msgstr "右端" -# Source-Hash: 9cce89f94c673821 +# Source-Hash: 40c9ef62055067e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Couldn't rebuild with these values." -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front slope" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.item.authoredParams.couldnTRebuildWithTheseValues" -msgstr "この値では再構築できませんでした。" +msgid "node.roof.glazing.face.front" +msgstr "前面の勾配" -# Source-Hash: 373b929318436fe3 +# Source-Hash: 1a88da71d5e5f0d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Parameters" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed slope" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.item.authoredParams.parameters" -msgstr "パラメーター" +msgid "node.roof.glazing.face.slope" +msgstr "片流れの勾配" -# Source-Hash: 558cb886dbe0babe +# Source-Hash: 3bcc542295b4c61e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rebuilding…" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Alignment" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.rebuilding" -msgstr "再構築中…" +msgid "node.roof.glazingControls.alignment" +msgstr "揃え" -# Source-Hash: a094c99dc8ad29a3 +# Source-Hash: 5211341ed18f33f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rebuilding in Blender…" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.rebuildingInBlender" -msgstr "Blender で再構築中…" +msgid "node.roof.glazingControls.center" +msgstr "中央" -# Source-Hash: 1778f93ee143cd95 +# Source-Hash: 512e47607a37af46 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset {param}" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a layout to edit the grid." +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.resetParam" -msgstr "{param}をリセット" +msgid "node.roof.glazingControls.chooseALayoutToEditThe" +msgstr "レイアウトを選んでグリッドを編集します。" -# Source-Hash: 5a28cf5f2402dd7a +# Source-Hash: 65b1cbba3b92c5b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset parameters" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Empty" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.resetParameters" -msgstr "パラメーターをリセット" +msgid "node.roof.glazingControls.empty" +msgstr "空" -# Source-Hash: 6eb8025c60d6d3ca +# Source-Hash: 135874d189176d13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset to default" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.resetToDefault" -msgstr "既定に戻す" +msgid "node.roof.glazingControls.end" +msgstr "終点" -# Source-Hash: 63f79b3c467177b3 +# Source-Hash: 4fb65101d0b1a222 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A catalog-backed item (furniture, fixtures, decorations)." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fixed spacing" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.description" -msgstr "カタログのアイテム(家具、設備、装飾)。" +msgid "node.roof.glazingControls.fixedSpacing" +msgstr "固定間隔" -# Source-Hash: 2743a0e9d2743807 +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Item" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.label" -msgstr "アイテム" +msgid "node.roof.glazingControls.glass" +msgstr "ガラス" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 54800340a0eeab23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layout" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.actions" -msgstr "操作" +msgid "node.roof.glazingControls.layout" +msgstr "レイアウト" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 321ca5101ab61db7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Maximum spacing" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.delete" -msgstr "削除" +msgid "node.roof.glazingControls.maximumSpacing" +msgstr "最大間隔" -# Source-Hash: 12df69f42beb0643 +# Source-Hash: d10743fce478d9f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Max spacing" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.dimensions" -msgstr "寸法" +msgid "node.roof.glazingControls.maxSpacing" +msgstr "最大間隔" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 37d9f63758abdb67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mixed" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.duplicate" -msgstr "複製" +msgid "node.roof.glazingControls.mixed" +msgstr "混在" -# Source-Hash: 6e68b62d2aa611a4 +# Source-Hash: b91302bf741c9fd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Info" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel count" +#: packages/nodes/src/roof/glazing-controls.tsx +#, fuzzy +msgid "node.roof.glazingControls.panelCount" +msgstr "パネル数" + +# Source-Hash: 6ce059aee1386f72 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panels" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.info" -msgstr "情報" +msgid "node.roof.glazingControls.panels" +msgstr "パネル" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: ef3e765e692faf4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.move" -msgstr "移動" +msgid "node.roof.glazingControls.solid" +msgstr "ソリッド" -# Source-Hash: 28fe6e9deddde6e8 +# Source-Hash: e4698e83d02beb6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "pos" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spacing" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.pos" -msgstr "位置" +msgid "node.roof.glazingControls.spacing" +msgstr "間隔" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: 0a26a1e61c825660 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.position" -msgstr "位置" +msgid "node.roof.glazingControls.start" +msgstr "始点" -# Source-Hash: 5f433581c8f404fa +# Source-Hash: 095237e9e2df4d9c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "rot" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{title} alignment" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.rot" -msgstr "回転" +msgid "node.roof.glazingControls.titleAlignment" +msgstr "{title}の揃え" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: c98a4e6b28f05e0f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Changes apply to all {length} roof segments." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.rotation" -msgstr "回転" +msgid "node.roof.glazingPanel.changesApplyToAllLengthRoof" +msgstr "変更は {length} 個すべての屋根セグメントに適用されます。" -# Source-Hash: 8210f376c0d29acc +# Source-Hash: c5d2ff7fda4787cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scale" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose one roof system to edit settings for all selected segments." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.scale" -msgstr "縮尺" +msgid "node.roof.glazingPanel.chooseOneRoofSystemToEdit" +msgstr "屋根システムを1つ選ぶと、選択したすべてのセグメントの設定を編集できます。" -# Source-Hash: 58fee802997c811c +# Source-Hash: 80e07a119b63187c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "scale" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close the roof ends" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.scale2" -msgstr "縮尺" +msgid "node.roof.glazingPanel.closeTheRoofEnds" +msgstr "屋根の端を閉じる" -# Source-Hash: b0d264950558d50e +# Source-Hash: e28dd27d54aaa7ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Uniform Scale" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default panel infill" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.uniformScale" -msgstr "均等スケール" +msgid "node.roof.glazingPanel.defaultPanelInfill" +msgstr "パネルの既定の充填" -# Source-Hash: 4b8d7e52013d1691 +# Source-Hash: 134d33e2465937e7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "XYZ" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divides each roof face into columns." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.xyz" -msgstr "XYZ" +msgid "node.roof.glazingPanel.dividesEachRoofFaceIntoColumns" +msgstr "各屋根面を列に分割します。" -# Source-Hash: a9e2d7b215696e2a +# Source-Hash: 896a6e4da3357c39 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "An attached mono-pitch or freestanding mono, gable, or butterfly canopy with managed structure and drainage." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divides the length of each arch bay into columns." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.leanToExtension.description" -msgstr "構造と排水を自動処理する、付属の片流れまたは独立型の片流れ・切妻・バタフライのキャノピー。" +msgid "node.roof.glazingPanel.dividesTheLengthOfEachArch" +msgstr "各アーチベイの長さを列に分割します。" -# Source-Hash: 8503bedfbafde9a3 +# Source-Hash: be9c810d28d1feb9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Canopy" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End infill fills the space above the walls. Edit room walls and ceilings separately." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.leanToExtension.label" -msgstr "キャノピー" +msgid "node.roof.glazingPanel.endInfillFillsTheSpaceAbove" +msgstr "端部の充填は壁の上の空間を埋めます。部屋の壁と天井は別々に編集してください。" -# Source-Hash: 45673462f914d3df +# Source-Hash: 0b8b27dbc57cca44 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A single floor of a building, holding walls / slabs / ceilings / items." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame color" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.level.description" -msgstr "建物の1つの階。壁・スラブ・天井・アイテムを含みます。" +msgid "node.roof.glazingPanel.frameColor" +msgstr "枠の色" -# Source-Hash: 0608743fc1736d86 +# Source-Hash: fd413477f1a9e5ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame depth" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.level.label" -msgstr "階層" +msgid "node.roof.glazingPanel.frameDepth" +msgstr "枠の奥行き" -# Source-Hash: 156bdee8fee5bec6 +# Source-Hash: 3519d91b7bda18a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Refrigerant lineset — copper suction + liquid pair joining a condenser to the indoor coil." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame width" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.lineset.description" -msgstr "冷媒配管 — 室外機と室内コイルを結ぶ銅製の吸入管と液管。" +msgid "node.roof.glazingPanel.frameWidth" +msgstr "枠の幅" -# Source-Hash: 362b03eba9d8234c +# Source-Hash: c7e72beff9fe4b37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lineset" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framing" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.lineset.label" -msgstr "冷媒配管" +msgid "node.roof.glazingPanel.framing" +msgstr "下地" -# Source-Hash: 2bd4a85bed158269 +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standalone refrigerant liquid line — a thin bare-copper run; Follow mode traces an existing lineset." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.liquidLine.description" -msgstr "単独の冷媒液管 — 細い裸銅管。追従モードは既存の冷媒配管に沿います。" +msgid "node.roof.glazingPanel.glass" +msgstr "ガラス" -# Source-Hash: c34c9b36492c6e21 +# Source-Hash: 9c38875c310547ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Liquid Line" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass tint" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.liquidLine.label" -msgstr "液管" +msgid "node.roof.glazingPanel.glassTint" +msgstr "ガラスの色合い" +# Source-Hash: dd330a94b3f7a65a # Review: required -# Source-Hash: 601aaf23ce5a9279 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click to trace this lineset run" -#: packages/nodes/src/liquid-line/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glazed" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.liquidLine.tool.clickToTraceThisLinesetRun" -msgstr "クリックしてこの冷媒配管をたどる" +msgid "node.roof.glazingPanel.glazed" +msgstr "ガラス張り" +# Source-Hash: e6be52df9197243a # Review: required -# Source-Hash: 77df017af9260468 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follow: hover a lineset" -#: packages/nodes/src/liquid-line/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glazing is available for gable, straight shed, and barrel roofs." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.liquidLine.tool.followHoverALineset" -msgstr "フォロー:冷媒配管にカーソルを合わせる" +msgid "node.roof.glazingPanel.glazingIsAvailableForGableStraight" +msgstr "ガラスは切妻、直線の片流れ、ヴォールト屋根で使えます。" -# Source-Hash: ff4e3bb72267859e +# Source-Hash: a4e7ef2e31d7220b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A persistent distance, angle, area, perimeter, or volume annotation." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid across the roof" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.measurement.description" -msgstr "距離、角度、面積、周長、体積の常設注記。" +msgid "node.roof.glazingPanel.gridAcrossTheRoof" +msgstr "屋根を横切るグリッド" -# Source-Hash: ec3567fd058bab7c +# Source-Hash: 2f28a3b33fccf56b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Measurement" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid along the length" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.measurement.label" -msgstr "計測" +msgid "node.roof.glazingPanel.gridAlongTheLength" +msgstr "長さ方向のグリッド" -# Source-Hash: d71b38e990539364 +# Source-Hash: 1f701893dbf9d72b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{kind} {number}" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid along the slope" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.numberedName" -msgstr "{kind} {number}" +msgid "node.roof.glazingPanel.gridAlongTheSlope" +msgstr "勾配方向のグリッド" -# Source-Hash: 09865d8781ef8699 +# Source-Hash: 20c8dfbadda20e3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Currently {value}" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/roof/panel.tsx -#: packages/nodes/src/stair/panel.tsx -#: packages/nodes/src/wall/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid within each arch bay" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.panel.currently" -msgstr "現在 {value}" +msgid "node.roof.glazingPanel.gridWithinEachArchBay" +msgstr "各アーチベイ内のグリッド" -# Source-Hash: 7764b50334e9f71d +# Source-Hash: 7c339a5fae55681d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV joint — elbow bend, 45° wye, or sanitary tee." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Infill" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.pipeFitting.description" -msgstr "排水継手 — エルボ、45°Y、衛生T。" +msgid "node.roof.glazingPanel.infill" +msgstr "充填" -# Source-Hash: c040baa6ed4c7aa5 +# Source-Hash: 1c0b8a5503c5daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pipe Fitting" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opacity" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.pipeFitting.label" -msgstr "配管継手" +msgid "node.roof.glazingPanel.opacity" +msgstr "不透明度" +# Source-Hash: 4d412746658f2faf # Review: required -# Source-Hash: dd86efcab72fc5c7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Axis" -#: packages/nodes/src/pipe-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pane thickness" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.pipeFitting.tool.axis" -msgstr "軸" +msgid "node.roof.glazingPanel.paneThickness" +msgstr "ガラス板の厚さ" +# Source-Hash: 570136e723cb7d99 # Review: required -# Source-Hash: 5232a826549f915e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "⌥ axis" -#: packages/nodes/src/pipe-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof system" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.pipeFitting.tool.axis2" -msgstr "⌥ 軸" +msgid "node.roof.glazingPanel.roofSystem" +msgstr "屋根システム" +# Source-Hash: a6a7a36d982b4911 # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/pipe-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roughness" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.pipeFitting.tool.rTRotate" -msgstr "R/T で回転" +msgid "node.roof.glazingPanel.roughness" +msgstr "粗さ" -# Source-Hash: a0bb4762aa66fa3e +# Source-Hash: 2fa6fbeda5d45949 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drain / waste / vent pipe run — draw level or toggle a ¼″ per foot fall with S." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spacing is measured on the slope, not its horizontal projection." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.pipeSegment.description" -msgstr "排水・汚水・通気管 — 水平に描くか、S で1フィートあたり¼″の勾配を切り替え。" +msgid "node.roof.glazingPanel.spacingIsMeasuredOnTheSlope" +msgstr "間隔は水平投影ではなく勾配面に沿って測ります。" -# Source-Hash: 457155657704f7cc +# Source-Hash: d998c212030bc7c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV Pipe" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.pipeSegment.label" -msgstr "排水管" +msgid "node.roof.glazingPanel.standard" +msgstr "標準" -# Source-Hash: 6d0cdd14d0675e05 +# Source-Hash: efbe1c4facf561f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV P-trap — water seal on the waste line. The trap arm runs to the vent." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Subdivides each flat arch bay. Arch bays controls the divisions around the curve." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.pipeTrap.description" -msgstr "Pトラップ — 排水管の封水。トラップアームは通気管へ伸びます。" +msgid "node.roof.glazingPanel.subdividesEachFlatArchBayArch" +msgstr "平らな各アーチベイを分割します。曲線方向の分割はアーチベイで設定します。" -# Source-Hash: b778a315e82065a0 +# Source-Hash: 1497eac9e4f63016 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trap" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a panel to override its default infill." +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeTrap.label" -msgstr "トラップ" +msgid "node.roof.glazingPanelEditor.chooseAPanelToOverrideIts" +msgstr "パネルを選んで既定の充填を上書きします。" +# Source-Hash: 3530ac1f4046cd22 # Review: required -# Source-Hash: 73078bc0f5d686fa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{diameter}\" Trap" -#: packages/nodes/src/pipe-trap/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Column" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeTrap.tool.diameterTrap" -msgstr "{diameter}\" トラップ" +msgid "node.roof.glazingPanelEditor.column2" +msgstr "柱" +# Source-Hash: 9e9715d52410c86f # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/pipe-trap/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeTrap.tool.rTRotate" -msgstr "R/T で回転" +msgid "node.roof.glazingPanelEditor.custom" +msgstr "カスタム" -# Source-Hash: 0efe82436b915f6d +# Source-Hash: 4ca0e0e73229540c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Experimental editable recipe" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.proceduralItem.description" -msgstr "実験的な編集可能レシピ" +msgid "node.roof.glazingPanelEditor.default" +msgstr "標準" -# Source-Hash: c8bbcc888cce7b8a +# Source-Hash: 9ef92ad8ae49ed72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Procedural item" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{columns, plural, one {{columnCount} column} other {{columnCount} columns}} · {rows, plural, one {{rowCount} row} other {{rowCount} rows}}" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.proceduralItem.label" -msgstr "プロシージャルアイテム" +msgid "node.roof.glazingPanelEditor.grid" +msgstr "{columns, plural, other {{columnCount} 列}} · {rows, plural, other {{rowCount} 行}}" -# Source-Hash: 356aa0ed69cb8ec5 +# Source-Hash: 11624abbcfdd5506 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ventilation strip running along the ridge of a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Individual panels" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.ridgeVent.description" -msgstr "屋根面の棟に沿う換気帯。" +msgid "node.roof.glazingPanelEditor.individualPanels" +msgstr "個別パネル" -# Source-Hash: 54b74080f33c8c4e +# Source-Hash: 3a019ce58d021431 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ridge Vent" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel infill" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.ridgeVent.label" -msgstr "棟換気" +msgid "node.roof.glazingPanelEditor.panelInfill" +msgstr "パネルの充填" + +# Source-Hash: 6eb8025c60d6d3ca +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset to default" +#: packages/nodes/src/roof/glazing-panel-editor.tsx +#, fuzzy +msgid "node.roof.glazingPanelEditor.resetToDefault" +msgstr "既定に戻す" +# Source-Hash: 6fba44f2bfd8af8e # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof face" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.ridgeVent.panel.actions" -msgstr "操作" +msgid "node.roof.glazingPanelEditor.roofFace" +msgstr "屋根面" +# Source-Hash: 03a22f6df69c47d3 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Row" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.ridgeVent.panel.delete" -msgstr "削除" +msgid "node.roof.glazingPanelEditor.row2" +msgstr "行" +# Source-Hash: 6c2cc2d9cd778998 # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selected panel infill" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.ridgeVent.panel.dimensions" -msgstr "寸法" +msgid "node.roof.glazingPanelEditor.selectedPanelInfill" +msgstr "選択パネルの充填" +# Source-Hash: f5f730969df63d1d # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.ridgeVent.panel.duplicate" -msgstr "複製" +msgid "node.roof.label" +msgstr "屋根" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 18bf817325c1c537 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End Caps" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.endCaps" -msgstr "エンドキャップ" +msgid "node.roof.panel.actions" +msgstr "操作" +# Source-Hash: d60471ce3cd45348 # Review: required -# Source-Hash: 466f817a0102d4a5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flanged" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Chimney" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.flanged" -msgstr "フランジ付き" +msgid "node.roof.panel.addChimney" +msgstr "煙突を追加" +# Source-Hash: 1ca6a1cf9cc6e3ed # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Cupola" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.height" -msgstr "高さ" +msgid "node.roof.panel.addCupola" +msgstr "キューポラを追加" +# Source-Hash: 94dea147eeaac52b # Review: required -# Source-Hash: 643687bc3adaac76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Dormer" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.length" -msgstr "長さ" +msgid "node.roof.panel.addDormer" +msgstr "ドーマーを追加" +# Source-Hash: 5679acdd64484726 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Eyebrow Vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.move" -msgstr "移動" +msgid "node.roof.panel.addEyebrowVent" +msgstr "アイブロウ換気口を追加" +# Source-Hash: 25a141dc0d7c4b44 # Review: required -# Source-Hash: 3e52f04f92e08070 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Gutter" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.open" -msgstr "開く" +msgid "node.roof.panel.addGutter" +msgstr "雨樋を追加" +# Source-Hash: 7230bdc8a2252626 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Skylight" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.position" -msgstr "位置" +msgid "node.roof.panel.addSkylight" +msgstr "天窓を追加" +# Source-Hash: 0f220e2602b7ff24 # Review: required -# Source-Hash: 54b74080f33c8c4e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ridge Vent" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Solar Panel" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.ridgeVent" -msgstr "棟換気" +msgid "node.roof.panel.addSolarPanel" +msgstr "ソーラーパネルを追加" +# Source-Hash: 4d83a2e5a4d9e6b4 # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.rotation" -msgstr "回転" +msgid "node.roof.panel.addVent" +msgstr "換気口を追加" +# Source-Hash: e9a89a5e4ac8cd61 # Review: required -# Source-Hash: e9046e9823b400a0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingled" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.shingled" -msgstr "シングル葺き" +msgid "node.roof.panel.box" +msgstr "ボックス" +# Source-Hash: 3bf078fe2560daca # Review: required -# Source-Hash: d998c212030bc7c2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "box vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.standard" -msgstr "標準" +msgid "node.roof.panel.boxVent" +msgstr "ボックス換気口" +# Source-Hash: 4986740251121471 # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "chimney" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.style" -msgstr "スタイル" +msgid "node.roof.panel.chimney" +msgstr "煙突" +# Source-Hash: 9e9715d52410c86f # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.width" -msgstr "幅" +msgid "node.roof.panel.custom" +msgstr "カスタム" -# Source-Hash: c6d3976b4eb80586 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arch bays" -#: packages/nodes/src/roof/barrel-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.barrelPanel.archBays" -msgstr "アーチベイ" +msgid "node.roof.panel.delete" +msgstr "削除" -# Source-Hash: 1cfdd5affedf153c +# Source-Hash: 5169968a4b0c1840 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Barrel arch" -#: packages/nodes/src/roof/barrel-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "dormer" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.barrelPanel.barrelArch" -msgstr "かまぼこアーチ" +msgid "node.roof.panel.dormer" +msgstr "ドーマー" + +# Source-Hash: 72e51c6e5e9c6c26 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw Segment" +#: packages/nodes/src/roof/panel.tsx +#, fuzzy +msgid "node.roof.panel.drawSegment" +msgstr "セグメントを描画" -# Source-Hash: b3e8929750d18f7b +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat panes follow a circular arch. Rise is measured from the eaves." -#: packages/nodes/src/roof/barrel-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.barrelPanel.flatPanesFollowACircularArch" -msgstr "平らなガラスが円弧に沿います。ライズは軒から測ります。" +msgid "node.roof.panel.duplicate" +msgstr "複製" -# Source-Hash: fe8c5b735495eb00 +# Source-Hash: 5c99a67253bfc02a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rise" -#: packages/nodes/src/roof/barrel-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eave overhang" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.barrelPanel.rise" -msgstr "高さ" +msgid "node.roof.panel.eaveOverhang" +msgstr "軒の出" -# Source-Hash: 6afeec8de7ed618d +# Source-Hash: 34756c5ea718ccb5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A pitched / hip / gable roof composed of one or more segments." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eaves" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.description" -msgstr "1つ以上の面で構成される勾配・寄棟・切妻屋根。" +msgid "node.roof.panel.eaves" +msgstr "軒" -# Source-Hash: b5be04471fd3fb7a +# Source-Hash: 7c4196b9e791c195 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arch bay {number}" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elements" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.archBay" -msgstr "アーチベイ {number}" +msgid "node.roof.panel.elements" +msgstr "要素" -# Source-Hash: 93381b9024a75a99 +# Source-Hash: 6b8ba49aa355fe87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back slope" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows walls" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.back" -msgstr "背面の勾配" +msgid "node.roof.panel.followsWalls" +msgstr "壁に従う" -# Source-Hash: 08b00107b635e11d +# Source-Hash: dbd062efc7f4fd7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left end" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable overhang" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.endLeft" -msgstr "左端" +msgid "node.roof.panel.gableOverhang" +msgstr "妻側のけらば" -# Source-Hash: 821734ea5d17a693 +# Source-Hash: 23b434461c990711 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right end" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "gutter" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.endRight" -msgstr "右端" +msgid "node.roof.panel.gutter" +msgstr "雨樋" -# Source-Hash: 40c9ef62055067e1 +# Source-Hash: 0608743fc1736d86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front slope" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.front" -msgstr "前面の勾配" +msgid "node.roof.panel.level" +msgstr "階層" -# Source-Hash: 1a88da71d5e5f0d6 +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed slope" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.slope" -msgstr "片流れの勾配" +msgid "node.roof.panel.move" +msgstr "移動" -# Source-Hash: 3bcc542295b4c61e +# Source-Hash: 39661f4827b0f435 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Alignment" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move to {level}" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.alignment" -msgstr "揃え" +msgid "node.roof.panel.moveToLevel" +msgstr "{level}へ移動" -# Source-Hash: 5211341ed18f33f6 +# Source-Hash: c534093ff560a9f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move to the roof level" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.center" -msgstr "中央" +msgid "node.roof.panel.moveToTheRoofLevel" +msgstr "屋根の階層へ移動" -# Source-Hash: 512e47607a37af46 +# Source-Hash: 0939fad1cb1831f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a layout to edit the grid." -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On {storey} with its walls, so it hides that floor's plan in solo and exploded views.{roofs, plural, =0 {} =1 {} other { The floor's {roofCount} roofs move together.}}" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.chooseALayoutToEditThe" -msgstr "レイアウトを選んでグリッドを編集します。" +msgid "node.roof.panel.onStoreyWalls" +msgstr "壁と同じ{storey}にあるため、単独表示と分解表示でその階の平面を隠します。{roofs, plural, =0 {} =1 {} other { この階の {roofCount} 個の屋根は一緒に動きます。}}" -# Source-Hash: 65b1cbba3b92c5b2 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Empty" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.empty" -msgstr "空" +msgid "node.roof.panel.position" +msgstr "位置" -# Source-Hash: 135874d189176d13 +# Source-Hash: e6ddc8a624465793 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.end" -msgstr "終点" +msgid "node.roof.panel.ridge" +msgstr "棟" -# Source-Hash: 4fb65101d0b1a222 +# Source-Hash: 83112cbc205e9972 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fixed spacing" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "ridge vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.fixedSpacing" -msgstr "固定間隔" +msgid "node.roof.panel.ridgeVent" +msgstr "棟換気" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: f5f730969df63d1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.glass" -msgstr "ガラス" +msgid "node.roof.panel.roof" +msgstr "屋根" -# Source-Hash: 54800340a0eeab23 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Layout" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.layout" -msgstr "レイアウト" +msgid "node.roof.panel.rotation" +msgstr "回転" -# Source-Hash: 321ca5101ab61db7 +# Source-Hash: 505d8419cf4cc5e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Maximum spacing" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segments" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.maximumSpacing" -msgstr "最大間隔" +msgid "node.roof.panel.segments" +msgstr "セグメント" -# Source-Hash: d10743fce478d9f4 +# Source-Hash: 0c084c517dbc153b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Max spacing" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{roofType, select, hip {Hip} gable {Gable} shed {Shed} gambrel {Gambrel} dutch {Dutch} mansard {Mansard} flat {Flat} conical {Conical} barrel {Barrel} other {Roof}}" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.maxSpacing" -msgstr "最大間隔" +msgid "node.roof.panel.segmentType" +msgstr "{roofType, select, hip {寄棟} gable {切妻} shed {片流れ} gambrel {腰折れ} dutch {入母屋} mansard {マンサード} flat {陸屋根} conical {円錐} barrel {ヴォールト} other {屋根}}" -# Source-Hash: 37d9f63758abdb67 +# Source-Hash: 0c4c82caccb4775c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mixed" -#: packages/nodes/src/roof/glazing-controls.tsx -#, fuzzy -msgid "node.roof.glazingControls.mixed" -msgstr "混在" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "skylight" +#: packages/nodes/src/roof/panel.tsx +#, fuzzy +msgid "node.roof.panel.skylight" +msgstr "天窓" -# Source-Hash: b91302bf741c9fd6 +# Source-Hash: b9f931508dd6ec70 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel count" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "solar panel" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.panelCount" -msgstr "パネル数" +msgid "node.roof.panel.solarPanel" +msgstr "ソーラーパネル" -# Source-Hash: 6ce059aee1386f72 +# Source-Hash: d2428b22f1757a4e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panels" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turbine" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.panels" -msgstr "パネル" +msgid "node.roof.panel.turbine" +msgstr "タービン" -# Source-Hash: ef3e765e692faf4c +# Source-Hash: 86d02a3d3a3a7fa2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "turbine vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.solid" -msgstr "ソリッド" +msgid "node.roof.panel.turbineVent" +msgstr "タービン換気扇" -# Source-Hash: e4698e83d02beb6c +# Source-Hash: 6df330bcfcaac604 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spacing" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Apply to all planes of this roof" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.spacing" -msgstr "間隔" +msgid "node.roofSegment.buildUpSection.applyToAllPlanesOfThis" +msgstr "この屋根のすべての面に適用" -# Source-Hash: 0a26a1e61c825660 +# Source-Hash: 7254a3eb47471b8a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Architectural shingle" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.start" -msgstr "始点" +msgid "node.roofSegment.buildUpSection.architecturalShingle" +msgstr "アーキテクチュラルシングル" -# Source-Hash: 095237e9e2df4d9c +# Source-Hash: afd23a6d653689c6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{title} alignment" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Asphalt 3-tab" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.titleAlignment" -msgstr "{title}の揃え" +msgid "node.roofSegment.buildUpSection.asphalt3Tab" +msgstr "アスファルト 3タブ" -# Source-Hash: c98a4e6b28f05e0f +# Source-Hash: 2650e7c436297ef2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Changes apply to all {length} roof segments." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clay tile" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.changesApplyToAllLengthRoof" -msgstr "変更は {length} 個すべての屋根セグメントに適用されます。" +msgid "node.roofSegment.buildUpSection.clayTile" +msgstr "粘土瓦" -# Source-Hash: c5d2ff7fda4787cd +# Source-Hash: 92af091c56892f25 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose one roof system to edit settings for all selected segments." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Concrete tile" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.chooseOneRoofSystemToEdit" -msgstr "屋根システムを1つ選ぶと、選択したすべてのセグメントの設定を編集できます。" +msgid "node.roofSegment.buildUpSection.concreteTile" +msgstr "コンクリート瓦" -# Source-Hash: 80e07a119b63187c +# Source-Hash: 75168c15633cbad3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close the roof ends" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Covering" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.closeTheRoofEnds" -msgstr "屋根の端を閉じる" +msgid "node.roofSegment.buildUpSection.covering" +msgstr "葺き材" -# Source-Hash: e28dd27d54aaa7ae +# Source-Hash: f3aa561772702108 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default panel infill" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.defaultPanelInfill" -msgstr "パネルの既定の充填" +msgid "node.roofSegment.buildUpSection.deck" +msgstr "デッキ" -# Source-Hash: 134d33e2465937e7 +# Source-Hash: 14187d972ce9e1de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Divides each roof face into columns." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit layers" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.dividesEachRoofFaceIntoColumns" -msgstr "各屋根面を列に分割します。" +msgid "node.roofSegment.buildUpSection.editLayers" +msgstr "層を編集" -# Source-Hash: 896a6e4da3357c39 +# Source-Hash: 5aff5f630e4b18c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Divides the length of each arch bay into columns." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.dividesTheLengthOfEachArch" -msgstr "各アーチベイの長さを列に分割します。" +msgid "node.roofSegment.buildUpSection.finishName" +msgstr "仕上げの名前" -# Source-Hash: be9c810d28d1feb9 +# Source-Hash: b9ed3f21665672eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End infill fills the space above the walls. Edit room walls and ceilings separately." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ice and water shield" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.endInfillFillsTheSpaceAbove" -msgstr "端部の充填は壁の上の空間を埋めます。部屋の壁と天井は別々に編集してください。" +msgid "node.roofSegment.buildUpSection.iceAndWaterShield" +msgstr "粘着式ルーフィング" -# Source-Hash: 0b8b27dbc57cca44 +# Source-Hash: 6d79431c0092abac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame color" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.frameColor" -msgstr "枠の色" +msgid "node.roofSegment.buildUpSection.insulationName" +msgstr "断熱材の名前" -# Source-Hash: fd413477f1a9e5ed +# Source-Hash: e4e9305964238fda # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame depth" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Interior finish" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.frameDepth" -msgstr "枠の奥行き" +msgid "node.roofSegment.buildUpSection.interiorFinish" +msgstr "内装仕上げ" -# Source-Hash: 3519d91b7bda18a5 +# Source-Hash: 4ccd2fc1a471fca5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame width" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layers" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.frameWidth" -msgstr "枠の幅" +msgid "node.roofSegment.buildUpSection.layers" +msgstr "層" -# Source-Hash: c7e72beff9fe4b37 +# Source-Hash: 8f343a87f121347e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Framing" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "#15 felt" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.framing" -msgstr "下地" +msgid "node.roofSegment.buildUpSection.n15Felt" +msgstr "#15 フェルト" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: faa54521399dc5b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "#30 felt" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.glass" -msgstr "ガラス" +msgid "node.roofSegment.buildUpSection.n30Felt" +msgstr "#30 フェルト" -# Source-Hash: 9c38875c310547ae +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass tint" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.glassTint" -msgstr "ガラスの色合い" +msgid "node.roofSegment.buildUpSection.none" +msgstr "なし" -# Source-Hash: dd330a94b3f7a65a +# Source-Hash: 441f7f652ea6a0d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glazed" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preset" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.glazed" -msgstr "ガラス張り" +msgid "node.roofSegment.buildUpSection.preset" +msgstr "プリセット" -# Source-Hash: e6be52df9197243a +# Source-Hash: a9cb232546779779 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glazing is available for gable, straight shed, and barrel roofs." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafters" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.glazingIsAvailableForGableStraight" -msgstr "ガラスは切妻、直線の片流れ、ヴォールト屋根で使えます。" +msgid "node.roofSegment.buildUpSection.rafters" +msgstr "垂木" -# Source-Hash: a4e7ef2e31d7220b +# Source-Hash: 5c0d95afa820e706 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid across the roof" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roofing" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.gridAcrossTheRoof" -msgstr "屋根を横切るグリッド" +msgid "node.roofSegment.buildUpSection.roofing" +msgstr "屋根材" -# Source-Hash: 2f28a3b33fccf56b +# Source-Hash: 75a1bff32810894e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid along the length" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roofing name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.gridAlongTheLength" -msgstr "長さ方向のグリッド" +msgid "node.roofSegment.buildUpSection.roofingName" +msgstr "屋根材の名前" -# Source-Hash: 1f701893dbf9d72b +# Source-Hash: 36a588e44085108c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid along the slope" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sheathing" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.gridAlongTheSlope" -msgstr "勾配方向のグリッド" +msgid "node.roofSegment.buildUpSection.sheathing" +msgstr "野地板" -# Source-Hash: 20c8dfbadda20e3b +# Source-Hash: abdad84e524e56e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid within each arch bay" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sheathing name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.gridWithinEachArchBay" -msgstr "各アーチベイ内のグリッド" +msgid "node.roofSegment.buildUpSection.sheathingName" +msgstr "野地板の名前" -# Source-Hash: 7c339a5fae55681d +# Source-Hash: a7b5921026935493 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Infill" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slate" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.infill" -msgstr "充填" +msgid "node.roofSegment.buildUpSection.slate" +msgstr "天然スレート" -# Source-Hash: 1c0b8a5503c5daeb +# Source-Hash: c156b8bd7920b129 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opacity" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standing-seam metal" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.opacity" -msgstr "不透明度" +msgid "node.roofSegment.buildUpSection.standingSeamMetal" +msgstr "金属立平葺き" -# Source-Hash: 4d412746658f2faf +# Source-Hash: f5defb7d8a17154e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pane thickness" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Synthetic" +#: packages/nodes/src/roof-segment/build-up-section.tsx +#, fuzzy +msgid "node.roofSegment.buildUpSection.synthetic" +msgstr "合成ルーフィング" + +# Source-Hash: 472f395a8b6319a0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top chord" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.paneThickness" -msgstr "ガラス板の厚さ" +msgid "node.roofSegment.buildUpSection.topChord" +msgstr "上弦材" -# Source-Hash: 570136e723cb7d99 +# Source-Hash: 4dd558e7eeec7acf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof system" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trusses" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.roofSystem" -msgstr "屋根システム" +msgid "node.roofSegment.buildUpSection.trusses" +msgstr "トラス" -# Source-Hash: a6a7a36d982b4911 +# Source-Hash: 3909955f8a920be1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roughness" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Underlayment" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.roughness" -msgstr "粗さ" +msgid "node.roofSegment.buildUpSection.underlayment" +msgstr "下葺き材" -# Source-Hash: 2fa6fbeda5d45949 +# Source-Hash: 0167cfd2ec25cf5d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spacing is measured on the slope, not its horizontal projection." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Underlayment name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.spacingIsMeasuredOnTheSlope" -msgstr "間隔は水平投影ではなく勾配面に沿って測ります。" +msgid "node.roofSegment.buildUpSection.underlaymentName" +msgstr "下葺き材の名前" -# Source-Hash: d998c212030bc7c2 +# Source-Hash: 7095fa6e1c927c5e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wood shake" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.standard" -msgstr "標準" +msgid "node.roofSegment.buildUpSection.woodShake" +msgstr "木製シェイク" -# Source-Hash: efbe1c4facf561f7 +# Source-Hash: 99afd827dbe5d647 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Subdivides each flat arch bay. Arch bays controls the divisions around the curve." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A single pitched plane of a parent roof." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.roof.glazingPanel.subdividesEachFlatArchBayArch" -msgstr "平らな各アーチベイを分割します。曲線方向の分割はアーチベイで設定します。" +msgid "node.roofSegment.description" +msgstr "親屋根の1つの勾配面。" -# Source-Hash: 1497eac9e4f63016 +# Source-Hash: e72a64b3e00aad98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a panel to override its default infill." -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Segment" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.roof.glazingPanelEditor.chooseAPanelToOverrideIts" -msgstr "パネルを選んで既定の充填を上書きします。" +msgid "node.roofSegment.label" +msgstr "屋根面" -# Source-Hash: 3530ac1f4046cd22 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Column" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.column2" -msgstr "柱" +msgid "node.roofSegment.panel.actions" +msgstr "操作" -# Source-Hash: 9e9715d52410c86f +# Source-Hash: c69865ec5d9d1ac9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Angle" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.custom" -msgstr "カスタム" +msgid "node.roofSegment.panel.angle" +msgstr "角度" -# Source-Hash: 4ca0e0e73229540c +# Source-Hash: eb8f344a3c137280 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arc" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.default" -msgstr "標準" +msgid "node.roofSegment.panel.arc" +msgstr "円弧" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 9ef92ad8ae49ed72 +# Source-Hash: 1eb45f83eeaabfad # Review: required -# English: "{columns, plural, one {{columnCount} column} other {{columnCount} columns}} · {rows, plural, one {{rowCount} row} other {{rowCount} rows}}" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto gutters" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.grid" -msgstr "{columns, plural, other {{columnCount} 列}} · {rows, plural, other {{rowCount} 行}}" +msgid "node.roofSegment.panel.autoGutters" +msgstr "自動雨樋" -# Source-Hash: 11624abbcfdd5506 +# Source-Hash: 0986c4933d2b5808 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Individual panels" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto ridge vent" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.individualPanels" -msgstr "個別パネル" +msgid "node.roofSegment.panel.autoRidgeVent" +msgstr "自動棟換気" -# Source-Hash: 3a019ce58d021431 +# Source-Hash: 344fe9d407a233a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel infill" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Barrel" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.panelInfill" -msgstr "パネルの充填" +msgid "node.roofSegment.panel.barrel" +msgstr "ヴォールト" -# Source-Hash: 6eb8025c60d6d3ca +# Source-Hash: 6ca418a2ecab5984 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset to default" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clipped version" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.resetToDefault" -msgstr "既定に戻す" +msgid "node.roofSegment.panel.clippedVersion" +msgstr "切り詰め版" -# Source-Hash: 6fba44f2bfd8af8e +# Source-Hash: 3241ecabee8221a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof face" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Conical" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.roofFace" -msgstr "屋根面" +msgid "node.roofSegment.panel.conical" +msgstr "円錐" -# Source-Hash: 03a22f6df69c47d3 +# Source-Hash: a37cfbc4db93cfd3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Row" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Conical Shape" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.row2" -msgstr "行" +msgid "node.roofSegment.panel.conicalShape" +msgstr "円錐形" -# Source-Hash: 6c2cc2d9cd778998 +# Source-Hash: a10f29fcde60eea9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Selected panel infill" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck Thick." +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.selectedPanelInfill" -msgstr "選択パネルの充填" +msgid "node.roofSegment.panel.deckThick" +msgstr "デッキ厚" -# Source-Hash: f5f730969df63d1d +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.label" -msgstr "屋根" +msgid "node.roofSegment.panel.delete" +msgstr "削除" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.actions" -msgstr "操作" +msgid "node.roofSegment.panel.depth" +msgstr "奥行き" -# Source-Hash: d60471ce3cd45348 +# Source-Hash: 016d8e70618916d4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Chimney" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diameter" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addChimney" -msgstr "煙突を追加" +msgid "node.roofSegment.panel.diameter" +msgstr "直径" -# Source-Hash: 1ca6a1cf9cc6e3ed +# Source-Hash: e132bf88b9e4d75e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Cupola" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done editing" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addCupola" -msgstr "キューポラを追加" +msgid "node.roofSegment.panel.doneEditing" +msgstr "編集を完了" -# Source-Hash: 94dea147eeaac52b +# Source-Hash: 00a4416e0a33d856 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Dormer" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drainage" +#: packages/nodes/src/roof-segment/panel.tsx +#, fuzzy +msgid "node.roofSegment.panel.drainage" +msgstr "排水" + +# Source-Hash: 34dc96fe77a31e51 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addDormer" -msgstr "ドーマーを追加" +msgid "node.roofSegment.panel.duplicate" +msgstr "複製" -# Source-Hash: 5679acdd64484726 +# Source-Hash: 6949d667043bee0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Eyebrow Vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addEyebrowVent" -msgstr "アイブロウ換気口を追加" +msgid "node.roofSegment.panel.dutch" +msgstr "入母屋" -# Source-Hash: 25a141dc0d7c4b44 +# Source-Hash: 4c539865731d5d66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Gutter" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eave cut" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addGutter" -msgstr "雨樋を追加" +msgid "node.roofSegment.panel.eaveCut" +msgstr "軒先の切り方" -# Source-Hash: 7230bdc8a2252626 +# Source-Hash: 5c99a67253bfc02a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Skylight" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eave overhang" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addSkylight" -msgstr "天窓を追加" +msgid "node.roofSegment.panel.eaveOverhang" +msgstr "軒の出" -# Source-Hash: 0f220e2602b7ff24 +# Source-Hash: dc90862aafc9d287 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Solar Panel" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit footprint" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addSolarPanel" -msgstr "ソーラーパネルを追加" +msgid "node.roofSegment.panel.editFootprint" +msgstr "フットプリントを編集" -# Source-Hash: 4d83a2e5a4d9e6b4 +# Source-Hash: 9532d5e73585ea62 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End overhang" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addVent" -msgstr "換気口を追加" +msgid "node.roofSegment.panel.endOverhang" +msgstr "端部の張り出し" -# Source-Hash: e9a89a5e4ac8cd61 +# Source-Hash: 74f4143cd02de4a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fascia" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.box" -msgstr "ボックス" +msgid "node.roofSegment.panel.fascia" +msgstr "鼻隠し" -# Source-Hash: 3bf078fe2560daca +# Source-Hash: 45baed9dc8b8047a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "box vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fascia height" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.boxVent" -msgstr "ボックス換気口" +msgid "node.roofSegment.panel.fasciaHeight" +msgstr "鼻隠しの高さ" -# Source-Hash: 4986740251121471 +# Source-Hash: 9cab4d4c95f63cdd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "chimney" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.chimney" -msgstr "煙突" +msgid "node.roofSegment.panel.flat" +msgstr "陸屋根" -# Source-Hash: 9e9715d52410c86f +# Source-Hash: a3c10560fa3c1612 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Footprint" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.custom" -msgstr "カスタム" +msgid "node.roofSegment.panel.footprint" +msgstr "フットプリント" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: deaffa095d126dfe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.delete" -msgstr "削除" +msgid "node.roofSegment.panel.gable" +msgstr "切妻" -# Source-Hash: 5169968a4b0c1840 +# Source-Hash: dbd062efc7f4fd7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "dormer" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable overhang" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.dormer" -msgstr "ドーマー" +msgid "node.roofSegment.panel.gableOverhang" +msgstr "妻側のけらば" -# Source-Hash: 72e51c6e5e9c6c26 +# Source-Hash: 7f53d9ffca39984a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw Segment" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.drawSegment" -msgstr "セグメントを描画" +msgid "node.roofSegment.panel.gambrel" +msgstr "腰折れ" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 9eda0ea8d447066d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hip" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.duplicate" -msgstr "複製" +msgid "node.roofSegment.panel.hip" +msgstr "寄棟" -# Source-Hash: 7c4196b9e791c195 +# Source-Hash: 7ae4179d0abd80f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elements" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kink Depth" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.elements" -msgstr "要素" +msgid "node.roofSegment.panel.kinkDepth" +msgstr "折れの奥行き" -# Source-Hash: 6b8ba49aa355fe87 +# Source-Hash: e19b2bca70030855 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows walls" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kink Height" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.followsWalls" -msgstr "壁に従う" +msgid "node.roofSegment.panel.kinkHeight" +msgstr "折れの高さ" -# Source-Hash: 23b434461c990711 +# Source-Hash: 643687bc3adaac76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "gutter" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.gutter" -msgstr "雨樋" +msgid "node.roofSegment.panel.length" +msgstr "長さ" -# Source-Hash: 0608743fc1736d86 +# Source-Hash: 7f7bb0e875af3260 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.level" -msgstr "階層" +msgid "node.roofSegment.panel.mansard" +msgstr "マンサード" # Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Move" -#: packages/nodes/src/roof/panel.tsx +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.move" +msgid "node.roofSegment.panel.move" msgstr "移動" -# Source-Hash: 39661f4827b0f435 +# Source-Hash: 75e3449fc1776d09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move to {level}" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pitch" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.moveToLevel" -msgstr "{level}へ移動" +msgid "node.roofSegment.panel.pitch" +msgstr "勾配" -# Source-Hash: c534093ff560a9f0 +# Source-Hash: 6ae4075a23bb4ec4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move to the roof level" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plumb" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.moveToTheRoofLevel" -msgstr "屋根の階層へ移動" +msgid "node.roofSegment.panel.plumb" +msgstr "垂直" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 0939fad1cb1831f0 +# Source-Hash: 16d8ab5937d74bdb # Review: required -# English: "On {storey} with its walls, so it hides that floor's plan in solo and exploded views.{roofs, plural, =0 {} =1 {} other { The floor's {roofCount} roofs move together.}}" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plumb + level" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.onStoreyWalls" -msgstr "壁と同じ{storey}にあるため、単独表示と分解表示でその階の平面を隠します。{roofs, plural, =0 {} =1 {} other { この階の {roofCount} 個の屋根は一緒に動きます。}}" +msgid "node.roofSegment.panel.plumbLevel" +msgstr "垂直 + 水平" # Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Position" -#: packages/nodes/src/roof/panel.tsx +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.position" +msgid "node.roofSegment.panel.position" msgstr "位置" -# Source-Hash: e6ddc8a624465793 +# Source-Hash: bf91b71a9aa76e94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ridge" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.ridge" -msgstr "棟" +msgid "node.roofSegment.panel.reset" +msgstr "リセット" -# Source-Hash: 83112cbc205e9972 +# Source-Hash: e72a64b3e00aad98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "ridge vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Segment" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.ridgeVent" -msgstr "棟換気" +msgid "node.roofSegment.panel.roofSegment" +msgstr "屋根面" -# Source-Hash: f5f730969df63d1d +# Source-Hash: 19ab9527ae7889f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Type" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.roof" -msgstr "屋根" +msgid "node.roofSegment.panel.roofType" +msgstr "屋根の種類" # Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rotation" -#: packages/nodes/src/roof/panel.tsx +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.rotation" +msgid "node.roofSegment.panel.rotation" msgstr "回転" -# Source-Hash: 505d8419cf4cc5e1 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segments" -#: packages/nodes/src/roof/panel.tsx -#, fuzzy -msgid "node.roof.panel.segments" -msgstr "セグメント" - -# Source-Hash: 0c084c517dbc153b +# Source-Hash: 85ea1d3c8b749680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{roofType, select, hip {Hip} gable {Gable} shed {Shed} gambrel {Gambrel} dutch {Dutch} mansard {Mansard} flat {Flat} conical {Conical} barrel {Barrel} other {Roof}}" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.segmentType" -msgstr "{roofType, select, hip {寄棟} gable {切妻} shed {片流れ} gambrel {腰折れ} dutch {入母屋} mansard {マンサード} flat {陸屋根} conical {円錐} barrel {ヴォールト} other {屋根}}" +msgid "node.roofSegment.panel.shape" +msgstr "形状" -# Source-Hash: 0c4c82caccb4775c +# Source-Hash: c8d0df27faa3feaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "skylight" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.skylight" -msgstr "天窓" +msgid "node.roofSegment.panel.shed" +msgstr "片流れ" -# Source-Hash: b9f931508dd6ec70 +# Source-Hash: 4d944a2393bbddb2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "solar panel" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingle Thick." +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.solarPanel" -msgstr "ソーラーパネル" +msgid "node.roofSegment.panel.shingleThick" +msgstr "シングル厚" -# Source-Hash: d2428b22f1757a4e +# Source-Hash: 93b34a5b546664c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Turbine" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Span" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.turbine" -msgstr "タービン" +msgid "node.roofSegment.panel.span" +msgstr "スパン" -# Source-Hash: 86d02a3d3a3a7fa2 +# Source-Hash: 39287346366fc206 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "turbine vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.turbineVent" -msgstr "タービン換気扇" +msgid "node.roofSegment.panel.square" +msgstr "直角" -# Source-Hash: 99afd827dbe5d647 +# Source-Hash: e90aceedf4a6b183 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A single pitched plane of a parent roof." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start Angle" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.description" -msgstr "親屋根の1つの勾配面。" +msgid "node.roofSegment.panel.startAngle" +msgstr "開始角度" -# Source-Hash: e72a64b3e00aad98 +# Source-Hash: a20c89205a4448d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Segment" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.label" -msgstr "屋根面" +msgid "node.roofSegment.panel.structure" +msgstr "構造" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: a2db62c74fe2bcee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Rake Length" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.actions" -msgstr "操作" +msgid "node.roofSegment.panel.topRakeLength" +msgstr "上部破風の長さ" -# Source-Hash: c69865ec5d9d1ac9 +# Source-Hash: 913d9552030ac86a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Rake Thick." #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.angle" -msgstr "角度" +msgid "node.roofSegment.panel.topRakeThick" +msgstr "上部破風の厚さ" -# Source-Hash: eb8f344a3c137280 +# Source-Hash: 3beb5eb35f0c5c17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arc" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trim" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.arc" -msgstr "円弧" +msgid "node.roofSegment.panel.trim" +msgstr "見切り" -# Source-Hash: 1eb45f83eeaabfad +# Source-Hash: e6c5009c0d31fca1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto gutters" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist Height" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.autoGutters" -msgstr "自動雨樋" +msgid "node.roofSegment.panel.waistHeight" +msgstr "腰の高さ" -# Source-Hash: 0986c4933d2b5808 +# Source-Hash: 4a8caffd24b6ee02 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto ridge vent" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist Length" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.autoRidgeVent" -msgstr "自動棟換気" +msgid "node.roofSegment.panel.waistLength" +msgstr "腰の長さ" -# Source-Hash: 344fe9d407a233a9 +# Source-Hash: 71045af5c81a11e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Barrel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist Width" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.barrel" -msgstr "ヴォールト" +msgid "node.roofSegment.panel.waistWidth" +msgstr "腰の幅" -# Source-Hash: 6ca418a2ecab5984 +# Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clipped version" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.clippedVersion" -msgstr "切り詰め版" +msgid "node.roofSegment.panel.wall" +msgstr "壁" -# Source-Hash: 3241ecabee8221a1 +# Source-Hash: e0f973edce3e4ca8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Conical" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall Height" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.conical" -msgstr "円錐" +msgid "node.roofSegment.panel.wallHeight" +msgstr "壁の高さ" -# Source-Hash: a37cfbc4db93cfd3 +# Source-Hash: d0db6dee5fe2edbd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Conical Shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall Thick." #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.conicalShape" -msgstr "円錐形" +msgid "node.roofSegment.panel.wallThick" +msgstr "壁厚" -# Source-Hash: a10f29fcde60eea9 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Deck Thick." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.deckThick" -msgstr "デッキ厚" +msgid "node.roofSegment.panel.width" +msgstr "幅" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 6600a850000b98ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A captured session with optional mesh, motion, media, and sensor data." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.roofSegment.panel.delete" -msgstr "削除" +msgid "node.scan.description" +msgstr "メッシュ、モーション、メディア、センサーデータを任意で含むキャプチャセッション。" -# Source-Hash: 99ac4d03c3061f3a +# Source-Hash: 3a0701ebcb9f26cb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Capture" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.roofSegment.panel.depth" -msgstr "奥行き" +msgid "node.scan.label" +msgstr "キャプチャ" -# Source-Hash: 016d8e70618916d4 +# Source-Hash: 95b5307eefb187c6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diameter" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segment {number}" +#: packages/nodes/src/door/panel.tsx +#: packages/nodes/src/roof/panel.tsx +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.diameter" -msgstr "直径" +msgid "node.segmentNumber" +msgstr "セグメント {number}" -# Source-Hash: e132bf88b9e4d75e +# Source-Hash: acb8cb92b3674b50 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done editing" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Separator" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.roofSegment.panel.doneEditing" -msgstr "編集を完了" +msgid "node.separator.label" +msgstr "区切り" -# Source-Hash: 00a4416e0a33d856 +# Source-Hash: e34eb5b5bfbfce7c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drainage" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Batt" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.drainage" -msgstr "排水" +msgid "node.shared.buildUpControls.batt" +msgstr "マット状" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 430cef5fa9bd2787 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Blown" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.duplicate" -msgstr "複製" +msgid "node.shared.buildUpControls.blown" +msgstr "吹込み" -# Source-Hash: 6949d667043bee0b +# Source-Hash: 4da800c75b9a6b23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drywall" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.dutch" -msgstr "入母屋" +msgid "node.shared.buildUpControls.drywall" +msgstr "石膏ボード" -# Source-Hash: 5c99a67253bfc02a +# Source-Hash: 4e8f119349fa2dd4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Eave overhang" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drywall thickness" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.eaveOverhang" -msgstr "軒の出" +msgid "node.shared.buildUpControls.drywallThickness" +msgstr "石膏ボードの厚さ" -# Source-Hash: dc90862aafc9d287 +# Source-Hash: 7d6ed24c02ab0c5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit footprint" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.editFootprint" -msgstr "フットプリントを編集" +msgid "node.shared.buildUpControls.insulation" +msgstr "断熱材" -# Source-Hash: 9532d5e73585ea62 +# Source-Hash: 4251fc1e9051a7db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End overhang" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation thickness" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.endOverhang" -msgstr "端部の張り出し" +msgid "node.shared.buildUpControls.insulationThickness" +msgstr "断熱材の厚さ" -# Source-Hash: 74f4143cd02de4a6 +# Source-Hash: f567133879529366 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fascia" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label} thickness" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.fascia" -msgstr "鼻隠し" +msgid "node.shared.buildUpControls.labelThickness" +msgstr "{label}の厚さ" -# Source-Hash: 45baed9dc8b8047a +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fascia height" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.fasciaHeight" -msgstr "鼻隠しの高さ" +msgid "node.shared.buildUpControls.none" +msgstr "なし" -# Source-Hash: 9cab4d4c95f63cdd +# Source-Hash: 4f7f8af75bf8e914 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "OSB" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.flat" -msgstr "陸屋根" +msgid "node.shared.buildUpControls.osb" +msgstr "OSB" -# Source-Hash: a3c10560fa3c1612 +# Source-Hash: a6fd2cbf5c2154e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Footprint" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plaster" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.footprint" -msgstr "フットプリント" +msgid "node.shared.buildUpControls.plaster" +msgstr "漆喰" -# Source-Hash: deaffa095d126dfe +# Source-Hash: e669c2c08bd80e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plywood" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.gable" -msgstr "切妻" +msgid "node.shared.buildUpControls.plywood" +msgstr "合板" -# Source-Hash: dbd062efc7f4fd7f +# Source-Hash: 3d153fa2037159f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable overhang" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rigid board" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.gableOverhang" -msgstr "妻側のけらば" +msgid "node.shared.buildUpControls.rigidBoard" +msgstr "硬質ボード" -# Source-Hash: 7f53d9ffca39984a +# Source-Hash: e4698e83d02beb6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spacing" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.gambrel" -msgstr "腰折れ" +msgid "node.shared.buildUpControls.spacing" +msgstr "間隔" -# Source-Hash: 9eda0ea8d447066d +# Source-Hash: bb2a1cccfd0bd194 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hip" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{spacing} o.c." +#. A framing spacing on centre (centre of one member to the next), e.g. 16" o.c. +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.hip" -msgstr "寄棟" +msgid "node.shared.buildUpControls.spacingOC" +msgstr "芯々 {spacing}" -# Source-Hash: 7ae4179d0abd80f5 +# Source-Hash: ab62afff8ba3f37f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kink Depth" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wood plank" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.kinkDepth" -msgstr "折れの奥行き" +msgid "node.shared.buildUpControls.woodPlank" +msgstr "板張り" -# Source-Hash: e19b2bca70030855 +# Source-Hash: e7512c891d8da7d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kink Height" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turn light off" +#: packages/nodes/src/shared/item-interaction-actions.tsx #, fuzzy -msgid "node.roofSegment.panel.kinkHeight" -msgstr "折れの高さ" +msgid "node.shared.itemInteractionActions.turnLightOff" +msgstr "照明を消す" -# Source-Hash: 643687bc3adaac76 +# Source-Hash: d47ec95e14909fe5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turn light on" +#: packages/nodes/src/shared/item-interaction-actions.tsx #, fuzzy -msgid "node.roofSegment.panel.length" -msgstr "長さ" +msgid "node.shared.itemInteractionActions.turnLightOn" +msgstr "照明をつける" -# Source-Hash: 7f7bb0e875af3260 +# Source-Hash: 18bf48fbbe121ef0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Casing" +#: packages/nodes/src/shared/opening-casing-section.tsx #, fuzzy -msgid "node.roofSegment.panel.mansard" -msgstr "マンサード" +msgid "node.shared.openingCasingSection.casing" +msgstr "額縁" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/shared/opening-casing-section.tsx +#, fuzzy +msgid "node.shared.openingCasingSection.width" +msgstr "幅" + +# Source-Hash: ee1c8bc3e27fb550 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Automatic support" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.move" -msgstr "移動" +msgid "node.shared.runHangerInspector.automaticSupport" +msgstr "自動サポート" -# Source-Hash: 75e3449fc1776d09 +# Source-Hash: 1353e40320c72a99 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pitch" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger {number} · segment {segment}" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.pitch" -msgstr "勾配" +msgid "node.shared.runHangerInspector.hangerOnSegment" +msgstr "吊り金具 {number} · セグメント {segment}" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: 737ced90d0454197 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Individual hangers" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.position" -msgstr "位置" +msgid "node.shared.runHangerInspector.individualHangers" +msgstr "個別の吊り金具" -# Source-Hash: bf91b71a9aa76e94 +# Source-Hash: e6b17b09ed91c8c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Missing support" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.reset" -msgstr "リセット" +msgid "node.shared.runHangerInspector.missingSupport" +msgstr "サポートなし" -# Source-Hash: e72a64b3e00aad98 +# Source-Hash: c895c3c603382ec9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Segment" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No support within reach. Move the hanger or choose another host." +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.roofSegment" -msgstr "屋根面" +msgid "node.shared.runHangerInspector.noSupportWithinReachMoveThe" +msgstr "届く範囲に支持体がありません。吊り金具を動かすか、別の支持体を選んでください。" -# Source-Hash: 19ab9527ae7889f4 +# Source-Hash: 6ce526cb7444be36 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Type" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger {number} position in metres" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.roofType" -msgstr "屋根の種類" +msgid "node.shared.runHangerInspector.positionLabel" +msgstr "吊り金具 {number} の位置(メートル)" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: cbd36c4b82a55539 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position (m)" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.rotation" -msgstr "回転" +msgid "node.shared.runHangerInspector.positionM" +msgstr "位置(m)" -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: b629c4f8388fd36f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Positions are measured along each path segment. Changing spacing regenerates the numbered slots." +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.shape" -msgstr "形状" +msgid "node.shared.runHangerInspector.positionsAreMeasuredAlongEachPath" +msgstr "位置はパスの各セグメントに沿って測ります。間隔を変えると番号付きの位置が作り直されます。" -# Source-Hash: c8d0df27faa3feaa +# Source-Hash: c21cfbdb64e53388 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reveal support" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.shed" -msgstr "片流れ" +msgid "node.shared.runHangerInspector.revealSupport" +msgstr "サポートを表示" -# Source-Hash: 4d944a2393bbddb2 +# Source-Hash: 9d5e4440db18e477 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingle Thick." -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Skip" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.shingleThick" -msgstr "シングル厚" +msgid "node.shared.runHangerInspector.skip" +msgstr "スキップ" -# Source-Hash: 93b34a5b546664c4 +# Source-Hash: 1b184f78bf989931 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Span" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger {number} support" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.span" -msgstr "スパン" +msgid "node.shared.runHangerInspector.supportLabel" +msgstr "吊り金具 {number} のサポート" -# Source-Hash: e90aceedf4a6b183 +# Source-Hash: b2d703d283baf64a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start Angle" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "About these checks" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.startAngle" -msgstr "開始角度" +msgid "node.shared.systemCheckPanel.aboutTheseChecks" +msgstr "これらのチェックについて" -# Source-Hash: a20c89205a4448d2 +# Source-Hash: 461cc26706956993 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All findings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.structure" -msgstr "構造" +msgid "node.shared.systemCheckPanel.allFindings" +msgstr "すべての検出結果" -# Source-Hash: a2db62c74fe2bcee +# Source-Hash: 7beeb4c4997f5edb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Rake Length" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All systems" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.topRakeLength" -msgstr "上部破風の長さ" +msgid "node.shared.systemCheckPanel.allSystems" +msgstr "すべてのシステム" -# Source-Hash: 913d9552030ac86a +# Source-Hash: d613df280aa13b42 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Rake Thick." -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connections" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.topRakeThick" -msgstr "上部破風の厚さ" +msgid "node.shared.systemCheckPanel.connections" +msgstr "接続" -# Source-Hash: 3beb5eb35f0c5c17 +# Source-Hash: 00a4416e0a33d856 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trim" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drainage" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.trim" -msgstr "見切り" +msgid "node.shared.systemCheckPanel.drainage" +msgstr "排水" -# Source-Hash: e6c5009c0d31fca1 +# Source-Hash: fc4ac19649f0ee8f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist Height" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Error" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.waistHeight" -msgstr "腰の高さ" +msgid "node.shared.systemCheckPanel.error" +msgstr "エラー" -# Source-Hash: 4a8caffd24b6ee02 +# Source-Hash: b92720ff88a1bcfd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist Length" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Errors" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.waistLength" -msgstr "腰の長さ" +msgid "node.shared.systemCheckPanel.errors" +msgstr "エラー" -# Source-Hash: 71045af5c81a11e4 +# Source-Hash: d0e23bdbe1b380ff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist Width" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Filter system checks" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.waistWidth" -msgstr "腰の幅" +msgid "node.shared.systemCheckPanel.filterSystemChecks" +msgstr "システムチェックを絞り込む" -# Source-Hash: 2210e5ee50b74dc9 +# Source-Hash: 30d8dba84c42040e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hangers" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.wall" -msgstr "壁" +msgid "node.shared.systemCheckPanel.hangers" +msgstr "吊り金具" -# Source-Hash: e0f973edce3e4ca8 +# Source-Hash: 8cd416ca57d969f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Height" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Intersections" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.wallHeight" -msgstr "壁の高さ" +msgid "node.shared.systemCheckPanel.intersections" +msgstr "交差" -# Source-Hash: d0db6dee5fe2edbd +# Source-Hash: 18d652275a9a525c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Thick." -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Locate {name} ({id})" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.wallThick" -msgstr "壁厚" +msgid "node.shared.systemCheckPanel.locate" +msgstr "{name}を表示({id})" -# Source-Hash: 3a0ccd6c46877a87 +# Source-Hash: 88546aa3a5987966 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Missing item" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.width" -msgstr "幅" +msgid "node.shared.systemCheckPanel.missingItem" +msgstr "見つからないアイテム" -# Source-Hash: 6600a850000b98ad +# Source-Hash: 2452d2922a7ecf4a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A captured session with optional mesh, motion, media, and sensor data." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No findings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.scan.description" -msgstr "メッシュ、モーション、メディア、センサーデータを任意で含むキャプチャセッション。" +msgid "node.shared.systemCheckPanel.noFindings" +msgstr "検出結果なし" -# Source-Hash: 3a0701ebcb9f26cb +# Source-Hash: 995442fbfc786768 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Capture" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No findings in this category" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.scan.label" -msgstr "キャプチャ" +msgid "node.shared.systemCheckPanel.noFindingsInThisCategory" +msgstr "このカテゴリーに検出結果はありません" -# Source-Hash: 95b5307eefb187c6 +# Source-Hash: b5c58159b3eef89c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segment {number}" -#: packages/nodes/src/door/panel.tsx -#: packages/nodes/src/roof/panel.tsx -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open ends" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.segmentNumber" -msgstr "セグメント {number}" +msgid "node.shared.systemCheckPanel.openEnds" +msgstr "開放端" -# Source-Hash: acb8cb92b3674b50 +# Source-Hash: 3003dacc858d36ff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Separator" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open ends and separate branches may be intentional. Intersection checks use bounding boxes; inspect openings and clearances." +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.separator.label" -msgstr "区切り" +msgid "node.shared.systemCheckPanel.openEndsAndSeparateBranchesMay" +msgstr "開放端や分離した分岐は意図的な場合があります。交差チェックはバウンディングボックスで行うため、開口とクリアランスを確認してください。" -# Source-Hash: e7512c891d8da7d8 +# Source-Hash: c40c64562b6a1a91 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Turn light off" -#: packages/nodes/src/shared/item-interaction-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selected connected system" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.itemInteractionActions.turnLightOff" -msgstr "照明を消す" +msgid "node.shared.systemCheckPanel.selectedConnectedSystem" +msgstr "選択した接続システム" -# Source-Hash: d47ec95e14909fe5 +# Source-Hash: 68355a98439229e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Turn light on" -#: packages/nodes/src/shared/item-interaction-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selected: {count, plural, one {{number} run} other {{number} runs}} · {length} m" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.itemInteractionActions.turnLightOn" -msgstr "照明をつける" +msgid "node.shared.systemCheckPanel.selectedRuns" +msgstr "選択中:{count, plural, other {{number} 系統}} · {length} m" +# Source-Hash: e7a352627f8fcd45 # Review: required -# Source-Hash: ee1c8bc3e27fb550 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Automatic support" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Separate branches" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.automaticSupport" -msgstr "自動サポート" +msgid "node.shared.systemCheckPanel.separateBranches" +msgstr "分離した分岐" +# Source-Hash: 910a5ee73f2ef8a6 # Review: required -# Source-Hash: 1353e40320c72a99 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger {number} · segment {segment}" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show all findings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.hangerOnSegment" -msgstr "吊り金具 {number} · セグメント {segment}" +msgid "node.shared.systemCheckPanel.showAllFindings" +msgstr "すべての検出結果を表示" +# Source-Hash: dda8887833d07390 # Review: required -# Source-Hash: 737ced90d0454197 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Individual hangers" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System checks" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.individualHangers" -msgstr "個別の吊り金具" +msgid "node.shared.systemCheckPanel.systemChecks" +msgstr "システムチェック" +# Source-Hash: 4dad0ed68e63d124 # Review: required -# Source-Hash: e6b17b09ed91c8c2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Missing support" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System finding" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.missingSupport" -msgstr "サポートなし" +msgid "node.shared.systemCheckPanel.systemFinding" +msgstr "システムの検出結果" +# Source-Hash: e37307a519466b38 # Review: required -# Source-Hash: c895c3c603382ec9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No support within reach. Move the hanger or choose another host." -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System findings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.noSupportWithinReachMoveThe" -msgstr "届く範囲に支持体がありません。吊り金具を動かすか、別の支持体を選んでください。" +msgid "node.shared.systemCheckPanel.systemFindings" +msgstr "システムの検出結果" +# Source-Hash: 5128de8b5a618339 # Review: required -# Source-Hash: 6ce526cb7444be36 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger {number} position in metres" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Warning" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.positionLabel" -msgstr "吊り金具 {number} の位置(メートル)" +msgid "node.shared.systemCheckPanel.warning" +msgstr "警告" +# Source-Hash: 7e1647f9ce51509e # Review: required -# Source-Hash: cbd36c4b82a55539 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position (m)" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Warnings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.positionM" -msgstr "位置(m)" +msgid "node.shared.systemCheckPanel.warnings" +msgstr "警告" +# Source-Hash: 26aff27b7284fc84 # Review: required -# Source-Hash: b629c4f8388fd36f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Positions are measured along each path segment. Changing spacing regenerates the numbered slots." -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A configurable shelving unit. Items host on each row." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.shared.runHangerInspector.positionsAreMeasuredAlongEachPath" -msgstr "位置はパスの各セグメントに沿って測ります。間隔を変えると番号付きの位置が作り直されます。" +msgid "node.shelf.description" +msgstr "設定可能な棚。各段にアイテムを置けます。" +# Source-Hash: d7145f84f8e0e3fe # Review: required -# Source-Hash: c21cfbdb64e53388 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reveal support" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shelf" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.shared.runHangerInspector.revealSupport" -msgstr "サポートを表示" +msgid "node.shelf.label" +msgstr "棚" +# Source-Hash: c52492c73312a922 # Review: required -# Source-Hash: 9d5e4440db18e477 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Skip" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The top-level container holding buildings, zones, and the property boundary." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.shared.runHangerInspector.skip" -msgstr "スキップ" +msgid "node.site.description" +msgstr "建物、ゾーン、敷地境界を含む最上位のコンテナ。" + +# Source-Hash: 91f90818d42a984e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Site" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.site.label" +msgstr "敷地" +# Source-Hash: 3b5a53b6d058a02a # Review: required -# Source-Hash: 1b184f78bf989931 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger {number} support" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Address" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.supportLabel" -msgstr "吊り金具 {number} のサポート" +msgid "node.site.panel.address" +msgstr "住所" -# Source-Hash: b2d703d283baf64a +# Source-Hash: ea03c49930137a0f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "About these checks" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "APN" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.aboutTheseChecks" -msgstr "これらのチェックについて" +msgid "node.site.panel.apn" +msgstr "区画番号" -# Source-Hash: 461cc26706956993 +# Source-Hash: 8519c9ddf5e6b371 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All findings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto — most north-facing edge" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.allFindings" -msgstr "すべての検出結果" +msgid "node.site.panel.autoMostNorthFacingEdge" +msgstr "自動 — 最も北向きの辺" -# Source-Hash: 7beeb4c4997f5edb +# Source-Hash: bc493d7655b3e3ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All systems" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Contour interval (site plan and 3D)" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.allSystems" -msgstr "すべてのシステム" +msgid "node.site.panel.contourIntervalSitePlanAnd3d" +msgstr "等高線間隔(配置図と3D)" -# Source-Hash: d613df280aa13b42 +# Source-Hash: 99208d226da1315f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connections" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "County" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.connections" -msgstr "接続" +msgid "node.site.panel.county" +msgstr "郡" -# Source-Hash: 00a4416e0a33d856 +# Source-Hash: 0830cf0f95ad429d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drainage" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "e.g. RS-60" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.drainage" -msgstr "排水" +msgid "node.site.panel.eGRs60" +msgstr "例:RS-60" -# Source-Hash: fc4ac19649f0ee8f +# Source-Hash: b3e7e118266b5074 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Error" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "e.g. Tampa LDC §27-156" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.error" -msgstr "エラー" +msgid "node.site.panel.eGTampaLdc27156" +msgstr "例:Tampa LDC §27-156" -# Source-Hash: b92720ff88a1bcfd +# Source-Hash: 187e11889d08a2dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Errors" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "every 12 in" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.errors" -msgstr "エラー" +msgid "node.site.panel.every12In" +msgstr "12 in ごと" -# Source-Hash: d0e23bdbe1b380ff +# Source-Hash: 17ee041f655085f8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Filter system checks" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "every 24 in" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.filterSystemChecks" -msgstr "システムチェックを絞り込む" +msgid "node.site.panel.every24In" +msgstr "24 in ごと" -# Source-Hash: 30d8dba84c42040e +# Source-Hash: 40d7f9ddf5efcb7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hangers" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "every 6 in" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.hangers" -msgstr "吊り金具" +msgid "node.site.panel.every6In" +msgstr "6 in ごと" -# Source-Hash: 8cd416ca57d969f5 +# Source-Hash: 442a3ce78ae6b462 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Intersections" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finding…" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.intersections" -msgstr "交差" +msgid "node.site.panel.finding" +msgstr "検索中…" -# Source-Hash: 18d652275a9a525c +# Source-Hash: 734c1eac014adc69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Locate {name} ({id})" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Find parcel" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.locate" -msgstr "{name}を表示({id})" +msgid "node.site.panel.findParcel" +msgstr "区画を検索" -# Source-Hash: 88546aa3a5987966 +# Source-Hash: ccb70faaf91dbcb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Missing item" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front (street) edge" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.missingItem" -msgstr "見つからないアイテム" +msgid "node.site.panel.frontStreetEdge" +msgstr "前面(道路側)の辺" -# Source-Hash: 2452d2922a7ecf4a +# Source-Hash: 4232218226616327 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No findings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Looking up the parcel and the streets around it…" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.noFindings" -msgstr "検出結果なし" +msgid "node.site.panel.lookingUpTheParcel" +msgstr "区画と周辺の道路を検索中…" -# Source-Hash: 995442fbfc786768 +# Source-Hash: c39eb5933468a637 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No findings in this category" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lot area" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.noFindingsInThisCategory" -msgstr "このカテゴリーに検出結果はありません" +msgid "node.site.panel.lotArea" +msgstr "敷地面積" -# Source-Hash: b5c58159b3eef89c +# Source-Hash: c8a874b339ff9696 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open ends" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "1200 W Cass St, Tampa, FL" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.openEnds" -msgstr "開放端" +msgid "node.site.panel.n1200WCassStTampaFl" +msgstr "1200 W Cass St, Tampa, FL" -# Source-Hash: 3003dacc858d36ff +# Source-Hash: 30a0924a3360be68 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open ends and separate branches may be intentional. Intersection checks use bounding boxes; inspect openings and clearances." -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "none" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.openEndsAndSeparateBranchesMay" -msgstr "開放端や分離した分岐は意図的な場合があります。交差チェックはバウンディングボックスで行うため、開口とクリアランスを確認してください。" +msgid "node.site.panel.none" +msgstr "なし" -# Source-Hash: c40c64562b6a1a91 +# Source-Hash: dd4e835cb90c5736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Selected connected system" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "North rotation" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.selectedConnectedSystem" -msgstr "選択した接続システム" +msgid "node.site.panel.northRotation" +msgstr "北の回転" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 68355a98439229e2 +# Source-Hash: a4bfb2891c820e2e # Review: required -# English: "Selected: {count, plural, one {{number} run} other {{number} runs}} · {length} m" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No surveyed lines — contours are drawn from the sculpted ground." +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.selectedRuns" -msgstr "選択中:{count, plural, other {{number} 系統}} · {length} m" +msgid "node.site.panel.noSurveyedLinesContoursAreDrawn" +msgstr "測量線はありません。等高線は造形した地面から描かれます。" -# Source-Hash: e7a352627f8fcd45 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Separate branches" -#: packages/nodes/src/shared/system-check-panel.tsx +# Source-Hash: 1f0d024c0adbf0e8 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Orientation" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.separateBranches" -msgstr "分離した分岐" +msgid "node.site.panel.orientation" +msgstr "向き" -# Source-Hash: 910a5ee73f2ef8a6 +# Source-Hash: 9a3961409e34bf66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show all findings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Parcel" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.showAllFindings" -msgstr "すべての検出結果を表示" +msgid "node.site.panel.parcel" +msgstr "区画" -# Source-Hash: dda8887833d07390 +# Source-Hash: 3aecc563cb9a2c68 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System checks" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Parcel lookup failed." +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.systemChecks" -msgstr "システムチェック" +msgid "node.site.panel.parcelLookupFailed" +msgstr "区画の検索に失敗しました。" -# Source-Hash: 4dad0ed68e63d124 +# Source-Hash: 36696c4a8bede421 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System finding" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Project look" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.systemFinding" -msgstr "システムの検出結果" +msgid "node.site.panel.projectLook" +msgstr "プロジェクトの外観" -# Source-Hash: e37307a519466b38 +# Source-Hash: 5b50fc78ccdaf7aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System findings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Save current look" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.systemFindings" -msgstr "システムの検出結果" +msgid "node.site.panel.saveCurrentLook" +msgstr "現在の外観を保存" -# Source-Hash: 5128de8b5a618339 +# Source-Hash: f06b316f421963d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Warning" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Save the current lighting and display as this project's default. Personal display changes stay in this browser." +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.warning" -msgstr "警告" +msgid "node.site.panel.saveTheCurrentLightingAndDisplay" +msgstr "現在の照明と表示をこのプロジェクトの既定として保存します。個人の表示設定はこのブラウザーに残ります。" -# Source-Hash: 7e1647f9ce51509e +# Source-Hash: e87df48b61eda8ce # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Warnings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Setbacks" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.warnings" -msgstr "警告" +msgid "node.site.panel.setbacks" +msgstr "セットバック" -# Source-Hash: 26aff27b7284fc84 +# Source-Hash: 9ede31abea7ad545 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A configurable shelving unit. Items host on each row." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show ground" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shelf.description" -msgstr "設定可能な棚。各段にアイテムを置けます。" +msgid "node.site.panel.showGround" +msgstr "地面を表示" -# Source-Hash: d7145f84f8e0e3fe +# Source-Hash: 1e16a47e5e10c83e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shelf" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show the contour lines in 3D" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shelf.label" -msgstr "棚" +msgid "node.site.panel.showTheContourLinesIn3d" +msgstr "等高線を3Dで表示" -# Source-Hash: c52492c73312a922 +# Source-Hash: 464241679edcbdb4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The top-level container holding buildings, zones, and the property boundary." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "side" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.description" -msgstr "建物、ゾーン、敷地境界を含む最上位のコンテナ。" +msgid "node.site.panel.side" +msgstr "側面" # Source-Hash: 91f90818d42a984e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Site" -#: packages/nodes/src/i18n/definition-messages.ts +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.label" +msgid "node.site.panel.site" msgstr "敷地" -# Source-Hash: 3b5a53b6d058a02a +# Source-Hash: 6165ee130f0082e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Address" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Source" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.address" -msgstr "住所" +msgid "node.site.panel.source" +msgstr "出典" -# Source-Hash: ea03c49930137a0f +# Source-Hash: 5f3110d075c6a1a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "APN" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Source / citation" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.apn" -msgstr "区画番号" +msgid "node.site.panel.sourceCitation" +msgstr "出典 / 引用" -# Source-Hash: 8519c9ddf5e6b371 +# Source-Hash: 041cfc610fef830b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto — most north-facing edge" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Street address" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.autoMostNorthFacingEdge" -msgstr "自動 — 最も北向きの辺" +msgid "node.site.panel.streetAddress" +msgstr "番地" -# Source-Hash: bc493d7655b3e3ad +# Source-Hash: bdca51c5e6437075 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Contour interval (site plan and 3D)" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "survey" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.contourIntervalSitePlanAnd3d" -msgstr "等高線間隔(配置図と3D)" +msgid "node.site.panel.survey" +msgstr "測量" -# Source-Hash: 99208d226da1315f +# Source-Hash: 2177f21713b01a24 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "County" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {{lineCount} surveyed line} other {{lineCount} surveyed lines}} at {interval} ft ({datum}) — {source}" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.county" -msgstr "郡" +msgid "node.site.panel.surveyedContours" +msgstr "{count, plural, other {{lineCount} 本の測量線}}、{interval} ft 間隔({datum})— {source}" -# Source-Hash: 0830cf0f95ad429d +# Source-Hash: d457508edd5bb8cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "e.g. RS-60" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terrain" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.eGRs60" -msgstr "例:RS-60" +msgid "node.site.panel.terrain" +msgstr "地形" -# Source-Hash: b3e7e118266b5074 +# Source-Hash: 4c8601a0b7aeed3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "e.g. Tampa LDC §27-156" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type an address first." #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.eGTampaLdc27156" -msgstr "例:Tampa LDC §27-156" +msgid "node.site.panel.typeAnAddressFirst" +msgstr "先に住所を入力してください。" -# Source-Hash: 187e11889d08a2dc +# Source-Hash: dfe4cd35b3e0d5f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "every 12 in" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use project look" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.every12In" -msgstr "12 in ごと" +msgid "node.site.panel.useProjectLook" +msgstr "プロジェクトの外観を使う" -# Source-Hash: 17ee041f655085f8 +# Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "every 24 in" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.every24In" -msgstr "24 in ごと" +msgid "node.site.panel.zone" +msgstr "ゾーン" -# Source-Hash: 40d7f9ddf5efcb7f +# Source-Hash: e360f89d3c0ec456 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "every 6 in" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front" +#: packages/nodes/src/site/panel.tsx +#, fuzzy +msgid "node.site.setback.front" +msgstr "前面" + +# Source-Hash: ab1354f1aa520a54 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left (override)" +#: packages/nodes/src/site/panel.tsx +#, fuzzy +msgid "node.site.setback.leftOverride" +msgstr "左(上書き)" + +# Source-Hash: 1a7e8e8f8e9232d7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rear" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.every6In" -msgstr "6 in ごと" +msgid "node.site.setback.rear" +msgstr "後面" -# Source-Hash: 442a3ce78ae6b462 +# Source-Hash: 8370146b38c30102 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finding…" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right (override)" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.finding" -msgstr "検索中…" +msgid "node.site.setback.rightOverride" +msgstr "右(上書き)" -# Source-Hash: 734c1eac014adc69 +# Source-Hash: feefe9c7cb273e79 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Find parcel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Side" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.findParcel" -msgstr "区画を検索" +msgid "node.site.setback.side" +msgstr "側面" -# Source-Hash: ccb70faaf91dbcb1 +# Source-Hash: 67d903d7fe0c69c1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front (street) edge" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framed glass opening on a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.site.panel.frontStreetEdge" -msgstr "前面(道路側)の辺" +msgid "node.skylight.description" +msgstr "屋根面の枠付きガラス開口。" -# Source-Hash: 4232218226616327 +# Source-Hash: 358826fbdeaf72b9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Looking up the parcel and the streets around it…" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Skylight" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.site.panel.lookingUpTheParcel" -msgstr "区画と周辺の道路を検索中…" +msgid "node.skylight.label" +msgstr "天窓" -# Source-Hash: c39eb5933468a637 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lot area" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.lotArea" -msgstr "敷地面積" +msgid "node.skylight.panel.actions" +msgstr "操作" -# Source-Hash: c8a874b339ff9696 +# Source-Hash: f1113261ad2797de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "1200 W Cass St, Tampa, FL" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Along X" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.n1200WCassStTampaFl" -msgstr "1200 W Cass St, Tampa, FL" +msgid "node.skylight.panel.alongX" +msgstr "X 方向" -# Source-Hash: 30a0924a3360be68 +# Source-Hash: 5b84b1c644493370 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "none" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Along Z" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.none" -msgstr "なし" +msgid "node.skylight.panel.alongZ" +msgstr "Z 方向" -# Source-Hash: dd4e835cb90c5736 +# Source-Hash: b3a163b453896bef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "North rotation" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.northRotation" -msgstr "北の回転" +msgid "node.skylight.panel.bottom" +msgstr "下" -# Source-Hash: a4bfb2891c820e2e +# Source-Hash: b8ff053666ee326b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No surveyed lines — contours are drawn from the sculpted ground." -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curb" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.noSurveyedLinesContoursAreDrawn" -msgstr "測量線はありません。等高線は造形した地面から描かれます。" +msgid "node.skylight.panel.curb" +msgstr "立ち上がり" -# Source-Hash: 1f0d024c0adbf0e8 +# Source-Hash: 14144df9e1364eea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Orientation" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cutout Offset" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.orientation" -msgstr "向き" +msgid "node.skylight.panel.cutoutOffset" +msgstr "開口のオフセット" -# Source-Hash: 9a3961409e34bf66 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Parcel" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.parcel" -msgstr "区画" +msgid "node.skylight.panel.delete" +msgstr "削除" -# Source-Hash: 3aecc563cb9a2c68 +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Parcel lookup failed." -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.parcelLookupFailed" -msgstr "区画の検索に失敗しました。" +msgid "node.skylight.panel.depth" +msgstr "奥行き" -# Source-Hash: 36696c4a8bede421 +# Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Project look" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.projectLook" -msgstr "プロジェクトの外観" +msgid "node.skylight.panel.dimensions" +msgstr "寸法" -# Source-Hash: 5b50fc78ccdaf7aa +# Source-Hash: ce3a6c03765dbbd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Save current look" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.saveCurrentLook" -msgstr "現在の外観を保存" +msgid "node.skylight.panel.frame" +msgstr "枠" -# Source-Hash: f06b316f421963d7 +# Source-Hash: 911ea36eb835f3a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Save the current lighting and display as this project's default. Personal display changes stay in this browser." -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass Thickness" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.saveTheCurrentLightingAndDisplay" -msgstr "現在の照明と表示をこのプロジェクトの既定として保存します。個人の表示設定はこのブラウザーに残ります。" +msgid "node.skylight.panel.glassThickness" +msgstr "ガラスの厚さ" -# Source-Hash: e87df48b61eda8ce +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Setbacks" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.setbacks" -msgstr "セットバック" +msgid "node.skylight.panel.height" +msgstr "高さ" -# Source-Hash: 9ede31abea7ad545 +# Source-Hash: d56303913961984f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show ground" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern Height" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.showGround" -msgstr "地面を表示" +msgid "node.skylight.panel.lanternHeight" +msgstr "頂塔の高さ" -# Source-Hash: 1e16a47e5e10c83e +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show the contour lines in 3D" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.showTheContourLinesIn3d" -msgstr "等高線を3Dで表示" +msgid "node.skylight.panel.left" +msgstr "左" -# Source-Hash: 464241679edcbdb4 +# Source-Hash: f3e9604e3b85510f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "side" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Motor" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.side" -msgstr "側面" +msgid "node.skylight.panel.motor" +msgstr "モーター" -# Source-Hash: 91f90818d42a984e +# Source-Hash: a025444e0f500725 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Site" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Motor Housing" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.site" -msgstr "敷地" +msgid "node.skylight.panel.motorHousing" +msgstr "モーターハウジング" -# Source-Hash: 6165ee130f0082e8 +# Source-Hash: b2cbc4e2e5545a6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Source" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.source" -msgstr "出典" +msgid "node.skylight.panel.no" +msgstr "いいえ" -# Source-Hash: 5f3110d075c6a1a7 +# Source-Hash: a8e0b9fe5cfb4e3e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Source / citation" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No Motor" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.sourceCitation" -msgstr "出典 / 引用" +msgid "node.skylight.panel.noMotor" +msgstr "モーターなし" -# Source-Hash: 041cfc610fef830b +# Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Street address" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.streetAddress" -msgstr "番地" +msgid "node.skylight.panel.open" +msgstr "開く" -# Source-Hash: bdca51c5e6437075 +# Source-Hash: 9bfc55f879926fe6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "survey" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening Angle" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.survey" -msgstr "測量" +msgid "node.skylight.panel.openingAngle" +msgstr "開き角度" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 2177f21713b01a24 +# Source-Hash: 9da0cbfad144d737 # Review: required -# English: "{count, plural, one {{lineCount} surveyed line} other {{lineCount} surveyed lines}} at {interval} ft ({datum}) — {source}" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.surveyedContours" -msgstr "{count, plural, other {{lineCount} 本の測量線}}、{interval} ft 間隔({datum})— {source}" +msgid "node.skylight.panel.position" +msgstr "位置" -# Source-Hash: d457508edd5bb8cf +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terrain" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.terrain" -msgstr "地形" +msgid "node.skylight.panel.right" +msgstr "右" -# Source-Hash: 4c8601a0b7aeed3a +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type an address first." -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.typeAnAddressFirst" -msgstr "先に住所を入力してください。" +msgid "node.skylight.panel.rotation" +msgstr "回転" -# Source-Hash: dfe4cd35b3e0d5f5 +# Source-Hash: 358826fbdeaf72b9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use project look" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Skylight" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.useProjectLook" -msgstr "プロジェクトの外観を使う" +msgid "node.skylight.panel.skylight" +msgstr "天窓" -# Source-Hash: a107b4d76d6972e3 +# Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.zone" -msgstr "ゾーン" +msgid "node.skylight.panel.thickness" +msgstr "厚さ" -# Source-Hash: e360f89d3c0ec456 +# Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.front" -msgstr "前面" +msgid "node.skylight.panel.top" +msgstr "上" -# Source-Hash: ab1354f1aa520a54 +# Source-Hash: 75991d106eb93dae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left (override)" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Scale" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.leftOverride" -msgstr "左(上書き)" +msgid "node.skylight.panel.topScale" +msgstr "上部の縮尺" -# Source-Hash: 1a7e8e8f8e9232d7 +# Source-Hash: 3272a61417949895 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rear" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Track Width" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.rear" -msgstr "後面" +msgid "node.skylight.panel.trackWidth" +msgstr "レールの幅" -# Source-Hash: 8370146b38c30102 +# Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right (override)" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.rightOverride" -msgstr "右(上書き)" +msgid "node.skylight.panel.type" +msgstr "種類" -# Source-Hash: feefe9c7cb273e79 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Side" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.side" -msgstr "側面" +msgid "node.skylight.panel.width" +msgstr "幅" -# Source-Hash: 67d903d7fe0c69c1 +# Source-Hash: 184fda5c980b9d9c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Framed glass opening on a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Yes" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.skylight.description" -msgstr "屋根面の枠付きガラス開口。" +msgid "node.skylight.panel.yes" +msgstr "はい" -# Source-Hash: 358826fbdeaf72b9 +# Source-Hash: 445aacf307de133d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Skylight" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat roof skylight" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.skylight.label" -msgstr "天窓" +msgid "node.skylight.type.flat" +msgstr "陸屋根用天窓" +# Source-Hash: 446176b7c5d8b284 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof lantern" #: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.skylight.panel.actions" -msgstr "操作" +msgid "node.skylight.type.lantern" +msgstr "頂塔" +# Source-Hash: a6559387f108518f # Review: required -# Source-Hash: f1113261ad2797de -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Along X" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening skylight" #: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.skylight.panel.alongX" -msgstr "X 方向" +msgid "node.skylight.type.opening" +msgstr "開閉式天窓" +# Source-Hash: 379436bb5a74867a # Review: required -# Source-Hash: 5b84b1c644493370 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Along Z" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sliding skylight" #: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.skylight.panel.alongZ" -msgstr "Z 方向" +msgid "node.skylight.type.sliding" +msgstr "スライド式天窓" +# Source-Hash: d26ac61f593fe1bf # Review: required -# Source-Hash: b3a163b453896bef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walk-on rooflight" #: packages/nodes/src/skylight/panel.tsx -#, fuzzy -msgid "node.skylight.panel.bottom" -msgstr "下" +#, fuzzy +msgid "node.skylight.type.walkOn" +msgstr "歩行可能なトップライト" +# Source-Hash: ad8f8036d34f6cea # Review: required -# Source-Hash: b8ff053666ee326b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curb" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A polygon-bounded floor surface that hosts items on top." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.skylight.panel.curb" -msgstr "立ち上がり" +msgid "node.slab.description" +msgstr "多角形で囲まれた床面。上にアイテムを置けます。" +# Source-Hash: 8775bc8dc9593964 # Review: required -# Source-Hash: 14144df9e1364eea -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cutout Offset" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.skylight.panel.cutoutOffset" -msgstr "開口のオフセット" +msgid "node.slab.label" +msgstr "スラブ" +# Source-Hash: 659e6b799ad7c27d # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Hole" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.delete" -msgstr "削除" +msgid "node.slab.panel.addHole" +msgstr "開口を追加" +# Source-Hash: 8332ab41e22958f1 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Area" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.depth" -msgstr "奥行き" +msgid "node.slab.panel.area" +msgstr "面積" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.dimensions" -msgstr "寸法" +msgid "node.slab.panel.auto" +msgstr "自動" +# Source-Hash: fadada809e27477c # Review: required -# Source-Hash: ce3a6c03765dbbd8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.frame" -msgstr "枠" +msgid "node.slab.panel.base" +msgstr "ベース" +# Source-Hash: 12195951bba19804 # Review: required -# Source-Hash: 911ea36eb835f3a6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass Thickness" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut hatch" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.glassThickness" -msgstr "ガラスの厚さ" +msgid "node.slab.panel.cutHatch" +msgstr "ハッチを切り抜く" +# Source-Hash: 4e4f1a24e4a9d61e # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut opening" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.height" -msgstr "高さ" +msgid "node.slab.panel.cutOpening" +msgstr "開口を切る" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: d56303913961984f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern Height" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.lanternHeight" -msgstr "頂塔の高さ" +msgid "node.slab.panel.depth" +msgstr "奥行き" +# Source-Hash: 16552c2580bbe8b8 # Review: required -# Source-Hash: f365c6b6dd9ebab9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.left" -msgstr "左" +msgid "node.slab.panel.done" +msgstr "完了" +# Source-Hash: 8a3bc5111b9e97f4 # Review: required -# Source-Hash: f3e9604e3b85510f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Motor" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevation" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.motor" -msgstr "モーター" +msgid "node.slab.panel.elevation" +msgstr "高さ" +# Source-Hash: 201b720b76d79762 # Review: required -# Source-Hash: a025444e0f500725 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Motor Housing" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Extends the perimeter down to terrain. The flat surface, base, and thickness stay unchanged." +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.motorHousing" -msgstr "モーターハウジング" +msgid "node.slab.panel.extendsThePerimeterDownToTerrain" +msgstr "外周を地形まで延長します。平面、底面、厚さは変わりません。" +# Source-Hash: 387ce45ca2eb045f # Review: required -# Source-Hash: b2cbc4e2e5545a6c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fixed" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.no" -msgstr "いいえ" +msgid "node.slab.panel.fixed" +msgstr "固定" +# Source-Hash: d7148fa065bc709b # Review: required -# Source-Hash: a8e0b9fe5cfb4e3e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No Motor" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.noMotor" -msgstr "モーターなし" +msgid "node.slab.panel.floor" +msgstr "階" +# Source-Hash: 89b2cfd72a0a7e23 # Review: required -# Source-Hash: 3e52f04f92e08070 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows terrain" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.open" -msgstr "開く" +msgid "node.slab.panel.followsTerrain" +msgstr "地形に従う" +# Source-Hash: 48c832c1fc389290 # Review: required -# Source-Hash: 9bfc55f879926fe6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening Angle" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.openingAngle" -msgstr "開き角度" +msgid "node.slab.panel.foundation" +msgstr "基礎" +# Source-Hash: 34504c6ca6445e76 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Holes" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.position" -msgstr "位置" +msgid "node.slab.panel.holes" +msgstr "開口" +# Source-Hash: 6e68b62d2aa611a4 # Review: required -# Source-Hash: b34d5ee0f218221d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Info" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.right" -msgstr "右" +msgid "node.slab.panel.info" +msgstr "情報" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.rotation" -msgstr "回転" +msgid "node.slab.panel.move" +msgstr "移動" + +# Source-Hash: 1d2dafb0d8f26ed5 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No holes" +#: packages/nodes/src/slab/panel.tsx +#, fuzzy +msgid "node.slab.panel.noHoles" +msgstr "開口なし" +# Source-Hash: c6a29e75bf215488 # Review: required -# Source-Hash: 358826fbdeaf72b9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Skylight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rim" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.skylight" -msgstr "天窓" +msgid "node.slab.panel.rim" +msgstr "縁" +# Source-Hash: 8775bc8dc9593964 # Review: required -# Source-Hash: fdbb503f0941bd56 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.thickness" -msgstr "厚さ" +msgid "node.slab.panel.slab" +msgstr "スラブ" +# Source-Hash: fb23c960abf5de23 # Review: required -# Source-Hash: 27644f0497fd9849 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard (2\")" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.top" -msgstr "上" +msgid "node.slab.panel.standard2" +msgstr "標準(2\")" +# Source-Hash: 5f865b052c9b40eb # Review: required -# Source-Hash: 75991d106eb93dae -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Scale" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard (5cm)" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.topScale" -msgstr "上部の縮尺" +msgid "node.slab.panel.standard5cm" +msgstr "標準(5cm)" +# Source-Hash: cff0e2e72cfab157 # Review: required -# Source-Hash: 3272a61417949895 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Track Width" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sunken (15cm)" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.trackWidth" -msgstr "レールの幅" +msgid "node.slab.panel.sunken15cm" +msgstr "下げ(15cm)" +# Source-Hash: 8abc2aec4be98fe9 # Review: required -# Source-Hash: c44f7ab8bbd24858 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sunken (6\")" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.type" -msgstr "種類" +msgid "node.slab.panel.sunken6" +msgstr "下げ(6\")" +# Source-Hash: 78a454b7ac7a3cd9 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.width" -msgstr "幅" +msgid "node.slab.panel.surface" +msgstr "面" +# Source-Hash: 516636d85be919f0 # Review: required -# Source-Hash: 184fda5c980b9d9c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Yes" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thick (15cm)" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.yes" -msgstr "はい" +msgid "node.slab.panel.thick15cm" +msgstr "厚(15cm)" +# Source-Hash: c84078f3560da233 # Review: required -# Source-Hash: 445aacf307de133d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat roof skylight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thick (6\")" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.type.flat" -msgstr "陸屋根用天窓" +msgid "node.slab.panel.thick6" +msgstr "厚(6\")" +# Source-Hash: fdbb503f0941bd56 # Review: required -# Source-Hash: 446176b7c5d8b284 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof lantern" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.type.lantern" -msgstr "頂塔" +msgid "node.slab.panel.thickness" +msgstr "厚さ" +# Source-Hash: 61c191f6df40285b # Review: required -# Source-Hash: a6559387f108518f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening skylight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thin (1\")" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.type.opening" -msgstr "開閉式天窓" +msgid "node.slab.panel.thin1" +msgstr "薄(1\")" +# Source-Hash: d345b1f707506fe7 # Review: required -# Source-Hash: 379436bb5a74867a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sliding skylight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thin (2cm)" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.type.sliding" -msgstr "スライド式天窓" +msgid "node.slab.panel.thin2cm" +msgstr "薄(2cm)" +# Source-Hash: 065ffaaf64ab479d # Review: required -# Source-Hash: d26ac61f593fe1bf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walk-on rooflight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid of photovoltaic panels mounted on a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.skylight.type.walkOn" -msgstr "歩行可能なトップライト" +msgid "node.solarPanel.description" +msgstr "屋根面に設置した太陽光パネルの配列。" -# Source-Hash: ad8f8036d34f6cea +# Source-Hash: 4d18446ff8eaa680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A polygon-bounded floor surface that hosts items on top." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solar Panel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.slab.description" -msgstr "多角形で囲まれた床面。上にアイテムを置けます。" +msgid "node.solarPanel.label" +msgstr "太陽光パネル" -# Source-Hash: 8775bc8dc9593964 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.label" -msgstr "スラブ" +msgid "node.solarPanel.panel.actions" +msgstr "操作" -# Source-Hash: 659e6b799ad7c27d +# Source-Hash: 2184867946897298 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Hole" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Array" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.addHole" -msgstr "開口を追加" +msgid "node.solarPanel.panel.array" +msgstr "アレイ" -# Source-Hash: 8332ab41e22958f1 +# Source-Hash: 6eaa0e2a78d44d59 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Area" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto-fit to roof" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.area" -msgstr "面積" +msgid "node.solarPanel.panel.autoFitToRoof" +msgstr "屋根に自動フィット" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: 30edd1c180aac9b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Columns" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.auto" -msgstr "自動" +msgid "node.solarPanel.panel.columns" +msgstr "列" -# Source-Hash: fadada809e27477c +# Source-Hash: d1c6dd6335337cc1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom — dimensions don't match any preset" +#: packages/nodes/src/solar-panel/panel.tsx +#, fuzzy +msgid "node.solarPanel.panel.customDimensionsDonTMatchAny" +msgstr "カスタム — 寸法がどのプリセットとも一致しません" + +# Source-Hash: b26de372b4b0eaac +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/solar-panel/panel.tsx +#, fuzzy +msgid "node.solarPanel.panel.delete" +msgstr "削除" + +# Source-Hash: fe9356b1d0e0396b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip orientation" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.base" -msgstr "ベース" +msgid "node.solarPanel.panel.flipOrientation" +msgstr "向きを反転" -# Source-Hash: 12195951bba19804 +# Source-Hash: eaaa20f3b603140f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut hatch" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flush" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.cutHatch" -msgstr "ハッチを切り抜く" +msgid "node.solarPanel.panel.flush" +msgstr "面一" -# Source-Hash: 4e4f1a24e4a9d61e +# Source-Hash: fd413477f1a9e5ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut opening" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame depth" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.cutOpening" -msgstr "開口を切る" +msgid "node.solarPanel.panel.frameDepth" +msgstr "枠の奥行き" -# Source-Hash: 99ac4d03c3061f3a +# Source-Hash: 6aa2318fa815e5f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame thickness" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.depth" -msgstr "奥行き" +msgid "node.solarPanel.panel.frameThickness" +msgstr "枠の厚さ" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: c5657f721eae3dff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap X" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.done" -msgstr "完了" +msgid "node.solarPanel.panel.gapX" +msgstr "X 間隔" -# Source-Hash: 8a3bc5111b9e97f4 +# Source-Hash: e6e3b393aa7c0d98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevation" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap Y" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.elevation" -msgstr "高さ" +msgid "node.solarPanel.panel.gapY" +msgstr "Y 間隔" -# Source-Hash: 201b720b76d79762 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Extends the perimeter down to terrain. The flat surface, base, and thickness stay unchanged." -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.extendsThePerimeterDownToTerrain" -msgstr "外周を地形まで延長します。平面、底面、厚さは変わりません。" +msgid "node.solarPanel.panel.height" +msgstr "高さ" -# Source-Hash: 387ce45ca2eb045f +# Source-Hash: 81d365ccef73068c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fixed" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.fixed" -msgstr "固定" +msgid "node.solarPanel.panel.mounting" +msgstr "取り付け方法" -# Source-Hash: d7148fa065bc709b +# Source-Hash: 482469f5a0873f73 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.floor" -msgstr "階" +msgid "node.solarPanel.panel.panel" +msgstr "パネル" -# Source-Hash: 89b2cfd72a0a7e23 +# Source-Hash: 441f7f652ea6a0d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows terrain" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preset" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.followsTerrain" -msgstr "地形に従う" +msgid "node.solarPanel.panel.preset" +msgstr "プリセット" -# Source-Hash: 48c832c1fc389290 +# Source-Hash: c913b494c3901a17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rows" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.foundation" -msgstr "基礎" +msgid "node.solarPanel.panel.rows" +msgstr "行" -# Source-Hash: 34504c6ca6445e76 +# Source-Hash: a4dba2b2675dbba0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Holes" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Setbacks too large to fit a panel." +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.holes" -msgstr "開口" +msgid "node.solarPanel.panel.setbacksTooLarge" +msgstr "セットバックが大きすぎてパネルを配置できません。" -# Source-Hash: 6e68b62d2aa611a4 +# Source-Hash: 4d18446ff8eaa680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Info" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solar Panel" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.info" -msgstr "情報" +msgid "node.solarPanel.panel.solarPanel" +msgstr "太陽光パネル" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 0af6194a8b8d8be6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standoff" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.move" -msgstr "移動" +msgid "node.solarPanel.panel.standoff" +msgstr "スタンドオフ" -# Source-Hash: 1d2dafb0d8f26ed5 +# Source-Hash: 58cb60c14826f1d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No holes" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilt angle" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.noHoles" -msgstr "開口なし" +msgid "node.solarPanel.panel.tiltAngle" +msgstr "傾斜角度" -# Source-Hash: c6a29e75bf215488 +# Source-Hash: 787005b26aec58a3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rim" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilted" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.rim" -msgstr "縁" +msgid "node.solarPanel.panel.tilted" +msgstr "傾斜" -# Source-Hash: 8775bc8dc9593964 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.slab" -msgstr "スラブ" +msgid "node.solarPanel.panel.width" +msgstr "幅" -# Source-Hash: fb23c960abf5de23 +# Source-Hash: cd53f16290b67f7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard (2\")" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Compact" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.standard2" -msgstr "標準(2\")" +msgid "node.solarPanel.preset.compact" +msgstr "コンパクト" -# Source-Hash: 5f865b052c9b40eb +# Source-Hash: 317ebe2aa996af70 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard (5cm)" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frameless" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.standard5cm" -msgstr "標準(5cm)" +msgid "node.solarPanel.preset.frameless" +msgstr "フレームレス" -# Source-Hash: cff0e2e72cfab157 +# Source-Hash: 46660ad432e19312 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sunken (15cm)" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Residential" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.sunken15cm" -msgstr "下げ(15cm)" +msgid "node.solarPanel.preset.residential" +msgstr "住宅用" -# Source-Hash: 8abc2aec4be98fe9 +# Source-Hash: b33386b8fe3725fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sunken (6\")" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Residential Large" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.sunken6" -msgstr "下げ(6\")" +msgid "node.solarPanel.preset.residentialLarge" +msgstr "住宅用(大)" -# Source-Hash: 78a454b7ac7a3cd9 +# Source-Hash: 638f17c80f424dd3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Player or camera origin within a level. One per level." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.slab.panel.surface" -msgstr "面" +msgid "node.spawn.description" +msgstr "階層内のプレイヤーまたはカメラの起点。階層ごとに1つ。" -# Source-Hash: 516636d85be919f0 +# Source-Hash: 3e2f6b4274f592c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thick (15cm)" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spawn Point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.slab.panel.thick15cm" -msgstr "厚(15cm)" +msgid "node.spawn.label" +msgstr "スポーン地点" -# Source-Hash: c84078f3560da233 +# Source-Hash: faaa4f6b40001667 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thick (6\")" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Body" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.slab.panel.thick6" -msgstr "厚(6\")" +msgid "node.stair.constructionControls.body" +msgstr "本体" -# Source-Hash: fdbb503f0941bd56 +# Source-Hash: 29b9fdb127a54435 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center stringer" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.slab.panel.thickness" -msgstr "厚さ" +msgid "node.stair.constructionControls.centerStringer" +msgstr "中央の桁" -# Source-Hash: 61c191f6df40285b +# Source-Hash: b2b2383577835a61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thin (1\")" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Closed risers" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.slab.panel.thin1" -msgstr "薄(1\")" +msgid "node.stair.constructionControls.closedRisers" +msgstr "蹴込み板あり" -# Source-Hash: d345b1f707506fe7 +# Source-Hash: 49a25acbaf33ee3d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thin (2cm)" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "From structure" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.slab.panel.thin2cm" -msgstr "薄(2cm)" +msgid "node.stair.constructionControls.fromStructure" +msgstr "構造から" -# Source-Hash: 065ffaaf64ab479d +# Source-Hash: 6f6b188bff3c0223 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid of photovoltaic panels mounted on a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inherit" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.description" -msgstr "屋根面に設置した太陽光パネルの配列。" +msgid "node.stair.constructionControls.inherit" +msgstr "継承" -# Source-Hash: 4d18446ff8eaa680 +# Source-Hash: ce25dc4a23f3ae10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solar Panel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Nosing" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.label" -msgstr "太陽光パネル" +msgid "node.stair.constructionControls.nosing" +msgstr "段鼻" +# Source-Hash: 3e52f04f92e08070 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.actions" -msgstr "操作" +msgid "node.stair.constructionControls.open" +msgstr "開く" +# Source-Hash: 7717e0464ad1e7df # Review: required -# Source-Hash: 2184867946897298 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Array" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Original" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.array" -msgstr "アレイ" +msgid "node.stair.constructionControls.original" +msgstr "元のまま" +# Source-Hash: 8a6f6c6b0cca7460 # Review: required -# Source-Hash: 6eaa0e2a78d44d59 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto-fit to roof" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Riser thickness" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.autoFitToRoof" -msgstr "屋根に自動フィット" +msgid "node.stair.constructionControls.riserThickness" +msgstr "蹴込み板の厚さ" +# Source-Hash: 2fe058966023b542 # Review: required -# Source-Hash: 30edd1c180aac9b4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Columns" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Side stringers" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.columns" -msgstr "列" +msgid "node.stair.constructionControls.sideStringers" +msgstr "側桁" +# Source-Hash: ef3e765e692faf4c # Review: required -# Source-Hash: d1c6dd6335337cc1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom — dimensions don't match any preset" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.customDimensionsDonTMatchAny" -msgstr "カスタム — 寸法がどのプリセットとも一致しません" +msgid "node.stair.constructionControls.solid" +msgstr "ソリッド" +# Source-Hash: 4c1489839e306865 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringer depth" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.delete" -msgstr "削除" +msgid "node.stair.constructionControls.stringerDepth" +msgstr "桁の高さ" +# Source-Hash: 17e1a09c422d3660 # Review: required -# Source-Hash: fe9356b1d0e0396b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip orientation" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringer width" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.flipOrientation" -msgstr "向きを反転" +msgid "node.stair.constructionControls.stringerWidth" +msgstr "桁の幅" +# Source-Hash: 146f8e61ff310dc5 # Review: required -# Source-Hash: eaaa20f3b603140f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flush" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tread finish" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.flush" -msgstr "面一" +msgid "node.stair.constructionControls.treadFinish" +msgstr "踏板の仕上げ" +# Source-Hash: 9089f91f3fbbf4cd # Review: required -# Source-Hash: fd413477f1a9e5ed -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame depth" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tread thickness" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.frameDepth" -msgstr "枠の奥行き" +msgid "node.stair.constructionControls.treadThickness" +msgstr "踏板の厚さ" +# Source-Hash: 44dda7136b93c8ee # Review: required -# Source-Hash: 6aa2318fa815e5f2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame thickness" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.frameThickness" -msgstr "枠の厚さ" +msgid "node.stair.constructionControls.waist" +msgstr "スラブ式" +# Source-Hash: dfd6d2ff7a94f22e # Review: required -# Source-Hash: c5657f721eae3dff -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap X" -#: packages/nodes/src/solar-panel/panel.tsx -#, fuzzy -msgid "node.solarPanel.panel.gapX" -msgstr "X 間隔" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist thickness" +#: packages/nodes/src/stair/construction-controls.tsx +#, fuzzy +msgid "node.stair.constructionControls.waistThickness" +msgstr "段板の厚さ" +# Source-Hash: 8535b75637105412 # Review: required -# Source-Hash: e6e3b393aa7c0d98 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap Y" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A stair composed of one or more flights with configurable treads, risers, railings." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.solarPanel.panel.gapY" -msgstr "Y 間隔" +msgid "node.stair.description" +msgstr "1つ以上の段部分で構成され、踏板・蹴込み・手すりを設定できる階段。" +# Source-Hash: c24b098693e1006d # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The flight chain does not reach the declared destination." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.height" -msgstr "高さ" +msgid "node.stair.diagnostic.arrivalMismatch" +msgstr "階段の連なりが指定の接続先に届いていません。" +# Source-Hash: 124ad1cd6bb00013 # Review: required -# Source-Hash: 81d365ccef73068c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Two risers plus going is outside the 0.60–0.65 m design range." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.mounting" -msgstr "取り付け方法" +msgid "node.stair.diagnostic.comfortTarget" +msgstr "蹴上げ2つと踏面の合計が設計範囲 0.60–0.65 m を外れています。" +# Source-Hash: 7452fcd8370bef34 # Review: required -# Source-Hash: 482469f5a0873f73 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Going is below the design target." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.panel" -msgstr "パネル" +msgid "node.stair.diagnostic.goingTarget" +msgstr "踏面が設計目標を下回っています。" +# Source-Hash: 449683eb727091d5 # Review: required -# Source-Hash: 441f7f652ea6a0d8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preset" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overhead surfaces leave less than the target headroom." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.preset" -msgstr "プリセット" +msgid "node.stair.diagnostic.headroomTarget" +msgstr "上部の面による頭上空間が目標を下回っています。" +# Source-Hash: 9e9357408f6a0d08 # Review: required -# Source-Hash: c913b494c3901a17 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rows" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Detailed headroom could not be evaluated: check riser counts and the surface query budget." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.rows" -msgstr "行" +msgid "node.stair.diagnostic.headroomUnresolved" +msgstr "詳細な頭上空間を評価できませんでした。段数と面クエリの上限を確認してください。" +# Source-Hash: 40fd019d72ff3835 # Review: required -# Source-Hash: a4dba2b2675dbba0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Setbacks too large to fit a panel." -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight dimensions and integer riser count must be positive." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.setbacksTooLarge" -msgstr "セットバックが大きすぎてパネルを配置できません。" +msgid "node.stair.diagnostic.invalidFlight" +msgstr "階段の寸法と整数の段数は正の値である必要があります。" +# Source-Hash: 3d4b6f859bd8de50 # Review: required -# Source-Hash: 4d18446ff8eaa680 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solar Panel" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The destination must be above the stair base." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.solarPanel" -msgstr "太陽光パネル" +msgid "node.stair.diagnostic.invalidRise" +msgstr "接続先は階段の基部より上である必要があります。" +# Source-Hash: 5f196b22e2c8296a # Review: required -# Source-Hash: 0af6194a8b8d8be6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standoff" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing depth exceeds a full circle at the walking line; the visible landing is limited to one circle." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.standoff" -msgstr "スタンドオフ" +msgid "node.stair.diagnostic.landingOverlap" +msgstr "踊り場の奥行きが歩行線上で一周を超えています。表示される踊り場は一周に制限されます。" +# Source-Hash: 0122ec92b951a114 # Review: required -# Source-Hash: 58cb60c14826f1d0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilt angle" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The narrow end of a winder tread is below 0.10 m; check the intended stair use." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.tiltAngle" -msgstr "傾斜角度" +msgid "node.stair.diagnostic.narrowWinderEnd" +msgstr "回り段の狭い側が 0.10 m 未満です。階段の用途を確認してください。" +# Source-Hash: a664dc7f3b014af8 # Review: required -# Source-Hash: 787005b26aec58a3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilted" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight riser heights differ. Use uniform-riser repair only if this is a proposed design." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.tilted" -msgstr "傾斜" +msgid "node.stair.diagnostic.nonuniformRisers" +msgstr "階段の蹴上げがそろっていません。均一化の修正は計画中の設計の場合にのみ使ってください。" +# Source-Hash: cd140b519d37b01e # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A landing has a stored rise; inspect its transition before repair." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.width" -msgstr "幅" +msgid "node.stair.diagnostic.raisedLanding" +msgstr "踊り場に高さが保存されています。修正前に接続部を確認してください。" +# Source-Hash: a94cfa7b2a21cf14 # Review: required -# Source-Hash: cd53f16290b67f7f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Compact" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Riser height exceeds the design target." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.preset.compact" -msgstr "コンパクト" +msgid "node.stair.diagnostic.riserTarget" +msgstr "蹴上げが設計目標を超えています。" +# Source-Hash: 53d7084bc41c1ad6 # Review: required -# Source-Hash: 317ebe2aa996af70 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frameless" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.solarPanel.preset.frameless" -msgstr "フレームレス" +msgid "node.stair.label" +msgstr "階段" +# Source-Hash: 4ee35f740730ae87 # Review: required -# Source-Hash: 46660ad432e19312 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Residential" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.preset.residential" -msgstr "住宅用" +msgid "node.stair.layout.straight" +msgstr "直進" +# Source-Hash: 1cda16cb49e6fb93 # Review: required -# Source-Hash: b33386b8fe3725fa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Residential Large" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{layout} turn" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.preset.residentialLarge" -msgstr "住宅用(大)" +msgid "node.stair.layout.turn" +msgstr "{layout} 折り返し" -# Source-Hash: 638f17c80f424dd3 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Player or camera origin within a level. One per level." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.spawn.description" -msgstr "階層内のプレイヤーまたはカメラの起点。階層ごとに1つ。" +msgid "node.stair.panel.actions" +msgstr "操作" -# Source-Hash: 3e2f6b4274f592c0 +# Source-Hash: 15eaf25f306541f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spawn Point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add flight" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.spawn.label" -msgstr "スポーン地点" +msgid "node.stair.panel.addFlight" +msgstr "階段を追加" -# Source-Hash: faaa4f6b40001667 +# Source-Hash: 1fa37c346bffb8e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Body" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add landing" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.body" -msgstr "本体" +msgid "node.stair.panel.addLanding" +msgstr "踊り場を追加" + +# Source-Hash: 9ccbd6c1785f1e73 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Apply {label} layout" +#: packages/nodes/src/stair/panel.tsx +#, fuzzy +msgid "node.stair.panel.applyLabelLayout" +msgstr "{label}レイアウトを適用" -# Source-Hash: 29b9fdb127a54435 +# Source-Hash: 7eb42ea0fc442b8d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center stringer" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto Cutout" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.centerStringer" -msgstr "中央の桁" +msgid "node.stair.panel.autoCutout" +msgstr "自動切り抜き" -# Source-Hash: b2b2383577835a61 +# Source-Hash: 3eda29328f91485d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Closed risers" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Balusters" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.closedRisers" -msgstr "蹴込み板あり" +msgid "node.stair.panel.balusters" +msgstr "手すり子" -# Source-Hash: 6f6b188bff3c0223 +# Source-Hash: 19ae2360207ecf5a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inherit" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Boards" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.inherit" -msgstr "継承" +msgid "node.stair.panel.boards" +msgstr "板" -# Source-Hash: ce25dc4a23f3ae10 +# Source-Hash: 69578b7dd7723fa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Nosing" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Both" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.nosing" -msgstr "段鼻" +msgid "node.stair.panel.both" +msgstr "両方" -# Source-Hash: 3e52f04f92e08070 +# Source-Hash: 5e2429ced8144ab4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cable" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.open" -msgstr "開く" +msgid "node.stair.panel.cable" +msgstr "ケーブル" -# Source-Hash: 7717e0464ad1e7df +# Source-Hash: 11d6eec5d485488d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Original" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center Column" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.original" -msgstr "元のまま" +msgid "node.stair.panel.centerColumn" +msgstr "中央の柱" -# Source-Hash: 8a6f6c6b0cca7460 +# Source-Hash: 5fbbf4ad24befa7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Riser thickness" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clockwise" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.riserThickness" -msgstr "蹴込み板の厚さ" +msgid "node.stair.panel.clockwise" +msgstr "時計回り" -# Source-Hash: 2fe058966023b542 +# Source-Hash: 31028ca51b49018b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Side stringers" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connected to {surface}. Move the stair to connect to another edge." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.sideStringers" -msgstr "側桁" +msgid "node.stair.panel.connectedTo" +msgstr "{surface}に接続されています。階段を移動すると別の辺に接続できます。" -# Source-Hash: ef3e765e692faf4c +# Source-Hash: 33133921e270509f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connected to a surface. Move the stair to connect to another edge." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.solid" -msgstr "ソリッド" +msgid "node.stair.panel.connectedToSurface" +msgstr "面に接続されています。階段を移動すると別の辺に接続できます。" -# Source-Hash: 4c1489839e306865 +# Source-Hash: ce1429556f57d7ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stringer depth" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Construction" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.stringerDepth" -msgstr "桁の高さ" +msgid "node.stair.panel.construction" +msgstr "構造" -# Source-Hash: 17e1a09c422d3660 +# Source-Hash: 5e3e3ab7d91c2c4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stringer width" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Counterclockwise" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.stringerWidth" -msgstr "桁の幅" +msgid "node.stair.panel.counterclockwise" +msgstr "反時計回り" -# Source-Hash: 146f8e61ff310dc5 +# Source-Hash: a028e08962c388e0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tread finish" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curved" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.treadFinish" -msgstr "踏板の仕上げ" +msgid "node.stair.panel.curved" +msgstr "曲線" -# Source-Hash: 9089f91f3fbbf4cd +# Source-Hash: 0bd4232a56d25366 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tread thickness" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom rise" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.treadThickness" -msgstr "踏板の厚さ" +msgid "node.stair.panel.customRise" +msgstr "カスタムの蹴上げ" -# Source-Hash: 44dda7136b93c8ee +# Source-Hash: f3aa561772702108 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.waist" -msgstr "スラブ式" +msgid "node.stair.panel.deck" +msgstr "デッキ" -# Source-Hash: dfd6d2ff7a94f22e +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist thickness" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.waistThickness" -msgstr "段板の厚さ" +msgid "node.stair.panel.delete" +msgstr "削除" -# Source-Hash: 8535b75637105412 +# Source-Hash: 1c34e5cc37add163 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A stair composed of one or more flights with configurable treads, risers, railings." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Design targets" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.description" -msgstr "1つ以上の段部分で構成され、踏板・蹴込み・手すりを設定できる階段。" +msgid "node.stair.panel.designTargets" +msgstr "設計目標" -# Source-Hash: c24b098693e1006d +# Source-Hash: 748877ae309c313c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The flight chain does not reach the declared destination." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Destination" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.arrivalMismatch" -msgstr "階段の連なりが指定の接続先に届いていません。" +msgid "node.stair.panel.destination" +msgstr "接続先" -# Source-Hash: 124ad1cd6bb00013 +# Source-Hash: 1fa48e82752d1505 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Two risers plus going is outside the 0.60–0.65 m design range." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag near a deck, patio, concrete slab, or landing edge to fit the stair." #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.comfortTarget" -msgstr "蹴上げ2つと踏面の合計が設計範囲 0.60–0.65 m を外れています。" +msgid "node.stair.panel.dragNearADeckPatioConcrete" +msgstr "デッキ、パティオ、コンクリートスラブ、踊り場の端の近くにドラッグして階段を合わせます。" -# Source-Hash: 7452fcd8370bef34 +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Going is below the design target." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.goingTarget" -msgstr "踏面が設計目標を下回っています。" +msgid "node.stair.panel.duplicate" +msgstr "複製" -# Source-Hash: 449683eb727091d5 +# Source-Hash: 776903eb3756eea9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overhead surfaces leave less than the target headroom." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equal angle" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.headroomTarget" -msgstr "上部の面による頭上空間が目標を下回っています。" +msgid "node.stair.panel.equalAngle" +msgstr "等角" -# Source-Hash: 9e9357408f6a0d08 +# Source-Hash: 8956a359d7cec0a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Detailed headroom could not be evaluated: check riser counts and the surface query budget." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equal going" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.headroomUnresolved" -msgstr "詳細な頭上空間を評価できませんでした。段数と面クエリの上限を確認してください。" +msgid "node.stair.panel.equalGoing" +msgstr "踏面を均等に" -# Source-Hash: 40fd019d72ff3835 +# Source-Hash: 6ff728d5058c7e31 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flight dimensions and integer riser count must be positive." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit risers and going" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.invalidFlight" -msgstr "階段の寸法と整数の段数は正の値である必要があります。" +msgid "node.stair.panel.fitRisersAndGoing" +msgstr "蹴上げと踏面を合わせる" -# Source-Hash: 3d4b6f859bd8de50 +# Source-Hash: d60a4c7995bd2184 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The destination must be above the stair base." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit To Floor" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.invalidRise" -msgstr "接続先は階段の基部より上である必要があります。" +msgid "node.stair.panel.fitToFloor" +msgstr "床に合わせる" -# Source-Hash: 5f196b22e2c8296a +# Source-Hash: 0638614580661eb0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing depth exceeds a full circle at the walking line; the visible landing is limited to one circle." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit uniform risers" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.landingOverlap" -msgstr "踊り場の奥行きが歩行線上で一周を超えています。表示される踊り場は一周に制限されます。" +msgid "node.stair.panel.fitUniformRisers" +msgstr "均一な蹴上げに合わせる" -# Source-Hash: 0122ec92b951a114 +# Source-Hash: 4d365dbc1fb92b90 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The narrow end of a winder tread is below 0.10 m; check the intended stair use." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight {number}: {count, plural, one {{riserCount} riser} other {{riserCount} risers}} · R {riser} · T {going} · {slope}" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.narrowWinderEnd" -msgstr "回り段の狭い側が 0.10 m 未満です。階段の用途を確認してください。" +msgid "node.stair.panel.flightMeasurements" +msgstr "階段 {number}:{count, plural, other {{riserCount} 段}} · 蹴上げ {riser} · 踏面 {going} · {slope}" -# Source-Hash: a664dc7f3b014af8 +# Source-Hash: 6e946bd1acd94637 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flight riser heights differ. Use uniform-riser repair only if this is a proposed design." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floors, ceilings and stairs only." #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.nonuniformRisers" -msgstr "階段の蹴上げがそろっていません。均一化の修正は計画中の設計の場合にのみ使ってください。" +msgid "node.stair.panel.floorsCeilingsAndStairsOnly" +msgstr "床、天井、階段のみ。" -# Source-Hash: cd140b519d37b01e +# Source-Hash: fa10ea42944107a8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A landing has a stored rise; inspect its transition before repair." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows deck" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.raisedLanding" -msgstr "踊り場に高さが保存されています。修正前に接続部を確認してください。" +msgid "node.stair.panel.followsDeck" +msgstr "デッキに追従" -# Source-Hash: a94cfa7b2a21cf14 +# Source-Hash: a5c2353769b603d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Riser height exceeds the design target." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows level" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.riserTarget" -msgstr "蹴上げが設計目標を超えています。" +msgid "node.stair.panel.followsLevel" +msgstr "階層に従う" -# Source-Hash: 53d7084bc41c1ad6 +# Source-Hash: b7fc627a965bc016 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "From Level" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.label" -msgstr "階段" +msgid "node.stair.panel.fromLevel" +msgstr "開始階層" -# Source-Hash: 4ee35f740730ae87 +# Source-Hash: 523b9912e283b644 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Geometry" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.layout.straight" -msgstr "直進" +msgid "node.stair.panel.geometry" +msgstr "ジオメトリ" -# Source-Hash: 1cda16cb49e6fb93 +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{layout} turn" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.layout.turn" -msgstr "{layout} 折り返し" +msgid "node.stair.panel.glass" +msgstr "ガラス" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 55adba80c39500f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Headroom:" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.actions" -msgstr "操作" +msgid "node.stair.panel.headroom" +msgstr "頭上空間:" -# Source-Hash: 15eaf25f306541f9 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add flight" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.addFlight" -msgstr "階段を追加" +msgid "node.stair.panel.height" +msgstr "高さ" -# Source-Hash: 1fa37c346bffb8e4 +# Source-Hash: 9bcdccd29e64c4d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add landing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inner gap" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.addLanding" -msgstr "踊り場を追加" +msgid "node.stair.panel.innerGap" +msgstr "内側の隙間" -# Source-Hash: 9ccbd6c1785f1e73 +# Source-Hash: 8b54356df7ae40bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Apply {label} layout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inner Radius" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.applyLabelLayout" -msgstr "{label}レイアウトを適用" +msgid "node.stair.panel.innerRadius" +msgstr "内半径" -# Source-Hash: 7eb42ea0fc442b8d +# Source-Hash: 88d5b9ecb242c650 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto Cutout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Integrated" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.autoCutout" -msgstr "自動切り抜き" +msgid "node.stair.panel.integrated" +msgstr "一体型" -# Source-Hash: 3eda29328f91485d +# Source-Hash: de9566487b17a73b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Balusters" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.balusters" -msgstr "手すり子" +msgid "node.stair.panel.landing" +msgstr "踊り場" -# Source-Hash: 19ae2360207ecf5a +# Source-Hash: 54800340a0eeab23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Boards" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layout" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.boards" -msgstr "板" +msgid "node.stair.panel.layout" +msgstr "レイアウト" -# Source-Hash: 69578b7dd7723fa1 +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Both" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.both" -msgstr "両方" +msgid "node.stair.panel.left" +msgstr "左" -# Source-Hash: 5e2429ced8144ab4 +# Source-Hash: 7d4f8532c0d115e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cable" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left turn" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.cable" -msgstr "ケーブル" +msgid "node.stair.panel.leftTurn" +msgstr "左折れ" -# Source-Hash: 11d6eec5d485488d +# Source-Hash: c6aa74075f37313a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center Column" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Measurements" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.centerColumn" -msgstr "中央の柱" +msgid "node.stair.panel.measurements" +msgstr "計測" -# Source-Hash: 5fbbf4ad24befa7f +# Source-Hash: 8e464a8f52254f27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clockwise" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Metal" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.clockwise" -msgstr "時計回り" +msgid "node.stair.panel.metal" +msgstr "金属" -# Source-Hash: 31028ca51b49018b +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connected to {surface}. Move the stair to connect to another edge." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.connectedTo" -msgstr "{surface}に接続されています。階段を移動すると別の辺に接続できます。" +msgid "node.stair.panel.move" +msgstr "移動" -# Source-Hash: 33133921e270509f +# Source-Hash: a4f1cc34aae4db27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connected to a surface. Move the stair to connect to another edge." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Moving this stair keeps its current rise, steps, and run." #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.connectedToSurface" -msgstr "面に接続されています。階段を移動すると別の辺に接続できます。" +msgid "node.stair.panel.movingThisStairKeepsItsCurrent" +msgstr "この階段を移動しても現在の高さ、段数、水平長は変わりません。" -# Source-Hash: ce1429556f57d7ee +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Construction" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.construction" -msgstr "構造" +msgid "node.stair.panel.none" +msgstr "なし" -# Source-Hash: 5e3e3ab7d91c2c4f +# Source-Hash: 47c858b3022b3ae5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Counterclockwise" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No overhead surface" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.counterclockwise" -msgstr "反時計回り" +msgid "node.stair.panel.noOverheadSurface" +msgstr "上部に面がありません" -# Source-Hash: a028e08962c388e0 +# Source-Hash: 17f1933d93cf655c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curved" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not evaluated" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.curved" -msgstr "曲線" +msgid "node.stair.panel.notEvaluated" +msgstr "未評価" -# Source-Hash: 0bd4232a56d25366 +# Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom rise" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.customRise" -msgstr "カスタムの蹴上げ" +msgid "node.stair.panel.opening" +msgstr "開口" -# Source-Hash: f3aa561772702108 +# Source-Hash: 599220556fc4bbfb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Deck" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening Offset" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.deck" -msgstr "デッキ" +msgid "node.stair.panel.openingOffset" +msgstr "開口のオフセット" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.delete" -msgstr "削除" +msgid "node.stair.panel.position" +msgstr "位置" -# Source-Hash: 1c34e5cc37add163 +# Source-Hash: f522323372a7a59e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Design targets" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post & rail" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.designTargets" -msgstr "設計目標" +msgid "node.stair.panel.postRail" +msgstr "支柱とレール" -# Source-Hash: 748877ae309c313c +# Source-Hash: 240ed9c77627b9a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Destination" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.destination" -msgstr "接続先" +msgid "node.stair.panel.railing" +msgstr "手すり" -# Source-Hash: 1fa48e82752d1505 +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag near a deck, patio, concrete slab, or landing edge to fit the stair." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.dragNearADeckPatioConcrete" -msgstr "デッキ、パティオ、コンクリートスラブ、踊り場の端の近くにドラッグして階段を合わせます。" +msgid "node.stair.panel.right" +msgstr "右" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: ae876c3e9a5913eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right turn" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.duplicate" -msgstr "複製" +msgid "node.stair.panel.rightTurn" +msgstr "右折れ" -# Source-Hash: 776903eb3756eea9 +# Source-Hash: fe8c5b735495eb00 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equal angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rise" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.equalAngle" -msgstr "等角" +msgid "node.stair.panel.rise" +msgstr "高さ" -# Source-Hash: 8956a359d7cec0a6 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equal going" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.equalGoing" -msgstr "踏面を均等に" +msgid "node.stair.panel.rotation" +msgstr "回転" -# Source-Hash: 6ff728d5058c7e31 +# Source-Hash: 505d8419cf4cc5e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fit risers and going" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segments" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.fitRisersAndGoing" -msgstr "蹴上げと踏面を合わせる" +msgid "node.stair.panel.segments" +msgstr "セグメント" -# Source-Hash: d60a4c7995bd2184 +# Source-Hash: 0b9a0bef102b75bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fit To Floor" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{type, select, landing {Landing} other {Stair}}" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.fitToFloor" -msgstr "床に合わせる" +msgid "node.stair.panel.segmentType" +msgstr "{type, select, landing {踊り場} other {階段}}" -# Source-Hash: 0638614580661eb0 +# Source-Hash: 87b926bbf34a78ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fit uniform risers" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sizing" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.fitUniformRisers" -msgstr "均一な蹴上げに合わせる" +msgid "node.stair.panel.sizing" +msgstr "サイズ設定" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 4d365dbc1fb92b90 +# Source-Hash: 8a0f4562198c266f # Review: required -# English: "Flight {number}: {count, plural, one {{riserCount} riser} other {{riserCount} risers}} · R {riser} · T {going} · {slope}" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snap to nearby surfaces" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.flightMeasurements" -msgstr "階段 {number}:{count, plural, other {{riserCount} 段}} · 蹴上げ {riser} · 踏面 {going} · {slope}" +msgid "node.stair.panel.snapToNearbySurfaces" +msgstr "近くの面にスナップ" -# Source-Hash: 6e946bd1acd94637 +# Source-Hash: f9a4a870cb3d3c41 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floors, ceilings and stairs only." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spiral" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.floorsCeilingsAndStairsOnly" -msgstr "床、天井、階段のみ。" +msgid "node.stair.panel.spiral" +msgstr "らせん" -# Source-Hash: fa10ea42944107a8 +# Source-Hash: f8d4f66145e1eba0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows deck" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Staircase" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.followsDeck" -msgstr "デッキに追従" +msgid "node.stair.panel.staircase" +msgstr "階段" -# Source-Hash: a5c2353769b603d5 +# Source-Hash: be8122fbf16dec33 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows level" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Steps" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.followsLevel" -msgstr "階層に従う" +msgid "node.stair.panel.steps" +msgstr "段" -# Source-Hash: b7fc627a965bc016 +# Source-Hash: 8846dc96332c5181 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "From Level" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Step Supports" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.fromLevel" -msgstr "開始階層" +msgid "node.stair.panel.stepSupports" +msgstr "段の支持材" -# Source-Hash: 523b9912e283b644 +# Source-Hash: 4ee35f740730ae87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Geometry" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.geometry" -msgstr "ジオメトリ" +msgid "node.stair.panel.straight" +msgstr "直進" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.glass" -msgstr "ガラス" +msgid "node.stair.panel.style" +msgstr "スタイル" -# Source-Hash: 55adba80c39500f9 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Headroom:" +# Source-Hash: cde3878287069df2 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface connection" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.headroom" -msgstr "頭上空間:" +msgid "node.stair.panel.surfaceConnection" +msgstr "面との接続" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: 4e0f8b363503efff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sweep" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.height" -msgstr "高さ" +msgid "node.stair.panel.sweep" +msgstr "スイープ" -# Source-Hash: 9bcdccd29e64c4d8 +# Source-Hash: 4c294d88d712855a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inner gap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target going" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.innerGap" -msgstr "内側の隙間" +msgid "node.stair.panel.targetGoing" +msgstr "目標の踏面" -# Source-Hash: 8b54356df7ae40bf +# Source-Hash: 74cfba22cf2e6eb8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inner Radius" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target headroom" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.innerRadius" -msgstr "内半径" +msgid "node.stair.panel.targetHeadroom" +msgstr "目標の頭上空間" -# Source-Hash: 88d5b9ecb242c650 +# Source-Hash: 9d05958a265a6726 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Integrated" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target max riser" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.integrated" -msgstr "一体型" +msgid "node.stair.panel.targetMaxRiser" +msgstr "目標の最大蹴上げ" -# Source-Hash: de9566487b17a73b +# Source-Hash: d10322b16178ce37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target minimum going" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.landing" -msgstr "踊り場" +msgid "node.stair.panel.targetMinimumGoing" +msgstr "目標の最小踏面" -# Source-Hash: 54800340a0eeab23 +# Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Layout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.layout" -msgstr "レイアウト" +msgid "node.stair.panel.thickness" +msgstr "厚さ" -# Source-Hash: f365c6b6dd9ebab9 +# Source-Hash: b3214a20e45a7aed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "To" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.left" -msgstr "左" +msgid "node.stair.panel.to" +msgstr "終点" -# Source-Hash: 7d4f8532c0d115e9 +# Source-Hash: 846fc58043454194 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left turn" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Landing" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.leftTurn" -msgstr "左折れ" +msgid "node.stair.panel.topLanding" +msgstr "上部の踊り場" -# Source-Hash: c6aa74075f37313a +# Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Measurements" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.measurements" -msgstr "計測" +msgid "node.stair.panel.type" +msgstr "種類" -# Source-Hash: 8e464a8f52254f27 +# Source-Hash: b4c2f503b19443c6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Metal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unavailable" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.metal" -msgstr "金属" +msgid "node.stair.panel.unavailable" +msgstr "利用不可" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 546fa6dd4e62e82d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walking line offset" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.move" -msgstr "移動" +msgid "node.stair.panel.walkingLineOffset" +msgstr "歩行線のオフセット" -# Source-Hash: a4f1cc34aae4db27 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Moving this stair keeps its current rise, steps, and run." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.movingThisStairKeepsItsCurrent" -msgstr "この階段を移動しても現在の高さ、段数、水平長は変わりません。" +msgid "node.stair.panel.width" +msgstr "幅" -# Source-Hash: f2953d2931e36d0c +# Source-Hash: 7b65cc10483fb191 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Winder" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.none" -msgstr "なし" +msgid "node.stair.panel.winder" +msgstr "回り段" -# Source-Hash: 47c858b3022b3ae5 +# Source-Hash: 69578b7dd7723fa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No overhead surface" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Both" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.noOverheadSurface" -msgstr "上部に面がありません" +msgid "node.stair.railingControls.both" +msgstr "両方" -# Source-Hash: 17f1933d93cf655c +# Source-Hash: fe633d20f198d7e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Not evaluated" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom sloped extension" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.notEvaluated" -msgstr "未評価" +msgid "node.stair.railingControls.bottomExtension" +msgstr "下部の傾斜延長" -# Source-Hash: e04298381837252f +# Source-Hash: 384842ae1e1c6825 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuous" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.opening" -msgstr "開口" +msgid "node.stair.railingControls.continuous" +msgstr "連続" -# Source-Hash: 599220556fc4bbfb +# Source-Hash: d7148fa065bc709b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening Offset" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.openingOffset" -msgstr "開口のオフセット" +msgid "node.stair.railingControls.floor" +msgstr "階" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: 644d2d9e9c3dd31f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handrail diameter" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.position" -msgstr "位置" +msgid "node.stair.railingControls.handrailDiameter" +msgstr "手すりの径" -# Source-Hash: f522323372a7a59e +# Source-Hash: 5f3f2be1e572a066 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post & rail" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handrail height" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.postRail" -msgstr "支柱とレール" +msgid "node.stair.railingControls.handrailHeight" +msgstr "手すりの高さ" -# Source-Hash: 240ed9c77627b9a1 +# Source-Hash: cb3239847f068a1b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handrail inset" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.railing" -msgstr "手すり" +msgid "node.stair.railingControls.handrailInset" +msgstr "手すりの内側オフセット" -# Source-Hash: b34d5ee0f218221d +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.right" -msgstr "右" +msgid "node.stair.railingControls.left" +msgstr "左" -# Source-Hash: ae876c3e9a5913eb +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right turn" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.rightTurn" -msgstr "右折れ" +msgid "node.stair.railingControls.none" +msgstr "なし" -# Source-Hash: fe8c5b735495eb00 +# Source-Hash: e6ac8d7c9639c351 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rise" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No return" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.rise" -msgstr "高さ" +msgid "node.stair.railingControls.noReturn" +msgstr "返しなし" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: 5688b2003002d03a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Original layout" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.rotation" -msgstr "回転" +msgid "node.stair.railingControls.originalLayout" +msgstr "元のレイアウト" -# Source-Hash: 505d8419cf4cc5e1 +# Source-Hash: d0d904fbd052d7b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segments" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post-facing" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.segments" -msgstr "セグメント" +msgid "node.stair.railingControls.postFacing" +msgstr "支柱側" -# Source-Hash: 0b9a0bef102b75bc +# Source-Hash: fc4d8c6f156b0430 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{type, select, landing {Landing} other {Stair}}" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return length" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.segmentType" -msgstr "{type, select, landing {踊り場} other {階段}}" +msgid "node.stair.railingControls.returnLength" +msgstr "返しの長さ" -# Source-Hash: 87b926bbf34a78ed +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sizing" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.sizing" -msgstr "サイズ設定" +msgid "node.stair.railingControls.right" +msgstr "右" -# Source-Hash: 8a0f4562198c266f +# Source-Hash: e1f8354a95b5060a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snap to nearby surfaces" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Separate handrail" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.snapToNearbySurfaces" -msgstr "近くの面にスナップ" +msgid "node.stair.railingControls.separateHandrail" +msgstr "独立した手すり" -# Source-Hash: f9a4a870cb3d3c41 +# Source-Hash: 005f0197ec3bc95a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spiral" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set the length to reach the wall or post." +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.spiral" -msgstr "らせん" +msgid "node.stair.railingControls.setTheLengthToReachThe" +msgstr "壁または支柱に届く長さに設定します。" -# Source-Hash: f8d4f66145e1eba0 +# Source-Hash: bef713f3ec96f758 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Staircase" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top horizontal extension" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.staircase" -msgstr "階段" +msgid "node.stair.railingControls.topExtension" +msgstr "上部の水平延長" -# Source-Hash: be8122fbf16dec33 +# Source-Hash: bdad79929de6b142 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Steps" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall-facing" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.steps" -msgstr "段" +msgid "node.stair.railingControls.wallFacing" +msgstr "壁側" -# Source-Hash: 8846dc96332c5181 +# Source-Hash: 1709ce71eba750ff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Step Supports" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A solid poured flight on a footing; risers closed, no stringers." +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.stepSupports" -msgstr "段の支持材" +msgid "node.stair.structureControls.aSolidPouredFlightOnA" +msgstr "フーチングの上に一体で打設した階段です。蹴込みは閉じ、桁はありません。" -# Source-Hash: 4ee35f740730ae87 +# Source-Hash: 56be143b76f65392 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto ({autoCount})" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.straight" -msgstr "直進" +msgid "node.stair.structureControls.autoAutocount" +msgstr "自動({autoCount})" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: d7820aaac08e4fcb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto (closed)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.style" -msgstr "スタイル" +msgid "node.stair.structureControls.autoClosed" +msgstr "自動(あり)" -# Source-Hash: cde3878287069df2 +# Source-Hash: c7cbd493df719e71 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface connection" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto (open)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.surfaceConnection" -msgstr "面との接続" +msgid "node.stair.structureControls.autoOpen" +msgstr "自動(なし)" -# Source-Hash: 4e0f8b363503efff +# Source-Hash: be21258d52930d5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sweep" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto (pressure-treated)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.sweep" -msgstr "スイープ" +msgid "node.stair.structureControls.autoPressureTreated" +msgstr "自動(加圧防腐処理)" -# Source-Hash: 4c294d88d712855a +# Source-Hash: 1828540d95a5b5c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target going" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto ({treads})" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.targetGoing" -msgstr "目標の踏面" +msgid "node.stair.structureControls.autoTreads" +msgstr "自動({treads})" -# Source-Hash: 74cfba22cf2e6eb8 +# Source-Hash: 43c1949fa53685b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target headroom" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto (untreated)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.targetHeadroom" -msgstr "目標の頭上空間" +msgid "node.stair.structureControls.autoUntreated" +msgstr "自動(未処理)" -# Source-Hash: 9d05958a265a6726 +# Source-Hash: d0a3ca3ce29ae833 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target max riser" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Closed (1x8 boards)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.targetMaxRiser" -msgstr "目標の最大蹴上げ" +msgid "node.stair.structureControls.closed1x8Boards" +msgstr "あり(1x8 板)" -# Source-Hash: d10322b16178ce37 +# Source-Hash: 824471a3691b51db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target minimum going" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Concrete" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.targetMinimumGoing" -msgstr "目標の最小踏面" +msgid "node.stair.structureControls.concrete" +msgstr "コンクリート" -# Source-Hash: fdbb503f0941bd56 +# Source-Hash: dcb2dd54c3301068 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# steel channel} other {# steel channels}}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.thickness" -msgstr "厚さ" +msgid "node.stair.structureControls.countSteelChannels" +msgstr "{count, plural, other {溝形鋼 # 本}}" -# Source-Hash: b3214a20e45a7aed +# Source-Hash: fbf12088b828a103 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "To" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# steel channel at {spacing} o.c.} other {# steel channels at {spacing} o.c.}}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.to" -msgstr "終点" +msgid "node.stair.structureControls.countSteelChannelsAtSpacing" +msgstr "{count, plural, other {溝形鋼 # 本(芯々 {spacing})}}" -# Source-Hash: 846fc58043454194 +# Source-Hash: 6f0f06f0531c7e96 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Landing" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# stringer} other {# stringers}}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.topLanding" -msgstr "上部の踊り場" +msgid "node.stair.structureControls.countStringers" +msgstr "{count, plural, other {桁 # 本}}" -# Source-Hash: c44f7ab8bbd24858 +# Source-Hash: cfdb3f3fc95ea940 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# stringer at {spacing} o.c.} other {# stringers at {spacing} o.c.}}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.type" -msgstr "種類" +msgid "node.stair.structureControls.countStringersAtSpacing" +msgstr "{count, plural, other {桁 # 本(芯々 {spacing})}}" -# Source-Hash: b4c2f503b19443c6 +# Source-Hash: fa4b97d3aa600bcd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unavailable" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.unavailable" -msgstr "利用不可" +msgid "node.stair.structureControls.cut" +msgstr "ささら桁" -# Source-Hash: 546fa6dd4e62e82d +# Source-Hash: ba4f3c1346b3e7af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walking line offset" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight {number}: {layout}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.walkingLineOffset" -msgstr "歩行線のオフセット" +msgid "node.stair.structureControls.flightLayout" +msgstr "階段 {number}:{layout}" -# Source-Hash: 3a0ccd6c46877a87 +# Source-Hash: 4cbb34fdf4c1e107 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Housed sides" +#: packages/nodes/src/stair/structure-controls.tsx +#, fuzzy +msgid "node.stair.structureControls.housedSides" +msgstr "側桁(彫り込み)" + +# Source-Hash: e3ddff241f642295 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{inches} in o.c." +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.width" -msgstr "幅" +msgid "node.stair.structureControls.inchesInOC" +msgstr "芯々 {inches} in" -# Source-Hash: 7b65cc10483fb191 +# Source-Hash: 542ca0bee99a1533 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Winder" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{layout} (auto)" +#. The stringer count was chosen automatically, not set by hand. +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.winder" -msgstr "回り段" +msgid "node.stair.structureControls.layoutAuto" +msgstr "{layout}(自動)" -# Source-Hash: 69578b7dd7723fa1 +# Source-Hash: 73dcfae611575500 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Both" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lumber" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.both" -msgstr "両方" +msgid "node.stair.structureControls.lumber" +msgstr "木材" -# Source-Hash: fe633d20f198d7e4 +# Source-Hash: d10743fce478d9f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom sloped extension" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Max spacing" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.bottomExtension" -msgstr "下部の傾斜延長" +msgid "node.stair.structureControls.maxSpacing" +msgstr "最大間隔" -# Source-Hash: 384842ae1e1c6825 +# Source-Hash: ce25dc4a23f3ae10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuous" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Nosing" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.continuous" -msgstr "連続" +msgid "node.stair.structureControls.nosing" +msgstr "段鼻" -# Source-Hash: d7148fa065bc709b +# Source-Hash: ba534b07476bc06d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "One {stock}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.floor" -msgstr "階" +msgid "node.stair.structureControls.oneStock" +msgstr "{stock} 1 枚" -# Source-Hash: 644d2d9e9c3dd31f +# Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handrail diameter" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.handrailDiameter" -msgstr "手すりの径" +msgid "node.stair.structureControls.open" +msgstr "なし" -# Source-Hash: 5f3f2be1e572a066 +# Source-Hash: 20f023962f848e14 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handrail height" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Original body" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.handrailHeight" -msgstr "手すりの高さ" +msgid "node.stair.structureControls.originalBody" +msgstr "元の本体" -# Source-Hash: cb3239847f068a1b +# Source-Hash: ac658d76a942652f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handrail inset" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plywood + finish" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.handrailInset" -msgstr "手すりの内側オフセット" +msgid "node.stair.structureControls.plywoodFinish" +msgstr "合板 + 仕上げ" -# Source-Hash: f365c6b6dd9ebab9 +# Source-Hash: 86fda85cdc89fd27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pressure-treated" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.left" -msgstr "左" +msgid "node.stair.structureControls.pressureTreated" +msgstr "加圧防腐処理" -# Source-Hash: f2953d2931e36d0c +# Source-Hash: d903bba423ddb755 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Risers" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.none" -msgstr "なし" +msgid "node.stair.structureControls.risers" +msgstr "蹴込み板" -# Source-Hash: e6ac8d7c9639c351 +# Source-Hash: ff0400a550f24adf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No return" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Steel stringers" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.noReturn" -msgstr "返しなし" +msgid "node.stair.structureControls.steelStringers" +msgstr "鋼製の桁" -# Source-Hash: 5688b2003002d03a +# Source-Hash: 50d4cac7f3002cd2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Original layout" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringer count" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.originalLayout" -msgstr "元のレイアウト" +msgid "node.stair.structureControls.stringerCount" +msgstr "桁の本数" -# Source-Hash: d0d904fbd052d7b2 +# Source-Hash: 71733e5b479af2a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post-facing" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringers" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.postFacing" -msgstr "支柱側" +msgid "node.stair.structureControls.stringers" +msgstr "桁" -# Source-Hash: fc4d8c6f156b0430 +# Source-Hash: 191196b94d1c86f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return length" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringer type" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.returnLength" -msgstr "返しの長さ" +msgid "node.stair.structureControls.stringerType" +msgstr "桁の種類" -# Source-Hash: b34d5ee0f218221d +# Source-Hash: a20c89205a4448d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.right" -msgstr "右" +msgid "node.stair.structureControls.structure" +msgstr "構造" -# Source-Hash: e1f8354a95b5060a +# Source-Hash: 869e3785611a0858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Separate handrail" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Treads" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.separateHandrail" -msgstr "独立した手すり" +msgid "node.stair.structureControls.treads" +msgstr "踏板" -# Source-Hash: 005f0197ec3bc95a +# Source-Hash: e1e6555b827b4620 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set the length to reach the wall or post." -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Two {stock}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.setTheLengthToReachThe" -msgstr "壁または支柱に届く長さに設定します。" +msgid "node.stair.structureControls.twoStock" +msgstr "{stock} 2 枚" -# Source-Hash: bef713f3ec96f758 +# Source-Hash: 5c362de43a2cbac1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top horizontal extension" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Untreated" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.topExtension" -msgstr "上部の水平延長" +msgid "node.stair.structureControls.untreated" +msgstr "未処理" -# Source-Hash: bdad79929de6b142 +# Source-Hash: 401bae5ffee978fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall-facing" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wood stringers" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.wallFacing" -msgstr "壁側" +msgid "node.stair.structureControls.woodStringers" +msgstr "木製の桁" # Source-Hash: ce0b6361eb77e93c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A single flight of a parent stair." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -29750,8 +32483,8 @@ msgstr "親階段の1つの段部分。" # Source-Hash: 2159ec5769e1c59a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stair Segment" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -29760,8 +32493,8 @@ msgstr "階段の段部分" # Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29770,8 +32503,8 @@ msgstr "操作" # Source-Hash: 551b04c03b07595e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Attachment" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29780,8 +32513,8 @@ msgstr "接続" # Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29790,8 +32523,8 @@ msgstr "削除" # Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dimensions" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29800,8 +32533,8 @@ msgstr "寸法" # Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duplicate" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29810,8 +32543,8 @@ msgstr "複製" # Source-Hash: ad063fb27f370c28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Editing switches the stair to Custom rise" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29820,8 +32553,8 @@ msgstr "編集すると階段はカスタムの蹴上げに切り替わります # Source-Hash: 776903eb3756eea9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Equal angle" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29830,8 +32563,8 @@ msgstr "等角" # Source-Hash: 8956a359d7cec0a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Equal going" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29840,8 +32573,8 @@ msgstr "踏面を均等に" # Source-Hash: 66f1018b50c2e426 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fill to floor" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29850,8 +32583,8 @@ msgstr "床まで埋める" # Source-Hash: deff4254bb163b2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flight" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29860,8 +32593,8 @@ msgstr "階段" # Source-Hash: d6da828cd0c5e8cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flight shape" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29870,8 +32603,8 @@ msgstr "階段の形状" # Source-Hash: e360f89d3c0ec456 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Front" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29880,8 +32613,8 @@ msgstr "前面" # Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Height" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29890,8 +32623,8 @@ msgstr "高さ" # Source-Hash: 9bcdccd29e64c4d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Inner gap" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29900,8 +32633,8 @@ msgstr "内側の隙間" # Source-Hash: de9566487b17a73b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Landing" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29910,8 +32643,8 @@ msgstr "踊り場" # Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Left" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29920,8 +32653,8 @@ msgstr "左" # Source-Hash: 7d4f8532c0d115e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Left turn" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29930,8 +32663,8 @@ msgstr "左折れ" # Source-Hash: 643687bc3adaac76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Length" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29940,8 +32673,8 @@ msgstr "長さ" # Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Move" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29950,8 +32683,8 @@ msgstr "移動" # Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Position" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29960,8 +32693,8 @@ msgstr "位置" # Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Right" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29970,8 +32703,8 @@ msgstr "右" # Source-Hash: ae876c3e9a5913eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Right turn" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29980,8 +32713,8 @@ msgstr "右折れ" # Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rotation" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29990,8 +32723,8 @@ msgstr "回転" # Source-Hash: 2159ec5769e1c59a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stair Segment" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30000,8 +32733,8 @@ msgstr "階段の段部分" # Source-Hash: be8122fbf16dec33 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Steps" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30010,8 +32743,8 @@ msgstr "段" # Source-Hash: 4ee35f740730ae87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Straight" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30020,8 +32753,8 @@ msgstr "直進" # Source-Hash: a20c89205a4448d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Structure" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30030,8 +32763,8 @@ msgstr "構造" # Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Thickness" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30040,8 +32773,8 @@ msgstr "厚さ" # Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Type" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30050,8 +32783,8 @@ msgstr "種類" # Source-Hash: 546fa6dd4e62e82d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Walking line offset" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30060,8 +32793,8 @@ msgstr "歩行線のオフセット" # Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Width" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30070,8 +32803,8 @@ msgstr "幅" # Source-Hash: 7b65cc10483fb191 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Winder" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30080,8 +32813,8 @@ msgstr "回り段" # Source-Hash: 5434a3189441c913 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Persistent construction grid axis with identification bubbles." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30090,8 +32823,8 @@ msgstr "符号付きバブルのある常設の通り芯。" # Source-Hash: 0cfe636f7fdd9fd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Structural Grid" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30100,8 +32833,8 @@ msgstr "構造通り芯" # Source-Hash: 36b714210f25c284 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wind-driven spinning whirlybird exhaust vent for a roof slope." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30110,198 +32843,198 @@ msgstr "屋根勾配用の風力で回るタービン排気口。" # Source-Hash: 4a855abb962f5e7a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Turbine Vent" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy msgid "node.turbineVent.label" msgstr "タービン換気扇" -# Review: required # Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.actions" msgstr "操作" -# Review: required # Source-Hash: c65f02bcdc3231d6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Cylinder" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.cylinder" msgstr "円柱" -# Review: required # Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.delete" msgstr "削除" -# Review: required # Source-Hash: 016d8e70618916d4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Diameter" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.diameter" msgstr "直径" -# Review: required # Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dimensions" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.dimensions" msgstr "寸法" -# Review: required # Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duplicate" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.duplicate" msgstr "複製" -# Review: required # Source-Hash: 2d4223f80dc3945c -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Globe" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.globe" msgstr "グローブ" -# Review: required # Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Height" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.height" msgstr "高さ" -# Review: required # Source-Hash: c0ff16d77ebc9593 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Motion" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.motion" msgstr "動き" -# Review: required # Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Move" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.move" msgstr "移動" -# Review: required # Source-Hash: 6faf9532dcbfe4bc -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Neck Height" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.neckHeight" msgstr "首の高さ" -# Review: required # Source-Hash: 1550d72740e66f77 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Pause" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.pause" msgstr "一時停止" -# Review: required # Source-Hash: c7b10382e01914ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Play" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.play" msgstr "再生" -# Review: required # Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Position" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.position" msgstr "位置" -# Review: required # Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rotation" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.rotation" msgstr "回転" -# Review: required # Source-Hash: bf553d40ce68834d -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Spin Speed" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.spinSpeed" msgstr "回転速度" -# Review: required # Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Style" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.style" msgstr "スタイル" -# Review: required # Source-Hash: 4a855abb962f5e7a -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Turbine Vent" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.turbineVent" msgstr "タービン換気扇" -# Review: required # Source-Hash: 80cef0dce71e121f -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Vanes" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy @@ -30310,8 +33043,8 @@ msgstr "羽根" # Source-Hash: e3d2aaaf5c72bc3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A named group of zones forming one apartment, hotel room or commercial lot." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30320,8 +33053,8 @@ msgstr "1つの住戸、客室、テナント区画を構成する名前付き # Source-Hash: 40e5a51d0d205fcf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Apartment" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30330,8 +33063,8 @@ msgstr "アパート" # Source-Hash: ad041d9634dd55ea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Commercial" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30340,8 +33073,8 @@ msgstr "商業" # Source-Hash: 862f30cb2d49f812 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Common" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30350,8 +33083,8 @@ msgstr "共用" # Source-Hash: cd7e1bc42d47a105 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hotel room" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30360,8 +33093,8 @@ msgstr "ホテル客室" # Source-Hash: 062cc0f1afef0c52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unit" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30370,8 +33103,8 @@ msgstr "住戸" # Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Room" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30380,8 +33113,8 @@ msgstr "部屋" # Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30390,8 +33123,8 @@ msgstr "ゾーン" # Source-Hash: e25d5b5630b9d8df # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Members sit on levels that are not adjacent." #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30400,8 +33133,8 @@ msgstr "メンバーが隣接していない階層にあります。" # Source-Hash: 5ebeb440e0e64d01 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No zones assigned yet." #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30410,8 +33143,8 @@ msgstr "ゾーンはまだ割り当てられていません。" # Source-Hash: 07731fa851c75d8c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Remove {name} from unit" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30420,8 +33153,8 @@ msgstr "{name}をユニットから外す" # Source-Hash: 389839734c8350b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Remove zone from unit" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30430,8 +33163,8 @@ msgstr "ゾーンをユニットから外す" # Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30440,8 +33173,8 @@ msgstr "操作" # Source-Hash: fe18958cedd627d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Color" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30450,8 +33183,8 @@ msgstr "色" # Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30460,8 +33193,8 @@ msgstr "削除" # Source-Hash: b80dc93401f953a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Focus" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30470,8 +33203,8 @@ msgstr "フォーカス" # Source-Hash: 1218205b3bb34f1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gross area" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30480,8 +33213,8 @@ msgstr "総面積" # Source-Hash: aa9d6710f4cac041 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kind" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30490,8 +33223,8 @@ msgstr "種類" # Source-Hash: cc3d601d59e2e26c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Levels" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30500,8 +33233,8 @@ msgstr "階層" # Source-Hash: 6bbc51529519435c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Members" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30510,8 +33243,8 @@ msgstr "メンバー" # Source-Hash: 6cc5df35f0338e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Name" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30520,8 +33253,8 @@ msgstr "名前" # Source-Hash: 54b25f70c7b63446 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No rooms yet. Pick this unit from a room's panel, or draw zones while it is focused." #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30530,8 +33263,8 @@ msgstr "部屋はまだありません。部屋のパネルからこのユニッ # Source-Hash: 85d640066187108d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Report" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30540,8 +33273,8 @@ msgstr "レポート" # Source-Hash: 062cc0f1afef0c52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unit" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30550,8 +33283,8 @@ msgstr "住戸" # Source-Hash: d53242481ff46157 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Merge walls" #: packages/nodes/src/wall/actions.tsx #, fuzzy @@ -30560,28 +33293,38 @@ msgstr "壁を結合" # Source-Hash: d7ead4708d50965f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Split wall" #: packages/nodes/src/wall/actions.tsx #, fuzzy msgid "node.wall.actions.splitWall" msgstr "壁を分割" +# Source-Hash: 2f8c3189a0b3972b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "These walls cannot be merged." +#: packages/nodes/src/wall/actions.tsx +#, fuzzy +msgid "node.wall.actions.theseWallsCannotBeMerged" +msgstr "これらの壁は結合できません。" + # Source-Hash: 96a6f084d095ea36 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column {column}, row {row}: {type, select, glass {glass} solid {solid} other {empty}}" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy msgid "node.wall.curtain.cell" msgstr "{column} 列 {row} 行:{type, select, glass {ガラス} solid {パネル} other {空}}" -# AI-Provider: cursor-agent -# AI-Model: claude-opus # Source-Hash: 904e9b269b68c670 # Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {{number} column} other {{number} columns}} · {spacing} grid spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30590,18 +33333,18 @@ msgstr "{count, plural, other {{number} 列}} · グリッド間隔 {spacing}" # Source-Hash: 8b2b2f11fca9f077 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No panels" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy msgid "node.wall.curtain.noPanels" msgstr "パネルなし" -# AI-Provider: cursor-agent -# AI-Model: claude-opus # Source-Hash: 9f5d9775377b666e # Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {{number} row} other {{number} rows}} · {spacing} grid spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30610,8 +33353,8 @@ msgstr "{count, plural, other {{number} 行}} · グリッド間隔 {spacing}" # Source-Hash: 90638d5a19a4f0a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Apply tint" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30620,8 +33363,8 @@ msgstr "色合いを適用" # Source-Hash: a7d624ec0f879829 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Border / opening frame" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30630,8 +33373,8 @@ msgstr "縁 / 開口枠" # Source-Hash: b3a163b453896bef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bottom" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30640,8 +33383,8 @@ msgstr "下" # Source-Hash: 5503fb89c40cefeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bottom row" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30650,8 +33393,8 @@ msgstr "最下段" # Source-Hash: 1928d9e7a16360d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Cancel tint" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30660,8 +33403,8 @@ msgstr "色合いを取り消す" # Source-Hash: 5211341ed18f33f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Center" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30670,8 +33413,8 @@ msgstr "中央" # Source-Hash: 9f4c033fa80119db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Choose a cell or enter its column and row. Use arrow keys to move between cells. Columns run from the wall start; rows count upward." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30680,8 +33423,8 @@ msgstr "セルを選ぶか、列と行を入力してください。矢印キー # Source-Hash: bbeadcebc59c923f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Clear hidden overrides" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30690,8 +33433,8 @@ msgstr "非表示の上書きをクリア" # Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30700,8 +33443,8 @@ msgstr "柱" # Source-Hash: 711a6426e336877a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column layout" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30710,8 +33453,8 @@ msgstr "列のレイアウト" # Source-Hash: 59b2ab5fdf54c2e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column {column}, row {row}" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30720,8 +33463,8 @@ msgstr "{column} 列 {row} 行" # Source-Hash: ce1429556f57d7ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Construction" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30729,9 +33472,9 @@ msgid "node.wall.curtainWallPanel.construction" msgstr "構造" # Source-Hash: 59d2bec8b9ae1025 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Continuous mullions and transoms assembled along the wall." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30740,8 +33483,8 @@ msgstr "壁に沿って組み立てた連続する方立と無目。" # Source-Hash: bbc5e5f3f3b99232 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Curtain wall panel selection" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30750,8 +33493,8 @@ msgstr "カーテンウォールのパネル選択" # Source-Hash: 9fd79cf417eab9ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Custom infill" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30760,8 +33503,8 @@ msgstr "カスタム充填" # Source-Hash: 097ed751fa47e5fd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Default panel" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30770,8 +33513,8 @@ msgstr "既定のパネル" # Source-Hash: 0a0c98ae42f519ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Edit individual panels" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30780,8 +33523,8 @@ msgstr "パネルを個別に編集" # Source-Hash: 8690f82f64806e4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Effective thickness: {thickness}, limited by frame depth." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30790,8 +33533,8 @@ msgstr "有効厚さ:{thickness}(枠の奥行きで制限)。" # Source-Hash: 65b1cbba3b92c5b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Empty" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30800,8 +33543,8 @@ msgstr "空" # Source-Hash: c6e7792839d09c69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Enable panel editing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30810,8 +33553,8 @@ msgstr "パネル編集を有効化" # Source-Hash: 135874d189176d13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "End" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30820,8 +33563,8 @@ msgstr "終点" # Source-Hash: 4fb65101d0b1a222 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fixed spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30830,8 +33573,8 @@ msgstr "固定間隔" # Source-Hash: 1c851bde836b3b57 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Following wall defaults" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30840,8 +33583,8 @@ msgstr "壁の既定値に従う" # Source-Hash: 49be990b89741501 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Frame dimensions" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30850,8 +33593,8 @@ msgstr "枠の寸法" # Source-Hash: c7e72beff9fe4b37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Framing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30860,8 +33603,8 @@ msgstr "下地" # Source-Hash: 221f418784836f11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fully capped" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30870,8 +33613,8 @@ msgstr "完全に覆う" # Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glass" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30880,8 +33623,8 @@ msgstr "ガラス" # Source-Hash: a17c63662aa4404d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glass appearance" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30890,8 +33633,8 @@ msgstr "ガラスの外観" # Source-Hash: f59c4938a2116a2e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glass appearance is controlled by the paint tool." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30900,8 +33643,8 @@ msgstr "ガラスの外観はペイントツールで設定します。" # Source-Hash: 9c38875c310547ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glass tint" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30910,8 +33653,8 @@ msgstr "ガラスの色合い" # Source-Hash: 7660a6aa7e7cd365 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glazing gap" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30920,8 +33663,8 @@ msgstr "ガラスの隙間" # Source-Hash: 6e739c8a698efaab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Grid limited to 32 panels per axis. Spacing expands to fit this wall." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30930,8 +33673,8 @@ msgstr "グリッドは各軸 32 パネルまでです。この壁に合わせ # Source-Hash: 1c63255b675bbcd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{length, plural, one {{number} custom panel is outside this grid. It returns if the grid expands.} other {{number} custom panels are outside this grid. They return if the grid expands.}}" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30940,8 +33683,8 @@ msgstr "{length, plural, other {{number} 個のカスタムパネルがこのグ # Source-Hash: 84af317e818c10cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Horizontal caps" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30950,8 +33693,8 @@ msgstr "水平キャップ" # Source-Hash: 7a71f6b25c5dc718 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Horizontal frame width" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30960,8 +33703,8 @@ msgstr "水平枠の幅" # Source-Hash: 54800340a0eeab23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Layout" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30970,8 +33713,8 @@ msgstr "レイアウト" # Source-Hash: fc37833ef19c8feb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Low roughness is smooth; high roughness gives a matte surface in rendered shading." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30980,8 +33723,8 @@ msgstr "粗さが低いと滑らか、高いとレンダリングでマットな # Source-Hash: 321ca5101ab61db7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Maximum spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30990,8 +33733,8 @@ msgstr "最大間隔" # Source-Hash: 1452f51ec5dfc6ba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Module joint width" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31000,8 +33743,8 @@ msgstr "モジュール目地の幅" # Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "None" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31010,8 +33753,8 @@ msgstr "なし" # Source-Hash: 1c0b8a5503c5daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opacity" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31020,8 +33763,8 @@ msgstr "不透明度" # Source-Hash: 0f9ba67daa6b4625 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opaque band" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31030,8 +33773,8 @@ msgstr "不透明帯" # Source-Hash: fdf533d6592eff60 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opaque bands replace a full row with solid panels. Apply their finish with the paint tool." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31040,8 +33783,8 @@ msgstr "不透明帯は1行全体を不透明パネルに置き換えます。 # Source-Hash: b91302bf741c9fd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Panel count" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31050,8 +33793,8 @@ msgstr "パネル数" # Source-Hash: 3a019ce58d021431 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Panel infill" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31060,8 +33803,8 @@ msgstr "パネルの充填" # Source-Hash: 6ce059aee1386f72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Panels" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31070,8 +33813,8 @@ msgstr "パネル" # Source-Hash: d24fe036670f54a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Panel thickness" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31080,8 +33823,8 @@ msgstr "パネルの厚さ" # Source-Hash: a780f13a732bab88 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reset this panel" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31090,8 +33833,8 @@ msgstr "このパネルをリセット" # Source-Hash: 03a22f6df69c47d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Row" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31100,8 +33843,8 @@ msgstr "行" # Source-Hash: 0e18ec19d0e4ea93 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Row layout" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31110,8 +33853,8 @@ msgstr "行のレイアウト" # Source-Hash: dfb58bbd8932811d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Separate framed modules with joints between units." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31120,8 +33863,8 @@ msgstr "ユニット間に目地のある独立した枠付きモジュール。 # Source-Hash: ef3e765e692faf4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Solid" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31130,8 +33873,8 @@ msgstr "ソリッド" # Source-Hash: e4698e83d02beb6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31140,8 +33883,8 @@ msgstr "間隔" # Source-Hash: 0a26a1e61c825660 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Start" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31150,8 +33893,8 @@ msgstr "始点" # Source-Hash: d3d738ccbc7103ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stick-built" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31160,8 +33903,8 @@ msgstr "現場組み" # Source-Hash: fbdb9260ee302d3d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Structural glazing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31170,8 +33913,8 @@ msgstr "構造ガラス" # Source-Hash: 393d5c5ec4e7014c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Surface roughness" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31180,8 +33923,8 @@ msgstr "表面の粗さ" # Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31190,8 +33933,8 @@ msgstr "上" # Source-Hash: 51aa1c35a1761178 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top row" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31200,8 +33943,8 @@ msgstr "最上段" # Source-Hash: 1181faa315f26c83 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Uncapped members sit behind the glazing." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31210,8 +33953,8 @@ msgstr "キャップなしの部材はガラスの裏側にあります。" # Source-Hash: e68eeb4033268842 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unitized" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31220,8 +33963,8 @@ msgstr "ユニット式" # Source-Hash: 355b469b8a9c42f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Use glass settings instead" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31230,8 +33973,8 @@ msgstr "代わりにガラスの設定を使う" # Source-Hash: 9d75fad413e547e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Use the Door or Window tool to add an opening through the wall." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31240,8 +33983,8 @@ msgstr "ドアまたは窓ツールで壁に開口を追加します。" # Source-Hash: c1fa8c24203a5dde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Vertical caps" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31250,8 +33993,8 @@ msgstr "垂直キャップ" # Source-Hash: 0560516882b93f0d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Vertical frame width" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31260,8 +34003,8 @@ msgstr "垂直枠の幅" # Source-Hash: 4b903041c38cdd72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall system" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31270,8 +34013,8 @@ msgstr "壁システム" # Source-Hash: 6c753f6234766116 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A straight or curved wall segment. Hosts doors, windows, lean-to extensions, and wall-mounted items." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -31280,8 +34023,8 @@ msgstr "直線または曲線の壁。ドア、窓、差し掛け、壁付けア # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -31290,8 +34033,8 @@ msgstr "壁" # Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31300,8 +34043,8 @@ msgstr "操作" # Source-Hash: 67d2ec01cdce2bdc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Assembly" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31310,8 +34053,8 @@ msgstr "構成" # Source-Hash: 05b65242d8c48791 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Auto" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31320,8 +34063,8 @@ msgstr "自動" # Source-Hash: 69578b7dd7723fa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Both" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31330,8 +34073,8 @@ msgstr "両方" # Source-Hash: b3a163b453896bef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bottom" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31340,8 +34083,8 @@ msgstr "下" # Source-Hash: 75d323d0159b0df8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Brick veneer" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31350,8 +34093,8 @@ msgstr "レンガ張り" # Source-Hash: 32d0bfee628c42a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Chair rail" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31360,8 +34103,8 @@ msgstr "チェアレール" # Source-Hash: a85f39db8f92f8e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "CMU" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31370,8 +34113,8 @@ msgstr "CMU" # Source-Hash: f76e125a47ed0612 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Colonial" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31380,8 +34123,8 @@ msgstr "コロニアル" # Source-Hash: a4962c0f39d629ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Cove" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31390,8 +34133,8 @@ msgstr "コーブ" # Source-Hash: e5d425095ade6f06 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Craft" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31400,8 +34143,8 @@ msgstr "クラフト" # Source-Hash: fa8a6b7f2f4eee63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Crown molding" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31410,8 +34153,8 @@ msgstr "廻り縁" # Source-Hash: 9736e0a78294e68d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Curtain wall" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31420,8 +34163,8 @@ msgstr "カーテンウォール" # Source-Hash: f08fbb462e9afc0e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Curve" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31430,8 +34173,8 @@ msgstr "曲線" # Source-Hash: 9e9715d52410c86f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Custom" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31440,8 +34183,8 @@ msgstr "カスタム" # Source-Hash: b2a1b3bc9676fe05 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Custom height" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31450,8 +34193,8 @@ msgstr "カスタムの高さ" # Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Depth" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31460,8 +34203,8 @@ msgstr "奥行き" # Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dimensions" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31470,8 +34213,8 @@ msgstr "寸法" # Source-Hash: 4da800c75b9a6b23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Drywall" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31480,8 +34223,8 @@ msgstr "石膏ボード" # Source-Hash: d6ba089e1ca40cdf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Extends downward to meet the terrain. Height and top stay unchanged." #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31490,8 +34233,8 @@ msgstr "下方向に地形まで延長します。高さと上面は変わりま # Source-Hash: 0ead5e5711b98bf6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Exterior" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31500,8 +34243,8 @@ msgstr "外部" # Source-Hash: fd89c31f16639f50 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fiber cement" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31510,8 +34253,8 @@ msgstr "繊維セメント" # Source-Hash: a6be391d580de5cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fill to terrain" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31520,8 +34263,8 @@ msgstr "地形まで埋める" # Source-Hash: 9cab4d4c95f63cdd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flat" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31530,8 +34273,8 @@ msgstr "陸屋根" # Source-Hash: a5c2353769b603d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follows level" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31540,18 +34283,28 @@ msgstr "階層に従う" # Source-Hash: fd413477f1a9e5ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Frame depth" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.frameDepth" msgstr "枠の奥行き" +# Source-Hash: cb22c8e4b0d92234 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framer's default" +#: packages/nodes/src/wall/panel.tsx +#, fuzzy +msgid "node.wall.panel.framersDefault" +msgstr "施工者の標準" + # Source-Hash: c7e72beff9fe4b37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Framing" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31559,9 +34312,9 @@ msgid "node.wall.panel.framing" msgstr "下地" # Source-Hash: eda78e8a76f068d8 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gypsum" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31570,8 +34323,8 @@ msgstr "石膏" # Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Height" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31580,8 +34333,8 @@ msgstr "高さ" # Source-Hash: 2d89c1638aa8dd7e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide code" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31590,8 +34343,8 @@ msgstr "コードを隠す" # Source-Hash: 0c6dcbbbda6b4dbb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "ICF" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31600,8 +34353,8 @@ msgstr "ICF" # Source-Hash: ff005196861cef68 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Interior" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31610,8 +34363,8 @@ msgstr "内部" # Source-Hash: 9a4325140858cfec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Lap siding" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31620,8 +34373,8 @@ msgstr "下見板張り" # Source-Hash: 297b21e90e8c25f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Layered" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31630,8 +34383,8 @@ msgstr "多層" # Source-Hash: bf279d0f8f1e3b78 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Layer thicknesses follow the 2021 IRC assembly data. Drafting aid, not engineering — verify with the authority having jurisdiction." #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31640,8 +34393,8 @@ msgstr "層の厚さは 2021 IRC の構成データに基づきます。作図 # Source-Hash: 643687bc3adaac76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Length" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31650,8 +34403,8 @@ msgstr "長さ" # Source-Hash: 9e84d6d7b9885c4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Loading…" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31660,8 +34413,8 @@ msgstr "読み込み中…" # Source-Hash: f6cbdaa17e989b91 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Modern" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31670,8 +34423,8 @@ msgstr "モダン" # Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "None" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31680,8 +34433,8 @@ msgstr "なし" # Source-Hash: c7300ca33851fba7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "None (single layer)" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31690,8 +34443,8 @@ msgstr "なし(単層)" # Source-Hash: 0f0e13abf9b2bb67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Offset" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31700,8 +34453,8 @@ msgstr "オフセット" # Source-Hash: 04b3006bd4e6e207 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Ogee" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31710,8 +34463,8 @@ msgstr "オジー" # Source-Hash: 4f7f8af75bf8e914 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "OSB" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31720,8 +34473,8 @@ msgstr "OSB" # Source-Hash: 1243161deca7d470 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Partition: the interior finish is applied to both faces." #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31730,8 +34483,8 @@ msgstr "間仕切り:内装仕上げが両面に適用されます。" # Source-Hash: 3ee270463954f502 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Picture" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31740,8 +34493,8 @@ msgstr "額縁" # Source-Hash: a6fd2cbf5c2154e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Plaster" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31750,8 +34503,8 @@ msgstr "漆喰" # Source-Hash: e669c2c08bd80e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Plywood" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31760,18 +34513,28 @@ msgstr "合板" # Source-Hash: 441f7f652ea6a0d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Preset" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.preset" msgstr "プリセット" +# Source-Hash: 240ed9c77627b9a1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" +#: packages/nodes/src/wall/panel.tsx +#, fuzzy +msgid "node.wall.panel.railing" +msgstr "手すり" + # Source-Hash: 62bf2677b9ec30fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31780,8 +34543,8 @@ msgstr "参照" # Source-Hash: 9469a102f04ea196 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Remove" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31790,8 +34553,8 @@ msgstr "削除" # Source-Hash: ad0457800a1f0eb4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Round" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31800,8 +34563,8 @@ msgstr "丸" # Source-Hash: e9a0a3688faba18b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scripted finish" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31810,8 +34573,8 @@ msgstr "スクリプトの仕上げ" # Source-Hash: 36a588e44085108c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Sheathing" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31820,8 +34583,8 @@ msgstr "下張り" # Source-Hash: 6ae9aa7061d8c617 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shoe" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31830,8 +34593,8 @@ msgstr "シュー" # Source-Hash: 136762ac1bc96e6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Side A" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31840,8 +34603,8 @@ msgstr "A面" # Source-Hash: 8b9cb16850549c35 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Side B" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31850,8 +34613,8 @@ msgstr "B面" # Source-Hash: e6a27f6f8cd489b9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Side {face}" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31860,8 +34623,8 @@ msgstr "{face}面" # Source-Hash: d9d55c5883a53789 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Skirting" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31870,8 +34633,8 @@ msgstr "幅木" # Source-Hash: d998c212030bc7c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Standard" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31880,8 +34643,8 @@ msgstr "標準" # Source-Hash: da3e3dd077163ba0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Steel studs" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31890,8 +34653,8 @@ msgstr "鋼製下地" # Source-Hash: ed3989f23a2d185e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Step" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31900,8 +34663,8 @@ msgstr "段" # Source-Hash: 9450fcb4a14674af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stone veneer" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31910,18 +34673,28 @@ msgstr "石張り" # Source-Hash: 687cf7bc64b0224e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stucco" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.stucco" msgstr "スタッコ" +# Source-Hash: 4fce02ee3f69bf99 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Studs" +#: packages/nodes/src/wall/panel.tsx +#, fuzzy +msgid "node.wall.panel.studs" +msgstr "スタッド" + # Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Thickness" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31930,18 +34703,28 @@ msgstr "厚さ" # Source-Hash: 00cb7b58f3a10140 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{thickness} · from assembly" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.thicknessFromAssembly" msgstr "{thickness} · 構成から" +# Source-Hash: 9eef4c34dfbc970b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This project" +#: packages/nodes/src/wall/panel.tsx +#, fuzzy +msgid "node.wall.panel.thisProject" +msgstr "このプロジェクト" + # Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31950,8 +34733,8 @@ msgstr "上" # Source-Hash: 3ee03b0e9ae1be4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Total thickness" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31960,8 +34743,8 @@ msgstr "総厚" # Source-Hash: ea7e8bbd87ce4152 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unverified: {presetNote}" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31970,8 +34753,8 @@ msgstr "未検証:{presetNote}" # Source-Hash: 21242af83a2a6d17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "View code" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31980,8 +34763,8 @@ msgstr "コードを表示" # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31990,8 +34773,8 @@ msgstr "壁" # Source-Hash: eab795728c4a3f5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall type" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32000,8 +34783,8 @@ msgstr "壁の種類" # Source-Hash: e97a456d667465f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Which face is outside is undetermined (no room detected on either side) — the exterior layers are drawn on side B." #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32010,18 +34793,108 @@ msgstr "どちらの面が外側か判定できません(両側とも部屋が # Source-Hash: 31e404a4a4870faf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wood studs" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.woodStuds" msgstr "木製下地" +# Source-Hash: ece946252401f4ab +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A guard's openings must not pass a 4 in sphere (IRC R312.1.3)." +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.aGuardSOpeningsMustNot" +msgstr "転落防止柵の隙間は、直径 4 in の球が通らないようにします(IRC R312.1.3)。" + +# Source-Hash: 646ef0fbcbc58edf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.height" +msgstr "高さ" + +# Source-Hash: 7c339a5fae55681d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Infill" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.infill" +msgstr "手すり子・面材" + +# Source-Hash: d814a47c4eccee3f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "2x6 cap" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.n2x6Cap" +msgstr "2x6 笠木" + +# Source-Hash: 137b45940b723a6e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "36 in" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.n36In" +msgstr "36 in" + +# Source-Hash: ebf854ac4dd4daaf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "42 in" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.n42In" +msgstr "42 in" + +# Source-Hash: ede386e1d510ebfb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Posts" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.posts" +msgstr "支柱" + +# Source-Hash: 240ed9c77627b9a1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.railing" +msgstr "手すり" + +# Source-Hash: 1a79a485d91f3f28 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.style" +msgstr "スタイル" + # Source-Hash: 5211341ed18f33f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Center" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32030,8 +34903,8 @@ msgstr "中央" # Source-Hash: 09576259041494f3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Inside face" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32040,8 +34913,8 @@ msgstr "内側の面" # Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Left" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32050,8 +34923,8 @@ msgstr "左" # Source-Hash: 697001376b872e74 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Outside face" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32060,8 +34933,8 @@ msgstr "外側の面" # Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Right" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32070,8 +34943,8 @@ msgstr "右" # Source-Hash: eac63d14f275db3d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{trim, select, skirting {Hide skirting} crown {Hide crown molding} other {Hide chair rail}}" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32080,18 +34953,28 @@ msgstr "{trim, select, skirting {幅木を隠す} crown {廻り縁を隠す} oth # Source-Hash: 8db070a4247db221 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{trim, select, skirting {Show skirting} crown {Show crown molding} other {Show chair rail}}" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.trim.show" msgstr "{trim, select, skirting {幅木を表示} crown {廻り縁を表示} other {チェアレールを表示}}" +# Source-Hash: b1757d76048706b7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap hinge side" +#: packages/nodes/src/window/actions.tsx +#, fuzzy +msgid "node.window.actions.swapHingeSide" +msgstr "丁番側を入れ替え" + # Source-Hash: ea6a51e66eb0c0dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A window cut into a wall. Animated open/close for opening windows." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -32100,8 +34983,8 @@ msgstr "壁に設けた窓。開閉する窓はアニメーション付き。" # Source-Hash: aa3c35ed33e181e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -32110,8 +34993,8 @@ msgstr "窓" # Source-Hash: 011e4de244050a78 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Raise" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32120,8 +35003,8 @@ msgstr "上げ下げ" # Source-Hash: 19ca2434d4f7eb87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slats" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32130,8 +35013,8 @@ msgstr "スラット" # Source-Hash: c00de0e2c9b0ddcb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slide" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32140,8 +35023,8 @@ msgstr "スライド" # Source-Hash: e48604b5f7b2a5f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Swing" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32150,8 +35033,8 @@ msgstr "開き" # Source-Hash: 1615637fe68e188a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Tilt" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32160,8 +35043,8 @@ msgstr "傾斜" # Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32170,8 +35053,8 @@ msgstr "操作" # Source-Hash: 663175a9c461a96d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "All" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32180,8 +35063,8 @@ msgstr "すべて" # Source-Hash: 710261f5ffb32617 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Arch" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32190,8 +35073,8 @@ msgstr "アーチ" # Source-Hash: 3715cd54e4775087 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Arch Height" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32201,7 +35084,7 @@ msgstr "アーチの高さ" # Source-Hash: 05b65242d8c48791 # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 +# AI-Model: claude-opus-5-5 # English: "Auto" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32211,7 +35094,7 @@ msgstr "自動" # Source-Hash: 8a04486ba122ea7d # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 +# AI-Model: claude-opus-5-5 # English: "Auto follows the wall" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32220,8 +35103,8 @@ msgstr "自動は壁に合わせます" # Source-Hash: 30edd1c180aac9b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Columns" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32230,8 +35113,8 @@ msgstr "列" # Source-Hash: 2f417371c399ad67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Col Widths" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32240,8 +35123,8 @@ msgstr "列幅" # Source-Hash: 2ee121dca87bb64a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Corner" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32250,8 +35133,8 @@ msgstr "コーナー" # Source-Hash: 04e3425c5ea29359 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Corner post" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32260,8 +35143,8 @@ msgstr "コーナーポスト" # Source-Hash: 7a90a42b578f2435 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Corner Radius" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32270,8 +35153,8 @@ msgstr "角の半径" # Source-Hash: 67d10b97eff316c1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Custom: the panes match no style." #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32280,8 +35163,8 @@ msgstr "カスタム:ガラス割りがどのスタイルとも一致しませ # Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32290,8 +35173,8 @@ msgstr "削除" # Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Depth" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32300,8 +35183,8 @@ msgstr "奥行き" # Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dimensions" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32310,8 +35193,8 @@ msgstr "寸法" # Source-Hash: c53c3307e2a2a32a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Divider" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32320,8 +35203,8 @@ msgstr "仕切り" # Source-Hash: 72c65752a1d1bbb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Down" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32330,8 +35213,8 @@ msgstr "下" # Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duplicate" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32340,8 +35223,8 @@ msgstr "複製" # Source-Hash: 8497c4373d5d18ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Enable Sill" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32350,8 +35233,8 @@ msgstr "窓台を有効化" # Source-Hash: 61f9413d3bbabde7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flip Side" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32360,8 +35243,8 @@ msgstr "向きを反転" # Source-Hash: ce3a6c03765dbbd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Frame" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32371,7 +35254,7 @@ msgstr "枠" # Source-Hash: 0cce8ae784f78478 # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 +# AI-Model: claude-opus-5-5 # English: "Depth (auto)" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32380,8 +35263,8 @@ msgstr "奥行き(自動)" # Source-Hash: 092033938ca2debb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "French" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32390,8 +35273,8 @@ msgstr "フレンチドア" # Source-Hash: a6362b937fffe999 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fused glass" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32400,8 +35283,8 @@ msgstr "フュージングガラス" # Source-Hash: 7e4a0a38f694be6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Grid" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32410,8 +35293,8 @@ msgstr "グリッド" # Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Height" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32420,8 +35303,8 @@ msgstr "高さ" # Source-Hash: 42824e50de26bc14 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Individual" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32430,8 +35313,8 @@ msgstr "個別" # Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Left" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32440,8 +35323,8 @@ msgstr "左" # Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Move" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32450,8 +35333,8 @@ msgstr "移動" # Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opening" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32460,8 +35343,8 @@ msgstr "開口" # Source-Hash: ecb81bd3eefa6a47 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opening Shape" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32470,8 +35353,8 @@ msgstr "開口の形状" # Source-Hash: cf40395b71bedcca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Other side" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32480,8 +35363,8 @@ msgstr "反対側" # Source-Hash: 28fe6e9deddde6e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "pos" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32490,8 +35373,8 @@ msgstr "位置" # Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Position" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32500,8 +35383,8 @@ msgstr "位置" # Source-Hash: 3b6f225112035fde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rect" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32510,8 +35393,8 @@ msgstr "矩形" # Source-Hash: 59236bd016c6b904 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reveal Radius" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32520,8 +35403,8 @@ msgstr "見込みの半径" # Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Right" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32530,8 +35413,8 @@ msgstr "右" # Source-Hash: fc826da6c99303e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rounded" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32540,8 +35423,8 @@ msgstr "角丸" # Source-Hash: fb811056b862b6d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Row Heights" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32550,8 +35433,8 @@ msgstr "行の高さ" # Source-Hash: c913b494c3901a17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rows" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32560,8 +35443,8 @@ msgstr "行" # Source-Hash: 62ded63b01564969 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Sill" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32570,8 +35453,8 @@ msgstr "窓台" # Source-Hash: 62ab2eb3c775da95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Single" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32580,8 +35463,8 @@ msgstr "片開き" # Source-Hash: a8096eb4beaadeef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Size is limited to the wall, including clearance for the opening frame." #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32590,8 +35473,8 @@ msgstr "サイズは開口枠のクリアランスを含めて壁の範囲に制 # Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Style" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32600,8 +35483,8 @@ msgstr "スタイル" # Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Thickness" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32610,8 +35493,8 @@ msgstr "厚さ" # Source-Hash: 79ff1ae7250c1711 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "This side" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32620,8 +35503,8 @@ msgstr "こちら側" # Source-Hash: 7e2505dd1d5e3513 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top Shape" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32630,8 +35513,8 @@ msgstr "上部の形状" # Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Type" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32640,8 +35523,8 @@ msgstr "種類" # Source-Hash: c29767f86bd9df1e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unwrap" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32650,8 +35533,8 @@ msgstr "解除" # Source-Hash: 1d732503a54a532f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Up" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32660,8 +35543,8 @@ msgstr "上" # Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Width" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32670,8 +35553,8 @@ msgstr "幅" # Source-Hash: aa3c35ed33e181e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32680,8 +35563,8 @@ msgstr "窓" # Source-Hash: f59cd625e6082651 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window Type" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32690,8 +35573,8 @@ msgstr "窓の種類" # Source-Hash: 7bf8c4e2b90b3021 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wraps the corner with {partner}" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32700,8 +35583,8 @@ msgstr "{partner}とコーナーを回ります" # Source-Hash: 8f1f8eff5fbe90e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wraps the corner with its partner" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32710,8 +35593,8 @@ msgstr "対の窓とコーナーを回ります" # Source-Hash: cccf75b8c8dc5ad6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wrap the corner" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32720,8 +35603,8 @@ msgstr "コーナーを回る" # Source-Hash: 9d63109edd8b22c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Casement" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32730,8 +35613,8 @@ msgstr "開き窓" # Source-Hash: e06fc5a432b74a5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Double-hung" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32740,8 +35623,8 @@ msgstr "上げ下げ(両)" # Source-Hash: 7e4a0a38f694be6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Grid" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32750,8 +35633,8 @@ msgstr "グリッド" # Source-Hash: fbb293fe8aee84b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Horizontal bands" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32760,8 +35643,8 @@ msgstr "横帯" # Source-Hash: 3ee270463954f502 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Picture" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32770,8 +35653,8 @@ msgstr "額縁" # Source-Hash: 62ab2eb3c775da95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Single" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32780,8 +35663,8 @@ msgstr "片開き" # Source-Hash: 18cbc73c5e1590aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Sliding" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32790,8 +35673,8 @@ msgstr "引き戸" # Source-Hash: 0c88aea2bd130193 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Tall grid" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32800,8 +35683,8 @@ msgstr "縦長グリッド" # Source-Hash: 9628d0cc155e29a3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Transom" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32810,8 +35693,8 @@ msgstr "欄間" # Source-Hash: 305f3aba543b1962 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Triple-hung" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32820,8 +35703,8 @@ msgstr "上げ下げ(3枚)" # Source-Hash: 8af77effb76bc6e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wide grid" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32830,8 +35713,8 @@ msgstr "横長グリッド" # Source-Hash: 50393830365aaf2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Awning" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32840,8 +35723,8 @@ msgstr "すべり出し窓" # Source-Hash: 8447ee52258e16e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bay" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32850,8 +35733,8 @@ msgstr "ベイウィンドウ" # Source-Hash: e828c89bd0ba1ea4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bow" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32860,8 +35743,8 @@ msgstr "ボウウィンドウ" # Source-Hash: 9d63109edd8b22c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Casement" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32870,8 +35753,8 @@ msgstr "開き窓" # Source-Hash: b0b737fc5cb1d32a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Double Hung" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32880,8 +35763,8 @@ msgstr "上げ下げ窓(両)" # Source-Hash: 387ce45ca2eb045f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fixed" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32890,8 +35773,8 @@ msgstr "固定" # Source-Hash: 04a40f27911c3192 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hopper" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32900,8 +35783,8 @@ msgstr "内倒し窓" # Source-Hash: 5746be19ba2a53be # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Louvered" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32910,8 +35793,8 @@ msgstr "ルーバー窓" # Source-Hash: de6ffb1cf676f270 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Single Hung" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32920,8 +35803,8 @@ msgstr "上げ下げ窓(片)" # Source-Hash: 18cbc73c5e1590aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Sliding" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32930,8 +35813,8 @@ msgstr "引き戸" # Source-Hash: 4a4d97a4101793b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A polygonal site zone (lawn, water, paving) with a TSL gradient material." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -32940,8 +35823,8 @@ msgstr "TSL グラデーション素材を使う多角形の敷地ゾーン( # Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -32950,8 +35833,8 @@ msgstr "ゾーン" # Source-Hash: e9a6d2e71b97e757 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Enclosed room" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -32960,8 +35843,8 @@ msgstr "囲まれた部屋" # Source-Hash: 3660922f0a8f1d3c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Floor surface" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -32970,8 +35853,8 @@ msgstr "床面" # Source-Hash: 88c8703c4ff21ee1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Footprint only" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -32980,8 +35863,8 @@ msgstr "フットプリントのみ" # Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "None" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -32990,8 +35873,8 @@ msgstr "なし" # Source-Hash: a9756a3da570c3dd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Not proven" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33000,8 +35883,8 @@ msgstr "未確認" # Source-Hash: ff97d005a536cf58 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Room quantities" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33010,8 +35893,8 @@ msgstr "部屋の数量" # Source-Hash: f520e6a06fbeb803 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top view with zone edge dimensions" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33020,8 +35903,8 @@ msgstr "ゾーンの辺の寸法付き平面図" # Source-Hash: 062cc0f1afef0c52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unit" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33030,8 +35913,8 @@ msgstr "住戸" # Source-Hash: 429bd43d726de417 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Volume" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33040,8 +35923,8 @@ msgstr "体積" # Source-Hash: a7941c60a3b6998a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall surface" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33050,8 +35933,8 @@ msgstr "壁面" # Source-Hash: b8b0dbdff53a83ca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone boundary unavailable" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33060,8 +35943,8 @@ msgstr "ゾーンの境界が利用できません" # Source-Hash: 6bfb4c6f4d7b0ff2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone quantities" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy diff --git a/packages/editor/src/i18n/locales/ja/messages.ts b/packages/editor/src/i18n/locales/ja/messages.ts index c213b9a5f3..87e5e64b50 100644 --- a/packages/editor/src/i18n/locales/ja/messages.ts +++ b/packages/editor/src/i18n/locales/ja/messages.ts @@ -1 +1 @@ -/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"core.level.basement\":[\"地下1階\"],\"core.level.basementNumber\":[\"地下\",[\"number\"],\"階\"],\"core.level.floorNumber\":[[\"number\"],\"階\"],\"core.level.groundFloor\":[\"1階\"],\"editor.buildPanel.advanced\":[\"詳細\"],\"editor.buildPanel.rooms.hint\":[\"壁 · 床 · 天井\"],\"editor.buildPanel.rooms.idle\":[\"形状を選んで開始します。部屋ごとに壁・床・天井が作成されます。\"],\"editor.buildPanel.rooms.polygon.caption\":[[\"lead\"],\"最後に始点をクリックして閉じます。L字型や斜めの部屋に使用します。\"],\"editor.buildPanel.rooms.polygon.label\":[\"多角形\"],\"editor.buildPanel.rooms.polygon.lead\":[\"各頂点をクリックし、\"],\"editor.buildPanel.rooms.polygon.title\":[\"多角形の部屋\"],\"editor.buildPanel.rooms.rectangle.caption\":[\"グリッド上で\",[\"lead\"],\"します。壁・床・天井をまとめて作成します。\"],\"editor.buildPanel.rooms.rectangle.label\":[\"長方形\"],\"editor.buildPanel.rooms.rectangle.lead\":[\"対角の2点をクリック\"],\"editor.buildPanel.rooms.rectangle.title\":[\"長方形の部屋\"],\"editor.buildPanel.rooms.title\":[\"部屋\"],\"editor.buildPanel.rooms.walls.caption\":[[\"lead\"],\"輪郭を閉じると部屋になり、開いたままにすると間仕切りになります。\"],\"editor.buildPanel.rooms.walls.label\":[\"壁\"],\"editor.buildPanel.rooms.walls.lead\":[\"壁を1面ずつ描画します。\"],\"editor.buildPanel.rooms.walls.title\":[\"壁\"],\"viewer.camera.orbitLeft\":[\"左に回転\"],\"viewer.camera.orbitRight\":[\"右に回転\"],\"viewer.camera.topView\":[\"上面図\"],\"viewer.common.off\":[\"オフ\"],\"viewer.common.on\":[\"オン\"],\"viewer.display.camera\":[\"カメラ\"],\"viewer.display.colored\":[\"カラー表示\"],\"viewer.display.colors\":[\"カラー\"],\"viewer.display.edges.off\":[\"オフ\"],\"viewer.display.edges.offDetail\":[\"エッジ線を表示しない\"],\"viewer.display.edges.soft\":[\"ソフト\"],\"viewer.display.edges.softDetail\":[\"主要な稜線を薄く表示\"],\"viewer.display.edges.strong\":[\"強調\"],\"viewer.display.edges.strongDetail\":[\"エッジ線をくっきり表示\"],\"viewer.display.edges.title\":[\"エッジ\"],\"viewer.display.monochrome\":[\"モノクロ\"],\"viewer.display.orthographic\":[\"平行投影\"],\"viewer.display.perspective\":[\"透視投影\"],\"viewer.display.render.rendered\":[\"レンダリング\"],\"viewer.display.render.renderedDetail\":[\"アンビエントオクルージョンを完全表示\"],\"viewer.display.render.solid\":[\"ソリッド\"],\"viewer.display.render.solidDetail\":[\"軽量表示(アンビエントオクルージョンなし)\"],\"viewer.display.render.title\":[\"レンダリング\"],\"viewer.display.shadows\":[\"影\"],\"viewer.display.title\":[\"表示設定\"],\"viewer.floorplan.alignNorth\":[\"北を上に表示\"],\"viewer.floorplan.empty\":[\"このシーンには表示できる平面図がありません。\"],\"viewer.floorplan.fit\":[\"全体を表示\"],\"viewer.floorplan.floor\":[\"階\"],\"viewer.floorplan.floorPlan\":[\"平面図\"],\"viewer.floorplan.viewLabel\":[[\"floor\"],\"の2Dビュー\"],\"viewer.floorplan.zoomIn\":[\"拡大\"],\"viewer.floorplan.zoomOut\":[\"縮小\"],\"viewer.header.back\":[\"戻る\"],\"viewer.header.levels\":[\"階層\"],\"viewer.header.rooms\":[\"部屋\"],\"viewer.header.selection\":[\"選択\"],\"viewer.header.units\":[\"住戸\"],\"viewer.header.untitled\":[\"名称未設定\"],\"viewer.header.zones\":[\"ゾーン\"],\"viewer.levels.exploded\":[\"分解\"],\"viewer.levels.label\":[\"階層:\",[\"mode\"]],\"viewer.levels.manual\":[\"手動\"],\"viewer.levels.solo\":[\"単独\"],\"viewer.levels.stacked\":[\"積層\"],\"viewer.stage.layout\":[\"ビュー配置\"],\"viewer.stage.split\":[\"分割\"],\"viewer.theme.blueprint\":[\"青図\"],\"viewer.theme.mediterranean\":[\"地中海\"],\"viewer.theme.night\":[\"夜景\"],\"viewer.theme.overcast\":[\"曇天\"],\"viewer.theme.paper\":[\"ペーパー\"],\"viewer.theme.studio\":[\"スタジオ\"],\"viewer.theme.sunset\":[\"夕景\"],\"viewer.theme.title\":[\"シーンテーマ\"],\"viewer.theme.twilight\":[\"薄暮\"],\"viewer.theme.verdant\":[\"緑景\"],\"viewer.visibility.guides\":[\"ガイド\"],\"viewer.visibility.scans\":[\"3Dスキャン\"],\"viewer.visibility.title\":[\"表示\"],\"viewer.walkthrough.label\":[\"ウォークスルー:\",[\"state\"]],\"viewer.walls.cutaway\":[\"カット表示\"],\"viewer.walls.fullHeight\":[\"全高\"],\"viewer.walls.label\":[\"壁:\",[\"mode\"]],\"viewer.walls.low\":[\"低く表示\"]}")as Messages; \ No newline at end of file +/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"core.level.basement\":[\"地下1階\"],\"core.level.basementNumber\":[\"地下\",[\"number\"],\"階\"],\"core.level.floorNumber\":[[\"number\"],\"階\"],\"core.level.groundFloor\":[\"1階\"],\"editor.buildPanel.advanced\":[\"詳細\"],\"editor.buildPanel.rooms.hint\":[\"壁 · 床 · 天井\"],\"editor.buildPanel.rooms.idle\":[\"形状を選んで開始します。部屋ごとに壁・床・天井が作成されます。\"],\"editor.buildPanel.rooms.polygon.caption\":[[\"lead\"],\"最後に始点をクリックして閉じます。L字型や斜めの部屋に使用します。\"],\"editor.buildPanel.rooms.polygon.label\":[\"多角形\"],\"editor.buildPanel.rooms.polygon.lead\":[\"各頂点をクリックし、\"],\"editor.buildPanel.rooms.polygon.title\":[\"多角形の部屋\"],\"editor.buildPanel.rooms.rectangle.caption\":[\"グリッド上で\",[\"lead\"],\"します。壁・床・天井をまとめて作成します。\"],\"editor.buildPanel.rooms.rectangle.label\":[\"長方形\"],\"editor.buildPanel.rooms.rectangle.lead\":[\"対角の2点をクリック\"],\"editor.buildPanel.rooms.rectangle.title\":[\"長方形の部屋\"],\"editor.buildPanel.rooms.title\":[\"部屋\"],\"editor.buildPanel.rooms.walls.label\":[\"壁\"],\"editor.buildPanel.rooms.walls.title\":[\"壁\"],\"viewer.camera.orbitLeft\":[\"左に回転\"],\"viewer.camera.orbitRight\":[\"右に回転\"],\"viewer.camera.topView\":[\"上面図\"],\"viewer.common.off\":[\"オフ\"],\"viewer.common.on\":[\"オン\"],\"viewer.display.camera\":[\"カメラ\"],\"viewer.display.colored\":[\"カラー表示\"],\"viewer.display.colors\":[\"カラー\"],\"viewer.display.edges.off\":[\"オフ\"],\"viewer.display.edges.offDetail\":[\"エッジ線を表示しない\"],\"viewer.display.edges.soft\":[\"ソフト\"],\"viewer.display.edges.softDetail\":[\"主要な稜線を薄く表示\"],\"viewer.display.edges.strong\":[\"強調\"],\"viewer.display.edges.strongDetail\":[\"エッジ線をくっきり表示\"],\"viewer.display.edges.title\":[\"エッジ\"],\"viewer.display.monochrome\":[\"モノクロ\"],\"viewer.display.orthographic\":[\"平行投影\"],\"viewer.display.perspective\":[\"透視投影\"],\"viewer.display.render.rendered\":[\"レンダリング\"],\"viewer.display.render.renderedDetail\":[\"アンビエントオクルージョンを完全表示\"],\"viewer.display.render.solid\":[\"ソリッド\"],\"viewer.display.render.solidDetail\":[\"軽量表示(アンビエントオクルージョンなし)\"],\"viewer.display.render.title\":[\"レンダリング\"],\"viewer.display.shadows\":[\"影\"],\"viewer.display.title\":[\"表示設定\"],\"viewer.floorplan.alignNorth\":[\"北を上に表示\"],\"viewer.floorplan.empty\":[\"このシーンには表示できる平面図がありません。\"],\"viewer.floorplan.fit\":[\"全体を表示\"],\"viewer.floorplan.floor\":[\"階\"],\"viewer.floorplan.floorPlan\":[\"平面図\"],\"viewer.floorplan.viewLabel\":[[\"floor\"],\"の2Dビュー\"],\"viewer.floorplan.zoomIn\":[\"拡大\"],\"viewer.floorplan.zoomOut\":[\"縮小\"],\"viewer.header.back\":[\"戻る\"],\"viewer.header.levels\":[\"階層\"],\"viewer.header.rooms\":[\"部屋\"],\"viewer.header.selection\":[\"選択\"],\"viewer.header.units\":[\"住戸\"],\"viewer.header.untitled\":[\"名称未設定\"],\"viewer.header.zones\":[\"ゾーン\"],\"viewer.levels.exploded\":[\"分解\"],\"viewer.levels.label\":[\"階層:\",[\"mode\"]],\"viewer.levels.manual\":[\"手動\"],\"viewer.levels.solo\":[\"単独\"],\"viewer.levels.stacked\":[\"積層\"],\"viewer.stage.layout\":[\"ビュー配置\"],\"viewer.stage.split\":[\"分割\"],\"viewer.theme.blueprint\":[\"青図\"],\"viewer.theme.mediterranean\":[\"地中海\"],\"viewer.theme.night\":[\"夜景\"],\"viewer.theme.overcast\":[\"曇天\"],\"viewer.theme.paper\":[\"ペーパー\"],\"viewer.theme.studio\":[\"スタジオ\"],\"viewer.theme.sunset\":[\"夕景\"],\"viewer.theme.title\":[\"シーンテーマ\"],\"viewer.theme.twilight\":[\"薄暮\"],\"viewer.theme.verdant\":[\"緑景\"],\"viewer.visibility.guides\":[\"ガイド\"],\"viewer.visibility.scans\":[\"3Dスキャン\"],\"viewer.visibility.title\":[\"表示\"],\"viewer.walkthrough.label\":[\"ウォークスルー:\",[\"state\"]],\"viewer.walls.cutaway\":[\"カット表示\"],\"viewer.walls.fullHeight\":[\"全高\"],\"viewer.walls.label\":[\"壁:\",[\"mode\"]],\"viewer.walls.low\":[\"低く表示\"]}")as Messages; \ No newline at end of file diff --git a/packages/editor/src/i18n/locales/zh-CN/messages.po b/packages/editor/src/i18n/locales/zh-CN/messages.po index 825e4445d1..b3af0b734a 100644 --- a/packages/editor/src/i18n/locales/zh-CN/messages.po +++ b/packages/editor/src/i18n/locales/zh-CN/messages.po @@ -15,8 +15,8 @@ msgstr "" # Source-Hash: 8ffb1c5066e53a8d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Pascal home" #: apps/editor/components/app-home-link.tsx #, fuzzy @@ -25,8 +25,8 @@ msgstr "Pascal 首页" # Source-Hash: 534540df302975a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Gate" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -35,8 +35,8 @@ msgstr "添加大门" # Source-Hash: 8b9110c4e72f2db2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Open Passage" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -45,8 +45,8 @@ msgstr "添加通道" # Source-Hash: 9a4d56454dc89966 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add to rooms" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -55,8 +55,8 @@ msgstr "添加到房间" # Source-Hash: a17210912addc85f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "← All build tools" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -65,8 +65,8 @@ msgstr "← 所有建造工具" # Source-Hash: 6b63404967e1d5b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Choose Gate or Open Passage, then click its position on any fence. Find placed gates and openings under their fence in the scene graph." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -75,8 +75,8 @@ msgstr "选择大门或通道,然后在任意围栏上点击其位置。已放 # Source-Hash: 8fd051e1e1a6c1a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Click a lineset to lay the line beside it." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -85,8 +85,8 @@ msgstr "点击冷媒管组,在其旁边布线。" # Source-Hash: 7308869944020839 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Double gate" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -95,8 +95,8 @@ msgstr "双开大门" # Source-Hash: 281d63a4b3e2de4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Features & extensions" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -105,8 +105,8 @@ msgstr "构件与扩建" # Source-Hash: b18788f1d889c1d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fence features" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -115,8 +115,8 @@ msgstr "围栏构件" # Source-Hash: 62803100bd6e7cc2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follow lineset" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -125,8 +125,8 @@ msgstr "沿冷媒管组" # Source-Hash: 4a479aa23542d766 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gate" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -135,8 +135,8 @@ msgstr "大门" # Source-Hash: 54098b5ee574737a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gate style" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -145,8 +145,8 @@ msgstr "大门样式" # Source-Hash: 8fec7e969045a8e7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Horizontal boards" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -155,8 +155,8 @@ msgstr "横向板条" # Source-Hash: 09197c4fea516277 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hover a fence to preview. Click to place. Esc cancels. Leave room between openings." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -165,8 +165,8 @@ msgstr "悬停在围栏上预览,点击放置,按 Esc 取消。开口之间 # Source-Hash: c390ba248e629b9e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Leaves" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -175,8 +175,8 @@ msgstr "门扇" # Source-Hash: c34c9b36492c6e21 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Liquid Line" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -185,8 +185,8 @@ msgstr "液管" # Source-Hash: c15c1af69ec5c1eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Match fence style" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -195,8 +195,8 @@ msgstr "匹配围栏样式" # Source-Hash: 95057eef5cd69340 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "MEP" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -205,8 +205,8 @@ msgstr "机电" # Source-Hash: 50accd740fa2e736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Off" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -215,8 +215,8 @@ msgstr "关" # Source-Hash: 9cc01faad79c28da # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "On" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -225,8 +225,8 @@ msgstr "开" # Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opening" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -235,8 +235,8 @@ msgstr "开口" # Source-Hash: 9514d3c022e68808 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opening width (m)" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -245,8 +245,8 @@ msgstr "开口宽度(米)" # Source-Hash: 6b108fb1d0eb8f9d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Open rails" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -255,8 +255,8 @@ msgstr "开放栏杆" # Source-Hash: a5a7af5e5fff1c81 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Outdoor" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -265,8 +265,8 @@ msgstr "室外" # Source-Hash: 9295ddc2805b21e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Picket" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -275,8 +275,8 @@ msgstr "尖桩" # Source-Hash: 3a08ede9e51d5395 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Roof type" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -285,8 +285,8 @@ msgstr "屋顶类型" # Source-Hash: 0f9daa442776a317 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rooms already create their floor and ceiling. Use these for platforms and one-off structure." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -295,8 +295,8 @@ msgstr "房间会自动创建地面和天花板。这些工具用于平台和单 # Source-Hash: fc79fd0c7730de76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Search build tools and kitchen items" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -305,8 +305,8 @@ msgstr "搜索建造工具和厨房物品" # Source-Hash: dc1901f276edca6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Search tools, fridge, sink…" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -315,8 +315,8 @@ msgstr "搜索工具、冰箱、水槽…" # Source-Hash: 9558db89023d4f05 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Select a curved wall to match its radius and arc." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -325,8 +325,8 @@ msgstr "选择一面曲面墙体以匹配其半径和弧度。" # Source-Hash: d327097d9ac1099f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Single gate" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -335,8 +335,8 @@ msgstr "单开大门" # Source-Hash: 99acd5128c51c8a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slab, ceiling, column…" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -345,8 +345,8 @@ msgstr "楼板、天花板、柱…" # Source-Hash: af6f8885fe0fa4e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Solid privacy" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -355,8 +355,8 @@ msgstr "实心遮挡" # Source-Hash: e2b1a3bb9630b33b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Trace a line alongside an existing lineset (F)." #: apps/editor/components/build-tab.tsx #, fuzzy @@ -365,8 +365,8 @@ msgstr "沿现有冷媒管组布线 (F)。" # Source-Hash: eba3df14a2de0812 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Vertical slats" #: apps/editor/components/build-tab.tsx #, fuzzy @@ -375,8 +375,8 @@ msgstr "竖向板条" # Source-Hash: 2ee62be78ba76f53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "All projects" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -385,8 +385,8 @@ msgstr "所有项目" # Source-Hash: 20226b68d5467072 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Preview" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -395,8 +395,8 @@ msgstr "预览" # Source-Hash: 9f2cbc9214c8f7b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Project name" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -405,8 +405,8 @@ msgstr "项目名称" # Source-Hash: 150e143a84240eee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rename project" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -415,8 +415,8 @@ msgstr "重命名项目" # Source-Hash: 331e1584943b09b9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Share" #: apps/editor/components/editor-navbar.tsx #, fuzzy @@ -425,8 +425,8 @@ msgstr "分享" # Source-Hash: 4b2f676fb4c9ec63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add {label}" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -435,8 +435,8 @@ msgstr "添加{label}" # Source-Hash: 53f98cc505aacbb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add to kitchen" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -445,8 +445,8 @@ msgstr "添加到厨房" # Source-Hash: 923a2e81dcc77852 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Choose an item, then click to place it. Appliances include their cabinetry." #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -455,8 +455,8 @@ msgstr "选择物品,然后点击放置。电器包含配套柜体。" # Source-Hash: 44156a2c888e8a4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Find in this project · {length}" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -465,8 +465,8 @@ msgstr "在本项目中查找 · {length}" # Source-Hash: aeda65db67edac21 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Find {name}" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -475,8 +475,8 @@ msgstr "查找{name}" # Source-Hash: c1d847411ba09cd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen · Add" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -485,8 +485,8 @@ msgstr "厨房 · 添加" # Source-Hash: bb3f4f8d3407c409 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen · In this project" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -495,8 +495,8 @@ msgstr "厨房 · 本项目中" # Source-Hash: 25ffad31086309f1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen cabinet" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -505,8 +505,8 @@ msgstr "厨房橱柜" # Source-Hash: a5af7817a7e8947d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No matching kitchen items placed yet." #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -515,8 +515,8 @@ msgstr "尚未放置匹配的厨房物品。" # Source-Hash: 640155f99c25773b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Select and show in scene" #: apps/editor/components/kitchen-browser.tsx #, fuzzy @@ -525,8 +525,8 @@ msgstr "选中并在场景中显示" # Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Ceiling" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -535,8 +535,8 @@ msgstr "天花板" # Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -545,8 +545,8 @@ msgstr "柱" # Source-Hash: 787e10f5db16904e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Door" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -555,8 +555,8 @@ msgstr "门" # Source-Hash: e971d82044e2f48e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duct" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -565,8 +565,8 @@ msgstr "风管" # Source-Hash: 457155657704f7cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "DWV Pipe" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -575,8 +575,8 @@ msgstr "排水管" # Source-Hash: ab5cbab7be160a1c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Elevator" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -585,8 +585,8 @@ msgstr "电梯" # Source-Hash: 02042fde61b5aa11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fence" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -595,8 +595,8 @@ msgstr "围栏" # Source-Hash: 3bf1c1a8dbb93743 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "HVAC Unit" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -605,8 +605,8 @@ msgstr "暖通设备" # Source-Hash: 1176d2568d093bf1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -615,8 +615,8 @@ msgstr "厨房" # Source-Hash: 362b03eba9d8234c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Lineset" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -625,8 +625,8 @@ msgstr "冷媒管组" # Source-Hash: c34c9b36492c6e21 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Liquid Line" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -635,18 +635,28 @@ msgstr "液管" # Source-Hash: 95057eef5cd69340 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "MEP" #: apps/editor/lib/build-palette.ts #, fuzzy msgid "app.lib.buildPalette.mep" msgstr "机电" +# Source-Hash: 5cc981e79d737694 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post" +#: apps/editor/lib/build-palette.ts +#, fuzzy +msgid "app.lib.buildPalette.post" +msgstr "立柱" + # Source-Hash: 161e5386b939e1bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Register" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -655,8 +665,8 @@ msgstr "风口" # Source-Hash: f5f730969df63d1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Roof" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -665,8 +675,8 @@ msgstr "屋顶" # Source-Hash: d7145f84f8e0e3fe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shelf" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -675,8 +685,8 @@ msgstr "置物架" # Source-Hash: 8775bc8dc9593964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slab" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -685,8 +695,8 @@ msgstr "楼板" # Source-Hash: 95e8af5d2b3ca73d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Spawn point" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -695,8 +705,8 @@ msgstr "出生点" # Source-Hash: f05bc67c57e4d530 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stairs" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -705,8 +715,8 @@ msgstr "楼梯" # Source-Hash: 96281876ce53ba08 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Terrace" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -715,8 +725,8 @@ msgstr "露台" # Source-Hash: d457508edd5bb8cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Terrain" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -725,8 +735,8 @@ msgstr "地形" # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -735,8 +745,8 @@ msgstr "墙体" # Source-Hash: aa3c35ed33e181e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window" #: apps/editor/lib/build-palette.ts #, fuzzy @@ -745,8 +755,8 @@ msgstr "窗" # Source-Hash: d40c50013043284f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Fitting" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -755,8 +765,8 @@ msgstr "添加管件" # Source-Hash: 534540df302975a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Gate" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -765,8 +775,8 @@ msgstr "添加大门" # Source-Hash: 8b9110c4e72f2db2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Open Passage" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -775,8 +785,8 @@ msgstr "添加通道" # Source-Hash: 7136b5836de6e69f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Add Trap" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -785,8 +795,8 @@ msgstr "添加存水弯" # Source-Hash: 8f4b2028ad75465d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Build" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -795,8 +805,8 @@ msgstr "建造" # Source-Hash: a23831beeb35ad3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Create from" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -805,8 +815,8 @@ msgstr "创建来源" # Source-Hash: 8146c309bd8326f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Draw the roof footprint with two corner clicks." #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -815,8 +825,8 @@ msgstr "点击两个角点绘制屋顶轮廓。" # Source-Hash: e971d82044e2f48e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duct" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -825,8 +835,8 @@ msgstr "风管" # Source-Hash: 457155657704f7cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "DWV Pipe" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -835,8 +845,8 @@ msgstr "排水管" # Source-Hash: 281d63a4b3e2de4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Features & extensions" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -845,8 +855,8 @@ msgstr "构件与扩建" # Source-Hash: 02042fde61b5aa11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fence" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -855,8 +865,8 @@ msgstr "围栏" # Source-Hash: 62803100bd6e7cc2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follow lineset" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -865,8 +875,8 @@ msgstr "沿冷媒管组" # Source-Hash: c80972ec078ac551 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gates & openings" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -875,8 +885,8 @@ msgstr "大门与开口" # Source-Hash: 3720347aa16ee777 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hover a room to preview its boundary, then click to place." #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -885,8 +895,8 @@ msgstr "悬停在房间上预览其边界,然后点击放置。" # Source-Hash: 1176d2568d093bf1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -895,8 +905,8 @@ msgstr "厨房" # Source-Hash: 95057eef5cd69340 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "MEP" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -905,8 +915,8 @@ msgstr "机电" # Source-Hash: 2e6d8cda361c648d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Modular Cabinet" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -915,8 +925,8 @@ msgstr "组合橱柜" # Source-Hash: 50accd740fa2e736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Off" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -925,8 +935,8 @@ msgstr "关" # Source-Hash: 9cc01faad79c28da # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "On" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -935,8 +945,8 @@ msgstr "开" # Source-Hash: 3fafdc69e7756f19 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Painting" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -945,8 +955,8 @@ msgstr "涂装" # Source-Hash: f5f730969df63d1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Roof" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -955,8 +965,8 @@ msgstr "屋顶" # Source-Hash: 3a08ede9e51d5395 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Roof type" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -965,8 +975,8 @@ msgstr "屋顶类型" # Source-Hash: 0c35bee851cc57a2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {# tool} other {# tools}}" #: apps/editor/lib/build-panel-model.ts #, fuzzy @@ -975,8 +985,8 @@ msgstr "{count, plural, other {# 个工具}}" # Source-Hash: 3241ecabee8221a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Conical" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -985,8 +995,8 @@ msgstr "圆锥" # Source-Hash: b5c56dd8c68de309 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Draw" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -995,8 +1005,8 @@ msgstr "绘制" # Source-Hash: 6949d667043bee0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dutch" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1005,8 +1015,8 @@ msgstr "荷兰式" # Source-Hash: 9cab4d4c95f63cdd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flat" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1015,8 +1025,8 @@ msgstr "平屋顶" # Source-Hash: deaffa095d126dfe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gable" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1025,8 +1035,8 @@ msgstr "双坡" # Source-Hash: 7f53d9ffca39984a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gambrel" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1035,8 +1045,8 @@ msgstr "复折式" # Source-Hash: 9eda0ea8d447066d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hip" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1045,8 +1055,8 @@ msgstr "四坡" # Source-Hash: 7f7bb0e875af3260 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Mansard" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1055,8 +1065,8 @@ msgstr "孟莎式" # Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Room" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1065,8 +1075,8 @@ msgstr "房间" # Source-Hash: c8d0df27faa3feaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shed" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1075,8 +1085,8 @@ msgstr "单坡" # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: apps/editor/lib/build-tab-state.ts #, fuzzy @@ -1085,8 +1095,8 @@ msgstr "墙体" # Source-Hash: 8d17e7556ce142da # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Another session saved first — refresh?" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1095,8 +1105,8 @@ msgstr "另一个会话已先保存——要刷新吗?" # Source-Hash: 8f4b2028ad75465d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Build" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1105,8 +1115,8 @@ msgstr "建造" # Source-Hash: a2bd204e93e90598 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dismiss" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1115,8 +1125,8 @@ msgstr "关闭" # Source-Hash: daebc0755d239c99 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Items" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1125,8 +1135,8 @@ msgstr "物品" # Source-Hash: cf2e870fce0f2f51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Paint" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1135,8 +1145,8 @@ msgstr "涂装" # Source-Hash: 854555777b69a4b1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reload" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1145,8 +1155,8 @@ msgstr "重新加载" # Source-Hash: 8dc78e215a97d9fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scene" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1155,8 +1165,8 @@ msgstr "场景" # Source-Hash: 83909f82446ee9c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Settings" #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1165,8 +1175,8 @@ msgstr "设置" # Source-Hash: ee255fa26d076dcc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Your changes haven't been saved. Reload to pick up the latest version." #: apps/editor/components/scene-loader.tsx #, fuzzy @@ -1175,8 +1185,8 @@ msgstr "你的更改尚未保存。重新加载以获取最新版本。" # Source-Hash: 703e1b4b9b715d3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Anyone with the link can view this project. They cannot edit it." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1185,8 +1195,8 @@ msgstr "任何拥有链接的人都可以查看此项目,但无法编辑。" # Source-Hash: 07e04484867c17d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Copied" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1195,8 +1205,8 @@ msgstr "已复制" # Source-Hash: 4f60d1e142affa9c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Copy" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1205,8 +1215,8 @@ msgstr "复制" # Source-Hash: 8ff50e1a9962a4db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Could not read the sharing state." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1215,8 +1225,8 @@ msgstr "无法读取分享状态。" # Source-Hash: 791e281338a51483 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Could not turn off the public link." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1225,8 +1235,8 @@ msgstr "无法关闭公开链接。" # Source-Hash: 2c5ddecfd652ba63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Could not turn on the public link." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1235,8 +1245,8 @@ msgstr "无法开启公开链接。" # Source-Hash: 15e49d4da8765318 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Embed code" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1245,8 +1255,8 @@ msgstr "嵌入代码" # Source-Hash: d4523c2d303f99b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Embed link" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1255,8 +1265,8 @@ msgstr "嵌入链接" # Source-Hash: 252f2cbf5e1609a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide controls" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1265,8 +1275,8 @@ msgstr "隐藏控件" # Source-Hash: ba77c0610a63bb2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Link" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1275,8 +1285,8 @@ msgstr "链接" # Source-Hash: a2560430aaec31d9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Only the 3D view, no header or toolbar." #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1285,8 +1295,8 @@ msgstr "仅显示 3D 视图,不显示标题栏或工具栏。" # Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Open" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1295,8 +1305,8 @@ msgstr "打开" # Source-Hash: b34faaa5378056c6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Public link" #: apps/editor/components/share-panel.tsx #, fuzzy @@ -1305,38 +1315,78 @@ msgstr "公开链接" # Source-Hash: 7525e8007fcab09b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Share project" #: apps/editor/components/share-panel.tsx #, fuzzy msgid "app.sharePanel.shareProject" msgstr "分享项目" +# Source-Hash: c90de8776040735c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Above" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.above" +msgstr "上层" + # Source-Hash: 3d3f438d5a49eba7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Automatic dimensions" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.automaticDimensions" msgstr "自动尺寸" +# Source-Hash: 1794e014a604344c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Below" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.below" +msgstr "下层" + +# Source-Hash: 69578b7dd7723fa1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Both" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.both" +msgstr "两者" + # Source-Hash: 14622745dbf93f4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Camera" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.camera" msgstr "相机" +# Source-Hash: a03ae72f209e32db +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceilings" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.ceilings" +msgstr "天花板" + # Source-Hash: e6bce525c47ba3ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Clean plan; dimensions appear with selection" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1345,8 +1395,8 @@ msgstr "简洁平面;选中时显示尺寸" # Source-Hash: 61ce356577cfb04a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Collapse sidebar" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1355,8 +1405,8 @@ msgstr "收起侧边栏" # Source-Hash: 2416a48df28d6205 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Crisp, opaque edge lines" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1365,8 +1415,8 @@ msgstr "清晰、不透明的边线" # Source-Hash: 4da8b3678ed77b45 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Cutaway" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1375,18 +1425,28 @@ msgstr "剖切" # Source-Hash: 4ca0e0e73229540c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Default" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.default" msgstr "默认" +# Source-Hash: 12df69f42beb0643 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.dimensions" +msgstr "尺寸" + # Source-Hash: a313661ef9dd0a65 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Display" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1395,8 +1455,8 @@ msgstr "显示" # Source-Hash: d0db46f206a88e2e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Display settings" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1405,8 +1465,8 @@ msgstr "显示设置" # Source-Hash: 0286962ab8e9cfcd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Door/window marks" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1415,18 +1475,28 @@ msgstr "门窗标记" # Source-Hash: 027bbc8b7287c06a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Edges" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.edges" msgstr "边线" +# Source-Hash: 9bacee5dbd658209 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Editing" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.editing" +msgstr "编辑" + # Source-Hash: d86126c5d16c6238 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Enter VR" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1435,8 +1505,8 @@ msgstr "进入 VR" # Source-Hash: eb99fb0b382e58cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Exit VR" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1445,8 +1515,8 @@ msgstr "退出 VR" # Source-Hash: aeac665749d3101d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Expand sidebar" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1455,8 +1525,8 @@ msgstr "展开侧边栏" # Source-Hash: 08c178ee733ff009 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Expert" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1465,28 +1535,18 @@ msgstr "专家" # Source-Hash: be12f8788f1f0a05 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Exploded" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.exploded" msgstr "分解" -# Source-Hash: c6f865a366ef5755 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Face of stud" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.faceOfStud" -msgstr "龙骨面" - # Source-Hash: 0c583f1d4201293b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Faint outline of major creases" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1495,28 +1555,18 @@ msgstr "主要折边的淡轮廓" # Source-Hash: 08ecd5878b08139d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Feet & inches" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.feetInches" msgstr "英尺和英寸" -# Source-Hash: 43b8017fa821c46c -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finished faces" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.finishedFaces" -msgstr "完成面" - # Source-Hash: 8827df1cdeb02ed9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flat and fast — no ambient occlusion" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1525,8 +1575,8 @@ msgstr "平面且快速 — 无环境光遮蔽" # Source-Hash: 060a718cdcff61b3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Floor plan annotations" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1535,8 +1585,8 @@ msgstr "平面图标注" # Source-Hash: 483171f79dc32ae5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Floor plan mode" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1545,8 +1595,8 @@ msgstr "平面图模式" # Source-Hash: 8bb9e54fc786ca77 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Full ambient occlusion" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1555,8 +1605,8 @@ msgstr "完整环境光遮蔽" # Source-Hash: 91fd3544d9ce16bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Full documentation and annotation controls" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1565,38 +1615,70 @@ msgstr "完整的图档与标注控件" # Source-Hash: 131bac2467f4fdf6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Full height" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.fullHeight" msgstr "全高" -# Source-Hash: c9838bc98cb35125 +# Source-Hash: 91c2dd3678e981b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Full wall thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ghosted for reference" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy -msgid "app.viewerToolbar.fullWallThickness" -msgstr "墙体全厚" +msgid "app.viewerToolbar.ghostedForReference" +msgstr "半透明显示以供参考" # Source-Hash: 7e4a0a38f694be6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Grid" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.grid" msgstr "网格" +# Source-Hash: 81ef3a25ccb6eaf7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "ID" +#. Short for inside dimension: measured between the inside faces of walls. +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.id" +msgstr "内" + +# Source-Hash: 09f615a2c6a14a76 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "ID + OD" +#. Inside and outside dimensions together. +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.idOd" +msgstr "内 + 外" + +# Source-Hash: 8a7ff5011275abbd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inside" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.inside" +msgstr "内侧" + # Source-Hash: 4bf4a6861d7d633e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Levels: {mode}" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1605,8 +1687,8 @@ msgstr "楼层:{mode}" # Source-Hash: 803532407fb5962b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Low" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1615,8 +1697,8 @@ msgstr "矮墙" # Source-Hash: 32f9a404c0bdce10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Magnetic snap" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1625,8 +1707,8 @@ msgstr "磁性吸附" # Source-Hash: 387082cd5f118bed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Manual" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1635,8 +1717,8 @@ msgstr "手动" # Source-Hash: 2fb69122dd996c0a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Manual dimensions" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1645,18 +1727,28 @@ msgstr "手动尺寸" # Source-Hash: c6aa74075f37313a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Measurements" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.measurements" msgstr "测量" +# Source-Hash: b2cac1ec253d4394 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Measure walls" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.measureWalls" +msgstr "墙体测量" + # Source-Hash: 0a39470be3b84536 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Meters" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1665,38 +1757,59 @@ msgstr "米" # Source-Hash: 83cce6c521e71d01 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Millimeters" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.millimeters" msgstr "毫米" -# Source-Hash: b784527bb90b9c5e +# Source-Hash: 340a0a4e7703227b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "3D measurements" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "2D only" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy -msgid "app.viewerToolbar.n3dMeasurements" -msgstr "3D 测量" +msgid "app.viewerToolbar.n2dOnly" +msgstr "仅 2D" + +# Source-Hash: ed5416e4329bd789 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "3D only" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.n3dOnly" +msgstr "仅 3D" # Source-Hash: 4ff58913a4492199 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No edge lines" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.noEdgeLines" msgstr "无边线" +# Source-Hash: fdaa3b3faa1844fd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "OD" +#. Short for outside dimension: measured between the outside faces of walls. +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.od" +msgstr "外" + # Source-Hash: 50accd740fa2e736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Off" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1705,8 +1818,8 @@ msgstr "关" # Source-Hash: 9cc01faad79c28da # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "On" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1715,28 +1828,68 @@ msgstr "开" # Source-Hash: ed59dd8ce7797a66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Orthographic" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.orthographic" msgstr "正交" +# Source-Hash: 370413dd021d6ea7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Other levels" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.otherLevels" +msgstr "其他楼层" + +# Source-Hash: dc4fe6cb415ed882 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outside" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.outside" +msgstr "外侧" + +# Source-Hash: 4b5cbc83a3533c2a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overall size, outside face to outside face" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.overallSizeOutsideFaceToOutsideFace" +msgstr "总尺寸,外表面到外表面" + # Source-Hash: 316e25993ff72b88 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Perspective" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.perspective" msgstr "透视" +# Source-Hash: 007a63bd7c1e2b55 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plan" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.plan" +msgstr "平面图" + # Source-Hash: 20226b68d5467072 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Preview" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1745,8 +1898,8 @@ msgstr "预览" # Source-Hash: 34c20b72a42ca618 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Preview mode" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1755,8 +1908,8 @@ msgstr "预览模式" # Source-Hash: 5e58af99d6d4fa6a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Render" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1765,8 +1918,8 @@ msgstr "渲染" # Source-Hash: f363702a10aedaeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rendered" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1775,18 +1928,48 @@ msgstr "渲染" # Source-Hash: 4959d5538efc595c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Room labels" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.roomLabels" msgstr "房间标签" +# Source-Hash: 257efab00820fb67 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room sizes, inside face to inside face" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.roomSizesInsideFaceToInsideFace" +msgstr "房间尺寸,内表面到内表面" + +# Source-Hash: 1ed28930a451001d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room sizes inside, overall size outside" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.roomSizesInsideOverallSizeOutside" +msgstr "内侧为房间尺寸,外侧为总尺寸" + +# Source-Hash: 8dc78e215a97d9fc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scene" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.scene" +msgstr "场景" + # Source-Hash: 82720864e5034398 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scene theme" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1795,28 +1978,38 @@ msgstr "场景主题" # Source-Hash: 4c6bcb30b40047fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shadows" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.shadows" msgstr "阴影" -# Source-Hash: 59dc62417b44931d +# Source-Hash: e04ae95c14479764 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single wall axis" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shared by 2D and 3D" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy -msgid "app.viewerToolbar.singleWallAxis" -msgstr "单一墙体轴线" +msgid "app.viewerToolbar.sharedBy2dAnd3d" +msgstr "2D 与 3D 共用" + +# Source-Hash: 827e0c6ac9936b69 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.show" +msgstr "显示" # Source-Hash: d266d83ec490df4e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Soft" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1825,8 +2018,8 @@ msgstr "柔和" # Source-Hash: ef3e765e692faf4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Solid" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1835,8 +2028,8 @@ msgstr "实体" # Source-Hash: e9f59b513f2f45ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Solo" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1845,8 +2038,8 @@ msgstr "单独" # Source-Hash: 481b7608ce12139b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stack" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1855,8 +2048,8 @@ msgstr "堆叠" # Source-Hash: 61ad94ca68b0458e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stair annotations" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1865,28 +2058,18 @@ msgstr "楼梯标注" # Source-Hash: f82927a01d4c5e45 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Strong" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.strong" msgstr "强烈" -# Source-Hash: e1be031e67d95382 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structural core face" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.structuralCoreFace" -msgstr "结构核心面" - # Source-Hash: efc50964d7b0ec47 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Structural grids & column centers" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1895,18 +2078,28 @@ msgstr "结构轴网与柱中心" # Source-Hash: 5ce4f6b80cd30f86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Translucent" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.translucent" msgstr "半透明" +# Source-Hash: 07511ce5a194e1ed +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turn on Dimensions to show them" +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.turnOnDimensionsToShowThem" +msgstr "开启尺寸后即可显示" + # Source-Hash: b404dded35241274 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Units" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1915,38 +2108,18 @@ msgstr "单位" # Source-Hash: faf51e28b748e0d9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Walkthrough" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy msgid "app.viewerToolbar.walkthrough" msgstr "漫游" -# Source-Hash: 62281975e51da7e3 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall centerline" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.wallCenterline" -msgstr "墙体中心线" - -# Source-Hash: ff145d7003118ec6 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall dimensions" -#: apps/editor/components/viewer-toolbar.tsx -#, fuzzy -msgid "app.viewerToolbar.wallDimensions" -msgstr "墙体尺寸" - # Source-Hash: 13969d1d6e310aa4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Walls: {label}" #: apps/editor/components/viewer-toolbar.tsx #, fuzzy @@ -1983,8 +2156,8 @@ msgstr "首层" # Source-Hash: fdd8b3366021a1cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Orbit Left" #: packages/editor/src/components/ui/action-menu/camera-actions.tsx #, fuzzy @@ -1993,8 +2166,8 @@ msgstr "向左环绕" # Source-Hash: 4a56359f284a3b17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Orbit Right" #: packages/editor/src/components/ui/action-menu/camera-actions.tsx #, fuzzy @@ -2003,8 +2176,8 @@ msgstr "向右环绕" # Source-Hash: f5c12d738240f889 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top View" #: packages/editor/src/components/ui/action-menu/camera-actions.tsx #, fuzzy @@ -2013,8 +2186,8 @@ msgstr "顶视图" # Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/editor/src/components/ui/action-menu/control-modes.tsx #, fuzzy @@ -2023,8 +2196,8 @@ msgstr "删除" # Source-Hash: a4395168488bb476 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Select" #: packages/editor/src/components/ui/action-menu/control-modes.tsx #, fuzzy @@ -2033,8 +2206,8 @@ msgstr "选择" # Source-Hash: d9a257653600d5a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Resume following" #: packages/editor/src/components/ui/action-menu/follow-pascal-pill.tsx #, fuzzy @@ -2043,8 +2216,8 @@ msgstr "恢复跟随" # Source-Hash: 4f073f8051cca3ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follow Pascal: Off" #: packages/editor/src/components/ui/action-menu/follow-pascal-toggle.tsx #, fuzzy @@ -2053,8 +2226,8 @@ msgstr "跟随 Pascal:关" # Source-Hash: 328ea04bb8cd12f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follow Pascal: On" #: packages/editor/src/components/ui/action-menu/follow-pascal-toggle.tsx #, fuzzy @@ -2063,8 +2236,8 @@ msgstr "跟随 Pascal:开" # Source-Hash: 7f4dcb90defe1ac2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Appliance" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2073,8 +2246,8 @@ msgstr "电器" # Source-Hash: 0655333424a8b6fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bathroom" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2083,8 +2256,8 @@ msgstr "浴室" # Source-Hash: ed68e72f5353712b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Furniture" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2093,8 +2266,8 @@ msgstr "家具" # Source-Hash: 1176d2568d093bf1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kitchen" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2103,8 +2276,8 @@ msgstr "厨房" # Source-Hash: a5a7af5e5fff1c81 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Outdoor" #: packages/editor/src/components/ui/action-menu/furnish-tools.tsx #, fuzzy @@ -2113,8 +2286,8 @@ msgstr "室外" # Source-Hash: c69865ec5d9d1ac9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Angle" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2123,8 +2296,8 @@ msgstr "角度" # Source-Hash: 622f566fe1e3d8e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Angular dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2133,8 +2306,8 @@ msgstr "角度尺寸" # Source-Hash: 7e3b0d541355305e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Arc length" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2143,8 +2316,8 @@ msgstr "弧长" # Source-Hash: 8332ab41e22958f1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Area" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2153,8 +2326,8 @@ msgstr "面积" # Source-Hash: 88c7750ed51d47a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Center mark" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2163,8 +2336,8 @@ msgstr "中心标记" # Source-Hash: 634912dabb092872 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Chord dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2173,8 +2346,8 @@ msgstr "弦长尺寸" # Source-Hash: 3cb090120253f68f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Continuous dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2183,8 +2356,8 @@ msgstr "连续尺寸" # Source-Hash: fb91b1d43b8362d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Coordinate dimensions" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2193,8 +2366,8 @@ msgstr "坐标尺寸" # Source-Hash: 530cb7ea461e8298 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Diameter dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2203,8 +2376,8 @@ msgstr "直径尺寸" # Source-Hash: fe7ddb094aa8ff4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Distance" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2213,8 +2386,8 @@ msgstr "距离" # Source-Hash: fee6203bb9046929 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Floor plan" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2223,8 +2396,8 @@ msgstr "平面图" # Source-Hash: a73539fc472e2e12 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Linear dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2233,8 +2406,8 @@ msgstr "线性尺寸" # Source-Hash: 6bba239f244c3d28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Measurement options" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2243,8 +2416,8 @@ msgstr "测量选项" # Source-Hash: 2cf5ca9b834ce8d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Measurement type" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2253,8 +2426,8 @@ msgstr "测量类型" # Source-Hash: 0431574a0e6d69d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Measure: {selectedLabel}" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2263,8 +2436,8 @@ msgstr "测量:{selectedLabel}" # Source-Hash: ac87e14dabd5a256 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Perimeter" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2273,8 +2446,8 @@ msgstr "周长" # Source-Hash: 6c9acc0589bdd4d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Radius dimension" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2283,8 +2456,8 @@ msgstr "半径尺寸" # Source-Hash: 01b0015e4e176124 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Smart" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2293,8 +2466,8 @@ msgstr "智能" # Source-Hash: 429bd43d726de417 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Volume" #: packages/editor/src/components/ui/action-menu/measurement-control.tsx #, fuzzy @@ -2303,8 +2476,8 @@ msgstr "体积" # Source-Hash: 64f3eb5e1936906d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Point and ask" #: packages/editor/src/components/ui/action-menu/point-ask-button.tsx #, fuzzy @@ -2313,8 +2486,8 @@ msgstr "指点提问" # Source-Hash: d86d31e83f6f0888 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Point and ask (C)" #: packages/editor/src/components/ui/action-menu/point-ask-button.tsx #, fuzzy @@ -2323,18 +2496,28 @@ msgstr "指点提问 (C)" # Source-Hash: 65622d2ef53c1f3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Point and ask works in the 3D view" #: packages/editor/src/components/ui/action-menu/point-ask-button.tsx #, fuzzy msgid "editor.actionMenu.pointAskButton.pointAndAskWorksInThe" msgstr "指点提问仅在 3D 视图中可用" +# Source-Hash: e14858b33b6e2623 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam" +#: packages/editor/src/components/ui/action-menu/structure-tools.tsx +#, fuzzy +msgid "editor.actionMenu.structureTools.beam" +msgstr "梁" + # Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Ceiling" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2343,8 +2526,8 @@ msgstr "天花板" # Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2353,8 +2536,8 @@ msgstr "柱" # Source-Hash: 787e10f5db16904e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Door" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2363,8 +2546,8 @@ msgstr "门" # Source-Hash: e971d82044e2f48e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duct" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2373,8 +2556,8 @@ msgstr "风管" # Source-Hash: 6d0c3833d87535e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duct Fitting" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2383,8 +2566,8 @@ msgstr "风管配件" # Source-Hash: 457155657704f7cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "DWV Pipe" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2393,8 +2576,8 @@ msgstr "排水管" # Source-Hash: ab5cbab7be160a1c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Elevator" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2403,8 +2586,8 @@ msgstr "电梯" # Source-Hash: 02042fde61b5aa11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fence" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2413,8 +2596,8 @@ msgstr "围栏" # Source-Hash: 7f4d93d5f2083844 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gable Roof" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2423,8 +2606,8 @@ msgstr "双坡屋顶" # Source-Hash: 3bf1c1a8dbb93743 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "HVAC Unit" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2433,8 +2616,8 @@ msgstr "暖通设备" # Source-Hash: 362b03eba9d8234c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Lineset" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2443,8 +2626,8 @@ msgstr "冷媒管组" # Source-Hash: c34c9b36492c6e21 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Liquid Line" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2453,8 +2636,8 @@ msgstr "液管" # Source-Hash: c040baa6ed4c7aa5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Pipe Fitting" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2463,8 +2646,8 @@ msgstr "管件" # Source-Hash: 161e5386b939e1bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Register" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2473,8 +2656,8 @@ msgstr "风口" # Source-Hash: d7145f84f8e0e3fe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shelf" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2483,8 +2666,8 @@ msgstr "置物架" # Source-Hash: 8775bc8dc9593964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slab" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2493,8 +2676,8 @@ msgstr "楼板" # Source-Hash: 3e2f6b4274f592c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Spawn Point" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2503,8 +2686,8 @@ msgstr "出生点" # Source-Hash: f05bc67c57e4d530 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stairs" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2513,8 +2696,8 @@ msgstr "楼梯" # Source-Hash: b778a315e82065a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Trap" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2523,8 +2706,8 @@ msgstr "存水弯" # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2533,8 +2716,8 @@ msgstr "墙体" # Source-Hash: aa3c35ed33e181e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy @@ -2543,18 +2726,28 @@ msgstr "窗" # Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone" #: packages/editor/src/components/ui/action-menu/structure-tools.tsx #, fuzzy msgid "editor.actionMenu.structureTools.zone" msgstr "区域" +# Source-Hash: a309ae5ee641f072 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dashed outlines of the neighbouring levels’ walls, to line walls up and check a roof against the walls under it." +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.dashedOutlinesOfTheNeighbouringLevels" +msgstr "以虚线显示相邻楼层的墙体轮廓,便于对齐墙体,并对照下方墙体检查屋顶。" + # Source-Hash: cdf3f12939ba108c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete guide image" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2563,8 +2756,8 @@ msgstr "删除参考图" # Source-Hash: 6add06abbafa8289 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete scan" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2573,8 +2766,8 @@ msgstr "删除扫描模型" # Source-Hash: 6f5e541cb5fb502f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {# guide image on this level} other {# guide images on this level}}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2583,8 +2776,8 @@ msgstr "{count, plural, other {本楼层有 # 张参考图}}" # Source-Hash: 8a832a2f33757bf8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guide image {number}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2593,8 +2786,8 @@ msgstr "参考图 {number}" # Source-Hash: 7f3aaccfe8d1af1f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guide images" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2603,8 +2796,8 @@ msgstr "参考图" # Source-Hash: 9b1de02505434d74 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guide image settings" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2613,8 +2806,8 @@ msgstr "参考图设置" # Source-Hash: 892d5dd34372028b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guides" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2623,8 +2816,8 @@ msgstr "参考图" # Source-Hash: ccfb05c78d47d6f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guides: Hidden" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2633,8 +2826,8 @@ msgstr "参考图:隐藏" # Source-Hash: 6d7ca85c4f389991 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Guides: Visible" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2643,8 +2836,8 @@ msgstr "参考图:显示" # Source-Hash: 5f6264ac469f57c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide guide images" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2653,8 +2846,8 @@ msgstr "隐藏参考图" # Source-Hash: cae234c23229c80b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide reference floor" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2663,8 +2856,8 @@ msgstr "隐藏参考楼层" # Source-Hash: 469a8416de876e0e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide scans" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2673,18 +2866,38 @@ msgstr "隐藏扫描模型" # Source-Hash: 873620c284a5651f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count} below" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy msgid "editor.actionMenu.viewToggles.levelsBelow" msgstr "下方 {count} 层" +# Source-Hash: 6661c6766fdd1a7f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No level above" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.noLevelAbove" +msgstr "上方无楼层" + +# Source-Hash: e34d9ec372c823ef +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No level below" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.noLevelBelow" +msgstr "下方无楼层" + # Source-Hash: 22a59ae72d8c9504 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No lower floor available." #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2693,8 +2906,8 @@ msgstr "没有可用的下层楼层。" # Source-Hash: 1c0b8a5503c5daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opacity" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2703,8 +2916,8 @@ msgstr "不透明度" # Source-Hash: 8bbd9bc90ac70a4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference floor" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2713,8 +2926,8 @@ msgstr "参考楼层" # Source-Hash: 45493691a23c7690 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference floor: {selectedLevelName}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2723,8 +2936,8 @@ msgstr "参考楼层:{selectedLevelName}" # Source-Hash: 7178c7b5a4581367 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference floor settings" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2733,8 +2946,8 @@ msgstr "参考楼层设置" # Source-Hash: a52848021f822f5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "References" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2743,8 +2956,8 @@ msgstr "参考资料" # Source-Hash: e59c9eec7dbd6ba1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Upload GLB meshes as scan references or blueprint images as guide references." #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2753,8 +2966,8 @@ msgstr "上传 GLB 网格作为扫描参考,或上传图纸图片作为参考 # Source-Hash: 3e73d06c3e96efba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference settings" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2763,8 +2976,8 @@ msgstr "参考资料设置" # Source-Hash: aa0df2c2f00672e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "References: Hidden" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2773,8 +2986,8 @@ msgstr "参考资料:隐藏" # Source-Hash: 9976708fc92bfa91 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "References: Visible" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2783,8 +2996,8 @@ msgstr "参考资料:显示" # Source-Hash: 320a5f1ec012900b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Riser diagram" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2793,8 +3006,8 @@ msgstr "立管图" # Source-Hash: 357b3d3eaf878a9f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {# scan on this level} other {# scans on this level}}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2803,8 +3016,8 @@ msgstr "{count, plural, other {本楼层有 # 个扫描模型}}" # Source-Hash: f09f12547484c888 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scan {number}" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2813,8 +3026,8 @@ msgstr "扫描模型 {number}" # Source-Hash: 3260bfa69cca50e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scans" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2823,8 +3036,8 @@ msgstr "扫描模型" # Source-Hash: c9c52015095997e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scan settings" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2833,8 +3046,8 @@ msgstr "扫描模型设置" # Source-Hash: 60abc9f1a8aec65c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scans: Hidden" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2843,8 +3056,8 @@ msgstr "扫描模型:隐藏" # Source-Hash: 2d2ff119a7dd7911 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scans: Visible" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2853,8 +3066,8 @@ msgstr "扫描模型:显示" # Source-Hash: 8211234b205fd9a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Show guide images" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2863,8 +3076,8 @@ msgstr "显示参考图" # Source-Hash: 7786cae6acb04cfa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Show reference floor" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy @@ -2873,31 +3086,93 @@ msgstr "显示参考楼层" # Source-Hash: 6066f0b6cff8a910 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Show scans" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy msgid "editor.actionMenu.viewToggles.showScans" msgstr "显示扫描模型" +# Source-Hash: c100768fc929ccf4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show walls below and above" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.showWallsBelowAndAbove" +msgstr "显示上下层墙体" + # Source-Hash: def6dff836767bda # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Upload scan or guide image" #: packages/editor/src/components/ui/action-menu/view-toggles.tsx #, fuzzy msgid "editor.actionMenu.viewToggles.uploadScanOrGuideImage" msgstr "上传扫描模型或参考图" -# Source-Hash: 6aee0962fc18c0f1 +# Source-Hash: e9ac75feeb58a5be # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back to home" -#: packages/editor/src/components/editor/index.tsx -#, fuzzy +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls above" +#: apps/editor/components/viewer-toolbar.tsx +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsAbove" +msgstr "上层墙体" + +# Source-Hash: 790a0b5c6dbf0e9b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below" +#: apps/editor/components/viewer-toolbar.tsx +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsBelow" +msgstr "下层墙体" + +# Source-Hash: e74e28937511bce9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below and above" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsBelowAndAbove" +msgstr "上下层墙体" + +# Source-Hash: 7c7bd2a996dfd5ce +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below and above settings" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsBelowAndAboveSettings" +msgstr "上下层墙体设置" + +# Source-Hash: 43bc80f62aeab442 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below and above: shown" +#: packages/editor/src/components/ui/action-menu/view-toggles.tsx +#, fuzzy +msgid "editor.actionMenu.viewToggles.wallsBelowAndAboveShown" +msgstr "上下层墙体:已显示" + +# Source-Hash: 6aee0962fc18c0f1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back to home" +#: packages/editor/src/components/editor/index.tsx +#, fuzzy msgid "editor.backToHome" msgstr "返回首页" @@ -2985,12 +3260,45 @@ msgstr "矩形房间" msgid "editor.buildPanel.rooms.title" msgstr "房间" -# Source-Hash: 8a21a03c4acf396b -# Review: human -# English: "{lead} Close a loop and it becomes a room; leave it open for partitions." +# Source-Hash: 9755d557ce490458 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divides a room or closes off a porch without building a wall; rooms close on it. Change any wall later from its controls." +#: packages/editor/src/components/ui/build-panel/build-panel.tsx +#, fuzzy +msgid "editor.buildPanel.rooms.wallKinds.invisibleHelp" +msgstr "无需砌墙即可分隔房间或围合门廊,房间以此闭合。之后可随时在控件中更改任意墙体。" + +# Source-Hash: abe7e7de0d337058 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall kind" +#: packages/editor/src/components/ui/build-panel/build-panel.tsx +#, fuzzy +msgid "editor.buildPanel.rooms.wallKinds.label" +msgstr "墙体种类" + +# Source-Hash: b4d012ac50ef1e82 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A guard for stairs, balconies and mezzanines; rooms close on it. Change any wall later from its controls." +#: packages/editor/src/components/ui/build-panel/build-panel.tsx +#, fuzzy +msgid "editor.buildPanel.rooms.wallKinds.railingHelp" +msgstr "用于楼梯、阳台和夹层的栏杆,房间以此闭合。之后可随时在控件中更改任意墙体。" + +# Source-Hash: 5e6d896656f4e056 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "One wall per two clicks. Its sides become exterior or interior from the rooms it bounds. Change any wall later from its controls." #: packages/editor/src/components/ui/build-panel/build-panel.tsx -msgid "editor.buildPanel.rooms.walls.caption" -msgstr "{lead}闭合轮廓后会形成房间;保持开口可绘制隔墙。" +#, fuzzy +msgid "editor.buildPanel.rooms.wallKinds.standardHelp" +msgstr "每两次点击绘制一面墙。墙面根据所围合的房间自动成为外墙面或内墙面。之后可随时在控件中更改任意墙体。" # Source-Hash: aac9a732d2159ccc # Review: human @@ -2999,13 +3307,6 @@ msgstr "{lead}闭合轮廓后会形成房间;保持开口可绘制隔墙。" msgid "editor.buildPanel.rooms.walls.label" msgstr "墙体" -# Source-Hash: 9843edd68426fa2d -# Review: human -# English: "Draw one wall at a time." -#: packages/editor/src/components/ui/build-panel/build-panel.tsx -msgid "editor.buildPanel.rooms.walls.lead" -msgstr "逐面绘制墙体。" - # Source-Hash: aac9a732d2159ccc # Review: human # English: "Walls" @@ -3013,26735 +3314,29167 @@ msgstr "逐面绘制墙体。" msgid "editor.buildPanel.rooms.walls.title" msgstr "墙体" -# Source-Hash: 1f3650da23603008 +# Source-Hash: 1dba2aacc55e0bb7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Camera controls hint" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete from this project" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.cameraControlsHint" -msgstr "相机操作提示" +msgid "editor.buildPanel.wallTypeControls.deleteFromThisProject" +msgstr "从本项目中删除" -# Source-Hash: 101b6a54c377049a +# Source-Hash: 58a1b780e877ddc3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pan" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate as a new type…" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.cameraHint.pan" -msgstr "平移" +msgid "editor.buildPanel.wallTypeControls.duplicateAsANewType" +msgstr "复制为新类型…" -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: 43e7aad9a5f75b6a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit layers…" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.cameraHint.rotate" -msgstr "旋转" +msgid "editor.buildPanel.wallTypeControls.editLayers" +msgstr "编辑构造层…" -# Source-Hash: 663cecc316eb91b8 +# Source-Hash: 8f1ea5a4c16ba810 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zoom" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit or duplicate this wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.cameraHint.zoom" -msgstr "缩放" +msgid "editor.buildPanel.wallTypeControls.editOrDuplicateThisWallType" +msgstr "编辑或复制此墙体类型" -# Source-Hash: 34b7ca7ff46c44a9 +# Source-Hash: 273fcb71b4f9272f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{label}: {finish}" -#: packages/editor/src/components/ui/controls/finish-swatch.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New wall type…" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.controls.finishSwatch.ariaLabel" -msgstr "{label}:{finish}" +msgid "editor.buildPanel.wallTypeControls.newWallType" +msgstr "新建墙体类型…" -# Source-Hash: 4ca0e0e73229540c +# Source-Hash: 079e4005e0093122 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default" -#: packages/editor/src/components/ui/controls/finish-swatch.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Presets stay as cited. Duplicate one to change its layers." +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.controls.finishSwatch.default" -msgstr "默认" +msgid "editor.buildPanel.wallTypeControls.presetsStayAsCitedDuplicateOne" +msgstr "预设保持引用原样。复制后即可更改其构造层。" -# Source-Hash: a2bd204e93e90598 +# Source-Hash: b071c943d8da1500 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dismiss" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.dismiss" -msgstr "关闭" +msgid "editor.buildPanel.wallTypeEditorDialog.add" +msgstr "添加" -# Source-Hash: 9222f970dce6cc60 +# Source-Hash: fcc69acc0fd92288 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dismiss camera controls hint" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Air space" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.dismissCameraControlsHint" -msgstr "关闭相机操作提示" +msgid "editor.buildPanel.wallTypeEditorDialog.airSpace" +msgstr "空气层" -# Source-Hash: aeac665749d3101d +# Source-Hash: 46fb2832f979d656 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Expand sidebar" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A wall type holds at most {limit, plural, one {# layer} other {# layers}}." +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.expandSidebar" -msgstr "展开侧边栏" +msgid "editor.buildPanel.wallTypeEditorDialog.aWallTypeHoldsAtMost" +msgstr "一种墙体类型最多包含 {limit, plural, other {# 层}}。" -# Source-Hash: dd86efcab72fc5c7 +# Source-Hash: 75d323d0159b0df8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Axis" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brick veneer" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.axis" -msgstr "轴" +msgid "editor.buildPanel.wallTypeEditorDialog.brickVeneer" +msgstr "砖饰面" -# Source-Hash: 5232a826549f915e +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "⌥ axis" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.axis2" -msgstr "⌥ 轴" +msgid "editor.buildPanel.wallTypeEditorDialog.cancel" +msgstr "取消" -# Source-Hash: 7001600001844c92 +# Source-Hash: 4da800c75b9a6b23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "⚠ no equipment" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drywall" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.noEquipment" -msgstr "⚠ 无设备" +msgid "editor.buildPanel.wallTypeEditorDialog.drywall" +msgstr "石膏板" -# Source-Hash: eae0194029f96edb +# Source-Hash: 1f2e15ce909adf0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {# register} other {# registers}}" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.registerCount" -msgstr "{count, plural, other {# 个风口}}" +msgid "editor.buildPanel.wallTypeEditorDialog.duplicateWallType" +msgstr "复制墙体类型" -# Source-Hash: 8fb180251a321cef +# Source-Hash: 832628bc67f36778 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.rTRotate" -msgstr "R/T 旋转" +msgid "editor.buildPanel.wallTypeEditorDialog.editWallType" +msgstr "编辑墙体类型" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 6fb660d4eabe8d6a +# Source-Hash: 7d3d13d418b64f1b # Review: required -# English: "{count, plural, one {{number} run} other {{number} runs}}" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Every wall type has one framing core" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.runCount" -msgstr "{count, plural, other {{number} 段}}" +msgid "editor.buildPanel.wallTypeEditorDialog.everyWallTypeHasOneFraming" +msgstr "每种墙体类型都有一个龙骨核心层" -# Source-Hash: 88e6c2e1c344b2fc +# Source-Hash: fd89c31f16639f50 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System" -#: packages/editor/src/components/editor/floating-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fiber cement" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingActionMenu.system" -msgstr "系统" +msgid "editor.buildPanel.wallTypeEditorDialog.fiberCement" +msgstr "纤维水泥" -# Source-Hash: f0e76aea883d4e48 +# Source-Hash: b3907da0ad234f10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add a floor under the roof" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.addAFloorUnderTheRoof" -msgstr "在屋顶下添加楼层" +msgid "editor.buildPanel.wallTypeEditorDialog.finish" +msgstr "饰面" -# Source-Hash: a982ff9b075af829 +# Source-Hash: 23306d290f066b1e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add level above" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framing core" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.addLevelAbove" -msgstr "在上方添加楼层" +msgid "editor.buildPanel.wallTypeEditorDialog.framingCore" +msgstr "龙骨核心层" -# Source-Hash: 0db7d221df08fa6b +# Source-Hash: b50fa488c2bfb502 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add level below" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{fullReason} Remove one to add another." +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.addLevelBelow" -msgstr "在下方添加楼层" +msgid "editor.buildPanel.wallTypeEditorDialog.fullreasonRemoveOneToAddAnother" +msgstr "{fullReason}移除一层后才能再添加。" -# Source-Hash: c0774c185060fc13 +# Source-Hash: e3e25fbbf14e97fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gypsum sheathing" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.cancel" -msgstr "取消" +msgid "editor.buildPanel.wallTypeEditorDialog.gypsumSheathing" +msgstr "石膏覆面板" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 8a7ff5011275abbd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inside" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.delete" -msgstr "删除" +msgid "editor.buildPanel.wallTypeEditorDialog.inside" +msgstr "内侧" -# Source-Hash: 8e29375893d63408 +# Source-Hash: 7d6ed24c02ab0c5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete level" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.deleteLevel" -msgstr "删除楼层" +msgid "editor.buildPanel.wallTypeEditorDialog.insulation" +msgstr "保温层" -# Source-Hash: c3bc69ec52022250 +# Source-Hash: 9a4325140858cfec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Are you sure you want to delete {levelName}? All walls, floors, and objects on this level will be permanently removed." -#: packages/editor/src/components/ui/floating-level-selector.tsx -#, fuzzy -msgid "editor.floatingLevelSelector.deleteLevelConfirm" -msgstr "确定要删除{levelName}吗?此楼层上的所有墙体、楼板和对象都将被永久移除。" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lap siding" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx +#, fuzzy +msgid "editor.buildPanel.wallTypeEditorDialog.lapSiding" +msgstr "搭接壁板" -# Source-Hash: 5b2826ddac95cd0c +# Source-Hash: d7ee1cefa20d0e32 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag to reorder" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layer" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.dragToReorder" -msgstr "拖动以重新排序" +msgid "editor.buildPanel.wallTypeEditorDialog.layer" +msgstr "构造层" -# Source-Hash: 933177338f5a03ed +# Source-Hash: bd00fff893ace820 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate level" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layer role" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.duplicateLevel" -msgstr "复制楼层" +msgid "editor.buildPanel.wallTypeEditorDialog.layerRole" +msgstr "层功能" -# Source-Hash: 9614c6825a7c67bf +# Source-Hash: e5536deeaabfacec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate with options..." -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lining" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.duplicateWithOptions" -msgstr "带选项复制..." +msgid "editor.buildPanel.wallTypeEditorDialog.lining" +msgstr "衬层" -# Source-Hash: 5ec91bb339806413 +# Source-Hash: 964b86ae1474ff98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Exit unit focus" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Material" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.exitUnitFocus" -msgstr "退出单元聚焦" +msgid "editor.buildPanel.wallTypeEditorDialog.material" +msgstr "材料" -# Source-Hash: a88c3f8bed58b4fa +# Source-Hash: 75d79fb9a2e8fcf6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Focused unit has zones here" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mineral wool board" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.focusedUnitHasZonesHere" -msgstr "聚焦的单元在此有区域" +msgid "editor.buildPanel.wallTypeEditorDialog.mineralWoolBoard" +msgstr "岩棉板" -# Source-Hash: 655055a310fb5d13 +# Source-Hash: 78acc1bad880ce0f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The ground floor stands {distance} over grade. Seat the ground floor 8 in over grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move in" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.groundFloorOverGrade" -msgstr "首层高出地坪 {distance}。将首层设为高出地坪 8 英寸" +msgid "editor.buildPanel.wallTypeEditorDialog.moveIn" +msgstr "向内移动" -# Source-Hash: 77548faae4869eec +# Source-Hash: 2de6ee30b4e608bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The ground floor stands {distance} under grade. Seat the ground floor 8 in over grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move out" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.groundFloorUnderGrade" -msgstr "首层低于地坪 {distance}。将首层设为高出地坪 8 英寸" +msgid "editor.buildPanel.wallTypeEditorDialog.moveOut" +msgstr "向外移动" -# Source-Hash: e3763ae2dc62c03f +# Source-Hash: 6cc5df35f0338e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground line: the levels under it are below grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Name" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.groundLineTheLevelsUnderIt" -msgstr "地坪线:其下方的楼层位于地坪以下" +msgid "editor.buildPanel.wallTypeEditorDialog.name" +msgstr "名称" -# Source-Hash: e12035eb47cc61cc +# Source-Hash: 4b3edeb00b32607e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground · {offset}" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.groundOffset" -msgstr "地坪 · {offset}" +msgid "editor.buildPanel.wallTypeEditorDialog.newWallType" +msgstr "新建墙体类型" -# Source-Hash: 5661c11383217661 +# Source-Hash: 4f7f8af75bf8e914 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Insert level here" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "OSB" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.insertLevelHere" -msgstr "在此插入楼层" +msgid "editor.buildPanel.wallTypeEditorDialog.osb" +msgstr "定向刨花板" -# Source-Hash: 0215b36d5a08597a +# Source-Hash: dc4fe6cb415ed882 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level height" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outside" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.levelHeight" -msgstr "楼层高度" +msgid "editor.buildPanel.wallTypeEditorDialog.outside" +msgstr "外侧" -# Source-Hash: 91af436e81bb0875 +# Source-Hash: a6fd2cbf5c2154e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paste copied selection" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plaster" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.pasteCopiedSelection" -msgstr "粘贴复制的选择" +msgid "editor.buildPanel.wallTypeEditorDialog.plaster" +msgstr "灰泥" -# Source-Hash: 68bc52f53240cbec +# Source-Hash: e669c2c08bd80e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reorder {levelName}" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plywood" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.reorderLevelname" -msgstr "重新排序{levelName}" +msgid "editor.buildPanel.wallTypeEditorDialog.plywood" +msgstr "胶合板" -# Source-Hash: 625d53de72ebc2ef +# Source-Hash: ca36e9fd7fba1fce # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Seat the building so this floor stands at grade; the floors under it are below grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove layer" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.seatTheBuildingSoThisFloor" -msgstr "调整建筑使此层位于地坪;其下方各层位于地坪以下" +msgid "editor.buildPanel.wallTypeEditorDialog.removeLayer" +msgstr "移除构造层" -# Source-Hash: 7ac9c00895c30d76 +# Source-Hash: 7d8f351c35f89b94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set as ground floor" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rigid foam" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.setAsGroundFloor" -msgstr "设为首层" +msgid "editor.buildPanel.wallTypeEditorDialog.rigidFoam" +msgstr "硬质泡沫板" -# Source-Hash: d6b381247066a7aa +# Source-Hash: e8bc984965d5753d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The ground level cannot be deleted" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Save wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.theGroundLevelCannotBeDeleted" -msgstr "无法删除首层楼层" +msgid "editor.buildPanel.wallTypeEditorDialog.saveWallType" +msgstr "保存墙体类型" -# Source-Hash: b1122051dce0d7a1 +# Source-Hash: 36a588e44085108c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "This floor stands at grade" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sheathing" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.thisFloorStandsAtGrade" -msgstr "此层位于地坪" +msgid "editor.buildPanel.wallTypeEditorDialog.sheathing" +msgstr "覆面板" -# Source-Hash: 062cc0f1afef0c52 +# Source-Hash: 9450fcb4a14674af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unit" -#: packages/editor/src/components/ui/floating-level-selector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stone veneer" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floatingLevelSelector.unit" -msgstr "单元" +msgid "editor.buildPanel.wallTypeEditorDialog.stoneVeneer" +msgstr "石材饰面" -# Source-Hash: 5871b7c20478f4a1 +# Source-Hash: 687cf7bc64b0224e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor area" -#: packages/editor/src/i18n/floor-footprint-name.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stucco" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floorFootprint.area" -msgstr "楼面区域" +msgid "editor.buildPanel.wallTypeEditorDialog.stucco" +msgstr "灰泥饰面" -# Source-Hash: 8b2e1435272aa86a +# Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{room} floor" -#: packages/editor/src/i18n/floor-footprint-name.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floorFootprint.room" -msgstr "{room}楼板" +msgid "editor.buildPanel.wallTypeEditorDialog.thickness" +msgstr "厚度" -# Source-Hash: 4731183fec06cbdf +# Source-Hash: 72e31eecaeb87447 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shared floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx -#: packages/editor/src/i18n/floor-footprint-name.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Total {thickness}" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.floorFootprint.shared" -msgstr "共用楼板" +msgid "editor.buildPanel.wallTypeEditorDialog.totalThickness" +msgstr "总计 {thickness}" -# Source-Hash: c0774c185060fc13 +# Source-Hash: eab795728c4a3f5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/helpers/building-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall type" +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "editor.helpers.buildingHelper.cancel" -msgstr "取消" +msgid "editor.buildPanel.wallTypeEditorDialog.wallType" +msgstr "墙体类型" -# Source-Hash: 4c6ca3441c74da9e +# Source-Hash: 3744d42a0e4ee161 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place building" -#: packages/editor/src/components/ui/helpers/building-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plain wall" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "editor.helpers.buildingHelper.placeBuilding" -msgstr "放置建筑" +msgid "editor.buildPanel.wallTypes.plainWall" +msgstr "普通墙体" -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: 1f3650da23603008 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" -#: packages/editor/src/components/ui/helpers/building-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera controls hint" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.buildingHelper.rotate" -msgstr "旋转" +msgid "editor.cameraControlsHint" +msgstr "相机操作提示" -# Source-Hash: 832470d3aeee82fd +# Source-Hash: 101b6a54c377049a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel placement" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pan" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.cancelPlacement" -msgstr "取消放置" +msgid "editor.cameraHint.pan" +msgstr "平移" -# Source-Hash: e374fcaee33c3e2c +# Source-Hash: 306d409f8a1cf480 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuation — click or press C to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.continuationClickOrPressCTo" -msgstr "连续放置 — 点击或按 C 切换" +msgid "editor.cameraHint.rotate" +msgstr "旋转" -# Source-Hash: b108c7dc2ec2b9de +# Source-Hash: 663cecc316eb91b8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuation: {label}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zoom" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.continuationLabel" -msgstr "连续放置:{label}" +msgid "editor.cameraHint.zoom" +msgstr "缩放" -# Source-Hash: 729d87891cb7dbb1 +# Source-Hash: 34b7ca7ff46c44a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag to draw fence" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label}: {finish}" +#: packages/editor/src/components/ui/controls/finish-swatch.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.dragToDrawFence" -msgstr "拖动绘制围栏" +msgid "editor.controls.finishSwatch.ariaLabel" +msgstr "{label}:{finish}" -# Source-Hash: b52e874718af1916 +# Source-Hash: 4ca0e0e73229540c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Erase: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default" +#: packages/editor/src/components/ui/controls/finish-swatch.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.eraseScope" -msgstr "擦除:{scope}" +msgid "editor.controls.finishSwatch.default" +msgstr "默认" -# Source-Hash: 61f7494abc319e66 +# Source-Hash: a2bd204e93e90598 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Erase scope — click or press Shift to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dismiss" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.eraseScopeClickOrPressShift" -msgstr "擦除范围 — 点击或按 Shift 切换" +msgid "editor.dismiss" +msgstr "关闭" -# Source-Hash: 59993c163d68cc53 +# Source-Hash: 9222f970dce6cc60 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Erase scope: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dismiss camera controls hint" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.eraseScopeLabel" -msgstr "擦除范围:{scope}" +msgid "editor.dismissCameraControlsHint" +msgstr "关闭相机操作提示" -# Source-Hash: a4bdcbc6cab772bf +# Source-Hash: aeac665749d3101d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fence type — click or press T to switch between straight, curved and freehand" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Expand sidebar" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.fenceTypeClickOrPressT" -msgstr "围栏类型 — 点击或按 T 在直线、曲线和手绘之间切换" +msgid "editor.expandSidebar" +msgstr "展开侧边栏" -# Source-Hash: 2a9ed258727078ac +# Source-Hash: dd86efcab72fc5c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fewer shortcuts" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Axis" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.fewerShortcuts" -msgstr "收起快捷键" +msgid "editor.floatingActionMenu.axis" +msgstr "轴" -# Source-Hash: 698fa6e78af4d4b7 +# Source-Hash: 5232a826549f915e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish curve (or double-click)" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "⌥ axis" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.finishCurveOrDoubleClick" -msgstr "完成曲线(或双击)" +msgid "editor.floatingActionMenu.axis2" +msgstr "⌥ 轴" -# Source-Hash: 09f6d79edf5cfd16 +# Source-Hash: 7001600001844c92 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid: {length}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "⚠ no equipment" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.gridLength" -msgstr "网格:{length}" +msgid "editor.floatingActionMenu.noEquipment" +msgstr "⚠ 无设备" -# Source-Hash: c493b562040c4328 +# Source-Hash: eae0194029f96edb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid step — click or tap Ctrl to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# register} other {# registers}}" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.gridStepClickOrTapCtrl" -msgstr "网格步长 — 点击或轻按 Ctrl 切换" +msgid "editor.floatingActionMenu.registerCount" +msgstr "{count, plural, other {# 个风口}}" -# Source-Hash: d36a8c93d81b3a36 +# Source-Hash: 8fb180251a321cef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid step: {length}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.gridStepLength" -msgstr "网格步长:{length}" +msgid "editor.floatingActionMenu.rTRotate" +msgstr "R/T 旋转" -# Source-Hash: abea993ede7daa7e +# Source-Hash: 6fb660d4eabe8d6a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a painted surface to erase" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {{number} run} other {{number} runs}}" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.hoverAPaintedSurfaceToErase" -msgstr "悬停在已涂装的表面上以擦除" +msgid "editor.floatingActionMenu.runCount" +msgstr "{count, plural, other {{number} 段}}" -# Source-Hash: fc1ed0ddc0cfcef5 +# Source-Hash: 88e6c2e1c344b2fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a surface to paint" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System" +#: packages/editor/src/components/editor/floating-action-menu.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.hoverASurfaceToPaint" -msgstr "悬停在表面上以涂装" +msgid "editor.floatingActionMenu.system" +msgstr "系统" -# Source-Hash: 63dec5de4a337015 +# Source-Hash: f0e76aea883d4e48 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a surface to pick its material" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add a floor under the roof" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.hoverASurfaceToPickIts" -msgstr "悬停在表面上以拾取其材质" +msgid "editor.floatingLevelSelector.addAFloorUnderTheRoof" +msgstr "在屋顶下添加楼层" -# Source-Hash: 7ad6dc1b1f03f970 +# Source-Hash: a982ff9b075af829 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "More shortcuts" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add level above" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.moreShortcuts" -msgstr "更多快捷键" +msgid "editor.floatingLevelSelector.addLevelAbove" +msgstr "在上方添加楼层" -# Source-Hash: 476b8f5f9ee542e6 +# Source-Hash: 0db7d221df08fa6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add level below" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.paintScope" -msgstr "涂装:{scope}" +msgid "editor.floatingLevelSelector.addLevelBelow" +msgstr "在下方添加楼层" -# Source-Hash: 9c09ce4c34122277 +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint scope — click or press Shift to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.paintScopeClickOrPressShift" -msgstr "涂装范围 — 点击或按 Shift 切换" +msgid "editor.floatingLevelSelector.cancel" +msgstr "取消" -# Source-Hash: 7890aa81687f6654 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint scope: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.paintScopeLabel" -msgstr "涂装范围:{scope}" +msgid "editor.floatingLevelSelector.delete" +msgstr "删除" -# Source-Hash: a75b3abc0784b12b +# Source-Hash: 8e29375893d63408 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick: {scope}" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete level" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.pickScope" -msgstr "拾取:{scope}" +msgid "editor.floatingLevelSelector.deleteLevel" +msgstr "删除楼层" -# Source-Hash: 69c1044e6ea87ccf +# Source-Hash: c3bc69ec52022250 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place gate on a fence" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Are you sure you want to delete {levelName}? All walls, floors, and objects on this level will be permanently removed." +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.placeGateOnAFence" -msgstr "在围栏上放置大门" - -# Source-Hash: 3754255b8affc7a0 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place passage on a fence" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx -#, fuzzy -msgid "editor.helpers.contextualHelperPanel.placePassageOnAFence" -msgstr "在围栏上放置通道" +msgid "editor.floatingLevelSelector.deleteLevelConfirm" +msgstr "确定要删除{levelName}吗?此楼层上的所有墙体、楼板和对象都将被永久移除。" -# Source-Hash: a8328c8964e947fa +# Source-Hash: 5b2826ddac95cd0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select a material to paint" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag to reorder" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.selectAMaterialToPaint" -msgstr "选择要涂装的材质" +msgid "editor.floatingLevelSelector.dragToReorder" +msgstr "拖动以重新排序" -# Source-Hash: 6f95d7116aea5738 +# Source-Hash: 933177338f5a03ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping: Angles" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate level" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingAngles" -msgstr "吸附:角度" +msgid "editor.floatingLevelSelector.duplicateLevel" +msgstr "复制楼层" -# Source-Hash: 2d6d8d85d2ebed47 +# Source-Hash: 9614c6825a7c67bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping: Grid" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate with options..." +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingGrid" -msgstr "吸附:网格" +msgid "editor.floatingLevelSelector.duplicateWithOptions" +msgstr "带选项复制..." -# Source-Hash: 9096c5f9d8ce0f7c +# Source-Hash: 5ec91bb339806413 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping: Lines" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Exit unit focus" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingLines" -msgstr "吸附:线条" +msgid "editor.floatingLevelSelector.exitUnitFocus" +msgstr "退出单元聚焦" -# Source-Hash: b663afbf0835cf32 +# Source-Hash: a88c3f8bed58b4fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping mode — click or press Shift to cycle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Focused unit has zones here" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingModeClickOrPressShift" -msgstr "吸附模式 — 点击或按 Shift 切换" +msgid "editor.floatingLevelSelector.focusedUnitHasZonesHere" +msgstr "聚焦的单元在此有区域" -# Source-Hash: d00e984fc88f71aa +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The ground floor stands {distance} over grade. Seat the ground floor 8 in over grade" +# Source-Hash: 6a00e82fda812178 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapping: Off" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.snappingOff" -msgstr "吸附:关" +msgid "editor.floatingLevelSelector.groundFloorOverGrade" +msgstr "首层高出地坪 {distance}。{action}" -# Source-Hash: 6be9d0d312200761 +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The ground floor stands {distance} under grade. Seat the ground floor 8 in over grade" +# Source-Hash: 61f400e77494df9b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight continuation is unavailable for curved or freehand fences" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.straightContinuationIsUnavailableForCurved" -msgstr "曲线或手绘围栏无法直线连续" +msgid "editor.floatingLevelSelector.groundFloorUnderGrade" +msgstr "首层低于地坪 {distance}。{action}" -# Source-Hash: 0d56b1f0a0493302 +# Source-Hash: e3763ae2dc62c03f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight: Continuous" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground line: the levels under it are below grade" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.straightContinuous" -msgstr "直线:连续" +msgid "editor.floatingLevelSelector.groundLineTheLevelsUnderIt" +msgstr "地坪线:其下方的楼层位于地坪以下" -# Source-Hash: c034e85d3e7fd27e +# Source-Hash: e12035eb47cc61cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight fence continuation — click or press C to toggle" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground · {offset}" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.straightFenceContinuationClickOrPress" -msgstr "直线围栏连续 — 点击或按 C 切换" +msgid "editor.floatingLevelSelector.groundOffset" +msgstr "地坪 · {offset}" -# Source-Hash: e3f679cdb4a3d603 +# Source-Hash: 5661c11383217661 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight: Single" -#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insert level here" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.contextualHelperPanel.straightSingle" -msgstr "直线:单段" +msgid "editor.floatingLevelSelector.insertLevelHere" +msgstr "在此插入楼层" -# Source-Hash: 9a56d90d461b4bca +# Source-Hash: 0215b36d5a08597a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add point" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level height" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.addPoint" -msgstr "添加点" +msgid "editor.floatingLevelSelector.levelHeight" +msgstr "楼层高度" -# Source-Hash: c3dc3918c823a5e6 +# Source-Hash: 91af436e81bb0875 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add point · click the first to close" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paste copied selection" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.addPointClickTheFirstTo" -msgstr "添加点 · 点击第一个点闭合" +msgid "editor.floatingLevelSelector.pasteCopiedSelection" +msgstr "粘贴复制的选择" -# Source-Hash: d8cf72d482d56cd7 +# Source-Hash: 68bc52f53240cbec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Brush size" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reorder {levelName}" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.brushSize" -msgstr "笔刷大小" +msgid "editor.floatingLevelSelector.reorderLevelname" +msgstr "重新排序{levelName}" -# Source-Hash: c0774c185060fc13 +# Source-Hash: 625d53de72ebc2ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Seat the building so this floor stands at grade; the floors under it are below grade" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.cancel" -msgstr "取消" +msgid "editor.floatingLevelSelector.seatTheBuildingSoThisFloor" +msgstr "调整建筑使此层位于地坪;其下方各层位于地坪以下" -# Source-Hash: 104fdab7934ec66c +# Source-Hash: 7ac9c00895c30d76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel picking" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set as ground floor" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.cancelPicking" -msgstr "取消拾取" +msgid "editor.floatingLevelSelector.setAsGroundFloor" +msgstr "设为首层" -# Source-Hash: c318cf0ce70b8977 +# Source-Hash: d6b381247066a7aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel stroke" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The ground level cannot be deleted" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.cancelStroke" -msgstr "取消笔画" +msgid "editor.floatingLevelSelector.theGroundLevelCannotBeDeleted" +msgstr "无法删除首层楼层" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: b1122051dce0d7a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This floor stands at grade" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.done" -msgstr "完成" +msgid "editor.floatingLevelSelector.thisFloorStandsAtGrade" +msgstr "此层位于地坪" -# Source-Hash: e297db9ca0ce6d31 +# Source-Hash: 062cc0f1afef0c52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw the mezzanine" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unit" +#: packages/editor/src/components/ui/floating-level-selector.tsx #, fuzzy -msgid "editor.helpers.helperManager.drawTheMezzanine" -msgstr "绘制夹层" +msgid "editor.floatingLevelSelector.unit" +msgstr "单元" -# Source-Hash: c8be604718a7a9fd +# Source-Hash: 5871b7c20478f4a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw the opening" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor area" +#: packages/editor/src/i18n/floor-footprint-name.ts #, fuzzy -msgid "editor.helpers.helperManager.drawTheOpening" -msgstr "绘制开口" +msgid "editor.floorFootprint.area" +msgstr "楼面区域" -# Source-Hash: 231386ae6d534163 +# Source-Hash: 8b2e1435272aa86a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw the terrace" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{room} floor" +#: packages/editor/src/i18n/floor-footprint-name.ts #, fuzzy -msgid "editor.helpers.helperManager.drawTheTerrace" -msgstr "绘制露台" +msgid "editor.floorFootprint.room" +msgstr "{room}楼板" -# Source-Hash: e092e803eb60af69 +# Source-Hash: 4731183fec06cbdf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Exit smart measure" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shared floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +#: packages/editor/src/i18n/floor-footprint-name.ts #, fuzzy -msgid "editor.helpers.helperManager.exitSmartMeasure" -msgstr "退出智能测量" +msgid "editor.floorFootprint.shared" +msgstr "共用楼板" -# Source-Hash: b3907da0ad234f10 +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/helpers/building-helper.tsx #, fuzzy -msgid "editor.helpers.helperManager.finish" -msgstr "完成" +msgid "editor.helpers.buildingHelper.cancel" +msgstr "取消" -# Source-Hash: f74bd937ae2e3a40 +# Source-Hash: 4c6ca3441c74da9e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish at the edge" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place building" +#: packages/editor/src/components/ui/helpers/building-helper.tsx #, fuzzy -msgid "editor.helpers.helperManager.finishAtTheEdge" -msgstr "在边缘处完成" +msgid "editor.helpers.buildingHelper.placeBuilding" +msgstr "放置建筑" -# Source-Hash: 21029cf1c45697cc +# Source-Hash: 306d409f8a1cf480 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Free move" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/editor/src/components/ui/helpers/building-helper.tsx #, fuzzy -msgid "editor.helpers.helperManager.freeMove" -msgstr "自由移动" +msgid "editor.helpers.buildingHelper.rotate" +msgstr "旋转" -# Source-Hash: 3247d8689bed6ff6 +# Source-Hash: 832470d3aeee82fd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Free move · slide doors and windows" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel placement" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.freeMoveSlideDoorsAndWindows" -msgstr "自由移动 · 滑动门窗" +msgid "editor.helpers.contextualHelperPanel.cancelPlacement" +msgstr "取消放置" -# Source-Hash: b5ad765b43e75a5c +# Source-Hash: e374fcaee33c3e2c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hold to pick a material" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuation — click or press C to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.holdToPickAMaterial" -msgstr "按住以拾取材质" +msgid "editor.helpers.contextualHelperPanel.continuationClickOrPressCTo" +msgstr "连续放置 — 点击或按 C 切换" -# Source-Hash: 46b53c5449c98964 +# Source-Hash: b108c7dc2ec2b9de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inspect surface dimensions" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuation: {label}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.inspectSurfaceDimensions" -msgstr "查看表面尺寸" +msgid "editor.helpers.contextualHelperPanel.continuationLabel" +msgstr "连续放置:{label}" -# Source-Hash: 63f1f7006ae14177 +# Source-Hash: 729d87891cb7dbb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint with this material" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag to draw fence" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.paintWithThisMaterial" -msgstr "使用此材质涂装" +msgid "editor.helpers.contextualHelperPanel.dragToDrawFence" +msgstr "拖动绘制围栏" -# Source-Hash: 188f55cc5afbe34f +# Source-Hash: b52e874718af1916 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick target height" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Erase: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.pickTargetHeight" -msgstr "拾取目标高度" +msgid "editor.helpers.contextualHelperPanel.eraseScope" +msgstr "擦除:{scope}" -# Source-Hash: 2880fc9752eababa +# Source-Hash: 61f7494abc319e66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pin measurement lens" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Erase scope — click or press Shift to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.pinMeasurementLens" -msgstr "固定测量放大镜" +msgid "editor.helpers.contextualHelperPanel.eraseScopeClickOrPressShift" +msgstr "擦除范围 — 点击或按 Shift 切换" -# Source-Hash: 722741535b346e09 +# Source-Hash: 59993c163d68cc53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Erase scope: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.place" -msgstr "放置" +msgid "editor.helpers.contextualHelperPanel.eraseScopeLabel" +msgstr "擦除范围:{scope}" -# Source-Hash: 82010a7fd6350c93 +# Source-Hash: a4bdcbc6cab772bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place inside the room" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fence type — click or press T to switch between straight, curved and freehand" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.placeInsideTheRoom" -msgstr "放置在房间内" +msgid "editor.helpers.contextualHelperPanel.fenceTypeClickOrPressT" +msgstr "围栏类型 — 点击或按 T 在直线、曲线和手绘之间切换" -# Source-Hash: 8b97f4503edb27b9 +# Source-Hash: 2a9ed258727078ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Press anywhere, drag to the opposite corner" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fewer shortcuts" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.pressAnywhereDragToTheOpposite" -msgstr "在任意位置按下,拖到对角" +msgid "editor.helpers.contextualHelperPanel.fewerShortcuts" +msgstr "收起快捷键" -# Source-Hash: 786f0b1c81b2a6c0 +# Source-Hash: 698fa6e78af4d4b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raise or lower" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish curve (or double-click)" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.raiseOrLower" -msgstr "升高或降低" +msgid "editor.helpers.contextualHelperPanel.finishCurveOrDoubleClick" +msgstr "完成曲线(或双击)" -# Source-Hash: b033f46ae3a0cbb7 +# Source-Hash: 09f6d79edf5cfd16 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove a painted part, or reset a surface" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid: {length}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.removeAPaintedPartOrReset" -msgstr "移除涂装部分或重置表面" +msgid "editor.helpers.contextualHelperPanel.gridLength" +msgstr "网格:{length}" -# Source-Hash: 0dc6d121791696f7 +# Source-Hash: c493b562040c4328 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove last point" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid step — click or tap Ctrl to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.removeLastPoint" -msgstr "移除最后一个点" +msgid "editor.helpers.contextualHelperPanel.gridStepClickOrTapCtrl" +msgstr "网格步长 — 点击或轻按 Ctrl 切换" -# Source-Hash: f85bdac0a1d16603 +# Source-Hash: d36a8c93d81b3a36 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Resize" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid step: {length}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.resize" -msgstr "调整大小" +msgid "editor.helpers.contextualHelperPanel.gridStepLength" +msgstr "网格步长:{length}" -# Source-Hash: 8a665ecaeffa9308 +# Source-Hash: abea993ede7daa7e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ±45°" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a painted surface to erase" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.rotate45" -msgstr "旋转 ±45°" +msgid "editor.helpers.contextualHelperPanel.hoverAPaintedSurfaceToErase" +msgstr "悬停在已涂装的表面上以擦除" -# Source-Hash: 6099ee99f8c38700 +# Source-Hash: fc1ed0ddc0cfcef5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate the selection ±45°" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a surface to paint" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.rotateTheSelection45" -msgstr "将所选旋转 ±45°" +msgid "editor.helpers.contextualHelperPanel.hoverASurfaceToPaint" +msgstr "悬停在表面上以涂装" -# Source-Hash: c93ae898b4d59f6f +# Source-Hash: 63dec5de4a337015 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set one corner, then the opposite" -#: packages/editor/src/components/ui/helpers/helper-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a surface to pick its material" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.helperManager.setOneCornerThenTheOpposite" -msgstr "设置一个角,再设置对角" +msgid "editor.helpers.contextualHelperPanel.hoverASurfaceToPickIts" +msgstr "悬停在表面上以拾取其材质" -# Source-Hash: c0774c185060fc13 +# Source-Hash: 7ad6dc1b1f03f970 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/helpers/item-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "More shortcuts" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.itemHelper.cancel" -msgstr "取消" +msgid "editor.helpers.contextualHelperPanel.moreShortcuts" +msgstr "更多快捷键" -# Source-Hash: ed7f3d8417a3e074 +# Source-Hash: 476b8f5f9ee542e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Force place" -#: packages/editor/src/components/ui/helpers/item-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.itemHelper.forcePlace" -msgstr "强制放置" +msgid "editor.helpers.contextualHelperPanel.paintScope" +msgstr "涂装:{scope}" -# Source-Hash: 722741535b346e09 +# Source-Hash: 9c09ce4c34122277 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place" -#: packages/editor/src/components/ui/helpers/item-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint scope — click or press Shift to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.itemHelper.place" -msgstr "放置" +msgid "editor.helpers.contextualHelperPanel.paintScopeClickOrPressShift" +msgstr "涂装范围 — 点击或按 Shift 切换" -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: 7890aa81687f6654 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" -#: packages/editor/src/components/ui/helpers/item-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint scope: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.itemHelper.rotate" -msgstr "旋转" +msgid "editor.helpers.contextualHelperPanel.paintScopeLabel" +msgstr "涂装范围:{scope}" -# Source-Hash: e9dfc2a178bca5f7 +# Source-Hash: a75b3abc0784b12b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guided constraints bypassed" -#: packages/editor/src/components/ui/helpers/registered-tool-helper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick: {scope}" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.helpers.registeredToolHelper.guidedConstraintsBypassed" -msgstr "已绕过引导约束" +msgid "editor.helpers.contextualHelperPanel.pickScope" +msgstr "拾取:{scope}" -# Source-Hash: c69865ec5d9d1ac9 +# Source-Hash: 69c1044e6ea87ccf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Angle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place gate on a fence" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.angle.g10zaw" -msgstr "角度" +msgid "editor.helpers.contextualHelperPanel.placeGateOnAFence" +msgstr "在围栏上放置大门" -# Source-Hash: 9c562983f6fed685 +# Source-Hash: 3754255b8affc7a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arm length m" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place passage on a fence" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.armLengthM.1jclqgw" -msgstr "臂长 m" +msgid "editor.helpers.contextualHelperPanel.placePassageOnAFence" +msgstr "在围栏上放置通道" -# Source-Hash: 38461bc364321749 +# Source-Hash: a8328c8964e947fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Attachment side" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select a material to paint" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.attachmentSide.6n9s5v" -msgstr "连接侧" +msgid "editor.helpers.contextualHelperPanel.selectAMaterialToPaint" +msgstr "选择要涂装的材质" -# Source-Hash: 441124187e7da2fc +# Source-Hash: 6f95d7116aea5738 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping: Angles" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.autoHangers.10554ka" -msgstr "自动吊架" +msgid "editor.helpers.contextualHelperPanel.snappingAngles" +msgstr "吸附:角度" -# Source-Hash: e20033e4b0045f1c +# Source-Hash: 2d6d8d85d2ebed47 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto miter corners" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping: Grid" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.autoMiterCorners.zxr5lt" -msgstr "自动斜接转角" +msgid "editor.helpers.contextualHelperPanel.snappingGrid" +msgstr "吸附:网格" -# Source-Hash: 92f3a8b63963daeb +# Source-Hash: 9096c5f9d8ce0f7c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto span" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping: Lines" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.autoSpan.1gas9r6" -msgstr "自动跨度" +msgid "editor.helpers.contextualHelperPanel.snappingLines" +msgstr "吸附:线条" -# Source-Hash: 8b2dfb9b9137fda0 +# Source-Hash: b663afbf0835cf32 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back ratio" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping mode — click or press Shift to cycle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.backRatio.1ughd99" -msgstr "后部比例" +msgid "editor.helpers.contextualHelperPanel.snappingModeClickOrPressShift" +msgstr "吸附模式 — 点击或按 Shift 切换" -# Source-Hash: 75dfae8d9f03fa0e +# Source-Hash: d00e984fc88f71aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapping: Off" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.baseHeight.1hs4zdf" -msgstr "底座高度" +msgid "editor.helpers.contextualHelperPanel.snappingOff" +msgstr "吸附:关" -# Source-Hash: 1cc2da12e8463e85 +# Source-Hash: 6be9d0d312200761 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base style" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight continuation is unavailable for curved or freehand fences" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.baseStyle.24vty5" -msgstr "底座样式" +msgid "editor.helpers.contextualHelperPanel.straightContinuationIsUnavailableForCurved" +msgstr "曲线或手绘围栏无法直线连续" -# Source-Hash: f9d95c6df06b6223 +# Source-Hash: 0d56b1f0a0493302 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Beam height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight: Continuous" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.beamHeight.1kq0oh1" -msgstr "梁高" +msgid "editor.helpers.contextualHelperPanel.straightContinuous" +msgstr "直线:连续" -# Source-Hash: a133f8d23b1274dc +# Source-Hash: c034e85d3e7fd27e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Beam width" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight fence continuation — click or press C to toggle" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.beamWidth.1q1mzbe" -msgstr "梁宽" +msgid "editor.helpers.contextualHelperPanel.straightFenceContinuationClickOrPress" +msgstr "直线围栏连续 — 点击或按 C 切换" -# Source-Hash: b98c0d0189526335 +# Source-Hash: e3f679cdb4a3d603 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Body shape" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight: Single" +#: packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx #, fuzzy -msgid "editor.inspector.field.bodyShape.arvkuw" -msgstr "主体形状" +msgid "editor.helpers.contextualHelperPanel.straightSingle" +msgstr "直线:单段" -# Source-Hash: 2251ecab18467631 +# Source-Hash: 9a56d90d461b4bca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bracket style" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add point" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.bracketStyle.1vvoptm" -msgstr "支架样式" +msgid "editor.helpers.helperManager.addPoint" +msgstr "添加点" -# Source-Hash: 5e9d4a4fcea481ca +# Source-Hash: c3dc3918c823a5e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Branch angle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add point · click the first to close" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.branchAngle.v56zme" -msgstr "分支角度" +msgid "editor.helpers.helperManager.addPointClickTheFirstTo" +msgstr "添加点 · 点击第一个点闭合" -# Source-Hash: dec709f1f9c714ee +# Source-Hash: d8cf72d482d56cd7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cab height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brush size" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cabHeight.1yn34mk" -msgstr "轿厢高度" +msgid "editor.helpers.helperManager.brushSize" +msgstr "笔刷大小" -# Source-Hash: 87863f8366e1c88a +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Canopy form" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.canopyForm.1czzggp" -msgstr "雨棚形式" +msgid "editor.helpers.helperManager.cancel" +msgstr "取消" -# Source-Hash: d52b53241789ee63 +# Source-Hash: 104fdab7934ec66c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel picking" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cap.s0thej" -msgstr "顶盖" +msgid "editor.helpers.helperManager.cancelPicking" +msgstr "取消拾取" -# Source-Hash: 2f2e49598ec8188e +# Source-Hash: c318cf0ce70b8977 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap overhang" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel stroke" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.capOverhang.kxxz9j" -msgstr "顶盖出挑" +msgid "editor.helpers.helperManager.cancelStroke" +msgstr "取消笔画" -# Source-Hash: 8523c086e95b83e2 +# Source-Hash: 16552c2580bbe8b8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap shape" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.capShape.17mbxhu" -msgstr "顶盖形状" +msgid "editor.helpers.helperManager.done" +msgstr "完成" -# Source-Hash: acd98600a518dd95 +# Source-Hash: e297db9ca0ce6d31 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap thickness" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw the mezzanine" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.capThickness.u835q9" -msgstr "顶盖厚度" +msgid "editor.helpers.helperManager.drawTheMezzanine" +msgstr "绘制夹层" -# Source-Hash: 7af3b69b4b5aeb19 +# Source-Hash: c8be604718a7a9fd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Carcass height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw the opening" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.carcassHeight.1aks0zy" -msgstr "柜体高度" +msgid "editor.helpers.helperManager.drawTheOpening" +msgstr "绘制开口" -# Source-Hash: 827709caa79db37f +# Source-Hash: 231386ae6d534163 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cleanout style" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw the terrace" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cleanoutStyle.127zz6z" -msgstr "清扫口样式" +msgid "editor.helpers.helperManager.drawTheTerrace" +msgstr "绘制露台" -# Source-Hash: a549dc98e2a1bd07 +# Source-Hash: e092e803eb60af69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar diameter" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Exit smart measure" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.collarDiameter.1d5k28r" -msgstr "套环直径" +msgid "editor.helpers.helperManager.exitSmartMeasure" +msgstr "退出智能测量" -# Source-Hash: aa0232fc6f3eeadc +# Source-Hash: b3907da0ad234f10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.collarHeight.1dqwsrf" -msgstr "套环高度" +msgid "editor.helpers.helperManager.finish" +msgstr "完成" -# Source-Hash: cbd8079c3f540a4c +# Source-Hash: f74bd937ae2e3a40 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar shape" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish at the edge" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.collarShape.1gacv11" -msgstr "套环形状" +msgid "editor.helpers.helperManager.finishAtTheEdge" +msgstr "在边缘处完成" -# Source-Hash: 557cde7f95616454 +# Source-Hash: 21029cf1c45697cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar width" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free move" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.collarWidth.qvc9ik" -msgstr "套环宽度" +msgid "editor.helpers.helperManager.freeMove" +msgstr "自由移动" -# Source-Hash: 30edd1c180aac9b4 +# Source-Hash: 3247d8689bed6ff6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Columns" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free move · slide doors and windows" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.columns.1sy73ks" -msgstr "列" +msgid "editor.helpers.helperManager.freeMoveSlideDoorsAndWindows" +msgstr "自由移动 · 滑动门窗" -# Source-Hash: cd5b2f70924b7c2d +# Source-Hash: b5ad765b43e75a5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Conical full circle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hold to pick a material" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.conicalFullCircle.1pgkpz5" -msgstr "锥形整圆" +msgid "editor.helpers.helperManager.holdToPickAMaterial" +msgstr "按住以拾取材质" -# Source-Hash: dc90f3abb935e7e2 +# Source-Hash: 46b53c5449c98964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connection mode" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inspect surface dimensions" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.connectionMode.1nty478" -msgstr "连接方式" +msgid "editor.helpers.helperManager.inspectSurfaceDimensions" +msgstr "查看表面尺寸" -# Source-Hash: 1a9a49d7135d4f15 +# Source-Hash: 63f1f7006ae14177 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connection offset" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint with this material" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.connectionOffset.2m70s8" -msgstr "连接偏移" +msgid "editor.helpers.helperManager.paintWithThisMaterial" +msgstr "使用此材质涂装" -# Source-Hash: 69be301fcb8030e2 +# Source-Hash: 188f55cc5afbe34f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner bevel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick target height" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cornerBevel.16iniho" -msgstr "转角倒角" +msgid "editor.helpers.helperManager.pickTargetHeight" +msgstr "拾取目标高度" -# Source-Hash: b997a96a9dc7e450 +# Source-Hash: 2880fc9752eababa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Covering type" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pin measurement lens" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.coveringType.95yd3k" -msgstr "覆盖层类型" +msgid "editor.helpers.helperManager.pinMeasurementLens" +msgstr "固定测量放大镜" -# Source-Hash: 03b33160d8baa966 +# Source-Hash: 722741535b346e09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cricketHeight.pok31n" -msgstr "泛水坡高度" +msgid "editor.helpers.helperManager.place" +msgstr "放置" -# Source-Hash: 21552eee05ccb5d6 +# Source-Hash: 82010a7fd6350c93 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket length" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place inside the room" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cricketLength.i2aht8" -msgstr "泛水坡长度" +msgid "editor.helpers.helperManager.placeInsideTheRoom" +msgstr "放置在房间内" -# Source-Hash: c13b707bfdeac855 +# Source-Hash: 8b97f4503edb27b9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket side" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Press anywhere, drag to the opposite corner" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cricketSide.1xnwil7" -msgstr "泛水坡侧" +msgid "editor.helpers.helperManager.pressAnywhereDragToTheOpposite" +msgstr "在任意位置按下,拖到对角" -# Source-Hash: 4ee7089fa1b3e63b +# Source-Hash: 786f0b1c81b2a6c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket style" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raise or lower" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.cricketStyle.10j0lat" -msgstr "泛水坡样式" +msgid "editor.helpers.helperManager.raiseOrLower" +msgstr "升高或降低" -# Source-Hash: b8ff053666ee326b +# Source-Hash: b033f46ae3a0cbb7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curb" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove a painted part, or reset a surface" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.curb.5xi2ol" -msgstr "路缘" +msgid "editor.helpers.helperManager.removeAPaintedPartOrReset" +msgstr "移除涂装部分或重置表面" -# Source-Hash: 8da648df210dbc0d +# Source-Hash: 0dc6d121791696f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curb height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove last point" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.curbHeight.1yn97sg" -msgstr "路缘高度" +msgid "editor.helpers.helperManager.removeLastPoint" +msgstr "移除最后一个点" -# Source-Hash: 0c01b9848f5d9673 +# Source-Hash: f85bdac0a1d16603 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curve offset" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Resize" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.curveOffset.l4xhvr" -msgstr "弧度偏移" +msgid "editor.helpers.helperManager.resize" +msgstr "调整大小" -# Source-Hash: 69179f4caa384585 +# Source-Hash: 8a665ecaeffa9308 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Damper angle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ±45°" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.damperAngle.h5fxn7" -msgstr "风阀角度" +msgid "editor.helpers.helperManager.rotate45" +msgstr "旋转 ±45°" -# Source-Hash: 15cff91231e806a4 +# Source-Hash: 6099ee99f8c38700 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Deck thickness" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate the selection ±45°" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.deckThickness.4jmqze" -msgstr "平台厚度" +msgid "editor.helpers.helperManager.rotateTheSelection45" +msgstr "将所选旋转 ±45°" -# Source-Hash: eff1e7dc0901b9d0 +# Source-Hash: c93ae898b4d59f6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default level id" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set one corner, then the opposite" +#: packages/editor/src/components/ui/helpers/helper-manager.tsx #, fuzzy -msgid "editor.inspector.field.defaultLevelId.xmrjzp" -msgstr "默认楼层 ID" +msgid "editor.helpers.helperManager.setOneCornerThenTheOpposite" +msgstr "设置一个角,再设置对角" -# Source-Hash: 99ac4d03c3061f3a +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/helpers/item-helper.tsx #, fuzzy -msgid "editor.inspector.field.depth.1lu11u2" -msgstr "深度" +msgid "editor.helpers.itemHelper.cancel" +msgstr "取消" -# Source-Hash: 016d8e70618916d4 +# Source-Hash: ed7f3d8417a3e074 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diameter" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Force place" +#: packages/editor/src/components/ui/helpers/item-helper.tsx #, fuzzy -msgid "editor.inspector.field.diameter.s3robe" -msgstr "直径" +msgid "editor.helpers.itemHelper.forcePlace" +msgstr "强制放置" -# Source-Hash: dab4100e83e4e6b3 +# Source-Hash: 722741535b346e09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diameter2" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place" +#: packages/editor/src/components/ui/helpers/item-helper.tsx #, fuzzy -msgid "editor.inspector.field.diameter2.pm6cl4" -msgstr "直径 2" +msgid "editor.helpers.itemHelper.place" +msgstr "放置" -# Source-Hash: 5747145349432396 +# Source-Hash: 306d409f8a1cf480 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door duration ms" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/editor/src/components/ui/helpers/item-helper.tsx #, fuzzy -msgid "editor.inspector.field.doorDurationMs.13nx909" -msgstr "门动作时长 ms" +msgid "editor.helpers.itemHelper.rotate" +msgstr "旋转" -# Source-Hash: 6f4aca26196c221f +# Source-Hash: e9dfc2a178bca5f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door height" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guided constraints bypassed" +#: packages/editor/src/components/ui/helpers/registered-tool-helper.tsx #, fuzzy -msgid "editor.inspector.field.doorHeight.92r9k4" -msgstr "门高" +msgid "editor.helpers.registeredToolHelper.guidedConstraintsBypassed" +msgstr "已绕过引导约束" -# Source-Hash: 990ae81752236e3a +# Source-Hash: c69865ec5d9d1ac9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door panel style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.doorPanelStyle.2qog4q" -msgstr "门板样式" +msgid "editor.inspector.field.angle.g10zaw" +msgstr "角度" -# Source-Hash: c94e002123bb1199 +# Source-Hash: 9c562983f6fed685 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arm length m" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.doorStyle.gerpos" -msgstr "门样式" +msgid "editor.inspector.field.armLengthM.1jclqgw" +msgstr "臂长 m" -# Source-Hash: 91aeb04b0b7b605e +# Source-Hash: 38461bc364321749 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Attachment side" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.doorWidth.sy732l" -msgstr "门宽" +msgid "editor.inspector.field.attachmentSide.6n9s5v" +msgstr "连接侧" -# Source-Hash: baad1238f70f79ea +# Source-Hash: 441124187e7da2fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspout enabled" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.downspoutEnabled.1gn00nv" -msgstr "启用落水管" +msgid "editor.inspector.field.autoHangers.10554ka" +msgstr "自动吊架" -# Source-Hash: e288531858c4c44d +# Source-Hash: e20033e4b0045f1c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspout position" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto miter corners" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.downspoutPosition.fxcsop" -msgstr "落水管位置" +msgid "editor.inspector.field.autoMiterCorners.zxr5lt" +msgstr "自动斜接转角" -# Source-Hash: 861d28317325cf61 +# Source-Hash: 92f3a8b63963daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct material" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto span" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.ductMaterial.i8eonq" -msgstr "风管材料" +msgid "editor.inspector.field.autoSpan.1gas9r6" +msgstr "自动跨度" -# Source-Hash: ad8ab4ae38c3299c +# Source-Hash: 8b2dfb9b9137fda0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch gablet rake" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchGabletRake.6paydp" -msgstr "歇山山花檐口" - -# Source-Hash: 913d25cf2c5ff179 +msgid "editor.inspector.field.backRatio.1ughd99" +msgstr "后部比例" + +# Source-Hash: 75dfae8d9f03fa0e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch hip height ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchHipHeightRatio.1etnwgg" -msgstr "歇山高度比" +msgid "editor.inspector.field.baseHeight.1hs4zdf" +msgstr "底座高度" -# Source-Hash: f4a80233d49f2b20 +# Source-Hash: 1cc2da12e8463e85 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch hip width ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchHipWidthRatio.1dopfvb" -msgstr "歇山宽度比" +msgid "editor.inspector.field.baseStyle.24vty5" +msgstr "底座样式" -# Source-Hash: 92021b0e37f9a25a +# Source-Hash: f9d95c6df06b6223 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch top rake thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchTopRakeThickness.1w9khxt" -msgstr "歇山顶部檐口厚度" +msgid "editor.inspector.field.beamHeight.1kq0oh1" +msgstr "梁高" -# Source-Hash: d0a2ec13d71ce659 +# Source-Hash: a133f8d23b1274dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch waist length ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dutchWaistLengthRatio.agtoxw" -msgstr "歇山腰部长度比" +msgid "editor.inspector.field.beamWidth.1q1mzbe" +msgstr "梁宽" -# Source-Hash: 993396ccca2cd1d5 +# Source-Hash: b98c0d0189526335 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dwell ms" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Body shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.dwellMs.1lkk0o5" -msgstr "停留 ms" +msgid "editor.inspector.field.bodyShape.arvkuw" +msgstr "主体形状" -# Source-Hash: 9cf550eb019bca1b +# Source-Hash: 2251ecab18467631 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edge inset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bracket style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.edgeInset.1obeimx" -msgstr "边缘内缩" +msgid "editor.inspector.field.bracketStyle.1vvoptm" +msgstr "支架样式" -# Source-Hash: 8a3bc5111b9e97f4 +# Source-Hash: 5e9d4a4fcea481ca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Branch angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.elevation.4jbp44" -msgstr "标高" +msgid "editor.inspector.field.branchAngle.v56zme" +msgstr "分支角度" -# Source-Hash: 1fc91958e30dbeaf +# Source-Hash: dec709f1f9c714ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End cap left" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cab height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.endCapLeft.19jel4v" -msgstr "左端盖" +msgid "editor.inspector.field.cabHeight.1yn34mk" +msgstr "轿厢高度" -# Source-Hash: 4c9ae62e0ed70635 +# Source-Hash: 87863f8366e1c88a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End cap right" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Canopy form" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.endCapRight.lhse9c" -msgstr "右端盖" +msgid "editor.inspector.field.canopyForm.1czzggp" +msgstr "雨棚形式" -# Source-Hash: a9cba06250228a55 +# Source-Hash: d52b53241789ee63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End caps" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.endCaps.4fsb5b" -msgstr "端盖" +msgid "editor.inspector.field.cap.s0thej" +msgstr "顶盖" -# Source-Hash: ebad74353b5a7610 +# Source-Hash: 2f2e49598ec8188e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End post" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.endPost.1guwsk0" -msgstr "端柱" +msgid "editor.inspector.field.capOverhang.kxxz9j" +msgstr "顶盖出挑" -# Source-Hash: ecbe36df4238439e +# Source-Hash: 8523c086e95b83e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equipment type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.equipmentType.1mc2ywt" -msgstr "设备类型" +msgid "editor.inspector.field.capShape.17mbxhu" +msgstr "顶盖形状" -# Source-Hash: 66f1018b50c2e426 +# Source-Hash: acd98600a518dd95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fill to floor" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.fillToFloor.1oppnkf" -msgstr "填充至地面" +msgid "editor.inspector.field.capThickness.u835q9" +msgstr "顶盖厚度" -# Source-Hash: 1cfe33235b30b1d8 +# Source-Hash: 7af3b69b4b5aeb19 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finial" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Carcass height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.finial.1ertf4s" -msgstr "尖顶饰" +msgid "editor.inspector.field.carcassHeight.1aks0zy" +msgstr "柜体高度" -# Source-Hash: 28cd69e506709f16 +# Source-Hash: 827709caa79db37f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fitting type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cleanout style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.fittingType.18mz17s" -msgstr "管件类型" +msgid "editor.inspector.field.cleanoutStyle.127zz6z" +msgstr "清扫口样式" -# Source-Hash: 3c1aec5e6fb180cf +# Source-Hash: a549dc98e2a1bd07 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flashing height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flashingHeight.3e8nn6" -msgstr "泛水高度" +msgid "editor.inspector.field.collarDiameter.1d5k28r" +msgstr "套环直径" -# Source-Hash: 327ba762101db94d +# Source-Hash: aa0232fc6f3eeadc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flashing projection" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flashingProjection.hhf0fk" -msgstr "泛水出挑" +msgid "editor.inspector.field.collarHeight.1dqwsrf" +msgstr "套环高度" -# Source-Hash: 9473e2ab53370b40 +# Source-Hash: cbd8079c3f540a4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueCount.j3t2ci" -msgstr "烟道数量" +msgid "editor.inspector.field.collarShape.1gacv11" +msgstr "套环形状" -# Source-Hash: fd0b65425ed3df8b +# Source-Hash: 557cde7f95616454 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueDiameter.cjhubg" -msgstr "烟道直径" +msgid "editor.inspector.field.collarWidth.qvc9ik" +msgstr "套环宽度" -# Source-Hash: 07ebe5e3780c624b +# Source-Hash: 30edd1c180aac9b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Columns" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueHeight.1dhc4y4" -msgstr "烟道高度" +msgid "editor.inspector.field.columns.1sy73ks" +msgstr "列" -# Source-Hash: ff8319792830d591 +# Source-Hash: cd5b2f70924b7c2d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Conical full circle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueShape.1ealiy4" -msgstr "烟道形状" +msgid "editor.inspector.field.conicalFullCircle.1pgkpz5" +msgstr "锥形整圆" -# Source-Hash: 5acf77854a0030ec +# Source-Hash: dc90f3abb935e7e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flue spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connection mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.flueSpacing.exhzco" -msgstr "烟道间距" +msgid "editor.inspector.field.connectionMode.1nty478" +msgstr "连接方式" -# Source-Hash: 0a64209c0edacaa1 +# Source-Hash: 1a9a49d7135d4f15 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Footing style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connection offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.footingStyle.e3btg6" -msgstr "基脚样式" +msgid "editor.inspector.field.connectionOffset.2m70s8" +msgstr "连接偏移" -# Source-Hash: fd413477f1a9e5ed +# Source-Hash: 69be301fcb8030e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner bevel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.frameDepth.1934a5n" -msgstr "框架深度" +msgid "editor.inspector.field.cornerBevel.16iniho" +msgstr "转角倒角" -# Source-Hash: 6aa2318fa815e5f2 +# Source-Hash: b997a96a9dc7e450 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Covering type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.frameThickness.1agxzd8" -msgstr "框架厚度" +msgid "editor.inspector.field.coveringType.95yd3k" +msgstr "覆盖层类型" -# Source-Hash: 9a3495a1e3181b56 +# Source-Hash: 03b33160d8baa966 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Framing strategy" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.framingStrategy.3jx9qe" -msgstr "龙骨方式" +msgid "editor.inspector.field.cricketHeight.pok31n" +msgstr "泛水坡高度" -# Source-Hash: 49f329aab535fd3a +# Source-Hash: 21552eee05ccb5d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "From level id" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket length" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.fromLevelId.15ieejs" -msgstr "起始楼层 ID" +msgid "editor.inspector.field.cricketLength.i2aht8" +msgstr "泛水坡长度" -# Source-Hash: dbd062efc7f4fd7f +# Source-Hash: c13b707bfdeac855 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket side" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gableOverhang.2z0obw" -msgstr "山墙出挑" +msgid "editor.inspector.field.cricketSide.1xnwil7" +msgstr "泛水坡侧" -# Source-Hash: 517caa8af48afb22 +# Source-Hash: 4ee7089fa1b3e63b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel lower height ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gambrelLowerHeightRatio.wqq7lg" -msgstr "复折下部高度比" +msgid "editor.inspector.field.cricketStyle.10j0lat" +msgstr "泛水坡样式" -# Source-Hash: 03ecb8f3b625d49d +# Source-Hash: b8ff053666ee326b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel lower width ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curb" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gambrelLowerWidthRatio.uvyb1v" -msgstr "复折下部宽度比" +msgid "editor.inspector.field.curb.5xi2ol" +msgstr "路缘" -# Source-Hash: f3ca5555e8c54375 +# Source-Hash: 8da648df210dbc0d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap x" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curb height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gapX.wjxa7" -msgstr "间隙 x" +msgid "editor.inspector.field.curbHeight.1yn97sg" +msgstr "路缘高度" -# Source-Hash: 2736f7c5dfc7d917 +# Source-Hash: 0c01b9848f5d9673 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap y" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curve offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gapY.mkbl8" -msgstr "间隙 y" +msgid "editor.inspector.field.curveOffset.l4xhvr" +msgstr "弧度偏移" -# Source-Hash: 5d03ca50d712339b +# Source-Hash: 69179f4caa384585 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Damper angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.glassThickness.s97b0x" -msgstr "玻璃厚度" +msgid "editor.inspector.field.damperAngle.h5fxn7" +msgstr "风阀角度" -# Source-Hash: 4fc3e60be28f60d5 +# Source-Hash: 15cff91231e806a4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground clearance" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.groundClearance.4os7f0" -msgstr "离地间隙" +msgid "editor.inspector.field.deckThickness.4jmqze" +msgstr "平台厚度" -# Source-Hash: 6a22a09b67309545 +# Source-Hash: eff1e7dc0901b9d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guard infill" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default level id" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.guardInfill.16heiig" -msgstr "护栏填充" +msgid "editor.inspector.field.defaultLevelId.xmrjzp" +msgstr "默认楼层 ID" -# Source-Hash: 98dfdac04af3c762 +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gutter enabled" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gutterEnabled.1oxiltf" -msgstr "启用檐沟" +msgid "editor.inspector.field.depth.1lu11u2" +msgstr "深度" -# Source-Hash: 4bdc3cdf0fe0ac3c +# Source-Hash: 016d8e70618916d4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gutter profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gutterProfile.1ngzqi3" -msgstr "檐沟型材" +msgid "editor.inspector.field.diameter.s3robe" +msgstr "直径" -# Source-Hash: 76555670cba9bb13 +# Source-Hash: dab4100e83e4e6b3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gutter size" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diameter2" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.gutterSize.jgavtz" -msgstr "檐沟尺寸" +msgid "editor.inspector.field.diameter2.pm6cl4" +msgstr "直径 2" -# Source-Hash: c14d3aa4a98efa98 +# Source-Hash: 5747145349432396 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger max reach" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door duration ms" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.hangerMaxReach.1869epv" -msgstr "吊架最大跨度" +msgid "editor.inspector.field.doorDurationMs.13nx909" +msgstr "门动作时长 ms" -# Source-Hash: dfbc357fb556559b +# Source-Hash: 6f4aca26196c221f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.hangerSpacing.i2b5d7" -msgstr "吊架间距" +msgid "editor.inspector.field.doorHeight.92r9k4" +msgstr "门高" -# Source-Hash: 3ce5e50c572644ed +# Source-Hash: 990ae81752236e3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door panel style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.hangerStyle.l7v7gb" -msgstr "吊架样式" +msgid "editor.inspector.field.doorPanelStyle.2qog4q" +msgstr "门板样式" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: c94e002123bb1199 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.height.7puwki" -msgstr "高度" +msgid "editor.inspector.field.doorStyle.gerpos" +msgstr "门样式" -# Source-Hash: d0b836103c795726 +# Source-Hash: 91aeb04b0b7b605e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height2" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.height2.7b3jlc" -msgstr "高度 2" +msgid "editor.inspector.field.doorWidth.sy732l" +msgstr "门宽" -# Source-Hash: 681fd794e601ace5 +# Source-Hash: baad1238f70f79ea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height above ridge" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspout enabled" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.heightAboveRidge.1k99brk" -msgstr "高出屋脊" +msgid "editor.inspector.field.downspoutEnabled.1gn00nv" +msgstr "启用落水管" -# Source-Hash: b4905e5ec62a170f +# Source-Hash: e288531858c4c44d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High edge height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspout position" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.highEdgeHeight.1s7v90t" -msgstr "高边高度" +msgid "editor.inspector.field.downspoutPosition.fxcsop" +msgstr "落水管位置" -# Source-Hash: c136d5cd7f3ce04a +# Source-Hash: 861d28317325cf61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct material" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.highOverhang.67w55d" -msgstr "高侧出挑" +msgid "editor.inspector.field.ductMaterial.i8eonq" +msgstr "风管材料" -# Source-Hash: 8b4cd537cc650dac +# Source-Hash: ad8ab4ae38c3299c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High side mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch gablet rake" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.highSideMode.1rc1r5j" -msgstr "高侧模式" +msgid "editor.inspector.field.dutchGabletRake.6paydp" +msgstr "歇山山花檐口" -# Source-Hash: c38e4e73ed9779f4 +# Source-Hash: 913d25cf2c5ff179 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hood overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch hip height ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.hoodOverhang.1q1hcin" -msgstr "罩出挑" +msgid "editor.inspector.field.dutchHipHeightRatio.1etnwgg" +msgstr "歇山高度比" -# Source-Hash: 9884ee52a0e84c0d +# Source-Hash: f4a80233d49f2b20 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Infill placement" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch hip width ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.infillPlacement.11dxzpo" -msgstr "填充位置" +msgid "editor.inspector.field.dutchHipWidthRatio.1dopfvb" +msgstr "歇山宽度比" -# Source-Hash: 37fde9f9290ddc59 +# Source-Hash: 92021b0e37f9a25a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inlet shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch top rake thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.inletShape.ypayh2" -msgstr "进口形状" +msgid "editor.inspector.field.dutchTopRakeThickness.1w9khxt" +msgstr "歇山顶部檐口厚度" -# Source-Hash: d840917007332b94 +# Source-Hash: d0a2ec13d71ce659 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inner radius" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch waist length ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.innerRadius.1fkmg0j" -msgstr "内半径" +msgid "editor.inspector.field.dutchWaistLengthRatio.agtoxw" +msgstr "歇山腰部长度比" -# Source-Hash: c8ce389856a90ae2 +# Source-Hash: 993396ccca2cd1d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Insulated" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dwell ms" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.insulated.iwziey" -msgstr "保温" +msgid "editor.inspector.field.dwellMs.1lkk0o5" +msgstr "停留 ms" -# Source-Hash: 043a7a10b6c91f4f +# Source-Hash: 9cf550eb019bca1b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Insulation r" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edge inset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.insulationR.663ufx" -msgstr "保温 R" +msgid "editor.inspector.field.edgeInset.1obeimx" +msgstr "边缘内缩" -# Source-Hash: fe661655ba41b709 +# Source-Hash: 8a3bc5111b9e97f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lanternHeight.oz7zpm" -msgstr "灯笼高度" +msgid "editor.inspector.field.elevation.4jbp44" +msgstr "标高" -# Source-Hash: ab22022e7d5597af +# Source-Hash: 1fc91958e30dbeaf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern top scale" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End cap left" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lanternTopScale.hkmpp2" -msgstr "灯笼顶部比例" +msgid "editor.inspector.field.endCapLeft.19jel4v" +msgstr "左端盖" -# Source-Hash: 17f854a76ebc033a +# Source-Hash: 4c9ae62e0ed70635 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ledger depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End cap right" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.ledgerDepth.7av8k9" -msgstr "托梁深度" +msgid "editor.inspector.field.endCapRight.lhse9c" +msgstr "右端盖" -# Source-Hash: 547d3a8a9e3e24f5 +# Source-Hash: a9cba06250228a55 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ledger height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End caps" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.ledgerHeight.zo2oif" -msgstr "托梁高度" +msgid "editor.inspector.field.endCaps.4fsb5b" +msgstr "端盖" -# Source-Hash: 88603f884243c81e +# Source-Hash: ebad74353b5a7610 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ledger vertical offset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End post" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.ledgerVerticalOffset.1athbgt" -msgstr "托梁垂直偏移" +msgid "editor.inspector.field.endPost.1guwsk0" +msgstr "端柱" -# Source-Hash: 6519f495202b830d +# Source-Hash: ecbe36df4238439e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left end condition" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equipment type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.leftEndCondition.1syqlaw" -msgstr "左端条件" +msgid "editor.inspector.field.equipmentType.1mc2ywt" +msgstr "设备类型" -# Source-Hash: d041b8217c356977 +# Source-Hash: 66f1018b50c2e426 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fill to floor" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.leftOverhang.1ydl9ma" -msgstr "左侧出挑" +msgid "editor.inspector.field.fillToFloor.1oppnkf" +msgstr "填充至地面" -# Source-Hash: 643687bc3adaac76 +# Source-Hash: 1cfe33235b30b1d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finial" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.length.1kpdcfp" -msgstr "长度" +msgid "editor.inspector.field.finial.1ertf4s" +msgstr "尖顶饰" -# Source-Hash: d6deaf0ceb9f43af +# Source-Hash: 28cd69e506709f16 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Liquid diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fitting type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.liquidDiameter.w3pk7c" -msgstr "液管直径" +msgid "editor.inspector.field.fittingType.18mz17s" +msgstr "管件类型" -# Source-Hash: 45aca762426392fa +# Source-Hash: 3c1aec5e6fb180cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Louver count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flashing height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.louverCount.lhw2gr" -msgstr "百叶数量" +msgid "editor.inspector.field.flashingHeight.3e8nn6" +msgstr "泛水高度" -# Source-Hash: c645a86c55eb0075 +# Source-Hash: 327ba762101db94d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low beam inset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flashing projection" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lowBeamInset.1g7yw5l" -msgstr "低梁内缩" +msgid "editor.inspector.field.flashingProjection.hhf0fk" +msgstr "泛水出挑" -# Source-Hash: 7e7b896682c78c5b +# Source-Hash: 9473e2ab53370b40 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low edge height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lowEdgeHeight.47mae1" -msgstr "低边高度" +msgid "editor.inspector.field.flueCount.j3t2ci" +msgstr "烟道数量" -# Source-Hash: 9deb775fc64854b2 +# Source-Hash: fd0b65425ed3df8b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.lowOverhang.t4nz1h" -msgstr "低侧出挑" +msgid "editor.inspector.field.flueDiameter.cjhubg" +msgstr "烟道直径" -# Source-Hash: 9aa621d270fe64b1 +# Source-Hash: 07ebe5e3780c624b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard steep height ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.mansardSteepHeightRatio.1hbb8rq" -msgstr "孟莎陡坡高度比" +msgid "editor.inspector.field.flueHeight.1dhc4y4" +msgstr "烟道高度" -# Source-Hash: 7cb03b27c632949b +# Source-Hash: ff8319792830d591 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard steep width ratio" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.mansardSteepWidthRatio.6xk6vd" -msgstr "孟莎陡坡宽度比" +msgid "editor.inspector.field.flueShape.1ealiy4" +msgstr "烟道形状" -# Source-Hash: 95772435857a7424 +# Source-Hash: 5acf77854a0030ec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match host roof material" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flue spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.matchHostRoofMaterial.s56zwj" -msgstr "匹配主屋顶材质" +msgid "editor.inspector.field.flueSpacing.exhzco" +msgstr "烟道间距" -# Source-Hash: dc22618e31654bde +# Source-Hash: 0a64209c0edacaa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match host roof structure" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Footing style" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.matchHostRoofStructure.bojht3" -msgstr "匹配主屋顶结构" +msgid "editor.inspector.field.footingStyle.e3btg6" +msgstr "基脚样式" -# Source-Hash: 06b36a09a84fa8b1 +# Source-Hash: fd413477f1a9e5ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mount" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame depth" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.mount.h80tay" -msgstr "安装" +msgid "editor.inspector.field.frameDepth.1934a5n" +msgstr "框架深度" -# Source-Hash: a288700f96d2b362 +# Source-Hash: 6aa2318fa815e5f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.mountingType.1xvin1e" -msgstr "安装类型" +msgid "editor.inspector.field.frameThickness.1agxzd8" +msgstr "框架厚度" -# Source-Hash: 3087bc9b219af9ef +# Source-Hash: 9a3495a1e3181b56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Neck height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framing strategy" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.neckHeight.19ym8n1" -msgstr "颈部高度" +msgid "editor.inspector.field.framingStrategy.3jx9qe" +msgstr "龙骨方式" -# Source-Hash: 1c0b8a5503c5daeb +# Source-Hash: 49f329aab535fd3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opacity" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "From level id" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.opacity.1pmpfd2" -msgstr "不透明度" +msgid "editor.inspector.field.fromLevelId.15ieejs" +msgstr "起始楼层 ID" -# Source-Hash: 51b7ab6a0a78d90a +# Source-Hash: dbd062efc7f4fd7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.openingAngle.brhi7c" -msgstr "开启角度" +msgid "editor.inspector.field.gableOverhang.2z0obw" +msgstr "山墙出挑" -# Source-Hash: 1d714b576a057902 +# Source-Hash: 517caa8af48afb22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening offset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel lower height ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.openingOffset.wpoqt6" -msgstr "开洞偏移" +msgid "editor.inspector.field.gambrelLowerHeightRatio.wqq7lg" +msgstr "复折下部高度比" -# Source-Hash: 55e5629865efd03d +# Source-Hash: 03ecb8f3b625d49d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening side" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel lower width ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.openingSide.18l2iwe" -msgstr "开启侧" +msgid "editor.inspector.field.gambrelLowerWidthRatio.uvyb1v" +msgstr "复折下部宽度比" -# Source-Hash: 9824d357692ecb8a +# Source-Hash: f3ca5555e8c54375 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Operation state" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap x" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.operationState.1lwrz07" -msgstr "开启状态" +msgid "editor.inspector.field.gapX.wjxa7" +msgstr "间隙 x" -# Source-Hash: 4f1cbc14dcfb8f3b +# Source-Hash: 2736f7c5dfc7d917 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Outlet shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap y" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.outletShape.lgpqhx" -msgstr "出口形状" +msgid "editor.inspector.field.gapY.mkbl8" +msgstr "间隙 y" -# Source-Hash: 88540def2ce16ac5 +# Source-Hash: 5d03ca50d712339b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.overhang.b5ljpv" -msgstr "出挑" +msgid "editor.inspector.field.glassThickness.s97b0x" +msgstr "玻璃厚度" -# Source-Hash: 50d7e5e370667f63 +# Source-Hash: 4fc3e60be28f60d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground clearance" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.panelHeight.1kf31vk" -msgstr "面板高度" +msgid "editor.inspector.field.groundClearance.4os7f0" +msgstr "离地间隙" -# Source-Hash: 068d9e0adabc4578 +# Source-Hash: 6a22a09b67309545 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guard infill" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.panelWidth.946581" -msgstr "面板宽度" +msgid "editor.inspector.field.guardInfill.16heiig" +msgstr "护栏填充" -# Source-Hash: aca94a3adc0b0f01 +# Source-Hash: 98dfdac04af3c762 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern alignment" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gutter enabled" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.patternAlignment.jd1ht0" -msgstr "图案对齐" +msgid "editor.inspector.field.gutterEnabled.1oxiltf" +msgstr "启用檐沟" -# Source-Hash: 9e9f9408ec2c8f0b +# Source-Hash: 4bdc3cdf0fe0ac3c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gutter profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.patternCount.1r37pve" -msgstr "图案数量" +msgid "editor.inspector.field.gutterProfile.1ngzqi3" +msgstr "檐沟型材" -# Source-Hash: 4712c449e9a42d3b +# Source-Hash: 76555670cba9bb13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern distribution" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gutter size" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.patternDistribution.fmam51" -msgstr "图案分布" +msgid "editor.inspector.field.gutterSize.jgavtz" +msgstr "檐沟尺寸" -# Source-Hash: 63f833f219b9a592 +# Source-Hash: c14d3aa4a98efa98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern remainder" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger max reach" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.patternRemainder.i47p5y" -msgstr "图案余量" +msgid "editor.inspector.field.hangerMaxReach.1869epv" +msgstr "吊架最大跨度" -# Source-Hash: e0b8f766411329ff +# Source-Hash: dfbc357fb556559b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketProfile.1xgzuyc" -msgstr "栅条型材" +msgid "editor.inspector.field.hangerSpacing.i2b5d7" +msgstr "吊架间距" -# Source-Hash: dfac7d68ea16e8a8 +# Source-Hash: 3ce5e50c572644ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket rail count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketRailCount.atgt6w" -msgstr "栅条横杆数量" +msgid "editor.inspector.field.hangerStyle.l7v7gb" +msgstr "吊架样式" -# Source-Hash: cd2652254a81d288 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketSpacing.p8d98w" -msgstr "栅条间距" +msgid "editor.inspector.field.height.7puwki" +msgstr "高度" -# Source-Hash: 462f6cb03b23d773 +# Source-Hash: d0b836103c795726 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket top" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height2" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketTop.1tskplu" -msgstr "栅条顶部" +msgid "editor.inspector.field.height2.7b3jlc" +msgstr "高度 2" -# Source-Hash: 0a4dbbe1cf592326 +# Source-Hash: 681fd794e601ace5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket top clearance" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height above ridge" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketTopClearance.16eq1k0" -msgstr "栅条顶部间隙" +msgid "editor.inspector.field.heightAboveRidge.1k99brk" +msgstr "高出屋脊" -# Source-Hash: c99ccea380ca41bf +# Source-Hash: b4905e5ec62a170f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket variation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High edge height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketVariation.f7vl1c" -msgstr "栅条变化" +msgid "editor.inspector.field.highEdgeHeight.1s7v90t" +msgstr "高边高度" -# Source-Hash: 798382373625fecd +# Source-Hash: c136d5cd7f3ce04a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.picketWidth.3fr3rh" -msgstr "栅条宽度" +msgid "editor.inspector.field.highOverhang.67w55d" +msgstr "高侧出挑" -# Source-Hash: 48ce215c3be034c7 +# Source-Hash: 8b4cd537cc650dac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pipe material" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High side mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.pipeMaterial.1ggc2wy" -msgstr "管材" +msgid "editor.inspector.field.highSideMode.1rc1r5j" +msgstr "高侧模式" -# Source-Hash: 75e3449fc1776d09 +# Source-Hash: c38e4e73ed9779f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pitch" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hood overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.pitch.xe6ekx" -msgstr "坡度" +msgid "editor.inspector.field.hoodOverhang.1q1hcin" +msgstr "罩出挑" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: 9884ee52a0e84c0d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Infill placement" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.position.1quewx6" -msgstr "位置" +msgid "editor.inspector.field.infillPlacement.11dxzpo" +msgstr "填充位置" -# Source-Hash: d090baf9f08c2280 +# Source-Hash: 37fde9f9290ddc59 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post bracing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inlet shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postBracing.crq8nn" -msgstr "立柱支撑" +msgid "editor.inspector.field.inletShape.ypayh2" +msgstr "进口形状" -# Source-Hash: 6467b580eed1d333 +# Source-Hash: d840917007332b94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post cap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inner radius" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postCap.1xcvxrv" -msgstr "立柱帽" +msgid "editor.inspector.field.innerRadius.1fkmg0j" +msgstr "内半径" -# Source-Hash: e1d91cdd16cc6593 +# Source-Hash: c8ce389856a90ae2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulated" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postCount.22r56c" -msgstr "立柱数量" +msgid "editor.inspector.field.insulated.iwziey" +msgstr "保温" -# Source-Hash: d6d8b8653cb43624 +# Source-Hash: 043a7a10b6c91f4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation r" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postDepth.1ko6j1m" -msgstr "立柱深度" +msgid "editor.inspector.field.insulationR.663ufx" +msgstr "保温 R" -# Source-Hash: dd071e84e259ee48 +# Source-Hash: fe661655ba41b709 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post inset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postInset.le36li" -msgstr "立柱内缩" +msgid "editor.inspector.field.lanternHeight.oz7zpm" +msgstr "灯笼高度" -# Source-Hash: 88c5d586822e58f0 +# Source-Hash: ab22022e7d5597af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post layout mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern top scale" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postLayoutMode.16jre62" -msgstr "立柱布置方式" +msgid "editor.inspector.field.lanternTopScale.hkmpp2" +msgstr "灯笼顶部比例" -# Source-Hash: faa36308c1ecb2a9 +# Source-Hash: 17f854a76ebc033a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post size" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ledger depth" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postSize.1jodxek" -msgstr "立柱尺寸" +msgid "editor.inspector.field.ledgerDepth.7av8k9" +msgstr "托梁深度" -# Source-Hash: c8e8490c957e01f3 +# Source-Hash: 547d3a8a9e3e24f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ledger height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postSpacing.voppfi" -msgstr "立柱间距" +msgid "editor.inspector.field.ledgerHeight.zo2oif" +msgstr "托梁高度" -# Source-Hash: b98cbe8478508d41 +# Source-Hash: 88603f884243c81e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post through" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ledger vertical offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postThrough.1abgu4a" -msgstr "立柱贯穿" +msgid "editor.inspector.field.ledgerVerticalOffset.1athbgt" +msgstr "托梁垂直偏移" -# Source-Hash: d1492df1fbb22c29 +# Source-Hash: 6519f495202b830d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left end condition" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.postWidth.rk26fz" -msgstr "立柱宽度" +msgid "editor.inspector.field.leftEndCondition.1syqlaw" +msgstr "左端条件" -# Source-Hash: 96ad4bd0f7baa40e +# Source-Hash: d041b8217c356977 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.profile.1kwlci6" -msgstr "轮廓" +msgid "editor.inspector.field.leftOverhang.1ydl9ma" +msgstr "左侧出挑" -# Source-Hash: d01cd36d3939abab +# Source-Hash: 643687bc3adaac76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Projection" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.projection.jhtig0" -msgstr "出挑" +msgid "editor.inspector.field.length.1kpdcfp" +msgstr "长度" -# Source-Hash: 800a7a9159519b46 +# Source-Hash: d6deaf0ceb9f43af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Purlin height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Liquid diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.purlinHeight.eo9cjm" -msgstr "檩条高度" +msgid "editor.inspector.field.liquidDiameter.w3pk7c" +msgstr "液管直径" -# Source-Hash: da4d0d12715d6c33 +# Source-Hash: 45aca762426392fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Purlin spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Louver count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.purlinSpacing.4gbzb2" -msgstr "檩条间距" +msgid "editor.inspector.field.louverCount.lhw2gr" +msgstr "百叶数量" -# Source-Hash: b4774bcbdf599812 +# Source-Hash: c645a86c55eb0075 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Purlin width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low beam inset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.purlinWidth.r6tu3j" -msgstr "檩条宽度" +msgid "editor.inspector.field.lowBeamInset.1g7yw5l" +msgstr "低梁内缩" -# Source-Hash: 2a4dd54f8a8c15ef +# Source-Hash: 7e7b896682c78c5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafter end inset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low edge height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rafterEndInset.14c0wy5" -msgstr "椽端内缩" +msgid "editor.inspector.field.lowEdgeHeight.47mae1" +msgstr "低边高度" -# Source-Hash: 5a80a11b97c0e043 +# Source-Hash: 9deb775fc64854b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafter height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rafterHeight.1e1n99w" -msgstr "椽高" +msgid "editor.inspector.field.lowOverhang.t4nz1h" +msgstr "低侧出挑" -# Source-Hash: b6348d554660af5b +# Source-Hash: 9aa621d270fe64b1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafter spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard steep height ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rafterSpacing.19subc0" -msgstr "椽距" +msgid "editor.inspector.field.mansardSteepHeightRatio.1hbb8rq" +msgstr "孟莎陡坡高度比" -# Source-Hash: 112c447946c3beaa +# Source-Hash: 7cb03b27c632949b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafter width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard steep width ratio" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rafterWidth.eksj4t" -msgstr "椽宽" +msgid "editor.inspector.field.mansardSteepWidthRatio.6xk6vd" +msgstr "孟莎陡坡宽度比" -# Source-Hash: 7020d720876a2106 +# Source-Hash: 95772435857a7424 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match host roof material" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.railingHeight.6wf4bm" -msgstr "栏杆高度" - -# Source-Hash: 3e89ce193885b5b4 +msgid "editor.inspector.field.matchHostRoofMaterial.s56zwj" +msgstr "匹配主屋顶材质" + +# Source-Hash: dc22618e31654bde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match host roof structure" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.railingMode.ov7xpu" -msgstr "栏杆模式" +msgid "editor.inspector.field.matchHostRoofStructure.bojht3" +msgstr "匹配主屋顶结构" -# Source-Hash: 174342bb31a86afc +# Source-Hash: 06b36a09a84fa8b1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mount" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.railingStyle.1nyd2u" -msgstr "栏杆样式" +msgid "editor.inspector.field.mount.h80tay" +msgstr "安装" -# Source-Hash: a44eedc895b95474 +# Source-Hash: a288700f96d2b362 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Resize lock" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.resizeLock.b2hbr0" -msgstr "锁定比例" +msgid "editor.inspector.field.mountingType.1xvin1e" +msgstr "安装类型" -# Source-Hash: edd319917231def8 +# Source-Hash: 3087bc9b219af9ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Neck height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.returnDiameter.166ozhe" -msgstr "回风直径" +msgid "editor.inspector.field.neckHeight.19ym8n1" +msgstr "颈部高度" -# Source-Hash: dafa151b183daa77 +# Source-Hash: 1c0b8a5503c5daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opacity" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.returnHeight.b9sq6y" -msgstr "回风高度" +msgid "editor.inspector.field.opacity.1pmpfd2" +msgstr "不透明度" -# Source-Hash: cd55fd029ad2803b +# Source-Hash: 51b7ab6a0a78d90a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.returnShape.1e3a27i" -msgstr "回风形状" +msgid "editor.inspector.field.openingAngle.brhi7c" +msgstr "开启角度" -# Source-Hash: 6a7c411667124177 +# Source-Hash: 1d714b576a057902 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.returnWidth.z9r3h3" -msgstr "回风宽度" +msgid "editor.inspector.field.openingOffset.wpoqt6" +msgstr "开洞偏移" -# Source-Hash: 460bd11bfc2e5697 +# Source-Hash: 55e5629865efd03d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right end condition" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening side" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rightEndCondition.tjlw3l" -msgstr "右端条件" +msgid "editor.inspector.field.openingSide.18l2iwe" +msgstr "开启侧" -# Source-Hash: 1ed35f8d27ae5583 +# Source-Hash: 9824d357692ecb8a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right overhang" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Operation state" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rightOverhang.yqbeft" -msgstr "右侧出挑" +msgid "editor.inspector.field.operationState.1lwrz07" +msgstr "开启状态" -# Source-Hash: 39c02aa2d97a62ba +# Source-Hash: 4f1cbc14dcfb8f3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outlet shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.roofHeight.1uhy6qy" -msgstr "屋顶高度" +msgid "editor.inspector.field.outletShape.lgpqhx" +msgstr "出口形状" -# Source-Hash: d62f8833d77ca8a1 +# Source-Hash: 88540def2ce16ac5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.roofStyle.pawqfy" -msgstr "屋顶样式" +msgid "editor.inspector.field.overhang.b5ljpv" +msgstr "出挑" -# Source-Hash: 0ddd561a4126b826 +# Source-Hash: 50d7e5e370667f63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.roofThickness.1xlr3rx" -msgstr "屋顶厚度" +msgid "editor.inspector.field.panelHeight.1kf31vk" +msgstr "面板高度" -# Source-Hash: 3a08ede9e51d5395 +# Source-Hash: 068d9e0adabc4578 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.roofType.1m9kv5h" -msgstr "屋顶类型" +msgid "editor.inspector.field.panelWidth.946581" +msgstr "面板宽度" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: aca94a3adc0b0f01 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern alignment" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rotation.ly2rj" -msgstr "旋转" +msgid "editor.inspector.field.patternAlignment.jd1ht0" +msgstr "图案对齐" -# Source-Hash: c913b494c3901a17 +# Source-Hash: 9e9f9408ec2c8f0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rows" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.rows.1ba1neg" -msgstr "行" +msgid "editor.inspector.field.patternCount.1r37pve" +msgstr "图案数量" -# Source-Hash: 8210f376c0d29acc +# Source-Hash: 4712c449e9a42d3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scale" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern distribution" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.scale.b6rpxt" -msgstr "比例" +msgid "editor.inspector.field.patternDistribution.fmam51" +msgstr "图案分布" -# Source-Hash: adb6face4bac5245 +# Source-Hash: 63f833f219b9a592 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Seam detail" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern remainder" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.seamDetail.197za48" -msgstr "接缝细节" +msgid "editor.inspector.field.patternRemainder.i47p5y" +msgstr "图案余量" -# Source-Hash: 4b2aed9d56cc4dee +# Source-Hash: e0b8f766411329ff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segment type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.segmentType.l667sy" -msgstr "分段类型" +msgid "editor.inspector.field.picketProfile.1xgzuyc" +msgstr "栅条型材" -# Source-Hash: a7794a81141b4de4 +# Source-Hash: dfac7d68ea16e8a8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket rail count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shaftStyle.1i5ampa" -msgstr "井道样式" +msgid "editor.inspector.field.picketRailCount.atgt6w" +msgstr "栅条横杆数量" -# Source-Hash: 8eb6438543b18cdb +# Source-Hash: cd2652254a81d288 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft wall thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shaftWallThickness.bduslr" -msgstr "井道墙厚" +msgid "editor.inspector.field.picketSpacing.p8d98w" +msgstr "栅条间距" -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: 462f6cb03b23d773 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket top" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shape.iq9t52" -msgstr "形状" +msgid "editor.inspector.field.picketTop.1tskplu" +msgstr "栅条顶部" -# Source-Hash: 44a8ab89c854cad1 +# Source-Hash: 0a4dbbe1cf592326 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape2" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket top clearance" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shape2.fi0nx8" -msgstr "形状 2" +msgid "editor.inspector.field.picketTopClearance.16eq1k0" +msgstr "栅条顶部间隙" -# Source-Hash: fcee9712879570ae +# Source-Hash: c99ccea380ca41bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed high side" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket variation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shedHighSide.bzzddg" -msgstr "单坡高侧" +msgid "editor.inspector.field.picketVariation.f7vl1c" +msgstr "栅条变化" -# Source-Hash: f5a931cd6e97e5e2 +# Source-Hash: 798382373625fecd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingle thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shingleThickness.1hn5wxr" -msgstr "瓦片厚度" +msgid "editor.inspector.field.picketWidth.3fr3rh" +msgstr "栅条宽度" -# Source-Hash: b14990b3e4222dd3 +# Source-Hash: 48ce215c3be034c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder extent" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pipe material" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shoulderExtent.11j8uiv" -msgstr "肩部范围" +msgid "editor.inspector.field.pipeMaterial.1ggc2wy" +msgstr "管材" -# Source-Hash: 505de343ec5010e6 +# Source-Hash: 75e3449fc1776d09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pitch" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shoulderHeight.xyqn6g" -msgstr "肩部高度" +msgid "editor.inspector.field.pitch.xe6ekx" +msgstr "坡度" -# Source-Hash: 58d48c01b7ec1a40 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.shoulderStyle.1hkcv2w" -msgstr "肩部样式" +msgid "editor.inspector.field.position.1quewx6" +msgstr "位置" -# Source-Hash: af84db1026bf2e6c +# Source-Hash: d090baf9f08c2280 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show center column" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post bracing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.showCenterColumn.1uggg45" -msgstr "显示中柱" +msgid "editor.inspector.field.postBracing.crq8nn" +msgstr "立柱支撑" -# Source-Hash: 80214dc086ebc1b1 +# Source-Hash: 6467b580eed1d333 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show infill" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post cap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.showInfill.33rv7u" -msgstr "显示填充" +msgid "editor.inspector.field.postCap.1xcvxrv" +msgstr "立柱帽" -# Source-Hash: f02d6cdfb4c6ad08 +# Source-Hash: e1d91cdd16cc6593 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show step supports" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.showStepSupports.1kg8h8m" -msgstr "显示踏步支撑" +msgid "editor.inspector.field.postCount.22r56c" +msgstr "立柱数量" -# Source-Hash: 5d1147c774718b76 +# Source-Hash: d6d8b8653cb43624 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Side flashing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post depth" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.sideFlashing.cv744o" -msgstr "侧面泛水" +msgid "editor.inspector.field.postDepth.1ko6j1m" +msgstr "立柱深度" -# Source-Hash: 60bb3338e0ad558c +# Source-Hash: dd071e84e259ee48 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Size" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post inset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.size.1a4x3zw" -msgstr "尺寸" +msgid "editor.inspector.field.postInset.le36li" +msgstr "立柱内缩" -# Source-Hash: fbdbc6c97c75b030 +# Source-Hash: 88c5d586822e58f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Skylight type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post layout mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.skylightType.1a5vj3i" -msgstr "天窗类型" +msgid "editor.inspector.field.postLayoutMode.16jre62" +msgstr "立柱布置方式" -# Source-Hash: c9a6561cb3c3da82 +# Source-Hash: faa36308c1ecb2a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab opening mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post size" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.slabOpeningMode.g4f730" -msgstr "楼板开洞方式" +msgid "editor.inspector.field.postSize.1jodxek" +msgstr "立柱尺寸" -# Source-Hash: ef0efc845ccdba78 +# Source-Hash: c8e8490c957e01f3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slat gap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.slatGap.slmk93" -msgstr "叶片间隙" +msgid "editor.inspector.field.postSpacing.voppfi" +msgstr "立柱间距" -# Source-Hash: 4daab7a2ce2ecef3 +# Source-Hash: b98cbe8478508d41 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slide direction" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post through" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.slideDirection.1527q13" -msgstr "推拉方向" +msgid "editor.inspector.field.postThrough.1abgu4a" +msgstr "立柱贯穿" -# Source-Hash: 93b34a5b546664c4 +# Source-Hash: d1492df1fbb22c29 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Span" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.span.1bmmuw1" -msgstr "跨度" +msgid "editor.inspector.field.postWidth.rk26fz" +msgstr "立柱宽度" -# Source-Hash: 3b006be0b1f0493f +# Source-Hash: 96ad4bd0f7baa40e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Speed" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.speed.2w2xwg" -msgstr "速度" +msgid "editor.inspector.field.profile.1kwlci6" +msgstr "轮廓" -# Source-Hash: c8cfb8336a240cb1 +# Source-Hash: d01cd36d3939abab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spin speed" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Projection" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.spinSpeed.1ozx746" -msgstr "旋转速度" +msgid "editor.inspector.field.projection.jhtig0" +msgstr "出挑" -# Source-Hash: c9f54c3b258961c7 +# Source-Hash: 800a7a9159519b46 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Purlin height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.stairType.1u05e02" -msgstr "楼梯类型" +msgid "editor.inspector.field.purlinHeight.eo9cjm" +msgstr "檩条高度" -# Source-Hash: 0af6194a8b8d8be6 +# Source-Hash: da4d0d12715d6c33 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standoff" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Purlin spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.standoff.4wv2g0" -msgstr "支脚" +msgid "editor.inspector.field.purlinSpacing.4gbzb2" +msgstr "檩条间距" -# Source-Hash: 0464d4efa1e80c62 +# Source-Hash: b4774bcbdf599812 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standoff height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Purlin width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.standoffHeight.1qdnff" -msgstr "支脚高度" +msgid "editor.inspector.field.purlinWidth.r6tu3j" +msgstr "檩条宽度" -# Source-Hash: 85da28b0b26b8c2a +# Source-Hash: 2a4dd54f8a8c15ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start post" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafter end inset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.startPost.1ood9kv" -msgstr "起始柱" +msgid "editor.inspector.field.rafterEndInset.14c0wy5" +msgstr "椽端内缩" -# Source-Hash: d5dc1ba8cca3193d +# Source-Hash: 5a80a11b97c0e043 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Step count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafter height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.stepCount.nzorrw" -msgstr "踏步数" +msgid "editor.inspector.field.rafterHeight.1e1n99w" +msgstr "椽高" -# Source-Hash: cadbb9cadd6a5e6f +# Source-Hash: b6348d554660af5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Strap spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafter spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.strapSpacing.1cyt3dc" -msgstr "吊带间距" +msgid "editor.inspector.field.rafterSpacing.19subc0" +msgstr "椽距" -# Source-Hash: c017cd56b3ae5865 +# Source-Hash: 112c447946c3beaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Strap style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafter width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.strapStyle.fh1oy4" -msgstr "吊带样式" +msgid "editor.inspector.field.rafterWidth.eksj4t" +msgstr "椽宽" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: 7020d720876a2106 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.style.nf3vcm" -msgstr "样式" +msgid "editor.inspector.field.railingHeight.6wf4bm" +msgstr "栏杆高度" -# Source-Hash: 7b3f016989c631a7 +# Source-Hash: 3e89ce193885b5b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Suction diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.suctionDiameter.nutxtj" -msgstr "吸气管直径" +msgid "editor.inspector.field.railingMode.ov7xpu" +msgstr "栏杆模式" -# Source-Hash: 3f1e0fd30e5b1f39 +# Source-Hash: 174342bb31a86afc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply diameter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supplyDiameter.h5ldh5" -msgstr "送风直径" +msgid "editor.inspector.field.railingStyle.1nyd2u" +msgstr "栏杆样式" -# Source-Hash: 05c9b608538e181d +# Source-Hash: a44eedc895b95474 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Resize lock" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supplyHeight.zy6ru1" -msgstr "送风高度" +msgid "editor.inspector.field.resizeLock.b2hbr0" +msgstr "锁定比例" -# Source-Hash: 3c9400722baa474d +# Source-Hash: edd319917231def8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supplyShape.k39wnb" -msgstr "送风形状" +msgid "editor.inspector.field.returnDiameter.166ozhe" +msgstr "回风直径" -# Source-Hash: af7619025438f995 +# Source-Hash: dafa151b183daa77 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supplyWidth.g66axi" -msgstr "送风宽度" +msgid "editor.inspector.field.returnHeight.b9sq6y" +msgstr "回风高度" -# Source-Hash: 617e198cf3f214d3 +# Source-Hash: cd55fd029ad2803b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Support offset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.supportOffset.1w4cocr" -msgstr "支撑偏移" +msgid "editor.inspector.field.returnShape.1e3a27i" +msgstr "回风形状" -# Source-Hash: 2686abc093f3dfb1 +# Source-Hash: 6a7c411667124177 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sweep angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.sweepAngle.ucmmlw" -msgstr "扫掠角度" +msgid "editor.inspector.field.returnWidth.z9r3h3" +msgstr "回风宽度" -# Source-Hash: 88e6c2e1c344b2fc +# Source-Hash: 460bd11bfc2e5697 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right end condition" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.system.13qbhrw" -msgstr "系统" +msgid "editor.inspector.field.rightEndCondition.tjlw3l" +msgstr "右端条件" -# Source-Hash: ccb3afc48bd9a284 +# Source-Hash: 1ed35f8d27ae5583 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terminal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right overhang" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.terminal.1501knl" -msgstr "风口" +msgid "editor.inspector.field.rightOverhang.yqbeft" +msgstr "右侧出挑" -# Source-Hash: de1777c521046f7d +# Source-Hash: 39c02aa2d97a62ba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terminal type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.terminalType.1ne8lgb" -msgstr "风口类型" +msgid "editor.inspector.field.roofHeight.1uhy6qy" +msgstr "屋顶高度" -# Source-Hash: fdbb503f0941bd56 +# Source-Hash: d62f8833d77ca8a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.thickness.1l8hu45" -msgstr "厚度" +msgid "editor.inspector.field.roofStyle.pawqfy" +msgstr "屋顶样式" -# Source-Hash: 58cb60c14826f1d0 +# Source-Hash: 0ddd561a4126b826 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilt angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.tiltAngle.1312yw1" -msgstr "倾斜角度" +msgid "editor.inspector.field.roofThickness.1xlr3rx" +msgstr "屋顶厚度" -# Source-Hash: 7057972ff4c78dc7 +# Source-Hash: 3a08ede9e51d5395 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "To level id" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.toLevelId.8i5qx7" -msgstr "目标楼层 ID" +msgid "editor.inspector.field.roofType.1m9kv5h" +msgstr "屋顶类型" -# Source-Hash: fa8fc3d5c612e774 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top landing depth" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.topLandingDepth.ki7gk2" -msgstr "顶部平台深度" +msgid "editor.inspector.field.rotation.ly2rj" +msgstr "旋转" -# Source-Hash: 6e4a0b98089ec2cd +# Source-Hash: c913b494c3901a17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top landing mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rows" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.topLandingMode.zk0h7e" -msgstr "顶部平台方式" +msgid "editor.inspector.field.rows.1ba1neg" +msgstr "行" -# Source-Hash: c182bb3c8a701085 +# Source-Hash: 8210f376c0d29acc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top rail height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scale" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.topRailHeight.fscisv" -msgstr "顶部横杆高度" +msgid "editor.inspector.field.scale.b6rpxt" +msgstr "比例" -# Source-Hash: 8c5502f1d8087b7b +# Source-Hash: adb6face4bac5245 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transition mode" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Seam detail" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.transitionMode.f3evgt" -msgstr "过渡方式" +msgid "editor.inspector.field.seamDetail.197za48" +msgstr "接缝细节" -# Source-Hash: 96eb5997f0aa2dde +# Source-Hash: 4b2aed9d56cc4dee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transition width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segment type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.transitionWidth.rtgz3m" -msgstr "过渡宽度" +msgid "editor.inspector.field.segmentType.l667sy" +msgstr "分段类型" -# Source-Hash: 812d27902509339f +# Source-Hash: a7794a81141b4de4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vane count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.vaneCount.55vtye" -msgstr "叶片数" +msgid "editor.inspector.field.shaftStyle.1i5ampa" +msgstr "井道样式" -# Source-Hash: 1e7dcd717c8ac239 +# Source-Hash: 8eb6438543b18cdb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft wall thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.wallHeight.18vmh5c" -msgstr "墙高" +msgid "editor.inspector.field.shaftWallThickness.bduslr" +msgstr "井道墙厚" -# Source-Hash: f14bdaed6101896a +# Source-Hash: 85ea1d3c8b749680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall shell" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.wallShell.vqsyhv" -msgstr "墙体外壳" +msgid "editor.inspector.field.shape.iq9t52" +msgstr "形状" -# Source-Hash: 801268585c9a679b +# Source-Hash: 44a8ab89c854cad1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall skirt height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape2" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.wallSkirtHeight.1uea2ad" -msgstr "墙裙高度" +msgid "editor.inspector.field.shape2.fi0nx8" +msgstr "形状 2" -# Source-Hash: 6b377d0ba1565477 +# Source-Hash: fcee9712879570ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall thickness" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed high side" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.wallThickness.17wn4iv" -msgstr "墙厚" +msgid "editor.inspector.field.shedHighSide.bzzddg" +msgstr "单坡高侧" -# Source-Hash: 3a0ccd6c46877a87 +# Source-Hash: f5a931cd6e97e5e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingle thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.width.gfxz9b" -msgstr "宽度" +msgid "editor.inspector.field.shingleThickness.1hn5wxr" +msgstr "瓦片厚度" -# Source-Hash: de05070474f589b4 +# Source-Hash: b14990b3e4222dd3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width2" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder extent" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.width2.1nqawvr" -msgstr "宽度 2" +msgid "editor.inspector.field.shoulderExtent.11j8uiv" +msgstr "肩部范围" -# Source-Hash: 6199b641888a83fa +# Source-Hash: 505de343ec5010e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "With back" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.withBack.1ay8nus" -msgstr "带背板" +msgid "editor.inspector.field.shoulderHeight.xyqn6g" +msgstr "肩部高度" -# Source-Hash: 699934d8b9571b64 +# Source-Hash: 58d48c01b7ec1a40 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "With bottom" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.withBottom.1x1z1vo" -msgstr "带底板" +msgid "editor.inspector.field.shoulderStyle.1hkcv2w" +msgstr "肩部样式" -# Source-Hash: 03987b9aadaab50f +# Source-Hash: af84db1026bf2e6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "With sides" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show center column" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.field.withSides.uq066x" -msgstr "带侧板" +msgid "editor.inspector.field.showCenterColumn.1uggg45" +msgstr "显示中柱" -# Source-Hash: f571cb2d06ae01ae +# Source-Hash: 80214dc086ebc1b1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Advanced" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show infill" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.advanced.qwfkor" -msgstr "高级" +msgid "editor.inspector.field.showInfill.33rv7u" +msgstr "显示填充" -# Source-Hash: a886619d15bae47e +# Source-Hash: f02d6cdfb4c6ad08 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Air" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show step supports" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.air.15jotdj" -msgstr "空气" +msgid "editor.inspector.field.showStepSupports.1kg8h8m" +msgstr "显示踏步支撑" -# Source-Hash: b69fc1f8128958fc +# Source-Hash: 5d1147c774718b76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Appearance" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Side flashing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.appearance.dli9wf" -msgstr "外观" +msgid "editor.inspector.field.sideFlashing.cv744o" +msgstr "侧面泛水" -# Source-Hash: faaa4f6b40001667 +# Source-Hash: 60bb3338e0ad558c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Body" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Size" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.body.ign4wl" -msgstr "主体" +msgid "editor.inspector.field.size.1a4x3zw" +msgstr "尺寸" -# Source-Hash: fdf7108a011bd94b +# Source-Hash: fbdbc6c97c75b030 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cab" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Skylight type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.cab.o4z1ox" -msgstr "轿厢" +msgid "editor.inspector.field.skylightType.1a5vj3i" +msgstr "天窗类型" -# Source-Hash: 5737c4567e0f6863 +# Source-Hash: c9a6561cb3c3da82 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab opening mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.cabinet.rzvymr" -msgstr "柜体" +msgid "editor.inspector.field.slabOpeningMode.g4f730" +msgstr "楼板开洞方式" -# Source-Hash: d52b53241789ee63 +# Source-Hash: ef0efc845ccdba78 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slat gap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.cap.s0thej" -msgstr "顶盖" +msgid "editor.inspector.field.slatGap.slmk93" +msgstr "叶片间隙" -# Source-Hash: 93a545688c917e69 +# Source-Hash: 4daab7a2ce2ecef3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collar" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slide direction" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.collar.1am2iqo" -msgstr "套环" +msgid "editor.inspector.field.slideDirection.1527q13" +msgstr "推拉方向" -# Source-Hash: 7a9c55b1c5a6e61d +# Source-Hash: 93b34a5b546664c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connection" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Span" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.connection.2r1h4p" -msgstr "连接" +msgid "editor.inspector.field.span.1bmmuw1" +msgstr "跨度" -# Source-Hash: d613df280aa13b42 +# Source-Hash: 3b006be0b1f0493f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connections" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Speed" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.connections.ai4w8u" -msgstr "连接" +msgid "editor.inspector.field.speed.2w2xwg" +msgstr "速度" -# Source-Hash: ce1429556f57d7ee +# Source-Hash: c8cfb8336a240cb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Construction" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spin speed" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.construction.j6p9kc" -msgstr "构造" +msgid "editor.inspector.field.spinSpeed.1ozx746" +msgstr "旋转速度" -# Source-Hash: f8ba7d73d3006d57 +# Source-Hash: c9f54c3b258961c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.cricket.6iwg8g" -msgstr "泛水坡" +msgid "editor.inspector.field.stairType.1u05e02" +msgstr "楼梯类型" -# Source-Hash: b8ff053666ee326b +# Source-Hash: 0af6194a8b8d8be6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curb" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standoff" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.curb.5xi2ol" -msgstr "路缘" +msgid "editor.inspector.field.standoff.4wv2g0" +msgstr "支脚" -# Source-Hash: 3b9c59e996dcc9c5 +# Source-Hash: 0464d4efa1e80c62 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curve points" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standoff height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.curvePoints.ztdcnn" -msgstr "曲线点" +msgid "editor.inspector.field.standoffHeight.1qdnff" +msgstr "支脚高度" -# Source-Hash: 12df69f42beb0643 +# Source-Hash: 85da28b0b26b8c2a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start post" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.dimensions.pewa8g" -msgstr "尺寸" +msgid "editor.inspector.field.startPost.1ood9kv" +msgstr "起始柱" -# Source-Hash: 20f60b98de67849b +# Source-Hash: d5dc1ba8cca3193d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Doors" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Step count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.doors.18w2kpa" -msgstr "门" +msgid "editor.inspector.field.stepCount.nzorrw" +msgstr "踏步数" -# Source-Hash: 6b6f8068bbc4c902 +# Source-Hash: cadbb9cadd6a5e6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dormer" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Strap spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.dormer.1fjs5tq" -msgstr "老虎窗" +msgid "editor.inspector.field.strapSpacing.1cyt3dc" +msgstr "吊带间距" -# Source-Hash: cda262793b4cc754 +# Source-Hash: c017cd56b3ae5865 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dormer roof" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Strap style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.dormerRoof.u9uy2g" -msgstr "老虎窗屋顶" +msgid "editor.inspector.field.strapStyle.fh1oy4" +msgstr "吊带样式" -# Source-Hash: 00a4416e0a33d856 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drainage" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.drainage.7easy0" -msgstr "排水" +msgid "editor.inspector.field.style.nf3vcm" +msgstr "样式" -# Source-Hash: 8a3bc5111b9e97f4 +# Source-Hash: 7b3f016989c631a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Suction diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.elevation.4jbp44" -msgstr "标高" +msgid "editor.inspector.field.suctionDiameter.nutxtj" +msgstr "吸气管直径" -# Source-Hash: a9cba06250228a55 +# Source-Hash: 3f1e0fd30e5b1f39 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End caps" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply diameter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.endCaps.4fsb5b" -msgstr "端盖" +msgid "editor.inspector.field.supplyDiameter.h5ldh5" +msgstr "送风直径" -# Source-Hash: 228f2206862e41cf +# Source-Hash: 05c9b608538e181d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equipment" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.equipment.1xtq0ev" -msgstr "设备" +msgid "editor.inspector.field.supplyHeight.zy6ru1" +msgstr "送风高度" -# Source-Hash: a19276baa3688cbf +# Source-Hash: 3c9400722baa474d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Face" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.face.1531fr0" -msgstr "面" +msgid "editor.inspector.field.supplyShape.k39wnb" +msgstr "送风形状" -# Source-Hash: fb34ee7c59cb84ac +# Source-Hash: af7619025438f995 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fitting" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.fitting.171z1r4" -msgstr "管件" +msgid "editor.inspector.field.supplyWidth.g66axi" +msgstr "送风宽度" -# Source-Hash: f817c09ef0bb6d69 +# Source-Hash: 617e198cf3f214d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flues" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Support offset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.flues.nq6pye" -msgstr "烟道" +msgid "editor.inspector.field.supportOffset.1w4cocr" +msgstr "支撑偏移" -# Source-Hash: a3c10560fa3c1612 +# Source-Hash: 2686abc093f3dfb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Footprint" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sweep angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.footprint.g8q2pg" -msgstr "基底" +msgid "editor.inspector.field.sweepAngle.ucmmlw" +msgstr "扫掠角度" -# Source-Hash: ce3a6c03765dbbd8 +# Source-Hash: 88e6c2e1c344b2fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.frame.q7q9fq" -msgstr "框架" +msgid "editor.inspector.field.system.13qbhrw" +msgstr "系统" -# Source-Hash: 523b9912e283b644 +# Source-Hash: ccb3afc48bd9a284 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Geometry" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terminal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.geometry.a21os1" -msgstr "几何" +msgid "editor.inspector.field.terminal.1501knl" +msgstr "风口" -# Source-Hash: 7e4a0a38f694be6b +# Source-Hash: de1777c521046f7d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terminal type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.grid.d8gwxd" -msgstr "网格" +msgid "editor.inspector.field.terminalType.1ne8lgb" +msgstr "风口类型" -# Source-Hash: 30d8dba84c42040e +# Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hangers" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.hangers.agnfzn" -msgstr "吊架" +msgid "editor.inspector.field.thickness.1l8hu45" +msgstr "厚度" -# Source-Hash: 8c1bc3a078056ff7 +# Source-Hash: 58cb60c14826f1d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hardware" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilt angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.hardware.1nygwm1" -msgstr "五金件" +msgid "editor.inspector.field.tiltAngle.1312yw1" +msgstr "倾斜角度" -# Source-Hash: 2a47557eb4a5f766 +# Source-Hash: 7057972ff4c78dc7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hung wall" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "To level id" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.hungWall.1ftr1gz" -msgstr "悬挂墙" +msgid "editor.inspector.field.toLevelId.8i5qx7" +msgstr "目标楼层 ID" -# Source-Hash: 7d6ed24c02ab0c5c +# Source-Hash: fa8fc3d5c612e774 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Insulation" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top landing depth" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.insulation.1kyo5e7" -msgstr "保温层" +msgid "editor.inspector.field.topLandingDepth.ki7gk2" +msgstr "顶部平台深度" -# Source-Hash: d4c6c2495c233bb5 +# Source-Hash: 6e4a0b98089ec2cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top landing mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.lantern.1h7o2xb" -msgstr "灯笼" +msgid "editor.inspector.field.topLandingMode.zk0h7e" +msgstr "顶部平台方式" -# Source-Hash: cc3d601d59e2e26c +# Source-Hash: c182bb3c8a701085 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Levels" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top rail height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.levels.1s6yaru" -msgstr "楼层" +msgid "editor.inspector.field.topRailHeight.fscisv" +msgstr "顶部横杆高度" -# Source-Hash: 1a849e52a46d5087 +# Source-Hash: 8c5502f1d8087b7b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Line" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transition mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.line.166mv5z" -msgstr "线" +msgid "editor.inspector.field.transitionMode.f3evgt" +msgstr "过渡方式" -# Source-Hash: 9ab4f7a738ebee13 +# Source-Hash: 96eb5997f0aa2dde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lines" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transition width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.lines.12bghr0" -msgstr "线" +msgid "editor.inspector.field.transitionWidth.rtgz3m" +msgstr "过渡宽度" -# Source-Hash: c0ff16d77ebc9593 +# Source-Hash: 812d27902509339f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Motion" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vane count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.motion.1be7sjr" -msgstr "运动" +msgid "editor.inspector.field.vaneCount.55vtye" +msgstr "叶片数" -# Source-Hash: 81d365ccef73068c +# Source-Hash: 1e7dcd717c8ac239 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.mounting.feutd2" -msgstr "安装方式" +msgid "editor.inspector.field.wallHeight.18vmh5c" +msgstr "墙高" -# Source-Hash: e04298381837252f +# Source-Hash: f14bdaed6101896a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall shell" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.opening.dfet3" -msgstr "开口" +msgid "editor.inspector.field.wallShell.vqsyhv" +msgstr "墙体外壳" -# Source-Hash: f46314c54627858d +# Source-Hash: 801268585c9a679b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel dimensions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall skirt height" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.panelDimensions.b59qe6" -msgstr "面板尺寸" - -# Source-Hash: 4712c449e9a42d3b +msgid "editor.inspector.field.wallSkirtHeight.1uea2ad" +msgstr "墙裙高度" + +# Source-Hash: 6b377d0ba1565477 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pattern distribution" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall thickness" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.patternDistribution.fmam51" -msgstr "图案分布" +msgid "editor.inspector.field.wallThickness.17wn4iv" +msgstr "墙厚" -# Source-Hash: b3be684ac62fbf53 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.placement.13lcvts" -msgstr "放置" +msgid "editor.inspector.field.width.gfxz9b" +msgstr "宽度" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: de05070474f589b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width2" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.position.1quewx6" -msgstr "位置" +msgid "editor.inspector.field.width2.1nqawvr" +msgstr "宽度 2" -# Source-Hash: 96ad4bd0f7baa40e +# Source-Hash: 6199b641888a83fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "With back" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.profile.1kwlci6" -msgstr "轮廓" +msgid "editor.inspector.field.withBack.1ay8nus" +msgstr "带背板" -# Source-Hash: 240ed9c77627b9a1 +# Source-Hash: 699934d8b9571b64 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "With bottom" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.railing.19a5bnr" -msgstr "栏杆" +msgid "editor.inspector.field.withBottom.1x1z1vo" +msgstr "带底板" -# Source-Hash: 2e0aa7113b021c67 +# Source-Hash: 03987b9aadaab50f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "With sides" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.return.1klrjrz" -msgstr "回风" +msgid "editor.inspector.field.withSides.uq066x" +msgstr "带侧板" -# Source-Hash: 83909f82446ee9c3 +# Source-Hash: f571cb2d06ae01ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Settings" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Advanced" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.settings.ktdb8o" -msgstr "设置" +msgid "editor.inspector.group.advanced.qwfkor" +msgstr "高级" -# Source-Hash: 4fc63ad21de30103 +# Source-Hash: a886619d15bae47e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Air" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.shaft.mad9cv" -msgstr "井道" +msgid "editor.inspector.group.air.15jotdj" +msgstr "空气" -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: b69fc1f8128958fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Appearance" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.shape.iq9t52" -msgstr "形状" +msgid "editor.inspector.group.appearance.dli9wf" +msgstr "外观" -# Source-Hash: 8c6e3985459dacf9 +# Source-Hash: faaa4f6b40001667 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Body" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.shoulder.1nyfx25" -msgstr "肩部" +msgid "editor.inspector.group.body.ign4wl" +msgstr "主体" -# Source-Hash: 60bb3338e0ad558c +# Source-Hash: fdf7108a011bd94b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Size" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cab" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.size.1a4x3zw" -msgstr "尺寸" +msgid "editor.inspector.group.cab.o4z1ox" +msgstr "轿厢" -# Source-Hash: a20c89205a4448d2 +# Source-Hash: 5737c4567e0f6863 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.structure.gezdra" -msgstr "结构" +msgid "editor.inspector.group.cabinet.rzvymr" +msgstr "柜体" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: d52b53241789ee63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.style.nf3vcm" -msgstr "样式" +msgid "editor.inspector.group.cap.s0thej" +msgstr "顶盖" -# Source-Hash: b45f382a67d6c0eb +# Source-Hash: 93a545688c917e69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collar" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.supply.1oy2zwu" -msgstr "送风" +msgid "editor.inspector.group.collar.1am2iqo" +msgstr "套环" -# Source-Hash: 78a454b7ac7a3cd9 +# Source-Hash: 7a9c55b1c5a6e61d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connection" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.surface.wtamqk" -msgstr "表面" +msgid "editor.inspector.group.connection.2r1h4p" +msgstr "连接" -# Source-Hash: ccb3afc48bd9a284 +# Source-Hash: d613df280aa13b42 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terminal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connections" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.terminal.1501knl" -msgstr "风口" +msgid "editor.inspector.group.connections.ai4w8u" +msgstr "连接" -# Source-Hash: 399fc3e62f491f08 +# Source-Hash: ce1429556f57d7ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Topology" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Construction" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.topology.18t8dyc" -msgstr "拓扑" +msgid "editor.inspector.group.construction.j6p9kc" +msgstr "构造" -# Source-Hash: f425799b82e085ed +# Source-Hash: f8ba7d73d3006d57 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transform" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.transform.1c55ayj" -msgstr "变换" +msgid "editor.inspector.group.cricket.6iwg8g" +msgstr "泛水坡" -# Source-Hash: b778a315e82065a0 +# Source-Hash: b8ff053666ee326b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curb" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.trap.1qc7vhe" -msgstr "存水弯" +msgid "editor.inspector.group.curb.5xi2ol" +msgstr "路缘" -# Source-Hash: c44f7ab8bbd24858 +# Source-Hash: 3b9c59e996dcc9c5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curve points" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.group.type.1m2zofh" -msgstr "类型" +msgid "editor.inspector.group.curvePoints.ztdcnn" +msgstr "曲线点" -# Source-Hash: c8fd17853839516f +# Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Abs" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.abs.132mz8b" -msgstr "ABS" +msgid "editor.inspector.group.dimensions.pewa8g" +msgstr "尺寸" -# Source-Hash: fd9eb1a16cb6b996 +# Source-Hash: 20f60b98de67849b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Access panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Doors" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.accessPanel.13sptb5" -msgstr "检修口" +msgid "editor.inspector.group.doors.18w2kpa" +msgstr "门" -# Source-Hash: db8064add8c27a5c +# Source-Hash: 6b6f8068bbc4c902 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Air handler" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dormer" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.airHandler.1crnyg3" -msgstr "空气处理机" +msgid "editor.inspector.group.dormer.1fjs5tq" +msgstr "老虎窗" -# Source-Hash: d8234782848be927 +# Source-Hash: cda262793b4cc754 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Alternating" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dormer roof" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.alternating.5jashi" -msgstr "交替" +msgid "editor.inspector.group.dormerRoof.u9uy2g" +msgstr "老虎窗屋顶" -# Source-Hash: 63cbda7b09662368 +# Source-Hash: 00a4416e0a33d856 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arched" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drainage" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.arched.14188w0" -msgstr "拱形" +msgid "editor.inspector.group.drainage.7easy0" +msgstr "排水" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: 8a3bc5111b9e97f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.auto.540b06" -msgstr "自动" +msgid "editor.inspector.group.elevation.4jbp44" +msgstr "标高" -# Source-Hash: d18036b75b2c3e4f +# Source-Hash: a9cba06250228a55 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Automatic" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End caps" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.automatic.r122ro" -msgstr "自动" +msgid "editor.inspector.group.endCaps.4fsb5b" +msgstr "端盖" -# Source-Hash: 7ceade8f25b58fe9 +# Source-Hash: 228f2206862e41cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equipment" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.back.1hzmxtu" -msgstr "返回" +msgid "editor.inspector.group.equipment.1xtq0ev" +msgstr "设备" -# Source-Hash: 3eda29328f91485d +# Source-Hash: a19276baa3688cbf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Balusters" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Face" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.balusters.1j3w6ng" -msgstr "栏杆柱" +msgid "editor.inspector.group.face.1531fr0" +msgstr "面" -# Source-Hash: f211248ec8619e4c +# Source-Hash: fb34ee7c59cb84ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Band" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fitting" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.band.160umau" -msgstr "腰线" +msgid "editor.inspector.group.fitting.171z1r4" +msgstr "管件" -# Source-Hash: 8f9ff05c6a3b08a6 +# Source-Hash: f817c09ef0bb6d69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base plate" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flues" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.basePlate.17fcg8k" -msgstr "底板" +msgid "editor.inspector.group.flues.nq6pye" +msgstr "烟道" -# Source-Hash: 19ae2360207ecf5a +# Source-Hash: a3c10560fa3c1612 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Boards" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Footprint" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.boards.u14hig" -msgstr "木板" +msgid "editor.inspector.group.footprint.g8q2pg" +msgstr "基底" -# Source-Hash: c0fee00bdfb09d37 +# Source-Hash: ce3a6c03765dbbd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bookshelf" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.bookshelf.ls0zqk" -msgstr "书架" +msgid "editor.inspector.group.frame.q7q9fq" +msgstr "框架" -# Source-Hash: 69578b7dd7723fa1 +# Source-Hash: 523b9912e283b644 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Both" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Geometry" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.both.mkyb42" -msgstr "两侧" +msgid "editor.inspector.group.geometry.a21os1" +msgstr "几何" -# Source-Hash: b3a163b453896bef +# Source-Hash: 7e4a0a38f694be6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.bottom.9mpruy" -msgstr "底部" +msgid "editor.inspector.group.grid.d8gwxd" +msgstr "网格" -# Source-Hash: e9a89a5e4ac8cd61 +# Source-Hash: 30d8dba84c42040e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hangers" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.box.1nbjcuq" -msgstr "盒形" +msgid "editor.inspector.group.hangers.agnfzn" +msgstr "吊架" -# Source-Hash: 2c2815df4f724abe +# Source-Hash: 8c1bc3a078056ff7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Break" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hardware" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.break.17spnvc" -msgstr "断开" +msgid "editor.inspector.group.hardware.1nygwm1" +msgstr "五金件" -# Source-Hash: 0d5a25303d3d8058 +# Source-Hash: 2a47557eb4a5f766 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Butterfly" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hung wall" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.butterfly.pvv0g4" -msgstr "蝶形" +msgid "editor.inspector.group.hungWall.1ftr1gz" +msgstr "悬挂墙" -# Source-Hash: 5e2429ced8144ab4 +# Source-Hash: 7d6ed24c02ab0c5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cable" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cable.fp50zq" -msgstr "钢索" +msgid "editor.inspector.group.insulation.1kyo5e7" +msgstr "保温层" -# Source-Hash: 69129e514347672a +# Source-Hash: d4c6c2495c233bb5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cast iron" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.castIron.1q2z4qk" -msgstr "铸铁" +msgid "editor.inspector.group.lantern.1h7o2xb" +msgstr "灯笼" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: cc3d601d59e2e26c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Levels" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.ceiling.1t2zaqo" -msgstr "天花板" +msgid "editor.inspector.group.levels.1s6yaru" +msgstr "楼层" -# Source-Hash: 5211341ed18f33f6 +# Source-Hash: 1a849e52a46d5087 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Line" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.center.kzdxno" -msgstr "居中" +msgid "editor.inspector.group.line.166mv5z" +msgstr "线" -# Source-Hash: 65f410261609060b +# Source-Hash: 9ab4f7a738ebee13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center opening" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lines" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.centerOpening.bn1rvw" -msgstr "中开" +msgid "editor.inspector.group.lines.12bghr0" +msgstr "线" -# Source-Hash: cf5f9756cc866f3e +# Source-Hash: c0ff16d77ebc9593 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cleanout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Motion" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cleanout.lww8bm" -msgstr "清扫口" +msgid "editor.inspector.group.motion.1be7sjr" +msgstr "运动" -# Source-Hash: e71d1d949f1d1b41 +# Source-Hash: 81d365ccef73068c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Concrete pad" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.concretePad.m1zdij" -msgstr "混凝土垫层" +msgid "editor.inspector.group.mounting.feutd2" +msgstr "安装方式" -# Source-Hash: a3804c4f5e6aefbc +# Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Condenser" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.condenser.a74nps" -msgstr "冷凝器" +msgid "editor.inspector.group.opening.dfet3" +msgstr "开口" -# Source-Hash: 6786ac75cbe9af57 +# Source-Hash: f46314c54627858d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corbeled" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel dimensions" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.corbeled.bovs4v" -msgstr "叠涩" +msgid "editor.inspector.group.panelDimensions.b59qe6" +msgstr "面板尺寸" -# Source-Hash: 8a4beb9a57edc26e +# Source-Hash: 4712c449e9a42d3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pattern distribution" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.count.1qoi4r8" -msgstr "数量" +msgid "editor.inspector.group.patternDistribution.fmam51" +msgstr "图案分布" -# Source-Hash: db1f8f141714b363 +# Source-Hash: b3be684ac62fbf53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Coupling" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.coupling.111aap2" -msgstr "管接头" +msgid "editor.inspector.group.placement.13lcvts" +msgstr "放置" -# Source-Hash: 7a9a92d2e59a3bbc +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Covering specific" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.coveringSpecific.1h9fo8w" -msgstr "覆盖层细节" +msgid "editor.inspector.group.position.1quewx6" +msgstr "位置" -# Source-Hash: d500c4b7827d3390 +# Source-Hash: 96ad4bd0f7baa40e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cross" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cross.1elubzv" -msgstr "十字" +msgid "editor.inspector.group.profile.1kwlci6" +msgstr "轮廓" -# Source-Hash: 7ca7f00b3ba531f4 +# Source-Hash: 240ed9c77627b9a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cubby" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cubby.ivq4qc" -msgstr "储物格" +msgid "editor.inspector.group.railing.19a5bnr" +msgstr "栏杆" -# Source-Hash: a028e08962c388e0 +# Source-Hash: 2e0aa7113b021c67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curved" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.curved.6noz1s" -msgstr "弧形" +msgid "editor.inspector.group.return.1klrjrz" +msgstr "回风" -# Source-Hash: c65f02bcdc3231d6 +# Source-Hash: 83909f82446ee9c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cylinder" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Settings" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.cylinder.eol6vj" -msgstr "圆柱" +msgid "editor.inspector.group.settings.ktdb8o" +msgstr "设置" -# Source-Hash: 53f224e2828d5ab7 +# Source-Hash: 4fc63ad21de30103 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Damper" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.damper.wgri80" -msgstr "风阀" +msgid "editor.inspector.group.shaft.mad9cv" +msgstr "井道" -# Source-Hash: 748877ae309c313c +# Source-Hash: 85ea1d3c8b749680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Destination" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.destination.gfzm1r" -msgstr "目标" +msgid "editor.inspector.group.shape.iq9t52" +msgstr "形状" -# Source-Hash: bfb3561e28d92a39 +# Source-Hash: 8c6e3985459dacf9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diffuser" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.diffuser.1igj0jh" -msgstr "散流器" +msgid "editor.inspector.group.shoulder.1nyfx25" +msgstr "肩部" -# Source-Hash: 6cff941e10ff22b3 +# Source-Hash: 60bb3338e0ad558c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dog ear" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Size" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.dogEar.xhtvjt" -msgstr "切角" +msgid "editor.inspector.group.size.1a4x3zw" +msgstr "尺寸" -# Source-Hash: de47e23eb81efe02 +# Source-Hash: a20c89205a4448d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dome" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.dome.1c87e56" -msgstr "穹顶" +msgid "editor.inspector.group.structure.gezdra" +msgstr "结构" -# Source-Hash: 3cd71355956a1821 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.double.13h5354" -msgstr "双扇" +msgid "editor.inspector.group.style.nf3vcm" +msgstr "样式" -# Source-Hash: 72a84a9762461745 +# Source-Hash: b45f382a67d6c0eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct board" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.ductBoard.lc3o4t" -msgstr "风管板" +msgid "editor.inspector.group.supply.1oy2zwu" +msgstr "送风" -# Source-Hash: 6949d667043bee0b +# Source-Hash: 78a454b7ac7a3cd9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.dutch.1djx429" -msgstr "荷兰式" +msgid "editor.inspector.group.surface.wtamqk" +msgstr "表面" -# Source-Hash: e6637bddef6aabd6 +# Source-Hash: ccb3afc48bd9a284 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elbow" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terminal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.elbow.1flup74" -msgstr "弯头" +msgid "editor.inspector.group.terminal.1501knl" +msgstr "风口" -# Source-Hash: 135874d189176d13 +# Source-Hash: 399fc3e62f491f08 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Topology" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.end.1llf32i" -msgstr "终点" +msgid "editor.inspector.group.topology.18t8dyc" +msgstr "拓扑" -# Source-Hash: ada9fc2eec2c7d61 +# Source-Hash: f425799b82e085ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End cap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transform" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.endCap.1p4v4na" -msgstr "端盖" +msgid "editor.inspector.group.transform.1c55ayj" +msgstr "变换" -# Source-Hash: 73916b8395208874 +# Source-Hash: b778a315e82065a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equal fit" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.equalFit.11vw52c" -msgstr "均匀适配" +msgid "editor.inspector.group.trap.1qc7vhe" +msgstr "存水弯" -# Source-Hash: 83579a6e420df2ec +# Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fixed count" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.fixedCount.1o3dznu" -msgstr "固定数量" +msgid "editor.inspector.group.type.1m2zofh" +msgstr "类型" -# Source-Hash: 4fb65101d0b1a222 +# Source-Hash: c8fd17853839516f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fixed spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Abs" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.fixedSpacing.hl4dr4" -msgstr "固定间距" +msgid "editor.inspector.option.abs.132mz8b" +msgstr "ABS" -# Source-Hash: 9cab4d4c95f63cdd +# Source-Hash: fd9eb1a16cb6b996 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Access panel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.flat.ly0bei" -msgstr "平屋顶" +msgid "editor.inspector.option.accessPanel.13sptb5" +msgstr "检修口" -# Source-Hash: a9cad0badcc16693 +# Source-Hash: db8064add8c27a5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flex" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Air handler" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.flex.ktpamq" -msgstr "软管" +msgid "editor.inspector.option.airHandler.1crnyg3" +msgstr "空气处理机" -# Source-Hash: 7843c5142b7d066d +# Source-Hash: d8234782848be927 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floating" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Alternating" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.floating.1oadpln" -msgstr "悬浮" +msgid "editor.inspector.option.alternating.5jashi" +msgstr "交替" -# Source-Hash: d7148fa065bc709b +# Source-Hash: 63cbda7b09662368 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arched" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.floor.q9caf1" -msgstr "楼层" +msgid "editor.inspector.option.arched.14188w0" +msgstr "拱形" -# Source-Hash: eaaa20f3b603140f +# Source-Hash: 05b65242d8c48791 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flush" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.flush.olwwu5" -msgstr "齐平" +msgid "editor.inspector.option.auto.540b06" +msgstr "自动" -# Source-Hash: e360f89d3c0ec456 +# Source-Hash: d18036b75b2c3e4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Automatic" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.front.uhugl4" -msgstr "前" +msgid "editor.inspector.option.automatic.r122ro" +msgstr "自动" -# Source-Hash: bccfc0565157dae6 +# Source-Hash: 7ceade8f25b58fe9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Furnace" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.furnace.w0mzpf" -msgstr "暖风炉" +msgid "editor.inspector.option.back.1hzmxtu" +msgstr "返回" -# Source-Hash: deaffa095d126dfe +# Source-Hash: 3eda29328f91485d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Balusters" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.gable.1ekyx6" -msgstr "双坡" +msgid "editor.inspector.option.balusters.1j3w6ng" +msgstr "栏杆柱" -# Source-Hash: 7f53d9ffca39984a +# Source-Hash: f211248ec8619e4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Band" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.gambrel.1yo90d9" -msgstr "复折式" +msgid "editor.inspector.option.band.160umau" +msgstr "腰线" -# Source-Hash: 3c4900155c96b139 +# Source-Hash: 8f9ff05c6a3b08a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Generic" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base plate" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.generic.1074oey" -msgstr "通用" +msgid "editor.inspector.option.basePlate.17fcg8k" +msgstr "底板" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: 19ae2360207ecf5a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Boards" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.glass.163tc5n" -msgstr "玻璃" +msgid "editor.inspector.option.boards.u14hig" +msgstr "木板" -# Source-Hash: 88810658a2b97bc6 +# Source-Hash: c0fee00bdfb09d37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass frame" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bookshelf" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.glassFrame.jp9s3m" -msgstr "玻璃框" +msgid "editor.inspector.option.bookshelf.ls0zqk" +msgstr "书架" -# Source-Hash: 2d4223f80dc3945c +# Source-Hash: 69578b7dd7723fa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Globe" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Both" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.globe.1avkqoy" -msgstr "球形" +msgid "editor.inspector.option.both.mkyb42" +msgstr "两侧" -# Source-Hash: 398af4f45ba60c85 +# Source-Hash: b3a163b453896bef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grounded" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.grounded.jwoq73" -msgstr "落地" +msgid "editor.inspector.option.bottom.9mpruy" +msgstr "底部" -# Source-Hash: 4972a0e68d69be58 +# Source-Hash: e9a89a5e4ac8cd61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guard" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.guard.1m575se" -msgstr "护栏" +msgid "editor.inspector.option.box.1nbjcuq" +msgstr "盒形" -# Source-Hash: 67be98efb58a7767 +# Source-Hash: 2c2815df4f724abe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Half round" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Break" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.halfRound.m5hob0" -msgstr "半圆" +msgid "editor.inspector.option.break.17spnvc" +msgstr "断开" -# Source-Hash: 229199467e9cf2db +# Source-Hash: 0d5a25303d3d8058 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hidden" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Butterfly" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.hidden.gp48rd" -msgstr "隐藏" +msgid "editor.inspector.option.butterfly.pvv0g4" +msgstr "蝶形" -# Source-Hash: 9eda0ea8d447066d +# Source-Hash: 5e2429ced8144ab4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hip" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cable" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.hip.r0jnjy" -msgstr "四坡" +msgid "editor.inspector.option.cable.fp50zq" +msgstr "钢索" -# Source-Hash: ac9c79f08ef130a1 +# Source-Hash: 69129e514347672a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Horizontal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cast iron" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.horizontal.tyapah" -msgstr "水平" +msgid "editor.inspector.option.castIron.1q2z4qk" +msgstr "铸铁" -# Source-Hash: 6a9b4142ab179557 +# Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Include" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.include.1a27vnr" -msgstr "包含" +msgid "editor.inspector.option.ceiling.1t2zaqo" +msgstr "天花板" -# Source-Hash: 8061b426b9d1b5fa +# Source-Hash: 5211341ed18f33f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Independent high beam" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.independentHighBeam.1tn0zvy" -msgstr "独立高梁" +msgid "editor.inspector.option.center.kzdxno" +msgstr "居中" -# Source-Hash: 1dc686f2068f976b +# Source-Hash: 65f410261609060b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Industrial" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center opening" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.industrial.8sd9u" -msgstr "工业风" +msgid "editor.inspector.option.centerOpening.bn1rvw" +msgstr "中开" -# Source-Hash: 0c9b1ec8947ee177 +# Source-Hash: cf5f9756cc866f3e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inline" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cleanout" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.inline.1uh05lg" -msgstr "直线" +msgid "editor.inspector.option.cleanout.lww8bm" +msgstr "清扫口" -# Source-Hash: 88d5b9ecb242c650 +# Source-Hash: e71d1d949f1d1b41 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Integrated" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Concrete pad" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.integrated.1xd9lv0" -msgstr "一体式" +msgid "editor.inspector.option.concretePad.m1zdij" +msgstr "混凝土垫层" -# Source-Hash: bb197b9219f32603 +# Source-Hash: a3804c4f5e6aefbc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Joined" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Condenser" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.joined.1x2o8ds" -msgstr "已合并" +msgid "editor.inspector.option.condenser.a74nps" +msgstr "冷凝器" -# Source-Hash: 0299cc0ee05d17fc +# Source-Hash: 6786ac75cbe9af57 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kickout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corbeled" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.kickout.vt8s6p" -msgstr "导水板" +msgid "editor.inspector.option.corbeled.bovs4v" +msgstr "叠涩" -# Source-Hash: a0712c8461bb0758 +# Source-Hash: 8a4beb9a57edc26e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Knee" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.knee.186hcui" -msgstr "膝墙" +msgid "editor.inspector.option.count.1qoi4r8" +msgstr "数量" -# Source-Hash: 083febe9876348ec +# Source-Hash: db1f8f141714b363 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "K style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Coupling" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.kStyle.m8kfwz" -msgstr "K 型" +msgid "editor.inspector.option.coupling.111aap2" +msgstr "管接头" -# Source-Hash: de9566487b17a73b +# Source-Hash: 7a9a92d2e59a3bbc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Covering specific" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.landing.tyqarg" -msgstr "平台" +msgid "editor.inspector.option.coveringSpecific.1h9fo8w" +msgstr "覆盖层细节" -# Source-Hash: d4c6c2495c233bb5 +# Source-Hash: d500c4b7827d3390 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cross" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.lantern.1h7o2xb" -msgstr "灯笼" +msgid "editor.inspector.option.cross.1elubzv" +msgstr "十字" -# Source-Hash: 9477f663422698ae +# Source-Hash: 7ca7f00b3ba531f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Leave" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cubby" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.leave.1xf0sbk" -msgstr "离开" +msgid "editor.inspector.option.cubby.ivq4qc" +msgstr "储物格" -# Source-Hash: f365c6b6dd9ebab9 +# Source-Hash: a028e08962c388e0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curved" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.left.14n06mo" -msgstr "左" +msgid "editor.inspector.option.curved.6noz1s" +msgstr "弧形" -# Source-Hash: 0608743fc1736d86 +# Source-Hash: c65f02bcdc3231d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cylinder" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.level.i4lhtp" -msgstr "楼层" +msgid "editor.inspector.option.cylinder.eol6vj" +msgstr "圆柱" -# Source-Hash: a281a83a9fef6b88 +# Source-Hash: 53f224e2828d5ab7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low profile" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Damper" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.lowProfile.1h9lgzg" -msgstr "低矮型" +msgid "editor.inspector.option.damper.wgri80" +msgstr "风阀" -# Source-Hash: 7f7bb0e875af3260 +# Source-Hash: 748877ae309c313c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Destination" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.mansard.dwzck9" -msgstr "孟莎式" +msgid "editor.inspector.option.destination.gfzm1r" +msgstr "目标" -# Source-Hash: 387082cd5f118bed +# Source-Hash: bfb3561e28d92a39 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Manual" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diffuser" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.manual.1wu7r43" -msgstr "手动" +msgid "editor.inspector.option.diffuser.1igj0jh" +msgstr "散流器" -# Source-Hash: 321ca5101ab61db7 +# Source-Hash: 6cff941e10ff22b3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Maximum spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dog ear" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.maximumSpacing.n1fzl4" -msgstr "最大间距" +msgid "editor.inspector.option.dogEar.xhtvjt" +msgstr "切角" -# Source-Hash: 8e464a8f52254f27 +# Source-Hash: de47e23eb81efe02 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Metal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dome" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.metal.1az9fgc" -msgstr "金属" +msgid "editor.inspector.option.dome.1c87e56" +msgstr "穹顶" -# Source-Hash: c6185ecb219a9435 +# Source-Hash: 3cd71355956a1821 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Metal panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.metalPanel.1xdz476" -msgstr "金属板" +msgid "editor.inspector.option.double.13h5354" +msgstr "双扇" -# Source-Hash: 2fd92342f3986843 +# Source-Hash: 72a84a9762461745 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Minimal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct board" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.minimal.fwmiwg" -msgstr "极简" +msgid "editor.inspector.option.ductBoard.lc3o4t" +msgstr "风管板" -# Source-Hash: 5d8a5912056f83ce +# Source-Hash: 6949d667043bee0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mono" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.mono.oszvd6" -msgstr "单坡" +msgid "editor.inspector.option.dutch.1djx429" +msgstr "荷兰式" -# Source-Hash: f2953d2931e36d0c +# Source-Hash: e6637bddef6aabd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elbow" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.none.deku7v" -msgstr "无" +msgid "editor.inspector.option.elbow.1flup74" +msgstr "弯头" -# Source-Hash: 7b6e4a6b86ba5112 +# Source-Hash: 135874d189176d13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Omit" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.omit.okcs7w" -msgstr "省略" +msgid "editor.inspector.option.end.1llf32i" +msgstr "终点" -# Source-Hash: 3e52f04f92e08070 +# Source-Hash: ada9fc2eec2c7d61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End cap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.open.n6hn1l" -msgstr "打开" +msgid "editor.inspector.option.endCap.1p4v4na" +msgstr "端盖" -# Source-Hash: e04298381837252f +# Source-Hash: 73916b8395208874 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equal fit" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.opening.dfet3" -msgstr "开口" +msgid "editor.inspector.option.equalFit.11vw52c" +msgstr "均匀适配" -# Source-Hash: cc72b9bda6b30b5c +# Source-Hash: 83579a6e420df2ec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open rack" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fixed count" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.openRack.mvt1x0" -msgstr "开放式架" +msgid "editor.inspector.option.fixedCount.1o3dznu" +msgstr "固定数量" -# Source-Hash: ed6d7b3dd9d5fc69 +# Source-Hash: 4fb65101d0b1a222 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Oval" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fixed spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.oval.1jiqzxx" -msgstr "椭圆" +msgid "editor.inspector.option.fixedSpacing.hl4dr4" +msgstr "固定间距" -# Source-Hash: 9295ddc2805b21e2 +# Source-Hash: 9cab4d4c95f63cdd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.picket.zyeoy1" -msgstr "尖桩" - -# Source-Hash: 180ffb8b75c977aa +msgid "editor.inspector.option.flat.ly0bei" +msgstr "平屋顶" + +# Source-Hash: a9cad0badcc16693 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pointed" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flex" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.pointed.effedk" -msgstr "尖头" +msgid "editor.inspector.option.flex.ktpamq" +msgstr "软管" -# Source-Hash: fca7919fb0c0669c +# Source-Hash: 7843c5142b7d066d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post and rail" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floating" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.postAndRail.lajk2u" -msgstr "立柱与横杆" +msgid "editor.inspector.option.floating.1oadpln" +msgstr "悬浮" -# Source-Hash: a78b28a428b27e20 +# Source-Hash: d7148fa065bc709b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preserve high edge" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.preserveHighEdge.y6ywf0" -msgstr "保持高边" +msgid "editor.inspector.option.floor.q9caf1" +msgstr "楼层" -# Source-Hash: 325c6f53f6dc7634 +# Source-Hash: eaaa20f3b603140f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preserve low edge" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flush" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.preserveLowEdge.196m5pk" -msgstr "保持低边" +msgid "editor.inspector.option.flush.olwwu5" +msgstr "齐平" -# Source-Hash: 95c0b860d22a62cb +# Source-Hash: e360f89d3c0ec456 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preserve pitch" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.preservePitch.1uq973r" -msgstr "保持坡度" +msgid "editor.inspector.option.front.uhugl4" +msgstr "前" -# Source-Hash: d4e11841abf22593 +# Source-Hash: bccfc0565157dae6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Privacy" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Furnace" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.privacy.1th4hrb" -msgstr "私密" +msgid "editor.inspector.option.furnace.w0mzpf" +msgstr "暖风炉" -# Source-Hash: 1a8c46c7712a83b6 +# Source-Hash: deaffa095d126dfe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Purlins" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.purlins.od124c" -msgstr "檩条" +msgid "editor.inspector.option.gable.1ekyx6" +msgstr "双坡" -# Source-Hash: a9650f6f94de9247 +# Source-Hash: 7f53d9ffca39984a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pvc" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.pvc.1oc4u2w" -msgstr "PVC" +msgid "editor.inspector.option.gambrel.1yo90d9" +msgstr "复折式" -# Source-Hash: 47587b825e9a696b +# Source-Hash: 3c4900155c96b139 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pyramid" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Generic" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.pyramid.17ucsqv" -msgstr "金字塔形" +msgid "editor.inspector.option.generic.1074oey" +msgstr "通用" -# Source-Hash: a9cb232546779779 +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rafters" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.rafters.16tzbby" -msgstr "椽子" +msgid "editor.inspector.option.glass.163tc5n" +msgstr "玻璃" -# Source-Hash: 947eacd2689daced +# Source-Hash: 88810658a2b97bc6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rail" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass frame" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.rail.39zqc9" -msgstr "横杆" +msgid "editor.inspector.option.glassFrame.jp9s3m" +msgstr "玻璃框" -# Source-Hash: bd50bd18e682db41 +# Source-Hash: 2d4223f80dc3945c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Globe" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.raised.4kyx9h" -msgstr "抬高" +msgid "editor.inspector.option.globe.1avkqoy" +msgstr "球形" -# Source-Hash: 3b6f225112035fde +# Source-Hash: 398af4f45ba60c85 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rect" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grounded" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.rect.tpfvaf" -msgstr "矩形" +msgid "editor.inspector.option.grounded.jwoq73" +msgstr "落地" -# Source-Hash: 68206f70689b2340 +# Source-Hash: 4972a0e68d69be58 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reducer" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guard" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.reducer.18byt67" -msgstr "异径管" +msgid "editor.inspector.option.guard.1m575se" +msgstr "护栏" -# Source-Hash: 2e0aa7113b021c67 +# Source-Hash: 67be98efb58a7767 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Half round" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.return.1klrjrz" -msgstr "回风" +msgid "editor.inspector.option.halfRound.m5hob0" +msgstr "半圆" -# Source-Hash: 63b39b1681f74fe4 +# Source-Hash: 229199467e9cf2db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return grille" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hidden" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.returnGrille.r28ncm" -msgstr "回风格栅" +msgid "editor.inspector.option.hidden.gp48rd" +msgstr "隐藏" -# Source-Hash: b34d5ee0f218221d +# Source-Hash: 9eda0ea8d447066d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hip" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.right.8humpx" -msgstr "右" +msgid "editor.inspector.option.hip.r0jnjy" +msgstr "四坡" -# Source-Hash: ad0457800a1f0eb4 +# Source-Hash: ac9c79f08ef130a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Horizontal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.round.1vx0wyj" -msgstr "圆形" +msgid "editor.inspector.option.horizontal.tyapah" +msgstr "水平" -# Source-Hash: fc826da6c99303e6 +# Source-Hash: 6a9b4142ab179557 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rounded" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Include" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.rounded.199nwpm" -msgstr "圆角" +msgid "editor.inspector.option.include.1a27vnr" +msgstr "包含" -# Source-Hash: dc67a1cdb2482f23 +# Source-Hash: 8061b426b9d1b5fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sanitary tee" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Independent high beam" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.sanitaryTee.oro3d4" -msgstr "卫生三通" +msgid "editor.inspector.option.independentHighBeam.1tn0zvy" +msgstr "独立高梁" -# Source-Hash: beb3fec22c287185 +# Source-Hash: 1dc686f2068f976b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scalloped" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Industrial" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.scalloped.1eltba0" -msgstr "扇贝形" +msgid "editor.inspector.option.industrial.8sd9u" +msgstr "工业风" -# Source-Hash: e16f85e4bebfefb1 +# Source-Hash: 0c9b1ec8947ee177 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scoop" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inline" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.scoop.qy5zdv" -msgstr "勺形" +msgid "editor.inspector.option.inline.1uh05lg" +msgstr "直线" -# Source-Hash: f9a95d8407fafda4 +# Source-Hash: 88d5b9ecb242c650 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segmented panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Integrated" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.segmentedPanel.5r3hwl" -msgstr "分段面板" +msgid "editor.inspector.option.integrated.1xd9lv0" +msgstr "一体式" -# Source-Hash: c8d0df27faa3feaa +# Source-Hash: bb197b9219f32603 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Joined" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.shed.6t994v" -msgstr "单坡" +msgid "editor.inspector.option.joined.1x2o8ds" +msgstr "已合并" -# Source-Hash: 7fbc26cd497cfd12 +# Source-Hash: 0299cc0ee05d17fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sheet metal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kickout" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.sheetMetal.l164lv" -msgstr "金属板" +msgid "editor.inspector.option.kickout.vt8s6p" +msgstr "导水板" -# Source-Hash: 26e2c261223cbb46 +# Source-Hash: a0712c8461bb0758 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Knee" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.shingle.pfmynh" -msgstr "瓦片" +msgid "editor.inspector.option.knee.186hcui" +msgstr "膝墙" -# Source-Hash: e9046e9823b400a0 +# Source-Hash: 083febe9876348ec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingled" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "K style" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.shingled.1nm9inf" -msgstr "瓦片铺设" +msgid "editor.inspector.option.kStyle.m8kfwz" +msgstr "K 型" -# Source-Hash: a05a390ae205fdd8 +# Source-Hash: de9566487b17a73b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Simple" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.simple.12mfu73" -msgstr "简单" +msgid "editor.inspector.option.landing.tyqarg" +msgstr "平台" -# Source-Hash: 62ab2eb3c775da95 +# Source-Hash: d4c6c2495c233bb5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.single.1uzxurt" -msgstr "单扇" +msgid "editor.inspector.option.lantern.1h7o2xb" +msgstr "灯笼" -# Source-Hash: aee3b2bd78c87d0b +# Source-Hash: 9477f663422698ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single left" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Leave" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.singleLeft.1atdh02" -msgstr "单扇左开" +msgid "editor.inspector.option.leave.1xf0sbk" +msgstr "离开" -# Source-Hash: cc43ffbef4ac7ae0 +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single right" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.singleRight.1axbu67" -msgstr "单扇右开" +msgid "editor.inspector.option.left.14n06mo" +msgstr "左" -# Source-Hash: 7672d2764445c110 +# Source-Hash: 0608743fc1736d86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slant box" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.slantBox.1ta99vy" -msgstr "斜面盒" +msgid "editor.inspector.option.level.i4lhtp" +msgstr "楼层" -# Source-Hash: 405e07a8cc2c88e1 +# Source-Hash: a281a83a9fef6b88 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slat" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low profile" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.slat.1p9njbz" -msgstr "叶片" +msgid "editor.inspector.option.lowProfile.1h9lgzg" +msgstr "低矮型" -# Source-Hash: 18cbc73c5e1590aa +# Source-Hash: 7f7bb0e875af3260 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sliding" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.sliding.cd0jox" -msgstr "推拉门" +msgid "editor.inspector.option.mansard.dwzck9" +msgstr "孟莎式" -# Source-Hash: e6d82e606b8c9301 +# Source-Hash: 387082cd5f118bed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slope" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Manual" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.slope.1bn2qw" -msgstr "坡度" +msgid "editor.inspector.option.manual.1wu7r43" +msgstr "手动" -# Source-Hash: f6998707123fe72d +# Source-Hash: 321ca5101ab61db7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sloped" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Maximum spacing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.sloped.lo4sh0" -msgstr "倾斜" +msgid "editor.inspector.option.maximumSpacing.n1fzl4" +msgstr "最大间距" -# Source-Hash: ef3e765e692faf4c +# Source-Hash: 8e464a8f52254f27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Metal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.solid.o4uy6s" -msgstr "实体" +msgid "editor.inspector.option.metal.1az9fgc" +msgstr "金属" -# Source-Hash: 8008b6f17089beaf +# Source-Hash: c6185ecb219a9435 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Metal panel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.solidPanel.2yaw62" -msgstr "实板" +msgid "editor.inspector.option.metalPanel.1xdz476" +msgstr "金属板" -# Source-Hash: f9a4a870cb3d3c41 +# Source-Hash: 2fd92342f3986843 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spiral" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Minimal" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.spiral.91hcl4" -msgstr "螺旋" +msgid "editor.inspector.option.minimal.fwmiwg" +msgstr "极简" -# Source-Hash: beef1cf79388b77b +# Source-Hash: 5d8a5912056f83ce # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Splash" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mono" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.splash.1uke4cm" -msgstr "溅水板" +msgid "editor.inspector.option.mono.oszvd6" +msgstr "单坡" -# Source-Hash: 324677a79ab15e22 +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spread" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.spread.1g1zysu" -msgstr "展开" +msgid "editor.inspector.option.none.deku7v" +msgstr "无" -# Source-Hash: 39287346366fc206 +# Source-Hash: 7b6e4a6b86ba5112 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Omit" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.square.1xl1lk6" -msgstr "方形" +msgid "editor.inspector.option.omit.okcs7w" +msgstr "省略" -# Source-Hash: 53d7084bc41c1ad6 +# Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.stair.1xf86e" -msgstr "楼梯" +msgid "editor.inspector.option.open.n6hn1l" +msgstr "打开" -# Source-Hash: d998c212030bc7c2 +# Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.standard.vuco" -msgstr "标准" +msgid "editor.inspector.option.opening.dfet3" +msgstr "开口" -# Source-Hash: 0a26a1e61c825660 +# Source-Hash: cc72b9bda6b30b5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open rack" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.start.30xvgf" -msgstr "起点" +msgid "editor.inspector.option.openRack.mvt1x0" +msgstr "开放式架" -# Source-Hash: ed3989f23a2d185e +# Source-Hash: ed6d7b3dd9d5fc69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Step" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Oval" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.step.jtn9kf" -msgstr "台阶" +msgid "editor.inspector.option.oval.1jiqzxx" +msgstr "椭圆" -# Source-Hash: 2c6b1cf17a973d67 +# Source-Hash: 9295ddc2805b21e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stepped" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.stepped.naxzh0" -msgstr "阶梯式" +msgid "editor.inspector.option.picket.zyeoy1" +msgstr "尖桩" -# Source-Hash: 4ee35f740730ae87 +# Source-Hash: 180ffb8b75c977aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pointed" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.straight.lxqbfr" -msgstr "直跑" +msgid "editor.inspector.option.pointed.effedk" +msgstr "尖头" -# Source-Hash: b9b45ac5ba1daeee +# Source-Hash: fca7919fb0c0669c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Strap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post and rail" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.strap.14q0ps9" -msgstr "吊带" +msgid "editor.inspector.option.postAndRail.lajk2u" +msgstr "立柱与横杆" -# Source-Hash: b45f382a67d6c0eb +# Source-Hash: a78b28a428b27e20 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preserve high edge" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.supply.1oy2zwu" -msgstr "送风" +msgid "editor.inspector.option.preserveHighEdge.y6ywf0" +msgstr "保持高边" -# Source-Hash: 00e7a2b3b2aa36ac +# Source-Hash: 325c6f53f6dc7634 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Supply register" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preserve low edge" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.supplyRegister.1lzdbbn" -msgstr "送风口" +msgid "editor.inspector.option.preserveLowEdge.196m5pk" +msgstr "保持低边" -# Source-Hash: f86f1f22230596b7 +# Source-Hash: 95c0b860d22a62cb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tapered" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preserve pitch" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.tapered.3y5blo" -msgstr "锥形" +msgid "editor.inspector.option.preservePitch.1uq973r" +msgstr "保持坡度" -# Source-Hash: 5fed23c2217b83fb +# Source-Hash: d4e11841abf22593 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target spacing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Privacy" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.targetSpacing.14uibc9" -msgstr "目标间距" +msgid "editor.inspector.option.privacy.1th4hrb" +msgstr "私密" -# Source-Hash: f3ceed7f867f090f +# Source-Hash: 1a8c46c7712a83b6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tee" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Purlins" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.tee.7d6tjp" -msgstr "三通" +msgid "editor.inspector.option.purlins.od124c" +msgstr "檩条" -# Source-Hash: 787005b26aec58a3 +# Source-Hash: a9650f6f94de9247 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilted" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pvc" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.tilted.6n0u5j" -msgstr "倾斜" +msgid "editor.inspector.option.pvc.1oc4u2w" +msgstr "PVC" -# Source-Hash: 27644f0497fd9849 +# Source-Hash: 47587b825e9a696b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pyramid" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.top.2nypcs" -msgstr "顶部" +msgid "editor.inspector.option.pyramid.17ucsqv" +msgstr "金字塔形" -# Source-Hash: e6657000554dfe53 +# Source-Hash: a9cb232546779779 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transition" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafters" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.transition.1rziz9e" -msgstr "过渡" +msgid "editor.inspector.option.rafters.16tzbby" +msgstr "椽子" -# Source-Hash: 04bc0909a133a7e9 +# Source-Hash: 947eacd2689daced # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vent" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rail" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.vent.xda5j2" -msgstr "通风口" +msgid "editor.inspector.option.rail.39zqc9" +msgstr "横杆" -# Source-Hash: 7eee9aff0dd520b6 +# Source-Hash: bd50bd18e682db41 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walk on" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.walkOn.1n5sg9l" -msgstr "行走面" +msgid "editor.inspector.option.raised.4kyx9h" +msgstr "抬高" -# Source-Hash: 2210e5ee50b74dc9 +# Source-Hash: 3b6f225112035fde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rect" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wall.blj585" -msgstr "墙体" +msgid "editor.inspector.option.rect.tpfvaf" +msgstr "矩形" -# Source-Hash: f3578f7177ad0054 +# Source-Hash: 68206f70689b2340 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall abutment" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reducer" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wallAbutment.lza941" -msgstr "靠墙" +msgid "editor.inspector.option.reducer.18byt67" +msgstr "异径管" -# Source-Hash: 8dcf182f91ba3245 +# Source-Hash: 2e0aa7113b021c67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall ledger" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wallLedger.5m8ana" -msgstr "墙上托梁" +msgid "editor.inspector.option.return.1klrjrz" +msgstr "回风" -# Source-Hash: 0adda30be5f17975 +# Source-Hash: 63b39b1681f74fe4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall shelf" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return grille" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wallShelf.yiozfl" -msgstr "墙面搁板" +msgid "editor.inspector.option.returnGrille.r28ncm" +msgstr "回风格栅" -# Source-Hash: 29d8590334492601 +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waste" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.waste.3xrp79" -msgstr "排污" +msgid "editor.inspector.option.right.8humpx" +msgstr "右" -# Source-Hash: 00249876bb37079f +# Source-Hash: ad0457800a1f0eb4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wye" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.inspector.option.wye.14vupc8" -msgstr "Y 形三通" +msgid "editor.inspector.option.round.1vx0wyj" +msgstr "圆形" -# Source-Hash: 179b025e25f9a091 +# Source-Hash: fc826da6c99303e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collapse" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rounded" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.collapse" -msgstr "折叠" +msgid "editor.inspector.option.rounded.199nwpm" +msgstr "圆角" -# Source-Hash: dbeae4c43f49327f +# Source-Hash: dc67a1cdb2482f23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling ({area})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sanitary tee" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.ceiling" -msgstr "天花板({area})" +msgid "editor.inspector.option.sanitaryTee.oro3d4" +msgstr "卫生三通" -# Source-Hash: d29165c9d4bfc3cb +# Source-Hash: beb3fec22c287185 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collection" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scalloped" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.collection" -msgstr "集合" +msgid "editor.inspector.option.scalloped.1eltba0" +msgstr "扇贝形" -# Source-Hash: 8f536b859be662a0 +# Source-Hash: e16f85e4bebfefb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flight ({width}×{length}m)" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scoop" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.flight" -msgstr "梯段({width}×{length}m)" +msgid "editor.inspector.option.scoop.qy5zdv" +msgstr "勺形" -# Source-Hash: 46dcbf4548374073 +# Source-Hash: f9a95d8407fafda4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing ({width}×{length}m)" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segmented panel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.landing" -msgstr "平台({width}×{length}m)" +msgid "editor.inspector.option.segmentedPanel.5r3hwl" +msgstr "分段面板" -# Source-Hash: 3ea44453fcd08a6e +# Source-Hash: c8d0df27faa3feaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Node" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.node" -msgstr "节点" +msgid "editor.inspector.option.shed.6t994v" +msgstr "单坡" -# Source-Hash: 93f3a04e15b6fb49 +# Source-Hash: 7fbc26cd497cfd12 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof ({count, plural, one {# segment} other {# segments}})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sheet metal" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.roof" -msgstr "屋顶({count, plural, other {# 个分段}})" +msgid "editor.inspector.option.sheetMetal.l164lv" +msgstr "金属板" -# Source-Hash: a730fab01c172704 +# Source-Hash: 26e2c261223cbb46 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{roofType, select, hip {Hip} gable {Gable} shed {Shed} gambrel {Gambrel} dutch {Dutch} mansard {Mansard} flat {Flat} conical {Conical} barrel {Barrel} other {Roof}} ({width}×{depth}m)" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.roofSegment" -msgstr "{roofType, select, hip {四坡} gable {双坡} shed {单坡} gambrel {复折} dutch {歇山} mansard {孟莎} flat {平屋顶} conical {锥形} barrel {筒形} other {屋顶}}({width}×{depth}m)" +msgid "editor.inspector.option.shingle.pfmynh" +msgstr "瓦片" -# Source-Hash: 54efcb0756c2f2c1 +# Source-Hash: e9046e9823b400a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room ({area})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingled" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.room" -msgstr "房间({area})" +msgid "editor.inspector.option.shingled.1nm9inf" +msgstr "瓦片铺设" -# Source-Hash: e38a4b9986a9d21a +# Source-Hash: a05a390ae205fdd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab ({area})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Simple" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.slab" -msgstr "楼板({area})" +msgid "editor.inspector.option.simple.12mfu73" +msgstr "简单" -# Source-Hash: 57398365d4b9066f +# Source-Hash: 62ab2eb3c775da95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Staircase ({count, plural, one {# segment} other {# segments}})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.staircase" -msgstr "楼梯({count, plural, other {# 个分段}})" +msgid "editor.inspector.option.single.1uzxurt" +msgstr "单扇" -# Source-Hash: a17f8fc29aae896e +# Source-Hash: aee3b2bd78c87d0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone ({area})" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single left" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.defaultName.zone" -msgstr "区域({area})" +msgid "editor.inspector.option.singleLeft.1atdh02" +msgstr "单扇左开" -# Source-Hash: 5cabcabb8bc14809 +# Source-Hash: cc43ffbef4ac7ae0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Expand" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single right" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.expand" -msgstr "展开" +msgid "editor.inspector.option.singleRight.1axbu67" +msgstr "单扇右开" -# Source-Hash: 6731e9dd94e8b268 +# Source-Hash: 7672d2764445c110 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{levelName} options" -#: packages/editor/src/components/ui/floating-level-selector.tsx -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slant box" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.levelOptions" -msgstr "{levelName}选项" +msgid "editor.inspector.option.slantBox.1ta99vy" +msgstr "斜面盒" -# Source-Hash: d6952b4e54d246dd +# Source-Hash: 405e07a8cc2c88e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rename" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slat" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.rename" -msgstr "重命名" +msgid "editor.inspector.option.slat.1p9njbz" +msgstr "叶片" -# Source-Hash: 21eafa019ad62fea +# Source-Hash: 18cbc73c5e1590aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{role, select, room {Room colour} other {Zone colour}}" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx -#: packages/editor/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sliding" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.spaceColour" -msgstr "{role, select, room {房间颜色} other {区域颜色}}" +msgid "editor.inspector.option.sliding.cd0jox" +msgstr "推拉门" -# Source-Hash: f5de042416a2c04f +# Source-Hash: e6d82e606b8c9301 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unit colour" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slope" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.layers.unitColour" -msgstr "单元颜色" +msgid "editor.inspector.option.slope.1bn2qw" +msgstr "坡度" -# Source-Hash: c0774c185060fc13 +# Source-Hash: f6998707123fe72d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sloped" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.cancel" -msgstr "取消" +msgid "editor.inspector.option.sloped.lo4sh0" +msgstr "倾斜" -# Source-Hash: 07c11e7e4d4681d6 +# Source-Hash: ef3e765e692faf4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose what to copy from {levelName}." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.chooseWhatToCopyFromLevel" -msgstr "选择要从{levelName}复制的内容。" +msgid "editor.inspector.option.solid.o4uy6s" +msgstr "实体" -# Source-Hash: 9500d4378a319532 +# Source-Hash: 8008b6f17089beaf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose what to copy from this level." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid panel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.chooseWhatToCopyFromThisLevel" -msgstr "选择要从此楼层复制的内容。" +msgid "editor.inspector.option.solidPanel.2yaw62" +msgstr "实板" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: f9a4a870cb3d3c41 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spiral" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.duplicate" -msgstr "复制" +msgid "editor.inspector.option.spiral.91hcl4" +msgstr "螺旋" -# Source-Hash: a56e3eb43e60b45c +# Source-Hash: beef1cf79388b77b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate Level" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Splash" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.duplicateLevel" -msgstr "复制楼层" +msgid "editor.inspector.option.splash.1uke4cm" +msgstr "溅水板" -# Source-Hash: e4c6ab1ea473a082 +# Source-Hash: 324677a79ab15e22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Everything" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spread" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.everything" -msgstr "全部" +msgid "editor.inspector.option.spread.1g1zysu" +msgstr "展开" -# Source-Hash: ac3f119e560388ab +# Source-Hash: 39287346366fc206 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure, finishes, and placed items, without guide references." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureFinishesAndPlacedItemsWithout" -msgstr "结构、饰面和已放置的物品,不含参考底图。" +msgid "editor.inspector.option.square.1xl1lk6" +msgstr "方形" -# Source-Hash: acbdf968391d5273 +# Source-Hash: 53d7084bc41c1ad6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure + furniture" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureFurniture" -msgstr "结构 + 家具" +msgid "editor.inspector.option.stair.1xf86e" +msgstr "楼梯" -# Source-Hash: ce682864a140fe75 +# Source-Hash: d998c212030bc7c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure + materials" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureMaterials" -msgstr "结构 + 材质" +msgid "editor.inspector.option.standard.vuco" +msgstr "标准" -# Source-Hash: 5ee44d53847c5ea2 +# Source-Hash: 0a26a1e61c825660 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure, materials, furniture, and references." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureMaterialsFurnitureAndReferences" -msgstr "结构、材质、家具和参考。" +msgid "editor.inspector.option.start.30xvgf" +msgstr "起点" -# Source-Hash: 95aa1b43dbdb3f02 +# Source-Hash: ed3989f23a2d185e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure only" -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Step" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureOnly" -msgstr "仅结构" +msgid "editor.inspector.option.step.jtn9kf" +msgstr "台阶" -# Source-Hash: 2c53b46c9ca9fe2f +# Source-Hash: 2c6b1cf17a973d67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure with the current material and finish assignments." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stepped" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.structureWithTheCurrentMaterialAnd" -msgstr "结构及当前的材质和饰面分配。" +msgid "editor.inspector.option.stepped.naxzh0" +msgstr "阶梯式" -# Source-Hash: 3350e9008eaba15d +# Source-Hash: 4ee35f740730ae87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls, slabs, roofs, stairs, windows, and doors without finishes." -#: packages/editor/src/components/ui/level-duplicate-dialog.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.levelDuplicateDialog.wallsSlabsRoofsStairsWindowsAnd" -msgstr "墙体、楼板、屋顶、楼梯、窗和门,不含饰面。" +msgid "editor.inspector.option.straight.lxqbfr" +msgstr "直跑" -# Source-Hash: 395fd0821b203517 +# Source-Hash: b9b45ac5ba1daeee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add or remove objects from the selection" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Strap" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.addOrRemoveObjectsFromThe" -msgstr "在选择中添加或移除对象" +msgid "editor.inspector.option.strap.14q0ps9" +msgstr "吊带" -# Source-Hash: 8428cb0af9c6d6a0 +# Source-Hash: b45f382a67d6c0eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Adjust one side’s corner radius" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.adjustOneSideSCornerRadius" -msgstr "调整一侧的圆角半径" +msgid "editor.inspector.option.supply.1oy2zwu" +msgstr "送风" -# Source-Hash: d63b45c195713993 +# Source-Hash: 00e7a2b3b2aa36ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear the selection (or click outside)" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Supply register" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.clearTheSelectionOrClickOutside" -msgstr "清除选择(或点击外部)" +msgid "editor.inspector.option.supplyRegister.1lzdbbn" +msgstr "送风口" -# Source-Hash: 40b1afbeadbd6213 +# Source-Hash: f86f1f22230596b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click a handle dot to show move arrows" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tapered" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.clickAHandleDotToShow" -msgstr "点击控制点以显示移动箭头" +msgid "editor.inspector.option.tapered.3y5blo" +msgstr "锥形" -# Source-Hash: 0b82a35c71549580 +# Source-Hash: 5fed23c2217b83fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click or drag the selection to move it as one" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target spacing" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.clickOrDragTheSelectionTo" -msgstr "点击或拖动选择以整体移动" +msgid "editor.inspector.option.targetSpacing.14uibc9" +msgstr "目标间距" -# Source-Hash: 73a761f393f69cb9 +# Source-Hash: f3ceed7f867f090f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click the handle dot to show move + rotate handles" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tee" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.clickTheHandleDotToShow" -msgstr "点击控制点以显示移动和旋转控件" +msgid "editor.inspector.option.tee.7d6tjp" +msgstr "三通" -# Source-Hash: c0045cef191fee69 +# Source-Hash: 787005b26aec58a3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Detach the joint while dragging an arrow" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilted" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.detachTheJointWhileDraggingAn" -msgstr "拖动箭头时断开连接" +msgid "editor.inspector.option.tilted.6n0u5j" +msgstr "倾斜" -# Source-Hash: a019c8948c104a9e +# Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag left or right to rotate selected object" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.dragLeftOrRightToRotate" -msgstr "左右拖动以旋转所选对象" +msgid "editor.inspector.option.top.2nypcs" +msgstr "顶部" -# Source-Hash: 7db0364deb12f06e +# Source-Hash: e6657000554dfe53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag selected movable object" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transition" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.dragSelectedMovableObject" -msgstr "拖动所选的可移动对象" +msgid "editor.inspector.option.transition.1rziz9e" +msgstr "过渡" -# Source-Hash: 0f258dd389afdc73 +# Source-Hash: 04bc0909a133a7e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Group selection (session only)" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vent" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.groupSelectionSessionOnly" -msgstr "组合所选(仅本次会话)" +msgid "editor.inspector.option.vent.xda5j2" +msgstr "通风口" -# Source-Hash: 85330d62893a45c3 +# Source-Hash: 7eee9aff0dd520b6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hold to rotate freely" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walk on" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.holdToRotateFreely" -msgstr "按住以自由旋转" +msgid "editor.inspector.option.walkOn.1n5sg9l" +msgstr "行走面" -# Source-Hash: 8a665ecaeffa9308 +# Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ±45°" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.rotate45" -msgstr "旋转 ±45°" +msgid "editor.inspector.option.wall.blj585" +msgstr "墙体" -# Source-Hash: 6099ee99f8c38700 +# Source-Hash: f3578f7177ad0054 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate the selection ±45°" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall abutment" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.rotateTheSelection45" -msgstr "将所选旋转 ±45°" +msgid "editor.inspector.option.wallAbutment.lza941" +msgstr "靠墙" -# Source-Hash: 0f6b418b18ff96f3 +# Source-Hash: 8dcf182f91ba3245 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotating freely (no angle step)" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall ledger" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.rotatingFreely" -msgstr "自由旋转(无角度步进)" +msgid "editor.inspector.option.wallLedger.5m8ana" +msgstr "墙上托梁" -# Source-Hash: 7ed174d6b03563b1 +# Source-Hash: 0adda30be5f17975 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Switch the rotation axis (Y → X → Z)" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall shelf" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.switchTheRotationAxisYX" -msgstr "切换旋转轴(Y → X → Z)" +msgid "editor.inspector.option.wallShelf.yiozfl" +msgstr "墙面搁板" -# Source-Hash: d6f2c5cea683de62 +# Source-Hash: 29d8590334492601 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ungroup session selection" -#: packages/editor/src/lib/contextual-help.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waste" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.contextualHelp.ungroupSessionSelection" -msgstr "取消会话中的组合" +msgid "editor.inspector.option.waste.3xrp79" +msgstr "排污" -# Source-Hash: 384842ae1e1c6825 +# Source-Hash: 00249876bb37079f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuous" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wye" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.lib.continuation.continuous" -msgstr "连续" +msgid "editor.inspector.option.wye.14vupc8" +msgstr "Y 形三通" -# Source-Hash: ebf0eb7af4636a16 +# Source-Hash: 179b025e25f9a091 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuous canopy" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collapse" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx #, fuzzy -msgid "editor.lib.continuation.continuousCanopy" -msgstr "连续雨棚" +msgid "editor.layers.collapse" +msgstr "折叠" -# Source-Hash: 1d8e87cd807e8d40 +# Source-Hash: dbeae4c43f49327f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuous run" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling ({area})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.continuousRun" -msgstr "连续排布" +msgid "editor.layers.defaultName.ceiling" +msgstr "天花板({area})" -# Source-Hash: 8990683667567c6b +# Source-Hash: d29165c9d4bfc3cb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curved fence" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collection" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx #, fuzzy -msgid "editor.lib.continuation.curvedFence" -msgstr "曲线围栏" +msgid "editor.layers.defaultName.collection" +msgstr "集合" -# Source-Hash: edf1b9a2ad3ab910 +# Source-Hash: 8f536b859be662a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Freehand fence" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight ({width}×{length}m)" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.freehandFence" -msgstr "手绘围栏" +msgid "editor.layers.defaultName.flight" +msgstr "梯段({width}×{length}m)" -# Source-Hash: 2cdb7c1c7cd7c4fd +# Source-Hash: 46dcbf4548374073 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place multiple" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing ({width}×{length}m)" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.placeMultiple" -msgstr "连续放置多个" +msgid "editor.layers.defaultName.landing" +msgstr "平台({width}×{length}m)" -# Source-Hash: 90bf945df6f9c979 +# Source-Hash: 3ea44453fcd08a6e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place once" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Node" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx #, fuzzy -msgid "editor.lib.continuation.placeOnce" -msgstr "放置一次" +msgid "editor.layers.defaultName.node" +msgstr "节点" -# Source-Hash: 8ec6152e139b0e3f +# Source-Hash: 93f3a04e15b6fb49 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Polygon room" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof ({count, plural, one {# segment} other {# segments}})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.polygonRoom" -msgstr "多边形房间" +msgid "editor.layers.defaultName.roof" +msgstr "屋顶({count, plural, other {# 个分段}})" -# Source-Hash: 83a45603ac7f41e8 +# Source-Hash: a730fab01c172704 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangle room" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{roofType, select, hip {Hip} gable {Gable} shed {Shed} gambrel {Gambrel} dutch {Dutch} mansard {Mansard} flat {Flat} conical {Conical} barrel {Barrel} other {Roof}} ({width}×{depth}m)" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.rectangleRoom" -msgstr "矩形房间" +msgid "editor.layers.defaultName.roofSegment" +msgstr "{roofType, select, hip {四坡} gable {双坡} shed {单坡} gambrel {复折} dutch {歇山} mansard {孟莎} flat {平屋顶} conical {锥形} barrel {筒形} other {屋顶}}({width}×{depth}m)" -# Source-Hash: 7fd85d0408141157 +# Source-Hash: 54efcb0756c2f2c1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single cabinet" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room ({area})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.singleCabinet" -msgstr "单个橱柜" +msgid "editor.layers.defaultName.room" +msgstr "房间({area})" -# Source-Hash: dd1bdbc26165baa5 +# Source-Hash: e38a4b9986a9d21a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single canopy" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab ({area})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.singleCanopy" -msgstr "单个雨棚" +msgid "editor.layers.defaultName.slab" +msgstr "楼板({area})" -# Source-Hash: 5fb1a69316be983e +# Source-Hash: 57398365d4b9066f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single fence" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Staircase ({count, plural, one {# segment} other {# segments}})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.singleFence" -msgstr "单段围栏" +msgid "editor.layers.defaultName.staircase" +msgstr "楼梯({count, plural, other {# 个分段}})" -# Source-Hash: aac9a732d2159ccc +# Source-Hash: a17f8fc29aae896e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls" -#: packages/editor/src/lib/continuation.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone ({area})" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/default-names.ts #, fuzzy -msgid "editor.lib.continuation.walls" -msgstr "墙体" +msgid "editor.layers.defaultName.zone" +msgstr "区域({area})" -# Source-Hash: 4e4f1a24e4a9d61e +# Source-Hash: 5cabcabb8bc14809 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut opening" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Expand" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx #, fuzzy -msgid "editor.lib.hudTitle.cutOpening" -msgstr "开洞" +msgid "editor.layers.expand" +msgstr "展开" -# Source-Hash: 60e8d235f3084a9e +# Source-Hash: 6731e9dd94e8b268 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Divide room" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{levelName} options" +#: packages/editor/src/components/ui/floating-level-selector.tsx +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.lib.hudTitle.divideRoom" -msgstr "分割房间" +msgid "editor.layers.levelOptions" +msgstr "{levelName}选项" -# Source-Hash: aa496ec33d21ab03 +# Source-Hash: d6952b4e54d246dd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit {kind}" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rename" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx #, fuzzy -msgid "editor.lib.hudTitle.editKind" -msgstr "编辑{kind}" +msgid "editor.layers.rename" +msgstr "重命名" -# Source-Hash: f3ea3efa7102844f +# Source-Hash: 21eafa019ad62fea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Erase" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{role, select, room {Room colour} other {Zone colour}}" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +#: packages/editor/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.lib.hudTitle.erase" -msgstr "擦除" +msgid "editor.layers.spaceColour" +msgstr "{role, select, room {房间颜色} other {区域颜色}}" -# Source-Hash: 3f907e76526472bf +# Source-Hash: f5de042416a2c04f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level terrain" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unit colour" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.lib.hudTitle.levelTerrain" -msgstr "整平地形" +msgid "editor.layers.unitColour" +msgstr "单元颜色" -# Source-Hash: 4e911c300d74eb47 +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lower terrain" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.lowerTerrain" -msgstr "降低地形" +msgid "editor.levelDuplicateDialog.cancel" +msgstr "取消" -# Source-Hash: 194a147d4618a994 +# Source-Hash: 07c11e7e4d4681d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose what to copy from {levelName}." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.mezzanine" -msgstr "夹层" +msgid "editor.levelDuplicateDialog.chooseWhatToCopyFromLevel" +msgstr "选择要从{levelName}复制的内容。" -# Source-Hash: c48c4129c9ed249a +# Source-Hash: 9500d4378a319532 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move {kind}" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose what to copy from this level." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.moveKind" -msgstr "移动{kind}" +msgid "editor.levelDuplicateDialog.chooseWhatToCopyFromThisLevel" +msgstr "选择要从此楼层复制的内容。" -# Source-Hash: 89f6b7ca8904c656 +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move room" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.moveRoom" -msgstr "移动房间" +msgid "editor.levelDuplicateDialog.duplicate" +msgstr "复制" -# Source-Hash: 9c707069572fb3db +# Source-Hash: a56e3eb43e60b45c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move selection" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate Level" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.moveSelection" -msgstr "移动所选" +msgid "editor.levelDuplicateDialog.duplicateLevel" +msgstr "复制楼层" -# Source-Hash: cf2e870fce0f2f51 +# Source-Hash: e4c6ab1ea473a082 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Everything" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.paint" -msgstr "涂装" +msgid "editor.levelDuplicateDialog.everything" +msgstr "全部" -# Source-Hash: ca197314cb70aa56 +# Source-Hash: ac3f119e560388ab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint a rectangle" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure, finishes, and placed items, without guide references." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.paintARectangle" -msgstr "涂装矩形" +msgid "editor.levelDuplicateDialog.structureFinishesAndPlacedItemsWithout" +msgstr "结构、饰面和已放置的物品,不含参考底图。" -# Source-Hash: ea4ce729e17254f8 +# Source-Hash: acbdf968391d5273 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint a shape" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure + furniture" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.paintAShape" -msgstr "涂装形状" +msgid "editor.levelDuplicateDialog.structureFurniture" +msgstr "结构 + 家具" -# Source-Hash: 01359502b07284d4 +# Source-Hash: ce682864a140fe75 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick material" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure + materials" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.pickMaterial" -msgstr "拾取材质" +msgid "editor.levelDuplicateDialog.structureMaterials" +msgstr "结构 + 材质" -# Source-Hash: 4066e8a3f60b1711 +# Source-Hash: 5ee44d53847c5ea2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raise terrain" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure, materials, furniture, and references." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.raiseTerrain" -msgstr "抬升地形" +msgid "editor.levelDuplicateDialog.structureMaterialsFurnitureAndReferences" +msgstr "结构、材质、家具和参考。" -# Source-Hash: f85bdac0a1d16603 +# Source-Hash: 95aa1b43dbdb3f02 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Resize" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure only" +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.resize" -msgstr "调整大小" +msgid "editor.levelDuplicateDialog.structureOnly" +msgstr "仅结构" -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: 2c53b46c9ca9fe2f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure with the current material and finish assignments." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.rotate" -msgstr "旋转" +msgid "editor.levelDuplicateDialog.structureWithTheCurrentMaterialAnd" +msgstr "结构及当前的材质和饰面分配。" -# Source-Hash: a4395168488bb476 +# Source-Hash: 3350e9008eaba15d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls, slabs, roofs, stairs, windows, and doors without finishes." +#: packages/editor/src/components/ui/level-duplicate-dialog.tsx #, fuzzy -msgid "editor.lib.hudTitle.select" -msgstr "选择" +msgid "editor.levelDuplicateDialog.wallsSlabsRoofsStairsWindowsAnd" +msgstr "墙体、楼板、屋顶、楼梯、窗和门,不含饰面。" -# Source-Hash: ec1f1d68af469867 +# Source-Hash: 4f60d1e142affa9c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Smart measure" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Copy" +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx #, fuzzy -msgid "editor.lib.hudTitle.smartMeasure" -msgstr "智能测量" +msgid "editor.levelWallCopyPrompt.copy" +msgstr "复制" -# Source-Hash: 5ba5f22bd1a69e09 +# Source-Hash: 8ccaf4c98e335cc8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Smooth terrain" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Copy exterior walls from the level {direction}?" +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx #, fuzzy -msgid "editor.lib.hudTitle.smoothTerrain" -msgstr "平滑地形" +msgid "editor.levelWallCopyPrompt.copyExteriorWallsFromTheLevel" +msgstr "要从{direction, select, below {下方} above {上方} other {{direction}}}楼层复制外墙吗?" -# Source-Hash: cbb4687261739397 +# Source-Hash: f6ad0e813d2945bb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Split {kind}" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No thanks" +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx #, fuzzy -msgid "editor.lib.hudTitle.splitKind" -msgstr "分割{kind}" +msgid "editor.levelWallCopyPrompt.noThanks" +msgstr "不用了" -# Source-Hash: 96281876ce53ba08 +# Source-Hash: d2aecc3c47120ad5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terrace" -#: packages/editor/src/lib/hud-title.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{sourceName}’s outside walls, in place, so this level lines up with it." +#: packages/editor/src/components/ui/level-wall-copy-prompt.tsx #, fuzzy -msgid "editor.lib.hudTitle.terrace" -msgstr "露台" +msgid "editor.levelWallCopyPrompt.sourcenameSOutsideWallsInPlace" +msgstr "原位复制{sourceName}的外墙,使此楼层与其对齐。" -# Source-Hash: 8ec6152e139b0e3f +# Source-Hash: 395fd0821b203517 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Polygon room" -#: packages/editor/src/lib/wall-draw-variant.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add or remove objects from the selection" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.lib.wallDrawVariant.polygonRoom" -msgstr "多边形房间" +msgid "editor.lib.contextualHelp.addOrRemoveObjectsFromThe" +msgstr "在选择中添加或移除对象" -# Source-Hash: 83a45603ac7f41e8 +# Source-Hash: 8428cb0af9c6d6a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangle room" -#: packages/editor/src/lib/wall-draw-variant.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Adjust one side’s corner radius" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.lib.wallDrawVariant.rectangleRoom" -msgstr "矩形房间" +msgid "editor.lib.contextualHelp.adjustOneSideSCornerRadius" +msgstr "调整一侧的圆角半径" -# Source-Hash: aac9a732d2159ccc +# Source-Hash: d63b45c195713993 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls" -#: packages/editor/src/lib/wall-draw-variant.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear the selection (or click outside)" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.lib.wallDrawVariant.walls" -msgstr "墙体" +msgid "editor.lib.contextualHelp.clearTheSelectionOrClickOutside" +msgstr "清除选择(或点击外部)" +# Source-Hash: 40b1afbeadbd6213 # Review: required -# Source-Hash: c2626e1fbf89b3c9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{action, select, close {Close} open {Open} stop {Stop} other {Play}}" -#: packages/editor/src/components/editor/registry-action-contributions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click a handle dot to show move arrows" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.mechanismAction" -msgstr "{action, select, close {关闭} open {打开} stop {停止} other {播放}}" +msgid "editor.lib.contextualHelp.clickAHandleDotToShow" +msgstr "点击控制点以显示移动箭头" +# Source-Hash: 0b82a35c71549580 # Review: required -# Source-Hash: f08fbb462e9afc0e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curve" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click or drag the selection to move it as one" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.curve" -msgstr "曲线" +msgid "editor.lib.contextualHelp.clickOrDragTheSelectionTo" +msgstr "点击或拖动选择以整体移动" +# Source-Hash: 73a761f393f69cb9 # Review: required -# Source-Hash: 5af05fb6661e4d6a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut out" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click the handle dot to show move + rotate handles" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.cutOut" -msgstr "挖空" +msgid "editor.lib.contextualHelp.clickTheHandleDotToShow" +msgstr "点击控制点以显示移动和旋转控件" +# Source-Hash: c0045cef191fee69 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Detach the joint while dragging an arrow" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.delete" -msgstr "删除" +msgid "editor.lib.contextualHelp.detachTheJointWhileDraggingAn" +msgstr "拖动箭头时断开连接" +# Source-Hash: a019c8948c104a9e # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag left or right to rotate selected object" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.duplicate" -msgstr "复制" +msgid "editor.lib.contextualHelp.dragLeftOrRightToRotate" +msgstr "左右拖动以旋转所选对象" +# Source-Hash: 7db0364deb12f06e # Review: required -# Source-Hash: 94b212bd79c05141 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit mesh" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag selected movable object" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.editMesh" -msgstr "编辑网格" +msgid "editor.lib.contextualHelp.dragSelectedMovableObject" +msgstr "拖动所选的可移动对象" +# Source-Hash: 0f258dd389afdc73 # Review: required -# Source-Hash: ce90cf37224f73cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Find in catalog" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Group selection (session only)" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.findInCatalog" -msgstr "在目录中查找" +msgid "editor.lib.contextualHelp.groupSelectionSessionOnly" +msgstr "组合所选(仅本次会话)" +# Source-Hash: 85330d62893a45c3 # Review: required -# Source-Hash: d5e550c345e7161c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Group selection" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hold to rotate freely" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.groupSelection" -msgstr "将所选编组" +msgid "editor.lib.contextualHelp.holdToRotateFreely" +msgstr "按住以自由旋转" +# Source-Hash: 8a665ecaeffa9308 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ±45°" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.move" -msgstr "移动" +msgid "editor.lib.contextualHelp.rotate45" +msgstr "旋转 ±45°" +# Source-Hash: 6099ee99f8c38700 # Review: required -# Source-Hash: 473a9d4463761107 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate left" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate the selection ±45°" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.rotateLeft" -msgstr "向左旋转" +msgid "editor.lib.contextualHelp.rotateTheSelection45" +msgstr "将所选旋转 ±45°" +# Source-Hash: 0f6b418b18ff96f3 # Review: required -# Source-Hash: b1bf4e65c8d8c8ef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate right" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotating freely (no angle step)" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.rotateRight" -msgstr "向右旋转" +msgid "editor.lib.contextualHelp.rotatingFreely" +msgstr "自由旋转(无角度步进)" +# Source-Hash: 7ed174d6b03563b1 # Review: required -# Source-Hash: 6f4dbbc4a3f58fca -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ungroup selection" -#: packages/editor/src/components/editor/node-action-menu.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Switch the rotation axis (Y → X → Z)" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeActionMenu.ungroupSelection" -msgstr "取消所选编组" +msgid "editor.lib.contextualHelp.switchTheRotationAxisYX" +msgstr "切换旋转轴(Y → X → Z)" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: d6f2c5cea683de62 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ungroup session selection" +#: packages/editor/src/lib/contextual-help.ts #, fuzzy -msgid "editor.nodeDisplay.ceiling" -msgstr "天花板" +msgid "editor.lib.contextualHelp.ungroupSessionSelection" +msgstr "取消会话中的组合" -# Source-Hash: 3530ac1f4046cd22 +# Source-Hash: 384842ae1e1c6825 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Column" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuous" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.column" -msgstr "柱" +msgid "editor.lib.continuation.continuous" +msgstr "连续" -# Source-Hash: 787e10f5db16904e +# Source-Hash: ebf0eb7af4636a16 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuous canopy" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.door" -msgstr "门" +msgid "editor.lib.continuation.continuousCanopy" +msgstr "连续雨棚" -# Source-Hash: ab5cbab7be160a1c +# Source-Hash: 1d8e87cd807e8d40 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevator" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuous run" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.elevator" -msgstr "电梯" +msgid "editor.lib.continuation.continuousRun" +msgstr "连续排布" -# Source-Hash: 02042fde61b5aa11 +# Source-Hash: 8990683667567c6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fence" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curved fence" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.fence" -msgstr "围栏" +msgid "editor.lib.continuation.curvedFence" +msgstr "曲线围栏" -# Source-Hash: 4c3ff8cdc6feda97 +# Source-Hash: edf1b9a2ad3ab910 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guide image" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Freehand fence" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.guide" -msgstr "参考图像" +msgid "editor.lib.continuation.freehandFence" +msgstr "手绘围栏" -# Source-Hash: 2743a0e9d2743807 +# Source-Hash: 2cdb7c1c7cd7c4fd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Item" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place multiple" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.item" -msgstr "物品" +msgid "editor.lib.continuation.placeMultiple" +msgstr "连续放置多个" -# Source-Hash: f5f730969df63d1d +# Source-Hash: 90bf945df6f9c979 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place once" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.roof" -msgstr "屋顶" +msgid "editor.lib.continuation.placeOnce" +msgstr "放置一次" -# Source-Hash: a130b4eec084c79a +# Source-Hash: 8ec6152e139b0e3f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof segment" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Polygon room" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.roofSegment" -msgstr "屋顶分段" +msgid "editor.lib.continuation.polygonRoom" +msgstr "多边形房间" -# Source-Hash: 612dcd5bf06a79c4 +# Source-Hash: 83a45603ac7f41e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangle room" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.room" -msgstr "房间" +msgid "editor.lib.continuation.rectangleRoom" +msgstr "矩形房间" -# Source-Hash: b22b2f20cc7cd416 +# Source-Hash: 7fd85d0408141157 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "3D Scan" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single cabinet" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.scan" -msgstr "扫描模型" +msgid "editor.lib.continuation.singleCabinet" +msgstr "单个橱柜" -# Source-Hash: 170b2049ef0f9131 +# Source-Hash: dd1bdbc26165baa5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Selection" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single canopy" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.selection" -msgstr "当前选择" +msgid "editor.lib.continuation.singleCanopy" +msgstr "单个雨棚" -# Source-Hash: 8775bc8dc9593964 +# Source-Hash: 5fb1a69316be983e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single fence" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.slab" -msgstr "楼板" +msgid "editor.lib.continuation.singleFence" +msgstr "单段围栏" -# Source-Hash: 53d7084bc41c1ad6 +# Source-Hash: aac9a732d2159ccc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls" +#: packages/editor/src/lib/continuation.ts #, fuzzy -msgid "editor.nodeDisplay.stair" -msgstr "楼梯" +msgid "editor.lib.continuation.walls" +msgstr "墙体" -# Source-Hash: 52de428c16bb81e6 +# Source-Hash: 4e4f1a24e4a9d61e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair segment" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut opening" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.nodeDisplay.stairSegment" -msgstr "楼梯分段" +msgid "editor.lib.hudTitle.cutOpening" +msgstr "开洞" -# Source-Hash: 2210e5ee50b74dc9 +# Source-Hash: 60e8d235f3084a9e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divide room" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.nodeDisplay.wall" -msgstr "墙体" +msgid "editor.lib.hudTitle.divideRoom" +msgstr "分割房间" -# Source-Hash: aa3c35ed33e181e5 +# Source-Hash: aa496ec33d21ab03 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Window" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit {kind}" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.nodeDisplay.window" -msgstr "窗" +msgid "editor.lib.hudTitle.editKind" +msgstr "编辑{kind}" -# Source-Hash: a107b4d76d6972e3 +# Source-Hash: f3ea3efa7102844f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone" -#: packages/editor/src/components/ui/panels/node-display.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Erase" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.nodeDisplay.zone" -msgstr "区域" +msgid "editor.lib.hudTitle.erase" +msgstr "擦除" -# Source-Hash: c0774c185060fc13 +# Source-Hash: 3f907e76526472bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level terrain" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.cancel" -msgstr "取消" +msgid "editor.lib.hudTitle.levelTerrain" +msgstr "整平地形" -# Source-Hash: 6dbabf32ff8c6f37 +# Source-Hash: 4e911c300d74eb47 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collection name…" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lower terrain" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.collectionName" -msgstr "集合名称…" +msgid "editor.lib.hudTitle.lowerTerrain" +msgstr "降低地形" -# Source-Hash: 135af27a14a4cda7 +# Source-Hash: 194a147d4618a994 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collections" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.collections" -msgstr "集合" +msgid "editor.lib.hudTitle.mezzanine" +msgstr "夹层" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: c48c4129c9ed249a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move {kind}" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.delete" -msgstr "删除" +msgid "editor.lib.hudTitle.moveKind" +msgstr "移动{kind}" -# Source-Hash: c53d71b05b8163b2 +# Source-Hash: 89f6b7ca8904c656 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete \"{name}\"?" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move room" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.deleteName" -msgstr "删除“{name}”?" +msgid "editor.lib.hudTitle.moveRoom" +msgstr "移动房间" -# Source-Hash: e9f7cceb39860c56 +# Source-Hash: 9c707069572fb3db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "New" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move selection" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.new" -msgstr "新建" +msgid "editor.lib.hudTitle.moveSelection" +msgstr "移动所选" -# Source-Hash: 649bc1b1799f2311 +# Source-Hash: cf2e870fce0f2f51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No collections yet. Create one to group elements together." -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.noCollectionsYetCreateOneTo" -msgstr "暂无集合。新建一个以将元素组合在一起。" +msgid "editor.lib.hudTitle.paint" +msgstr "涂装" -# Source-Hash: d6952b4e54d246dd +# Source-Hash: ca197314cb70aa56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rename" -#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint a rectangle" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.collections.collectionsPopover.rename" -msgstr "重命名" +msgid "editor.lib.hudTitle.paintARectangle" +msgstr "涂装矩形" -# Source-Hash: 2000cf124b4e1139 +# Source-Hash: ea4ce729e17254f8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A thicker floor grows upward: the rooms below keep their height." -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx -#, fuzzy -msgid "editor.panels.floorFoundationPanel.aThickerFloorGrowsUpwardThe" -msgstr "加厚的楼板向上增长:下方房间保持原有高度。" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint a shape" +#: packages/editor/src/lib/hud-title.ts +#, fuzzy +msgid "editor.lib.hudTitle.paintAShape" +msgstr "涂装形状" -# Source-Hash: 0d57958b99b6b352 +# Source-Hash: 01359502b07284d4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edge finish" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick material" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.edgeFinish" -msgstr "边缘处理" +msgid "editor.lib.hudTitle.pickMaterial" +msgstr "拾取材质" -# Source-Hash: 8e458d8b21f26f09 +# Source-Hash: 4066e8a3f60b1711 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raise terrain" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorPlate" -msgstr "楼板" +msgid "editor.lib.hudTitle.raiseTerrain" +msgstr "抬升地形" -# Source-Hash: 2bb71e5633801afb +# Source-Hash: f85bdac0a1d16603 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate {thicknessLabel} thick, resting on the walls below" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Resize" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorPlateThicknesslabelThickRestingOn" -msgstr "楼板厚 {thicknessLabel},支承于下方墙体" +msgid "editor.lib.hudTitle.resize" +msgstr "调整大小" -# Source-Hash: 73614b8faa059cd6 +# Source-Hash: 306d409f8a1cf480 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor thickness" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorThickness" -msgstr "楼板厚度" +msgid "editor.lib.hudTitle.rotate" +msgstr "旋转" -# Source-Hash: a40a1fbacd5d2551 +# Source-Hash: a4395168488bb476 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor top +{height}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorTopAbove" -msgstr "楼面顶 +{height}" +msgid "editor.lib.hudTitle.select" +msgstr "选择" -# Source-Hash: 5c3849e15933737f +# Source-Hash: ec1f1d68af469867 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor top {height}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Smart measure" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.floorTopValue" -msgstr "楼面顶 {height}" +msgid "editor.lib.hudTitle.smartMeasure" +msgstr "智能测量" -# Source-Hash: 19802dd369749ea7 +# Source-Hash: 5ba5f22bd1a69e09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation finish" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Smooth terrain" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.foundationFinish" -msgstr "基础饰面" +msgid "editor.lib.hudTitle.smoothTerrain" +msgstr "平滑地形" -# Source-Hash: 3a4599be1ad687be +# Source-Hash: cbb4687261739397 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation height" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Split {kind}" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.foundationHeight" -msgstr "基础高度" +msgid "editor.lib.hudTitle.splitKind" +msgstr "分割{kind}" -# Source-Hash: 8e458d8b21f26f09 +# Source-Hash: 96281876ce53ba08 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terrace" +#: packages/editor/src/lib/hud-title.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.kicker" -msgstr "楼板" +msgid "editor.lib.hudTitle.terrace" +msgstr "露台" -# Source-Hash: 66d52bfbb94f7bb3 +# Source-Hash: 472d127eb9416ec5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate · {level}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invisible" +#: packages/editor/src/lib/wall-draw-variant.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.kickerLevel" -msgstr "楼板 · {level}" +msgid "editor.lib.wallDrawVariant.kind.invisible" +msgstr "隐形墙" -# Source-Hash: 0189e5a1987b4ec0 +# Source-Hash: 240ed9c77627b9a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate · {level} · rests on {below}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" +#: packages/editor/src/lib/wall-draw-variant.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.kickerRestsOn" -msgstr "楼板 · {level} · 支承于{below}" +msgid "editor.lib.wallDrawVariant.kind.railing" +msgstr "栏杆" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 648ef10535b0af73 +# Source-Hash: d998c212030bc7c2 # Review: required -# English: "{count, plural, =2 {Lower both} other {Lower all {number}}}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/editor/src/lib/wall-draw-variant.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.lowerTogether" -msgstr "{count, plural, =2 {同时降低两者} other {全部 {number} 个一起降低}}" +msgid "editor.lib.wallDrawVariant.kind.standard" +msgstr "标准" -# Source-Hash: c2fcc43bb7f1c5e2 +# Source-Hash: 8ec6152e139b0e3f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Not to scale" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Polygon room" +#: packages/editor/src/lib/wall-draw-variant.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.notToScale" -msgstr "非按比例" +msgid "editor.lib.wallDrawVariant.polygonRoom" +msgstr "多边形房间" -# Source-Hash: e9440fa9f770b7a4 +# Source-Hash: 83a45603ac7f41e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "On the ground" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangle room" +#: packages/editor/src/lib/wall-draw-variant.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.onTheGround" -msgstr "位于地面" +msgid "editor.lib.wallDrawVariant.rectangleRoom" +msgstr "矩形房间" -# Source-Hash: 7c3692a361075ecf +# Source-Hash: aac9a732d2159ccc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised on a foundation" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls" +#: packages/editor/src/lib/wall-draw-variant.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.raisedOnAFoundation" -msgstr "抬高于基础之上" +msgid "editor.lib.wallDrawVariant.walls" +msgstr "墙体" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 769c3ca1ca0cd4f0 +# Source-Hash: c2626e1fbf89b3c9 # Review: required -# English: "{count, plural, =2 {Raise both} other {Raise all {number}}}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{action, select, close {Close} open {Open} stop {Stop} other {Play}}" +#: packages/editor/src/components/editor/registry-action-contributions.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.raiseTogether" -msgstr "{count, plural, =2 {同时抬高两者} other {全部 {number} 个一起抬高}}" +msgid "editor.mechanismAction" +msgstr "{action, select, close {关闭} open {打开} stop {停止} other {播放}}" -# Source-Hash: 719ae422da204ca7 +# Source-Hash: f08fbb462e9afc0e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor plate · {thickness}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curve" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.floorPlate" -msgstr "楼板 · {thickness}" +msgid "editor.nodeActionMenu.curve" +msgstr "曲线" -# Source-Hash: 069d64adffa05db7 +# Source-Hash: 5af05fb6661e4d6a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor top" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut out" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.floorTop" -msgstr "楼面顶" +msgid "editor.nodeActionMenu.cutOut" +msgstr "挖空" -# Source-Hash: 48c832c1fc389290 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.foundation" -msgstr "基础" +msgid "editor.nodeActionMenu.delete" +msgstr "删除" -# Source-Hash: 7759a59b8685c885 +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation · {foundation}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx -#, fuzzy -msgid "editor.panels.floorFoundationPanel.section.foundationKind" -msgstr "基础 · {foundation}" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/editor/node-action-menu.tsx +#, fuzzy +msgid "editor.nodeActionMenu.duplicate" +msgstr "复制" -# Source-Hash: 94cc8e9f1ee16edb +# Source-Hash: 94b212bd79c05141 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit mesh" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.ground" -msgstr "地面" +msgid "editor.nodeActionMenu.editMesh" +msgstr "编辑网格" -# Source-Hash: 51e274b2c90e2cf3 +# Source-Hash: ce90cf37224f73cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab · {thickness}" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Find in catalog" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.slab" -msgstr "楼板 · {thickness}" +msgid "editor.nodeActionMenu.findInCatalog" +msgstr "在目录中查找" -# Source-Hash: 790a0b5c6dbf0e9b +# Source-Hash: d5e550c345e7161c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls below" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Group selection" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.section.wallsBelow" -msgstr "下方墙体" +msgid "editor.nodeActionMenu.groupSelection" +msgstr "将所选编组" -# Source-Hash: 90e96ae5f3d3f69c +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab {thickness} thick on the ground, floor top {top} above the ground" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.sectionOnGround" -msgstr "楼板厚 {thickness},位于地面上,楼面顶高出地面 {top}" +msgid "editor.nodeActionMenu.move" +msgstr "移动" -# Source-Hash: 71ed2295d9932ed0 +# Source-Hash: 473a9d4463761107 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab {thickness} thick on a {foundation} foundation, floor top {top} above the ground" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate left" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.sectionRaised" -msgstr "楼板厚 {thickness},位于{foundation}基础上,楼面顶高出地面 {top}" +msgid "editor.nodeActionMenu.rotateLeft" +msgstr "向左旋转" -# Source-Hash: 8775bc8dc9593964 +# Source-Hash: b1bf4e65c8d8c8ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate right" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.slab" -msgstr "楼板" +msgid "editor.nodeActionMenu.rotateRight" +msgstr "向右旋转" -# Source-Hash: ca51d643691c29ae +# Source-Hash: 6f4dbbc4a3f58fca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab thickness" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ungroup selection" +#: packages/editor/src/components/editor/node-action-menu.tsx #, fuzzy -msgid "editor.panels.floorFoundationPanel.slabThickness" -msgstr "楼板厚度" +msgid "editor.nodeActionMenu.ungroupSelection" +msgstr "取消所选编组" -# Source-Hash: 678c39468593275b +# Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The floor's outside edge, all around the footprint." -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.theFloorSOutsideEdgeAll" -msgstr "楼板的外缘,沿基底一周。" +msgid "editor.nodeDisplay.ceiling" +msgstr "天花板" -# Source-Hash: 6638ed5caa43bdb9 +# Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The foundation stands on the ground; the slab sits on it." -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Column" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.theFoundationStandsOnTheGround" -msgstr "基础立于地面上;楼板位于基础上。" +msgid "editor.nodeDisplay.column" +msgstr "柱" -# Source-Hash: 5321416b442f23b4 +# Source-Hash: 787e10f5db16904e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The slab sits on the foundation (or the ground): a thicker slab raises the floor top and everything on it." -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.theSlabSitsOnTheFoundation" -msgstr "楼板位于基础(或地面)上:加厚楼板会抬高楼面顶及其上的一切。" +msgid "editor.nodeDisplay.door" +msgstr "门" -# Source-Hash: 044ccae8bec574e7 +# Source-Hash: ab5cbab7be160a1c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Under the floor" -#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevator" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorFoundationPanel.underTheFloor" -msgstr "楼板下方" +msgid "editor.nodeDisplay.elevator" +msgstr "电梯" -# Source-Hash: 6aca44df3e582a81 +# Source-Hash: 02042fde61b5aa11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A hatch in the mezzanine: it cuts only the mezzanine’s floor." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fence" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.aHatchInTheMezzanineIt" -msgstr "夹层中的开口:只切穿夹层的楼板。" +msgid "editor.nodeDisplay.fence" +msgstr "围栏" -# Source-Hash: 2ce79639d42da658 +# Source-Hash: 4c3ff8cdc6feda97 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Also cut the ceiling below" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guide image" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.alsoCutTheCeilingBelow" -msgstr "同时切穿下方天花板" +msgid "editor.nodeDisplay.guide" +msgstr "参考图像" -# Source-Hash: e360814f64792300 +# Source-Hash: 2743a0e9d2743807 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Also cut the floor above" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Item" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.alsoCutTheFloorAbove" -msgstr "同时切穿上方楼板" +msgid "editor.nodeDisplay.item" +msgstr "物品" -# Source-Hash: c25cddf8b831c2b2 +# Source-Hash: f5f730969df63d1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{area} · Drag its corners to change the shape." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.areaDragCorners" -msgstr "{area} · 拖动其角点以更改形状。" +msgid "editor.nodeDisplay.roof" +msgstr "屋顶" -# Source-Hash: 32b168cf010a5daa +# Source-Hash: a130b4eec084c79a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{area} · Shape follows its owner." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof segment" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.areaOwned" -msgstr "{area} · 形状跟随其所属对象。" +msgid "editor.nodeDisplay.roofSegment" +msgstr "屋顶分段" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.delete" -msgstr "删除" +msgid "editor.nodeDisplay.room" +msgstr "房间" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: b22b2f20cc7cd416 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "3D Scan" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.done" -msgstr "完成" +msgid "editor.nodeDisplay.scan" +msgstr "扫描模型" -# Source-Hash: e04298381837252f +# Source-Hash: 170b2049ef0f9131 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selection" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.kicker" -msgstr "开口" +msgid "editor.nodeDisplay.selection" +msgstr "当前选择" -# Source-Hash: 079ad92dac7947cf +# Source-Hash: 8775bc8dc9593964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening · {level}" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.kickerLevel" -msgstr "开洞 · {level}" +msgid "editor.nodeDisplay.slab" +msgstr "楼板" -# Source-Hash: baf2c2c209637e5f +# Source-Hash: 53d7084bc41c1ad6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening · in {room}" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.kickerRoom" -msgstr "开洞 · 位于{room}" +msgid "editor.nodeDisplay.stair" +msgstr "楼梯" -# Source-Hash: 1712c164335ecd86 +# Source-Hash: 52de428c16bb81e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening · in {room} · {level}" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair segment" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.kickerRoomLevel" -msgstr "开洞 · 位于{room} · {level}" +msgid "editor.nodeDisplay.stairSegment" +msgstr "楼梯分段" -# Source-Hash: 88e673123b9dbfe1 +# Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "On {level}, as one void with this opening." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.oneVoidWith" -msgstr "在{level},与此开洞形成一个洞口。" +msgid "editor.nodeDisplay.wall" +msgstr "墙体" -# Source-Hash: c38959fc8fd3e59d +# Source-Hash: aa3c35ed33e181e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Owned by Elevator" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Window" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.ownedByElevator" -msgstr "归属于电梯" +msgid "editor.nodeDisplay.window" +msgstr "窗" -# Source-Hash: 01494805cf60d78d +# Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Owned by Staircase" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone" +#: packages/editor/src/components/ui/panels/node-display.ts #, fuzzy -msgid "editor.panels.floorOpeningPanel.ownedByStaircase" -msgstr "归属于楼梯" +msgid "editor.nodeDisplay.zone" +msgstr "区域" -# Source-Hash: 612dcd5bf06a79c4 +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.room" -msgstr "房间" +msgid "editor.panels.collections.collectionsPopover.cancel" +msgstr "取消" -# Source-Hash: 1405b914a324b153 +# Source-Hash: 6dbabf32ff8c6f37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "There is no floor above this storey." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collection name…" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.thereIsNoFloorAboveThis" -msgstr "此层上方没有楼板。" +msgid "editor.panels.collections.collectionsPopover.collectionName" +msgstr "集合名称…" -# Source-Hash: 776170dcae88e969 +# Source-Hash: 135af27a14a4cda7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "There is no storey below." -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collections" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.thereIsNoStoreyBelow" -msgstr "下方没有楼层。" +msgid "editor.panels.collections.collectionsPopover.collections" +msgstr "集合" -# Source-Hash: 0fdd1877a0f2d777 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{source, select, stair {Stair opening} elevator {Elevator opening} ceiling {Ceiling opening} other {Floor opening}}" -#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.floorOpeningPanel.title" -msgstr "{source, select, stair {楼梯开洞} elevator {电梯开洞} ceiling {天花板开洞} other {楼板开洞}}" +msgid "editor.panels.collections.collectionsPopover.delete" +msgstr "删除" -# Source-Hash: fa35c7653e1f649e +# Source-Hash: c53d71b05b8163b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "One of them already wraps another corner. Unwrap it first." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete \"{name}\"?" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.alreadyJoined" -msgstr "其中一扇已包住另一个转角。请先解除。" +msgid "editor.panels.collections.collectionsPopover.deleteName" +msgstr "删除“{name}”?" -# Source-Hash: dd87eb1983876459 +# Source-Hash: e9f7cceb39860c56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{kind, select, item {There is an item between them.} door {There is a door between them.} window {There is a window between them.} shelf {There is a shelf between them.} other {There is something between them.}}" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.between" -msgstr "{kind, select, item {它们之间有一个物品。} door {它们之间有一扇门。} window {它们之间有一扇窗。} shelf {它们之间有一个搁板。} other {它们之间有其他对象。}}" +msgid "editor.panels.collections.collectionsPopover.new" +msgstr "新建" -# Source-Hash: 58aea0b9789ae280 +# Source-Hash: 649bc1b1799f2311 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "These windows cannot be merged." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No collections yet. Create one to group elements together." +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.cannotMerge" -msgstr "这些窗户无法合并。" +msgid "editor.panels.collections.collectionsPopover.noCollectionsYetCreateOneTo" +msgstr "暂无集合。新建一个以将元素组合在一起。" -# Source-Hash: 15170cfd9d666c4f +# Source-Hash: d6952b4e54d246dd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Their walls meet at too sharp or too flat an angle for a corner window." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rename" +#: packages/editor/src/components/ui/panels/collections/collections-popover.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.cornerAngle" -msgstr "它们的墙体相交角度过锐或过钝,无法做转角窗。" +msgid "editor.panels.collections.collectionsPopover.rename" +msgstr "重命名" -# Source-Hash: f2818a1e20ebd6ca +# Source-Hash: 0a605a51555bb514 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The window selected first is taller than the other wall. Select the other one first." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Along house" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.heightExceedsWall" -msgstr "先选中的窗户比另一面墙高。请先选择另一扇。" +msgid "editor.panels.deckBoardsFields.alongHouse" +msgstr "沿房屋" -# Source-Hash: 7c97fb4af929d4db +# Source-Hash: 19ae2360207ecf5a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "They are too far apart. Windows merge with at most {reach} between them." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Boards" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.notAdjacent" -msgstr "它们相距太远。窗户之间最多相隔 {reach} 才能合并。" +msgid "editor.panels.deckBoardsFields.boards" +msgstr "铺板" -# Source-Hash: 57a281bdc4229b6d +# Source-Hash: 2bc05aaf1fc289b3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "One of them is too far from the corner. A window joins one within {reach} of it." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label} boards {thickness} × {width} in, {gap} in apart, {direction, select, parallel {along the house, on joists square to it} diagonal {at 45° to the house} other {out from the house, on joists along it, carried by beams square to the house}}; joists {spacing} in on centre." +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.notAtCorner" -msgstr "其中一扇离转角太远。窗户只能与 {reach} 以内的窗合并。" +msgid "editor.panels.deckBoardsFields.boardsSummary" +msgstr "{label} 铺板 {thickness} × {width} in,板缝 {gap} in,{direction, select, parallel {沿房屋方向铺设,搁栅与房屋垂直} diagonal {与房屋成 45° 铺设} other {由房屋向外铺设,搁栅沿房屋方向,由垂直于房屋的梁承托}};搁栅中距 {spacing} in。" -# Source-Hash: e7d41ce7879ec075 +# Source-Hash: 24c6255bfa1abd8f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A roof or dormer window cannot join another window." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck boards" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.notOnWall" -msgstr "屋顶窗或老虎窗不能与其他窗合并。" +msgid "editor.panels.deckBoardsFields.deckBoards" +msgstr "平台铺板" -# Source-Hash: eaad567d5e4257dc +# Source-Hash: 7420c0d2caee1c22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{kind, select, item {Sliding them to the corner would overlap an item.} door {Sliding them to the corner would overlap a door.} window {Sliding them to the corner would overlap a window.} shelf {Sliding them to the corner would overlap a shelf.} other {Sliding them to the corner would overlap something.}}" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diagonal" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.overlap" -msgstr "{kind, select, item {将它们滑到转角会与一个物品重叠。} door {将它们滑到转角会与一扇门重叠。} window {将它们滑到转角会与一扇窗重叠。} shelf {将它们滑到转角会与一个搁板重叠。} other {将它们滑到转角会与其他对象重叠。}}" +msgid "editor.panels.deckBoardsFields.diagonal" +msgstr "斜向" -# Source-Hash: ecb092821ed5b5e8 +# Source-Hash: df708ece3529bcba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Their walls do not meet at a corner." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mergeRefusal.wallsNotMeeting" -msgstr "它们的墙体没有在转角相交。" +msgid "editor.panels.deckBoardsFields.gap" +msgstr "板缝" -# Source-Hash: 37d9f63758abdb67 +# Source-Hash: 3660fcdd12159277 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mixed" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx -#: packages/editor/src/components/ui/panels/parametric-field-control.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Out from house" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mixed" -msgstr "混合" +msgid "editor.panels.deckBoardsFields.outFromHouse" +msgstr "由房屋向外" -# Source-Hash: d7cf5045c01b2eb9 +# Source-Hash: 9ac7e4955593cc34 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close" -#: packages/editor/src/components/ui/panels/mobile-panel-sheet.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Run" +#: packages/editor/src/components/ui/panels/deck-boards-fields.tsx #, fuzzy -msgid "editor.panels.mobilePanelSheet.close" -msgstr "关闭" +msgid "editor.panels.deckBoardsFields.run" +msgstr "铺设方向" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 2000cf124b4e1139 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A thicker floor grows upward: the rooms below keep their height." +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.delete" -msgstr "删除" +msgid "editor.panels.floorFoundationPanel.aThickerFloorGrowsUpwardThe" +msgstr "加厚的楼板向上增长:下方房间保持原有高度。" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 0d57958b99b6b352 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edge finish" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.duplicate" -msgstr "复制" +msgid "editor.panels.floorFoundationPanel.edgeFinish" +msgstr "边缘处理" -# Source-Hash: 7eb955d866c2668b +# Source-Hash: 8e458d8b21f26f09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit properties" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.editProperties" -msgstr "编辑属性" +msgid "editor.panels.floorFoundationPanel.floorPlate" +msgstr "楼板" -# Source-Hash: 89f25aa13e8192bc +# Source-Hash: 2bb71e5633801afb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit {resolvedLabel}" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate {thicknessLabel} thick, resting on the walls below" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.editResolvedlabel" -msgstr "编辑{resolvedLabel}" +msgid "editor.panels.floorFoundationPanel.floorPlateThicknesslabelThickRestingOn" +msgstr "楼板厚 {thicknessLabel},支承于下方墙体" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 73614b8faa059cd6 # Review: required # AI-Provider: cursor-agent # AI-Model: claude-opus -# English: "Move" -#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx +# English: "Floor thickness" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.mobileSelectionBar.move" -msgstr "移动" +msgid "editor.panels.floorFoundationPanel.floorThickness" +msgstr "楼板厚度" -# Source-Hash: 72be05e1796526c9 +# Source-Hash: a40a1fbacd5d2551 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Currently {currentLabel}" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor top +{height}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.currentlyCurrentlabel" -msgstr "当前为{currentLabel}" +msgid "editor.panels.floorFoundationPanel.floorTopAbove" +msgstr "楼面顶 +{height}" -# Source-Hash: b2a1b3bc9676fe05 +# Source-Hash: 5c3849e15933737f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom height" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor top {height}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.customHeight" -msgstr "自定义高度" +msgid "editor.panels.floorFoundationPanel.floorTopValue" +msgstr "楼面顶 {height}" -# Source-Hash: a5c2353769b603d5 +# Source-Hash: 19802dd369749ea7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows level" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation finish" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.followsLevel" -msgstr "跟随楼层" +msgid "editor.panels.floorFoundationPanel.foundationFinish" +msgstr "基础饰面" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: 3a4599be1ad687be # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation height" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.height" -msgstr "高度" +msgid "editor.panels.floorFoundationPanel.foundationHeight" +msgstr "基础高度" -# Source-Hash: 27644f0497fd9849 +# Source-Hash: 8e458d8b21f26f09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiHeightMode.top" -msgstr "顶部" +msgid "editor.panels.floorFoundationPanel.kicker" +msgstr "楼板" -# Source-Hash: 70f48b0141b656f2 +# Source-Hash: 66d52bfbb94f7bb3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{label} (session only). Plain click reselects all members. Not saved with the project." -#: packages/editor/src/components/ui/panels/multi-parametric-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate · {level}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiParametricInspector.labelSessionOnlyPlainClickReselects" -msgstr "{label}(仅限本次会话)。普通点击会重新选中所有成员。不会随项目保存。" +msgid "editor.panels.floorFoundationPanel.kickerLevel" +msgstr "楼板 · {level}" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 0189e5a1987b4ec0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate · {level} · rests on {below}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.delete" -msgstr "删除" +msgid "editor.panels.floorFoundationPanel.kickerRestsOn" +msgstr "楼板 · {level} · 支承于{below}" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 648ef10535b0af73 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, =2 {Lower both} other {Lower all {number}}}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.duplicate" -msgstr "复制" +msgid "editor.panels.floorFoundationPanel.lowerTogether" +msgstr "{count, plural, =2 {同时降低两者} other {全部 {number} 个一起降低}}" -# Source-Hash: b0e7e3b47dfb5a0b +# Source-Hash: c2fcc43bb7f1c5e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Group" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not to scale" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.group" -msgstr "编组" +msgid "editor.panels.floorFoundationPanel.notToScale" +msgstr "非按比例" -# Source-Hash: ca0a95fe0b08b8b6 +# Source-Hash: e9440fa9f770b7a4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Group (Ctrl/Cmd+G)" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On the ground" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.groupCtrlCmdG" -msgstr "编组(Ctrl/Cmd+G)" +msgid "editor.panels.floorFoundationPanel.onTheGround" +msgstr "位于地面" -# Source-Hash: 70f48b0141b656f2 +# Source-Hash: 7c3692a361075ecf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{label} (session only). Plain click reselects all members. Not saved with the project." -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised on a foundation" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.labelSessionOnlyPlainClickReselects" -msgstr "{label}(仅限本次会话)。普通点击会重新选中所有成员。不会随项目保存。" +msgid "editor.panels.floorFoundationPanel.raisedOnAFoundation" +msgstr "抬高于基础之上" -# Source-Hash: fc98ef29c2842341 +# Source-Hash: 769c3ca1ca0cd4f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{length} selected" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, =2 {Raise both} other {Raise all {number}}}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.lengthSelected" -msgstr "已选择 {length} 个" +msgid "editor.panels.floorFoundationPanel.raiseTogether" +msgstr "{count, plural, =2 {同时抬高两者} other {全部 {number} 个一起抬高}}" -# Source-Hash: 323aaf1ebd04ada7 +# Source-Hash: 719ae422da204ca7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Merge windows" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor plate · {thickness}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.mergeWindows" -msgstr "合并窗户" +msgid "editor.panels.floorFoundationPanel.section.floorPlate" +msgstr "楼板 · {thickness}" -# Source-Hash: 7855d03a6140af77 +# Source-Hash: 069d64adffa05db7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Merge windows into a corner window: both take the height, sill and type of the one you selected first" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor top" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.mergeWindowsIntoACornerWindow" -msgstr "合并为转角窗:两者都采用先选中窗户的高度、窗台和类型" +msgid "editor.panels.floorFoundationPanel.section.floorTop" +msgstr "楼面顶" -# Source-Hash: b79da96502d2e1c0 +# Source-Hash: 48c832c1fc389290 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Merge windows into one across both: it keeps the type and style of the one you selected first" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.mergeWindowsIntoOneAcrossBoth" -msgstr "合并为跨越两者的一扇窗:保留先选中窗户的类型和样式" +msgid "editor.panels.floorFoundationPanel.section.foundation" +msgstr "基础" -# Source-Hash: f409934681a046e8 +# Source-Hash: 7759a59b8685c885 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select building" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx -#, fuzzy -msgid "editor.panels.multiSelectionPanel.selectBuilding" -msgstr "选择建筑" - -# Source-Hash: c62a73873bd0164d -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select the whole building to move all its levels" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation · {foundation}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.selectTheWholeBuildingToMove" -msgstr "选择整栋建筑以移动其所有楼层" +msgid "editor.panels.floorFoundationPanel.section.foundationKind" +msgstr "基础 · {foundation}" -# Source-Hash: 7bd5f29203a28efb +# Source-Hash: 94cc8e9f1ee16edb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ungroup" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.ungroup" -msgstr "取消编组" +msgid "editor.panels.floorFoundationPanel.section.ground" +msgstr "地面" -# Source-Hash: aec9c3983a440d4a +# Source-Hash: 51e274b2c90e2cf3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ungroup (Ctrl/Cmd+Shift+G)" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab · {thickness}" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.ungroupCtrlCmdShiftG" -msgstr "取消编组(Ctrl/Cmd+Shift+G)" +msgid "editor.panels.floorFoundationPanel.section.slab" +msgstr "楼板 · {thickness}" -# Source-Hash: 420385f27c627cee +# Source-Hash: 790a0b5c6dbf0e9b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unwrap the corner" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls below" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.unwrapTheCorner" -msgstr "解除转角" +msgid "editor.panels.floorFoundationPanel.section.wallsBelow" +msgstr "下方墙体" -# Source-Hash: 7906c9f4baebc70b +# Source-Hash: 90e96ae5f3d3f69c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unwrap the corner: both windows stay, each framed at the corner" -#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab {thickness} thick on the ground, floor top {top} above the ground" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.multiSelectionPanel.unwrapTheCornerBothWindowsStay" -msgstr "解除转角:两扇窗都保留,各自在转角处加框" +msgid "editor.panels.floorFoundationPanel.sectionOnGround" +msgstr "楼板厚 {thickness},位于地面上,楼面顶高出地面 {top}" -# Source-Hash: 170b2049ef0f9131 +# Source-Hash: 71ed2295d9932ed0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Selection" -#: packages/editor/src/components/ui/panels/panel-manager.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab {thickness} thick on a {foundation} foundation, floor top {top} above the ground" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelManager.selection" -msgstr "当前选择" +msgid "editor.panels.floorFoundationPanel.sectionRaised" +msgstr "楼板厚 {thickness},位于{foundation}基础上,楼面顶高出地面 {top}" -# Source-Hash: 7ceade8f25b58fe9 +# Source-Hash: 8775bc8dc9593964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.back" -msgstr "返回" +msgid "editor.panels.floorFoundationPanel.slab" +msgstr "楼板" -# Source-Hash: d7cf5045c01b2eb9 +# Source-Hash: ca51d643691c29ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab thickness" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.close" -msgstr "关闭" +msgid "editor.panels.floorFoundationPanel.slabThickness" +msgstr "楼板厚度" -# Source-Hash: 2dff25ca30c80559 +# Source-Hash: 678c39468593275b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close {title}" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The floor's outside edge, all around the footprint." +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.closeTitle" -msgstr "关闭{title}" +msgid "editor.panels.floorFoundationPanel.theFloorSOutsideEdgeAll" +msgstr "楼板的外缘,沿基底一周。" -# Source-Hash: 4f15c3e0fe6178b5 +# Source-Hash: 6638ed5caa43bdb9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collapse panel" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The foundation stands on the ground; the slab sits on it." +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.collapsePanel" -msgstr "收起面板" +msgid "editor.panels.floorFoundationPanel.theFoundationStandsOnTheGround" +msgstr "基础立于地面上;楼板位于基础上。" -# Source-Hash: 135af27a14a4cda7 +# Source-Hash: 5321416b442f23b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collections" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The slab sits on the foundation (or the ground): a thicker slab raises the floor top and everything on it." +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.collections" -msgstr "集合" +msgid "editor.panels.floorFoundationPanel.theSlabSitsOnTheFoundation" +msgstr "楼板位于基础(或地面)上:加厚楼板会抬高楼面顶及其上的一切。" -# Source-Hash: 64916cc9ea80f43f +# Source-Hash: 044ccae8bec574e7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Expand panel" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Under the floor" +#: packages/editor/src/components/ui/panels/floor-foundation-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.expandPanel" -msgstr "展开面板" +msgid "editor.panels.floorFoundationPanel.underTheFloor" +msgstr "楼板下方" -# Source-Hash: 8a9a25621f200922 +# Source-Hash: 6aca44df3e582a81 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Manage collections…" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A hatch in the mezzanine: it cuts only the mezzanine’s floor." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.manageCollections" -msgstr "管理集合…" +msgid "editor.panels.floorOpeningPanel.aHatchInTheMezzanineIt" +msgstr "夹层中的开口:只切穿夹层的楼板。" -# Source-Hash: 2ff02ed91f54235c +# Source-Hash: 2ce79639d42da658 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open {title}" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Also cut the ceiling below" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.openTitle" -msgstr "打开{title}" +msgid "editor.panels.floorOpeningPanel.alsoCutTheCeilingBelow" +msgstr "同时切穿下方天花板" -# Source-Hash: bf91b71a9aa76e94 +# Source-Hash: e360814f64792300 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset" -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Also cut the floor above" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.reset" -msgstr "重置" +msgid "editor.panels.floorOpeningPanel.alsoCutTheFloorAbove" +msgstr "同时切穿上方楼板" -# Source-Hash: 04a212d6317f6787 +# Source-Hash: c25cddf8b831c2b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "“{title}” hit an error and was unloaded for this session." -#: packages/editor/src/components/ui/panels/panel-wrapper.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} · Drag its corners to change the shape." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.panelWrapper.titleHitAnErrorAndWas" -msgstr "“{title}”发生错误,已在本次会话中卸载。" +msgid "editor.panels.floorOpeningPanel.areaDragCorners" +msgstr "{area} · 拖动其角点以更改形状。" -# Source-Hash: 37d9f63758abdb67 +# Source-Hash: 32b168cf010a5daa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mixed" -#: packages/editor/src/components/ui/panels/parametric-field-control.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} · Shape follows its owner." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.parametricFieldControl.mixed" -msgstr "混合" +msgid "editor.panels.floorOpeningPanel.areaOwned" +msgstr "{area} · 形状跟随其所属对象。" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 71b5c7184cbd2e5d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/editor/src/components/ui/panels/parametric-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} · Drag its sides or corners to resize it; it moves with the stair." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.parametricInspector.actions" -msgstr "操作" +msgid "editor.panels.floorOpeningPanel.areaStairResize" +msgstr "{area} · 拖动其边或角点以调整大小;它会随楼梯移动。" # Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" -#: packages/editor/src/components/ui/panels/parametric-inspector.tsx +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.parametricInspector.delete" +msgid "editor.panels.floorOpeningPanel.delete" msgstr "删除" -# Source-Hash: e2411929697b7ed4 +# Source-Hash: 16552c2580bbe8b8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete with contents" -#: packages/editor/src/components/ui/panels/parametric-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.parametricInspector.deleteWithContents" -msgstr "连同内容一起删除" +msgid "editor.panels.floorOpeningPanel.done" +msgstr "完成" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/editor/src/components/ui/panels/parametric-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.parametricInspector.move" -msgstr "移动" +msgid "editor.panels.floorOpeningPanel.kicker" +msgstr "开口" -# Source-Hash: c0774c185060fc13 +# Source-Hash: 079ad92dac7947cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening · {level}" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.cancel" -msgstr "取消" +msgid "editor.panels.floorOpeningPanel.kickerLevel" +msgstr "开洞 · {level}" -# Source-Hash: 3a0701ebcb9f26cb +# Source-Hash: baf2c2c209637e5f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Capture" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening · in {room}" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.capture" -msgstr "采集" +msgid "editor.panels.floorOpeningPanel.kickerRoom" +msgstr "开洞 · 位于{room}" -# Source-Hash: 5211341ed18f33f6 +# Source-Hash: 1712c164335ecd86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening · in {room} · {level}" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.center" -msgstr "居中" +msgid "editor.panels.floorOpeningPanel.kickerRoomLevel" +msgstr "开洞 · 位于{room} · {level}" -# Source-Hash: a5b965dfb0bf2cd3 +# Source-Hash: 88e673123b9dbfe1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On {level}, as one void with this opening." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.clearScale" -msgstr "清除比例" +msgid "editor.panels.floorOpeningPanel.oneVoidWith" +msgstr "在{level},与此开洞形成一个洞口。" -# Source-Hash: 4edc6e45b0c19447 +# Source-Hash: c38959fc8fd3e59d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click both ends of a known distance on the plan, then type its real length." -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Owned by Elevator" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.clickBothEndsOfAKnown" -msgstr "在平面上点击已知距离的两端,然后输入其实际长度。" +msgid "editor.panels.floorOpeningPanel.ownedByElevator" +msgstr "归属于电梯" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 01494805cf60d78d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Owned by Staircase" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.delete" -msgstr "删除" +msgid "editor.panels.floorOpeningPanel.ownedByStaircase" +msgstr "归属于楼梯" -# Source-Hash: 59f7d81e8d36a157 +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw a line over a known dimension on the plan, then type its real length to scale the image exactly." -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.drawALineOverAKnown" -msgstr "在平面上沿已知尺寸画一条线,然后输入其实际长度以精确缩放图像。" +msgid "editor.panels.floorOpeningPanel.room" +msgstr "房间" -# Source-Hash: 42f6d0e4f065f114 +# Source-Hash: 1405b914a324b153 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "There is no floor above this storey." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.editScale" -msgstr "编辑比例" +msgid "editor.panels.floorOpeningPanel.thereIsNoFloorAboveThis" +msgstr "此层上方没有楼板。" -# Source-Hash: e156c84cbc90e0a7 +# Source-Hash: 776170dcae88e969 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guide Image" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "There is no storey below." +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.guideImage" -msgstr "参考图像" +msgid "editor.panels.floorOpeningPanel.thereIsNoStoreyBelow" +msgstr "下方没有楼层。" -# Source-Hash: 591087ea83a48ead +# Source-Hash: 0fdd1877a0f2d777 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{source, select, stair {Stair opening} elevator {Elevator opening} ceiling {Ceiling opening} other {Floor opening}}" +#: packages/editor/src/components/ui/panels/floor-opening-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.hide" -msgstr "隐藏" +msgid "editor.panels.floorOpeningPanel.title" +msgstr "{source, select, stair {楼梯开洞} elevator {电梯开洞} ceiling {天花板开洞} other {楼板开洞}}" -# Source-Hash: dd282ce13b9085ba +# Source-Hash: fa35c7653e1f649e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "One of them already wraps another corner. Unwrap it first." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.hideScale" -msgstr "隐藏比例" +msgid "editor.panels.mergeRefusal.alreadyJoined" +msgstr "其中一扇已包住另一个转角。请先解除。" -# Source-Hash: fc6eaa65315f601d +# Source-Hash: dd87eb1983876459 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Image" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{kind, select, item {There is an item between them.} door {There is a door between them.} window {There is a window between them.} shelf {There is a shelf between them.} other {There is something between them.}}" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.image" -msgstr "图像" +msgid "editor.panels.mergeRefusal.between" +msgstr "{kind, select, item {它们之间有一个物品。} door {它们之间有一扇门。} window {它们之间有一扇窗。} shelf {它们之间有一个搁板。} other {它们之间有其他对象。}}" -# Source-Hash: 241399e11d93bd7b +# Source-Hash: 58aea0b9789ae280 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lock" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "These windows cannot be merged." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.lock" -msgstr "锁定" +msgid "editor.panels.mergeRefusal.cannotMerge" +msgstr "这些窗户无法合并。" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 15170cfd9d666c4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Their walls meet at too sharp or too flat an angle for a corner window." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.move" -msgstr "移动" +msgid "editor.panels.mergeRefusal.cornerAngle" +msgstr "它们的墙体相交角度过锐或过钝,无法做转角窗。" -# Source-Hash: 1c0b8a5503c5daeb +# Source-Hash: f2818a1e20ebd6ca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opacity" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The window selected first is taller than the other wall. Select the other one first." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.opacity" -msgstr "不透明度" +msgid "editor.panels.mergeRefusal.heightExceedsWall" +msgstr "先选中的窗户比另一面墙高。请先选择另一扇。" -# Source-Hash: 6ca213a6b299f19f +# Source-Hash: 7c97fb4af929d4db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overlay image unavailable. Replace the image to restore it." -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "They are too far apart. Windows merge with at most {reach} between them." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.overlayImageUnavailableReplaceTheImage" -msgstr "叠加图像不可用。替换图像即可恢复。" +msgid "editor.panels.mergeRefusal.notAdjacent" +msgstr "它们相距太远。窗户之间最多相隔 {reach} 才能合并。" -# Source-Hash: 28fe6e9deddde6e8 +# Source-Hash: 57a281bdc4229b6d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "pos" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "One of them is too far from the corner. A window joins one within {reach} of it." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.pos" -msgstr "位置" +msgid "editor.panels.mergeRefusal.notAtCorner" +msgstr "其中一扇离转角太远。窗户只能与 {reach} 以内的窗合并。" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: e7d41ce7879ec075 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A roof or dormer window cannot join another window." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.position" -msgstr "位置" +msgid "editor.panels.mergeRefusal.notOnWall" +msgstr "屋顶窗或老虎窗不能与其他窗合并。" -# Source-Hash: 8b003432b36230c4 +# Source-Hash: eaad567d5e4257dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Quick Actions" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{kind, select, item {Sliding them to the corner would overlap an item.} door {Sliding them to the corner would overlap a door.} window {Sliding them to the corner would overlap a window.} shelf {Sliding them to the corner would overlap a shelf.} other {Sliding them to the corner would overlap something.}}" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.quickActions" -msgstr "快捷操作" +msgid "editor.panels.mergeRefusal.overlap" +msgstr "{kind, select, item {将它们滑到转角会与一个物品重叠。} door {将它们滑到转角会与一扇门重叠。} window {将它们滑到转角会与一扇窗重叠。} shelf {将它们滑到转角会与一个搁板重叠。} other {将它们滑到转角会与其他对象重叠。}}" -# Source-Hash: dcd4728e9ca90181 +# Source-Hash: ecb092821ed5b5e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reference Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Their walls do not meet at a corner." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.referenceScale" -msgstr "参考比例" +msgid "editor.panels.mergeRefusal.wallsNotMeeting" +msgstr "它们的墙体没有在转角相交。" -# Source-Hash: 0cb87327b8076151 +# Source-Hash: 37d9f63758abdb67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mixed" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx +#: packages/editor/src/components/ui/panels/parametric-field-control.tsx #, fuzzy -msgid "editor.panels.referencePanel.replace" -msgstr "替换" +msgid "editor.panels.mixed" +msgstr "混合" -# Source-Hash: 08b45f9ba66eab3b +# Source-Hash: d7cf5045c01b2eb9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replacing..." -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close" +#: packages/editor/src/components/ui/panels/mobile-panel-sheet.tsx #, fuzzy -msgid "editor.panels.referencePanel.replacing" -msgstr "替换中..." +msgid "editor.panels.mobilePanelSheet.close" +msgstr "关闭" -# Source-Hash: 2714b5a81cedb625 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset Image Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx #, fuzzy -msgid "editor.panels.referencePanel.resetImageScale" -msgstr "重置图像比例" +msgid "editor.panels.mobileSelectionBar.delete" +msgstr "删除" -# Source-Hash: a05d3e429ae259ae +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset Rotation" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx #, fuzzy -msgid "editor.panels.referencePanel.resetRotation" -msgstr "重置旋转" +msgid "editor.panels.mobileSelectionBar.duplicate" +msgstr "复制" -# Source-Hash: 5f433581c8f404fa +# Source-Hash: 7eb955d866c2668b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "rot" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit properties" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx #, fuzzy -msgid "editor.panels.referencePanel.rot" -msgstr "旋转" +msgid "editor.panels.mobileSelectionBar.editProperties" +msgstr "编辑属性" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: 89f25aa13e8192bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit {resolvedLabel}" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx #, fuzzy -msgid "editor.panels.referencePanel.rotation" -msgstr "旋转" +msgid "editor.panels.mobileSelectionBar.editResolvedlabel" +msgstr "编辑{resolvedLabel}" -# Source-Hash: 58fee802997c811c +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/editor/src/components/ui/panels/mobile-selection-bar.tsx #, fuzzy -msgid "editor.panels.referencePanel.scale" -msgstr "比例" +msgid "editor.panels.mobileSelectionBar.move" +msgstr "移动" -# Source-Hash: e7d0e7d41a775fd8 +# Source-Hash: 72be05e1796526c9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scaled · {scale}" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Currently {currentLabel}" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.panels.referencePanel.scaled" -msgstr "已缩放 · {scale}" +msgid "editor.panels.multiHeightMode.currentlyCurrentlabel" +msgstr "当前为{currentLabel}" -# Source-Hash: cd92eebfb30e708f +# Source-Hash: b2a1b3bc9676fe05 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scaled (hidden) · {scale}" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom height" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.panels.referencePanel.scaledHidden" -msgstr "已缩放(隐藏)· {scale}" +msgid "editor.panels.multiHeightMode.customHeight" +msgstr "自定义高度" -# Source-Hash: bfd20999de7f216a +# Source-Hash: a5c2353769b603d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scale & Opacity" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows level" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.panels.referencePanel.scaleOpacity" -msgstr "比例与不透明度" +msgid "editor.panels.multiHeightMode.followsLevel" +msgstr "跟随楼层" -# Source-Hash: 8d8777505acdf78e +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.panels.referencePanel.setScale" -msgstr "设置比例" +msgid "editor.panels.multiHeightMode.height" +msgstr "高度" -# Source-Hash: 827e0c6ac9936b69 +# Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/editor/src/components/ui/panels/multi-height-mode.tsx #, fuzzy -msgid "editor.panels.referencePanel.show" -msgstr "显示" +msgid "editor.panels.multiHeightMode.top" +msgstr "顶部" -# Source-Hash: 78be2337f0e81973 +# Source-Hash: 70f48b0141b656f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show Scale" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label} (session only). Plain click reselects all members. Not saved with the project." +#: packages/editor/src/components/ui/panels/multi-parametric-inspector.tsx #, fuzzy -msgid "editor.panels.referencePanel.showScale" -msgstr "显示比例" +msgid "editor.panels.multiParametricInspector.labelSessionOnlyPlainClickReselects" +msgstr "{label}(仅限本次会话)。普通点击会重新选中所有成员。不会随项目保存。" -# Source-Hash: ad85a193442c8f76 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Uncalibrated" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.uncalibrated" -msgstr "未校准" +msgid "editor.panels.multiSelectionPanel.delete" +msgstr "删除" -# Source-Hash: 6c500cc253ab3fd4 +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unlock" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.unlock" -msgstr "解锁" +msgid "editor.panels.multiSelectionPanel.duplicate" +msgstr "复制" -# Source-Hash: 4b8d7e52013d1691 +# Source-Hash: b0e7e3b47dfb5a0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "XYZ" -#: packages/editor/src/components/ui/panels/reference-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Group" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.referencePanel.xyz" -msgstr "XYZ" +msgid "editor.panels.multiSelectionPanel.group" +msgstr "编组" -# Source-Hash: e01549105012f8d2 +# Source-Hash: ca0a95fe0b08b8b6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "+ Add mezzanine" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Group (Ctrl/Cmd+G)" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.addMezzanine" -msgstr "+ 添加夹层" +msgid "editor.panels.multiSelectionPanel.groupCtrlCmdG" +msgstr "编组(Ctrl/Cmd+G)" -# Source-Hash: 167b0fe7fdbcd51d +# Source-Hash: 70f48b0141b656f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A drawn slab: set its thickness and finishes here. It has no footprint height or foundation." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label} (session only). Plain click reselects all members. Not saved with the project." +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.aDrawnSlabSetItsThickness" -msgstr "绘制的楼板:在此设置其厚度和饰面。它没有基底高度或基础。" +msgid "editor.panels.multiSelectionPanel.labelSessionOnlyPlainClickReselects" +msgstr "{label}(仅限本次会话)。普通点击会重新选中所有成员。不会随项目保存。" -# Source-Hash: 6cb0969b65fb60bf +# Source-Hash: fc98ef29c2842341 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "At floor level" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{length} selected" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.atFloorLevel" -msgstr "与楼面齐平" +msgid "editor.panels.multiSelectionPanel.lengthSelected" +msgstr "已选择 {length} 个" -# Source-Hash: e8563d5ae1ee7390 +# Source-Hash: 323aaf1ebd04ada7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Built on" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Merge windows" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.builtOn" -msgstr "建于" +msgid "editor.panels.multiSelectionPanel.mergeWindows" +msgstr "合并窗户" -# Source-Hash: 8e5ca7510677460c +# Source-Hash: 7855d03a6140af77 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Built with" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Merge windows into a corner window: both take the height, sill and type of the one you selected first" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.builtWith" -msgstr "构造" +msgid "editor.panels.multiSelectionPanel.mergeWindowsIntoACornerWindow" +msgstr "合并为转角窗:两者都采用先选中窗户的高度、窗台和类型" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: b79da96502d2e1c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Merge windows into one across both: it keeps the type and style of the one you selected first" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.ceiling" -msgstr "天花板" +msgid "editor.panels.multiSelectionPanel.mergeWindowsIntoOneAcrossBoth" +msgstr "合并为跨越两者的一扇窗:保留先选中窗户的类型和样式" -# Source-Hash: 9bf177f59f971033 +# Source-Hash: f409934681a046e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "At {height}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select building" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.ceilingAt" -msgstr "位于 {height}" +msgid "editor.panels.multiSelectionPanel.selectBuilding" +msgstr "选择建筑" -# Source-Hash: 48768dc0fc7b86a4 +# Source-Hash: c62a73873bd0164d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close with walls" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select the whole building to move all its levels" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.closeWithWalls" -msgstr "用墙体封闭" +msgid "editor.panels.multiSelectionPanel.selectTheWholeBuildingToMove" +msgstr "选择整栋建筑以移动其所有楼层" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 75c84b4f21aefde4 +# Source-Hash: 7bd5f29203a28efb # Review: required -# English: "{ambiguous, select, yes {Floor is several drawn slabs, mostly {name}} other {Floor is a drawn slab: {name}}}{shared, plural, =0 {} one { (shared with {sharedCount} room)} other { (shared with {sharedCount} rooms)}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ungroup" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.drawnFloor" -msgstr "{ambiguous, select, yes {楼板由多块绘制楼板组成,主要是{name}} other {楼板是一块绘制楼板:{name}}}{shared, plural, =0 {} other {(与 {sharedCount} 个房间共用)}}" +msgid "editor.panels.multiSelectionPanel.ungroup" +msgstr "取消编组" -# Source-Hash: 97e0fab8ffda6d6c +# Source-Hash: aec9c3983a440d4a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "This floor is a drawn slab: select it to edit or delete it." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ungroup (Ctrl/Cmd+Shift+G)" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.drawnFloorSwitchHint" -msgstr "此楼板是绘制的楼板:选中它以编辑或删除。" +msgid "editor.panels.multiSelectionPanel.ungroupCtrlCmdShiftG" +msgstr "取消编组(Ctrl/Cmd+Shift+G)" -# Source-Hash: ad5426620188242c +# Source-Hash: 420385f27c627cee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawn slab" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unwrap the corner" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.drawnSlab" -msgstr "绘制楼板" +msgid "editor.panels.multiSelectionPanel.unwrapTheCorner" +msgstr "解除转角" -# Source-Hash: 0da0d104eaefbbad +# Source-Hash: 7906c9f4baebc70b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawn slab at {height}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unwrap the corner: both windows stay, each framed at the corner" +#: packages/editor/src/components/ui/panels/multi-selection-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.drawnSlabAt" -msgstr "绘制楼板位于 {height}" +msgid "editor.panels.multiSelectionPanel.unwrapTheCornerBothWindowsStay" +msgstr "解除转角:两扇窗都保留,各自在转角处加框" -# Source-Hash: 5dfead58503dbc86 +# Source-Hash: 170b2049ef0f9131 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit shape" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selection" +#: packages/editor/src/components/ui/panels/panel-manager.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.editShape" -msgstr "编辑形状" +msgid "editor.panels.panelManager.selection" +msgstr "当前选择" -# Source-Hash: fadf264be55063e5 +# Source-Hash: 7ceade8f25b58fe9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat, at wall height" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.flatAtWallHeight" -msgstr "平顶,位于墙高" +msgid "editor.panels.panelWrapper.back" +msgstr "返回" -# Source-Hash: d7148fa065bc709b +# Source-Hash: d7cf5045c01b2eb9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.floor" -msgstr "楼层" +msgid "editor.panels.panelWrapper.close" +msgstr "关闭" -# Source-Hash: 996e8191c069e779 +# Source-Hash: 4f15c3e0fe6178b5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{distance} down" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collapse panel" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.floorDown" -msgstr "下降 {distance}" +msgid "editor.panels.panelWrapper.collapsePanel" +msgstr "收起面板" -# Source-Hash: 73614b8faa059cd6 +# Source-Hash: 135af27a14a4cda7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor thickness" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collections" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.floorThickness" -msgstr "楼板厚度" +msgid "editor.panels.panelWrapper.collections" +msgstr "集合" -# Source-Hash: 79cdde853c3e8f61 +# Source-Hash: 64916cc9ea80f43f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{distance} up" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Expand panel" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.floorUp" -msgstr "上升 {distance}" +msgid "editor.panels.panelWrapper.expandPanel" +msgstr "展开面板" -# Source-Hash: 77bc12b7aba0eb60 +# Source-Hash: 8a9a25621f200922 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hand-drawn ceiling" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Manage collections…" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.handDrawnCeiling" -msgstr "手绘天花板" +msgid "editor.panels.panelWrapper.manageCollections" +msgstr "管理集合…" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: bf91b71a9aa76e94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset" +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.height" -msgstr "高度" +msgid "editor.panels.panelWrapper.reset" +msgstr "重置" -# Source-Hash: 4d35023efe090b82 +# Source-Hash: 04a212d6317f6787 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Include floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "“{title}” hit an error and was unloaded for this session." +#: packages/editor/src/components/ui/panels/panel-wrapper.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.includeFloor" -msgstr "包含楼板" +msgid "editor.panels.panelWrapper.titleHitAnErrorAndWas" +msgstr "“{title}”发生错误,已在本次会话中卸载。" -# Source-Hash: 6398ac77644eb5f6 +# Source-Hash: 37d9f63758abdb67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{part, select, floor {Include floor} walls {Include walls} other {Include ceiling}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mixed" +#: packages/editor/src/components/ui/panels/parametric-field-control.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.includePart" -msgstr "{part, select, floor {包含楼板} walls {包含墙体} other {包含天花板}}" +msgid "editor.panels.parametricFieldControl.mixed" +msgstr "混合" -# Source-Hash: 3629e64a6e796ca9 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Include walls" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/editor/src/components/ui/panels/parametric-inspector.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.includeWalls" -msgstr "包含墙体" +msgid "editor.panels.parametricInspector.actions" +msgstr "操作" -# Source-Hash: f6d07fc7f239278b +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Keep outside dimensions" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/parametric-inspector.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.keepOutsideDimensions" -msgstr "保持外部尺寸" +msgid "editor.panels.parametricInspector.delete" +msgstr "删除" -# Source-Hash: 544410e3cb0e0b07 +# Source-Hash: e2411929697b7ed4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lowered {lift}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete with contents" +#: packages/editor/src/components/ui/panels/parametric-inspector.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.lowered" -msgstr "降低 {lift}" +msgid "editor.panels.parametricInspector.deleteWithContents" +msgstr "连同内容一起删除" -# Source-Hash: c2daf78b740e4397 +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "+ New floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/editor/src/components/ui/panels/parametric-inspector.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.newFloor" -msgstr "+ 新建楼板" +msgid "editor.panels.parametricInspector.move" +msgstr "移动" -# Source-Hash: ba9edc7910a60cea +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No floor" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.noFloor" -msgstr "无楼板" +msgid "editor.panels.referencePanel.cancel" +msgstr "取消" -# Source-Hash: ea2675041df74f40 +# Source-Hash: 3a0701ebcb9f26cb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Nothing to change." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Capture" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.nothingToChange" -msgstr "没有需要更改的内容。" +msgid "editor.panels.referencePanel.capture" +msgstr "采集" -# Source-Hash: ebe0d375d7938c93 +# Source-Hash: 5211341ed18f33f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Not included" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.notIncluded" -msgstr "未包含" +msgid "editor.panels.referencePanel.center" +msgstr "居中" -# Source-Hash: e9440fa9f770b7a4 +# Source-Hash: a5b965dfb0bf2cd3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "On the ground" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.onTheGround" -msgstr "位于地面" +msgid "editor.panels.referencePanel.clearScale" +msgstr "清除比例" -# Source-Hash: a5deb36c485d91bd +# Source-Hash: 4edc6e45b0c19447 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "On the walls below" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click both ends of a known distance on the plan, then type its real length." +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.onTheWallsBelow" -msgstr "位于下方墙体上" +msgid "editor.panels.referencePanel.clickBothEndsOfAKnown" +msgstr "在平面上点击已知距离的两端,然后输入其实际长度。" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 2256aec0d5bdc3ea +# Source-Hash: b26de372b4b0eaac # Review: required -# English: "{openSides, plural, one {{openSideCount} open side} other {{openSideCount} open sides}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.openSides" -msgstr "{openSides, plural, other {{openSideCount} 个开放边}}" +msgid "editor.panels.referencePanel.delete" +msgstr "删除" -# Source-Hash: f704520c5e5b92b2 +# Source-Hash: 59f7d81e8d36a157 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Partial · {coverage, number, percent} covered" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw a line over a known dimension on the plan, then type its real length to scale the image exactly." +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.partialCovered" -msgstr "部分 · 覆盖 {coverage, number, percent}" +msgid "editor.panels.referencePanel.drawALineOverAKnown" +msgstr "在平面上沿已知尺寸画一条线,然后输入其实际长度以精确缩放图像。" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: b648bee0231a41cd +# Source-Hash: 42f6d0e4f065f114 # Review: required -# English: "Partial · {walls, plural, one {{wallCount} wall} other {{wallCount} walls}}, {openSides, plural, one {{openSideCount} open side} other {{openSideCount} open sides}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.partialWalls" -msgstr "部分 · {walls, plural, other {{wallCount} 面墙}},{openSides, plural, other {{openSideCount} 个开放边}}" +msgid "editor.panels.referencePanel.editScale" +msgstr "编辑比例" -# Source-Hash: e503250e8ecb0030 +# Source-Hash: e156c84cbc90e0a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised {lift}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guide Image" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.raised" -msgstr "抬高 {lift}" +msgid "editor.panels.referencePanel.guideImage" +msgstr "参考图像" -# Source-Hash: 0cb87327b8076151 +# Source-Hash: 591087ea83a48ead # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.replace" -msgstr "替换" +msgid "editor.panels.referencePanel.hide" +msgstr "隐藏" -# Source-Hash: a4395168488bb476 +# Source-Hash: dd282ce13b9085ba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.select" -msgstr "选择" +msgid "editor.panels.referencePanel.hideScale" +msgstr "隐藏比例" -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: fc6eaa65315f601d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Image" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.shape" -msgstr "形状" +msgid "editor.panels.referencePanel.image" +msgstr "图像" -# Source-Hash: aafd84823715d698 +# Source-Hash: 241399e11d93bd7b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Turning walls off keeps the ones shared with {rooms}." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lock" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.sharedWallsNote" -msgstr "关闭墙体时会保留与{rooms}共用的墙体。" +msgid "editor.panels.referencePanel.lock" +msgstr "锁定" -# Source-Hash: c98df900d43f77bc +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sits on: {name} · {preset}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.sitsOnPreset" -msgstr "支承于:{name} · {preset}" +msgid "editor.panels.referencePanel.move" +msgstr "移动" -# Source-Hash: a17a79e835fa2064 +# Source-Hash: 1c0b8a5503c5daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "the next room" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opacity" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.theNextRoom" -msgstr "相邻房间" +msgid "editor.panels.referencePanel.opacity" +msgstr "不透明度" -# Source-Hash: ebae699e0cb18ea6 +# Source-Hash: 6ca213a6b299f19f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use existing" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overlay image unavailable. Replace the image to restore it." +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.useExisting" -msgstr "使用现有" +msgid "editor.panels.referencePanel.overlayImageUnavailableReplaceTheImage" +msgstr "叠加图像不可用。替换图像即可恢复。" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 9976021d9162cd5e +# Source-Hash: 28fe6e9deddde6e8 # Review: required -# English: "{walls, plural, one {{wallCount} wall} other {{wallCount} walls}}" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "pos" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.wallCount" -msgstr "{walls, plural, other {{wallCount} 面墙}}" +msgid "editor.panels.referencePanel.pos" +msgstr "位置" -# Source-Hash: aac9a732d2159ccc +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls" -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.walls" -msgstr "墙体" +msgid "editor.panels.referencePanel.position" +msgstr "位置" -# Source-Hash: 6c69eb46a0c40d52 +# Source-Hash: 8b003432b36230c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walls thicken inward, so the building's outer size stays the same." -#: packages/editor/src/components/ui/panels/room-construction-rows.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Quick Actions" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomConstructionRows.wallsThickenInwardSoTheBuilding" -msgstr "墙体向内加厚,因此建筑外部尺寸保持不变。" +msgid "editor.panels.referencePanel.quickActions" +msgstr "快捷操作" -# Source-Hash: 4e4f1a24e4a9d61e +# Source-Hash: dcd4728e9ca90181 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut opening" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reference Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.cutOpening" -msgstr "开洞" +msgid "editor.panels.referencePanel.referenceScale" +msgstr "参考比例" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: 0cb87327b8076151 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.done" -msgstr "完成" +msgid "editor.panels.referencePanel.replace" +msgstr "替换" -# Source-Hash: 2c89abb1778a3f9b +# Source-Hash: 08b45f9ba66eab3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit floor" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replacing..." +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.editFloor" -msgstr "编辑楼板" +msgid "editor.panels.referencePanel.replacing" +msgstr "替换中..." -# Source-Hash: ca18a6c5398fc8ab +# Source-Hash: 2714b5a81cedb625 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevator opening" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset Image Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.elevatorOpening" -msgstr "电梯开洞" +msgid "editor.panels.referencePanel.resetImageScale" +msgstr "重置图像比例" -# Source-Hash: eafea43e795f3708 +# Source-Hash: a05d3e429ae259ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No openings yet. Cut one for a stair void or a hatch." -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset Rotation" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.noOpeningsYetCutOneFor" -msgstr "暂无开洞。可为楼梯洞口或检修口开一个。" +msgid "editor.panels.referencePanel.resetRotation" +msgstr "重置旋转" -# Source-Hash: 60fac94ffa614238 +# Source-Hash: 5f433581c8f404fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening {number}" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "rot" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.openingNumber" -msgstr "开洞 {number}" +msgid "editor.panels.referencePanel.rot" +msgstr "旋转" -# Source-Hash: 7aafbf90d659dcf6 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, =0 {No openings} one {{number} opening} other {{number} openings}}" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.openings" -msgstr "{count, plural, =0 {无开口} other {{number} 个开口}}" +msgid "editor.panels.referencePanel.rotation" +msgstr "旋转" -# Source-Hash: c1a1794d31990f5a +# Source-Hash: 58fee802997c811c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair opening" -#: packages/editor/src/components/ui/panels/room-openings-field.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomOpeningsField.stairOpening" -msgstr "楼梯开洞" +msgid "editor.panels.referencePanel.scale" +msgstr "比例" -# Source-Hash: f0a46329fef44d94 +# Source-Hash: e7d0e7d41a775fd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add stairs" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scaled · {scale}" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.addStairs" -msgstr "添加楼梯" +msgid "editor.panels.referencePanel.scaled" +msgstr "已缩放 · {scale}" -# Source-Hash: 8a2ab34a61b9d181 +# Source-Hash: cd92eebfb30e708f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add to a unit" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scaled (hidden) · {scale}" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.addToAUnit" -msgstr "添加到单元" +msgid "editor.panels.referencePanel.scaledHidden" +msgstr "已缩放(隐藏)· {scale}" -# Source-Hash: 8332ab41e22958f1 +# Source-Hash: bfd20999de7f216a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Area" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scale & Opacity" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.area" -msgstr "面积" +msgid "editor.panels.referencePanel.scaleOpacity" +msgstr "比例与不透明度" -# Source-Hash: 88f1a727e5528c10 +# Source-Hash: 8d8777505acdf78e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Browse" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.browse" -msgstr "浏览" +msgid "editor.panels.referencePanel.setScale" +msgstr "设置比例" -# Source-Hash: 8e5ca7510677460c +# Source-Hash: 827e0c6ac9936b69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Built with" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.builtWith" -msgstr "构造" +msgid "editor.panels.referencePanel.show" +msgstr "显示" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: 78be2337f0e81973 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show Scale" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.ceiling" -msgstr "天花板" +msgid "editor.panels.referencePanel.showScale" +msgstr "显示比例" -# Source-Hash: a5e4fe4960deced9 +# Source-Hash: ad85a193442c8f76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete room" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Uncalibrated" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.deleteRoom" -msgstr "删除房间" +msgid "editor.panels.referencePanel.uncalibrated" +msgstr "未校准" -# Source-Hash: 5dfead58503dbc86 +# Source-Hash: 6c500cc253ab3fd4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit shape" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unlock" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.editShape" -msgstr "编辑形状" +msgid "editor.panels.referencePanel.unlock" +msgstr "解锁" -# Source-Hash: d7148fa065bc709b +# Source-Hash: 4b8d7e52013d1691 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "XYZ" +#: packages/editor/src/components/ui/panels/reference-panel.tsx #, fuzzy -msgid "editor.panels.roomPanel.floor" -msgstr "楼层" +msgid "editor.panels.referencePanel.xyz" +msgstr "XYZ" -# Source-Hash: d17c3b63449c052b +# Source-Hash: e01549105012f8d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{height} headroom" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "+ Add mezzanine" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.headroom" -msgstr "净空 {height}" +msgid "editor.panels.roomConstructionRows.addMezzanine" +msgstr "+ 添加夹层" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: 167b0fe7fdbcd51d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A drawn slab: set its thickness and finishes here. It has no footprint height or foundation." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.height" -msgstr "高度" +msgid "editor.panels.roomConstructionRows.aDrawnSlabSetItsThickness" +msgstr "绘制的楼板:在此设置其厚度和饰面。它没有基底高度或基础。" -# Source-Hash: 2d89c1638aa8dd7e +# Source-Hash: 6cb0969b65fb60bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide code" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "At floor level" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.hideCode" -msgstr "隐藏代码" +msgid "editor.panels.roomConstructionRows.atFloorLevel" +msgstr "与楼面齐平" -# Source-Hash: e93969f5a7cbb140 +# Source-Hash: e14858b33b6e2623 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room · {level}" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.kickerLevel" -msgstr "房间 · {level}" +msgid "editor.panels.roomConstructionRows.beam" +msgstr "梁" -# Source-Hash: f4ad56b4e0c014b3 +# Source-Hash: 4b03c226d5f88a42 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine · in {room}" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam size" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.kickerMezzanineIn" -msgstr "夹层 · 位于{room}" +msgid "editor.panels.roomConstructionRows.beamSize" +msgstr "梁尺寸" -# Source-Hash: de37205633316011 +# Source-Hash: e8563d5ae1ee7390 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room · not enclosed" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Built on" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.kickerNotEnclosed" -msgstr "房间 · 未封闭" +msgid "editor.panels.roomConstructionRows.builtOn" +msgstr "建于" -# Source-Hash: 9e84d6d7b9885c4f +# Source-Hash: 8e5ca7510677460c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Loading…" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Built with" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.loading" -msgstr "加载中…" +msgid "editor.panels.roomConstructionRows.builtWith" +msgstr "构造" -# Source-Hash: 194a147d4618a994 +# Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.mezzanine" -msgstr "夹层" +msgid "editor.panels.roomConstructionRows.ceiling" +msgstr "天花板" -# Source-Hash: 97de3df03c4a0be6 +# Source-Hash: 9bf177f59f971033 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine name" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "At {height}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.mezzanineName" -msgstr "夹层名称" +msgid "editor.panels.roomConstructionRows.ceilingAt" +msgstr "位于 {height}" -# Source-Hash: 42cfb1bcb80d09e7 +# Source-Hash: 48768dc0fc7b86a4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine names" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close with walls" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.mezzanineNames" -msgstr "夹层名称" +msgid "editor.panels.roomConstructionRows.closeWithWalls" +msgstr "用墙体封闭" -# Source-Hash: 13b3e6a6afe319d1 +# Source-Hash: 75c84b4f21aefde4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "New unit" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{ambiguous, select, yes {Floor is several drawn slabs, mostly {name}} other {Floor is a drawn slab: {name}}}{shared, plural, =0 {} one { (shared with {sharedCount} room)} other { (shared with {sharedCount} rooms)}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.newUnit" -msgstr "新建单元" +msgid "editor.panels.roomConstructionRows.drawnFloor" +msgstr "{ambiguous, select, yes {楼板由多块绘制楼板组成,主要是{name}} other {楼板是一块绘制楼板:{name}}}{shared, plural, =0 {} other {(与 {sharedCount} 个房间共用)}}" -# Source-Hash: f2953d2931e36d0c +# Source-Hash: 97e0fab8ffda6d6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This floor is a drawn slab: select it to edit or delete it." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.none" -msgstr "无" +msgid "editor.panels.roomConstructionRows.drawnFloorSwitchHint" +msgstr "此楼板是绘制的楼板:选中它以编辑或删除。" -# Source-Hash: e92d6108b57df9e1 +# Source-Hash: ad5426620188242c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Not enough headroom" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawn slab" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.notEnoughHeadroom" -msgstr "净空不足" +msgid "editor.panels.roomConstructionRows.drawnSlab" +msgstr "绘制楼板" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 81a6770092b05d48 +# Source-Hash: 0da0d104eaefbbad # Review: required -# English: "{doors, plural, one {{doorCount} door} other {{doorCount} doors}} · {windows, plural, one {{windowCount} window} other {{windowCount} windows}}" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawn slab at {height}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.openingCounts" -msgstr "{doors, plural, other {{doorCount} 扇门}} · {windows, plural, other {{windowCount} 扇窗}}" +msgid "editor.panels.roomConstructionRows.drawnSlabAt" +msgstr "绘制楼板位于 {height}" -# Source-Hash: a8cd9507ce472a48 +# Source-Hash: 5dfead58503dbc86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{area} · Close its walls to build its floor and ceiling." -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit shape" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.openRoomArea" -msgstr "{area} · 围合其墙体以生成楼板和天花板。" +msgid "editor.panels.roomConstructionRows.editShape" +msgstr "编辑形状" -# Source-Hash: f8aa48ec39a15616 +# Source-Hash: fadf264be55063e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Over the mezzanine" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat, at wall height" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.overTheMezzanine" -msgstr "位于夹层上方" +msgid "editor.panels.roomConstructionRows.flatAtWallHeight" +msgstr "平顶,位于墙高" -# Source-Hash: ac87e14dabd5a256 +# Source-Hash: d7148fa065bc709b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Perimeter" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.perimeter" -msgstr "周长" +msgid "editor.panels.roomConstructionRows.floor" +msgstr "楼层" -# Source-Hash: ed2aaf0a8d5a9b7b +# Source-Hash: 996e8191c069e779 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{distance} down" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.pick" -msgstr "选择" +msgid "editor.panels.roomConstructionRows.floorDown" +msgstr "下降 {distance}" -# Source-Hash: 7baaebbd411cc837 +# Source-Hash: 73614b8faa059cd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picking it adds a number" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor thickness" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.pickingItAddsANumber" -msgstr "选择后会添加编号" +msgid "editor.panels.roomConstructionRows.floorThickness" +msgstr "楼板厚度" -# Source-Hash: 9469a102f04ea196 +# Source-Hash: 79cdde853c3e8f61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{distance} up" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.remove" -msgstr "移除" +msgid "editor.panels.roomConstructionRows.floorUp" +msgstr "上升 {distance}" -# Source-Hash: 41ac9dd23bb558d7 +# Source-Hash: b6b724f9f4db6d3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove from unit" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{posts, plural, one {{postCount} post} other {{postCount} posts}} and {beams, plural, one {{beamCount} beam} other {{beamCount} beams}}, a post on each outside corner, kept with {room, select, deck {the deck} patio {the patio} other {the porch}}." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.removeFromUnit" -msgstr "从单元中移除" +msgid "editor.panels.roomConstructionRows.framingAutoHint" +msgstr "{posts, plural, other {{postCount} 根立柱}}和 {beams, plural, other {{beamCount} 根梁}},每个外角各设一根立柱,随{room, select, deck {平台} patio {露台} other {门廊}}自动更新。" -# Source-Hash: a11d13b92b3cefdb +# Source-Hash: d18036b75b2c3e4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove from {unit}" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Automatic" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.removeFromUnitNamed" -msgstr "从{unit}中移除" +msgid "editor.panels.roomConstructionRows.framingAutomatic" +msgstr "自动" -# Source-Hash: d6952b4e54d246dd +# Source-Hash: 387082cd5f118bed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rename" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Manual" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.rename" -msgstr "重命名" +msgid "editor.panels.roomConstructionRows.framingManual" +msgstr "手动" -# Source-Hash: 3562f9bea0a4a8f3 +# Source-Hash: 287400b1b4b46abd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{name} · Rename" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kept as you edited them. Automatic rebuilds them from these settings." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.renameNamed" -msgstr "{name} · 重命名" +msgid "editor.panels.roomConstructionRows.framingManualHint" +msgstr "保持手动编辑后的状态。选择“自动”将按这些设置重建。" -# Source-Hash: d0d4e919bb58a977 +# Source-Hash: 50accd740fa2e736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Revert" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Off" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.revert" -msgstr "还原" +msgid "editor.panels.roomConstructionRows.framingOff" +msgstr "关闭" -# Source-Hash: 612dcd5bf06a79c4 +# Source-Hash: 4dfa7082b7e30280 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None. Automatic puts a post on each outside corner and a beam on them, to carry a roof over {room, select, deck {the deck} patio {the patio} other {the porch}}." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.room" -msgstr "房间" +msgid "editor.panels.roomConstructionRows.framingOffHint" +msgstr "无。“自动”会在每个外角设一根立柱并在其上架梁,以承托{room, select, deck {平台} patio {露台} other {门廊}}上方的屋顶。" -# Source-Hash: 15ae260fae44f42f +# Source-Hash: 77bc12b7aba0eb60 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room colour — used in the plan and labels" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hand-drawn ceiling" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.roomColourUsedInThePlan" -msgstr "房间颜色 — 用于平面图和标签" +msgid "editor.panels.roomConstructionRows.handDrawnCeiling" +msgstr "手绘天花板" -# Source-Hash: bf75e739dd7e5877 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room name" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.roomName" -msgstr "房间名称" +msgid "editor.panels.roomConstructionRows.height" +msgstr "高度" -# Source-Hash: 2ecf8c059646873b +# Source-Hash: 4d35023efe090b82 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room names" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Include floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.roomNames" -msgstr "房间名称" +msgid "editor.panels.roomConstructionRows.includeFloor" +msgstr "包含楼板" -# Source-Hash: e9a0a3688faba18b +# Source-Hash: 6398ac77644eb5f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scripted finish" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{part, select, floor {Include floor} walls {Include walls} other {Include ceiling}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.scriptedFinish" -msgstr "脚本饰面" +msgid "editor.panels.roomConstructionRows.includePart" +msgstr "{part, select, floor {包含楼板} walls {包含墙体} other {包含天花板}}" -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: 3629e64a6e796ca9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Include walls" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.shape" -msgstr "形状" +msgid "editor.panels.roomConstructionRows.includeWalls" +msgstr "包含墙体" -# Source-Hash: e51144ca1759a7bf +# Source-Hash: f6d07fc7f239278b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show mezzanine names" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keep outside dimensions" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.showMezzanineNames" -msgstr "显示夹层名称" +msgid "editor.panels.roomConstructionRows.keepOutsideDimensions" +msgstr "保持外部尺寸" -# Source-Hash: 875b7303c47df33f +# Source-Hash: 544410e3cb0e0b07 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show room names" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lowered {lift}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.showRoomNames" -msgstr "显示房间名称" +msgid "editor.panels.roomConstructionRows.lowered" +msgstr "降低 {lift}" -# Source-Hash: f05bc67c57e4d530 +# Source-Hash: c2daf78b740e4397 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stairs" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "+ New floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.stairs" -msgstr "楼梯" +msgid "editor.panels.roomConstructionRows.newFloor" +msgstr "+ 新建楼板" -# Source-Hash: 062cc0f1afef0c52 +# Source-Hash: ba9edc7910a60cea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unit" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No floor" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.unit" -msgstr "单元" +msgid "editor.panels.roomConstructionRows.noFloor" +msgstr "无楼板" -# Source-Hash: 91436d6b374e8263 +# Source-Hash: ea2675041df74f40 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Nothing to change." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.use" -msgstr "使用" +msgid "editor.panels.roomConstructionRows.nothingToChange" +msgstr "没有需要更改的内容。" -# Source-Hash: 61880aff6cd698c9 +# Source-Hash: ebe0d375d7938c93 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{used} on this level" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not included" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.usedOnThisLevel" -msgstr "此楼层已有 {used} 个" +msgid "editor.panels.roomConstructionRows.notIncluded" +msgstr "未包含" -# Source-Hash: 611604740ed4549c +# Source-Hash: e9440fa9f770b7a4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{use} “{name}”" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On the ground" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.useTyped" -msgstr "{use}“{name}”" +msgid "editor.panels.roomConstructionRows.onTheGround" +msgstr "位于地面" -# Source-Hash: 21242af83a2a6d17 +# Source-Hash: a5deb36c485d91bd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "View code" -#: packages/editor/src/components/ui/panels/room-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On the walls below" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.roomPanel.viewCode" -msgstr "查看代码" +msgid "editor.panels.roomConstructionRows.onTheWallsBelow" +msgstr "位于下方墙体上" -# Source-Hash: ba15840e60ce672b +# Source-Hash: 2256aec0d5bdc3ea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The script could not be read." -#: packages/editor/src/components/ui/panels/room-panel.tsx -#: packages/nodes/src/wall/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{openSides, plural, one {{openSideCount} open side} other {{openSideCount} open sides}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.scriptUnreadable" -msgstr "无法读取脚本。" +msgid "editor.panels.roomConstructionRows.openSides" +msgstr "{openSides, plural, other {{openSideCount} 个开放边}}" -# Source-Hash: 4e186fc057733162 +# Source-Hash: f704520c5e5b92b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Polygon" -#: packages/editor/src/components/ui/panels/shape-choice.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Partial · {coverage, number, percent} covered" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.shapeChoice.polygon" -msgstr "多边形" +msgid "editor.panels.roomConstructionRows.partialCovered" +msgstr "部分 · 覆盖 {coverage, number, percent}" -# Source-Hash: 2c2c20272b0370cc +# Source-Hash: b648bee0231a41cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangle" -#: packages/editor/src/components/ui/panels/shape-choice.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Partial · {walls, plural, one {{wallCount} wall} other {{wallCount} walls}}, {openSides, plural, one {{openSideCount} open side} other {{openSideCount} open sides}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.shapeChoice.rectangle" -msgstr "矩形" +msgid "editor.panels.roomConstructionRows.partialWalls" +msgstr "部分 · {walls, plural, other {{wallCount} 面墙}},{openSides, plural, other {{openSideCount} 个开放边}}" -# Source-Hash: 5dc88f90e6aa4129 +# Source-Hash: 4b2a51c39b382184 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete region" -#: packages/editor/src/components/ui/panels/wall-region-list.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Posts and beam" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.wallRegionList.deleteRegion" -msgstr "删除区域" +msgid "editor.panels.roomConstructionRows.postsAndBeam" +msgstr "立柱与梁" -# Source-Hash: d81d8cbadf5d4f33 +# Source-Hash: faa36308c1ecb2a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paint regions" -#: packages/editor/src/components/ui/panels/wall-region-list.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post size" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.panels.wallRegionList.paintRegions" -msgstr "涂刷区域" +msgid "editor.panels.roomConstructionRows.postSize" +msgstr "立柱尺寸" +# Source-Hash: cc25439729a97f76 # Review: required -# Source-Hash: 89ee318aad485f83 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Adjust design" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post spacing (max)" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.adjustDesign" -msgstr "调整设计" +msgid "editor.panels.roomConstructionRows.postSpacingMax" +msgstr "立柱间距(最大)" +# Source-Hash: e503250e8ecb0030 # Review: required -# Source-Hash: 7ceade8f25b58fe9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised {lift}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.back" -msgstr "返回" +msgid "editor.panels.roomConstructionRows.raised" +msgstr "抬高 {lift}" +# Source-Hash: 0cb87327b8076151 # Review: required -# Source-Hash: ba9b68175315e177 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit parts" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.editParts" -msgstr "编辑部件" +msgid "editor.panels.roomConstructionRows.replace" +msgstr "替换" +# Source-Hash: be1c56bb3ddc63c7 # Review: required -# Source-Hash: 07c62820f014ed6c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid attachment" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room type" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidAttachment" -msgstr "附着无效" +msgid "editor.panels.roomConstructionRows.roomType" +msgstr "房间类型" +# Source-Hash: f3aa561772702108 # Review: required -# Source-Hash: f862aea8d7957c55 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid edit" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidEdit" -msgstr "编辑无效" +msgid "editor.panels.roomConstructionRows.roomTypeDeck" +msgstr "平台" +# Source-Hash: f0028986efecf7d1 # Review: required -# Source-Hash: 190cf30b8edd8dd1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid placement" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outdoors: deck boards on a wood frame and posts, 1 in down from the house; no ceiling." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidPlacement" -msgstr "放置无效" +msgid "editor.panels.roomConstructionRows.roomTypeDeckHint" +msgstr "室外:平台铺板铺于木框架和立柱上,比房屋低 1 in;无天花板。" +# Source-Hash: 78dbe13192c0894b # Review: required -# Source-Hash: 45bd2ec690cc48dc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid position" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Patio" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidPosition" -msgstr "位置无效" +msgid "editor.panels.roomConstructionRows.roomTypePatio" +msgstr "露台" +# Source-Hash: 5e4ea6a084f67808 # Review: required -# Source-Hash: faccab895717c598 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Invalid reset" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outdoors and open: a concrete slab 1½ in down from the house, no ceiling." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.invalidReset" -msgstr "重置无效" +msgid "editor.panels.roomConstructionRows.roomTypePatioHint" +msgstr "室外露天:混凝土板比房屋低 1½ in,无天花板。" +# Source-Hash: 97d20e41044a3235 # Review: required -# Source-Hash: 28fe6e9deddde6e8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "pos" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Porch" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.pos" -msgstr "位置" +msgid "editor.panels.roomConstructionRows.roomTypePorch" +msgstr "门廊" +# Source-Hash: af2c941e8ef874bf # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outdoors under a ceiling: a concrete slab 1½ in down from the house, ceiling at the house’s." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.position" -msgstr "位置" +msgid "editor.panels.roomConstructionRows.roomTypePorchHint" +msgstr "室外有顶:混凝土板比房屋低 1½ in,天花板与房屋齐平。" +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# Source-Hash: 3fce677837d5a876 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset this part" -#: packages/editor/src/components/procedural-items/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.proceduralItems.inspector.resetThisPart" -msgstr "重置此部件" +msgid "editor.panels.roomConstructionRows.roomTypeRoom" +msgstr "房间" -# Source-Hash: 5eab376947d29a50 +# Source-Hash: fb0a6cc444058631 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reload editor" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An ordinary room inside the house." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.reloadEditor" -msgstr "重新加载编辑器" +msgid "editor.panels.roomConstructionRows.roomTypeRoomHint" +msgstr "房屋内的普通房间。" +# Source-Hash: a4395168488bb476 # Review: required -# Source-Hash: 1063f1e315258b20 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close riser diagram" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.close" -msgstr "关闭立管图" +msgid "editor.panels.roomConstructionRows.select" +msgstr "选择" +# Source-Hash: 85ea1d3c8b749680 # Review: required -# Source-Hash: c2d59ee62035974c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV plumbing isometric" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.dwvPlumbingIsometric" -msgstr "排水与通气管道轴测图" +msgid "editor.panels.roomConstructionRows.shape" +msgstr "形状" +# Source-Hash: aafd84823715d698 # Review: required -# Source-Hash: 3501a7c8a93d3b19 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV riser diagram" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turning walls off keeps the ones shared with {rooms}." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.dwvRiserDiagram" -msgstr "排水通气立管图" +msgid "editor.panels.roomConstructionRows.sharedWallsNote" +msgstr "关闭墙体时会保留与{rooms}共用的墙体。" +# Source-Hash: c98df900d43f77bc # Review: required -# Source-Hash: 225e3e3dc3bb01ee -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No drain, waste, or vent pipes yet. Draw plumbing to see the riser diagram." -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sits on: {name} · {preset}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.noDrainWasteOrVentPipes" -msgstr "尚无排水、污水或通气管道。绘制管道后即可查看立管图。" +msgid "editor.panels.roomConstructionRows.sitsOnPreset" +msgstr "支承于:{name} · {preset}" +# Source-Hash: a17a79e835fa2064 # Review: required -# Source-Hash: bc8e172ba55160ae -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Riser Diagram" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "the next room" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.riserDiagram" -msgstr "立管图" +msgid "editor.panels.roomConstructionRows.theNextRoom" +msgstr "相邻房间" +# Source-Hash: ebae699e0cb18ea6 # Review: required -# Source-Hash: 6a1132961f17f320 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{diameter}\" P-trap" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use existing" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.trap" -msgstr "{diameter}\" 存水弯" +msgid "editor.panels.roomConstructionRows.useExisting" +msgstr "使用现有" +# Source-Hash: 9976021d9162cd5e # Review: required -# Source-Hash: 04bc0909a133a7e9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vent" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{walls, plural, one {{wallCount} wall} other {{wallCount} walls}}" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.vent" -msgstr "通风口" +msgid "editor.panels.roomConstructionRows.wallCount" +msgstr "{walls, plural, other {{wallCount} 面墙}}" +# Source-Hash: aac9a732d2159ccc # Review: required -# Source-Hash: 02f3eef9f0fb6d9e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{diameter}\" VTR" -#. Vent through roof: where a plumbing vent stack exits the roof. -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls" +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.ventTermination" -msgstr "{diameter}\" 出屋面通气口" +msgid "editor.panels.roomConstructionRows.walls" +msgstr "墙体" +# Source-Hash: 6c69eb46a0c40d52 # Review: required -# Source-Hash: 29d8590334492601 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waste" -#: packages/editor/src/components/editor/riser-diagram-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walls thicken inward, so the building's outer size stays the same." +#: packages/editor/src/components/ui/panels/room-construction-rows.tsx #, fuzzy -msgid "editor.riserDiagramPanel.waste" -msgstr "排污" +msgid "editor.panels.roomConstructionRows.wallsThickenInwardSoTheBuilding" +msgstr "墙体向内加厚,因此建筑外部尺寸保持不变。" -# Source-Hash: 0f8d128255bf4afa +# Source-Hash: 4e4f1a24e4a9d61e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{current} · {distance} above {shared}" -#: packages/editor/src/lib/room-built-on.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut opening" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.room.builtOn.above" -msgstr "{current} · 高于{shared} {distance}" +msgid "editor.panels.roomOpeningsField.cutOpening" +msgstr "开洞" -# Source-Hash: 8416f433385a2936 +# Source-Hash: 16552c2580bbe8b8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{current} · {distance} below {shared}" -#: packages/editor/src/lib/room-built-on.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.room.builtOn.below" -msgstr "{current} · 低于{shared} {distance}" +msgid "editor.panels.roomOpeningsField.done" +msgstr "完成" -# Source-Hash: 6dc18e9fada391f2 +# Source-Hash: 2c89abb1778a3f9b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{current} · level with {shared}" -#: packages/editor/src/lib/room-built-on.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit floor" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.room.builtOn.levelWith" -msgstr "{current} · 与{shared}齐平" +msgid "editor.panels.roomOpeningsField.editFloor" +msgstr "编辑楼板" -# Source-Hash: 612dcd5bf06a79c4 +# Source-Hash: ca18a6c5398fc8ab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room" -#: packages/editor/src/components/editor/room-labels.tsx -#: packages/editor/src/lib/viewer-selection.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevator opening" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.roomLabel.room" -msgstr "房间" +msgid "editor.panels.roomOpeningsField.elevatorOpening" +msgstr "电梯开洞" -# Source-Hash: a107b4d76d6972e3 +# Source-Hash: eafea43e795f3708 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone" -#: packages/editor/src/components/editor/room-labels.tsx -#: packages/editor/src/lib/viewer-selection.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No openings yet. Cut one for a stair void or a hatch." +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.roomLabel.zone" -msgstr "区域" +msgid "editor.panels.roomOpeningsField.noOpeningsYetCutOneFor" +msgstr "暂无开洞。可为楼梯洞口或检修口开一个。" -# Source-Hash: 7da15e7c88dab485 +# Source-Hash: 60fac94ffa614238 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Attic" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening {number}" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.roomName.attic" -msgstr "阁楼" +msgid "editor.panels.roomOpeningsField.openingNumber" +msgstr "开洞 {number}" -# Source-Hash: 52adf6ccf54fd772 +# Source-Hash: 7aafbf90d659dcf6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Balcony" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, =0 {No openings} one {{number} opening} other {{number} openings}}" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.roomName.balcony" -msgstr "阳台" +msgid "editor.panels.roomOpeningsField.openings" +msgstr "{count, plural, =0 {无开口} other {{number} 个开口}}" -# Source-Hash: 8caa959c0ae800c3 +# Source-Hash: c1a1794d31990f5a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Basement" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair opening" +#: packages/editor/src/components/ui/panels/room-openings-field.tsx #, fuzzy -msgid "editor.roomName.basement" -msgstr "地下层" +msgid "editor.panels.roomOpeningsField.stairOpening" +msgstr "楼梯开洞" -# Source-Hash: 0655333424a8b6fb +# Source-Hash: f0a46329fef44d94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bathroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add stairs" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.bathroom" -msgstr "浴室" +msgid "editor.panels.roomPanel.addStairs" +msgstr "添加楼梯" -# Source-Hash: f25239fe3891ea8f +# Source-Hash: 8a2ab34a61b9d181 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bedroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add to a unit" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.bedroom" -msgstr "卧室" +msgid "editor.panels.roomPanel.addToAUnit" +msgstr "添加到单元" -# Source-Hash: 77d15570e2eba719 +# Source-Hash: 8332ab41e22958f1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Boiler room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Area" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.boilerRoom" -msgstr "锅炉房" +msgid "editor.panels.roomPanel.area" +msgstr "面积" -# Source-Hash: 5fbe77592f8f0ca9 +# Source-Hash: 88f1a727e5528c10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Carport" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Browse" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.carport" -msgstr "车棚" +msgid "editor.panels.roomPanel.browse" +msgstr "浏览" -# Source-Hash: f31dc305ce3a803a +# Source-Hash: 8e5ca7510677460c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cellar" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Built with" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.cellar" -msgstr "地窖" +msgid "editor.panels.roomPanel.builtWith" +msgstr "构造" -# Source-Hash: e9af4141e3f8bdd1 +# Source-Hash: 4275c05172abd7fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Closet" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.closet" -msgstr "壁橱" +msgid "editor.panels.roomPanel.ceiling" +msgstr "天花板" -# Source-Hash: 388530b7b9c6647d +# Source-Hash: a5e4fe4960deced9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corridor" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete room" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.corridor" -msgstr "走廊" +msgid "editor.panels.roomPanel.deleteRoom" +msgstr "删除房间" -# Source-Hash: 4d4a23b87e911d2b +# Source-Hash: 5dfead58503dbc86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Courtyard" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit shape" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.courtyard" -msgstr "庭院" +msgid "editor.panels.roomPanel.editShape" +msgstr "编辑形状" -# Source-Hash: f3aa561772702108 +# Source-Hash: d7148fa065bc709b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Deck" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.deck" -msgstr "平台" +msgid "editor.panels.roomPanel.floor" +msgstr "楼层" -# Source-Hash: 18d7f85ff03c43c9 +# Source-Hash: d17c3b63449c052b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Den" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{height} headroom" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.den" -msgstr "书房" +msgid "editor.panels.roomPanel.headroom" +msgstr "净空 {height}" -# Source-Hash: 4424343cad1f08b0 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dining room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.diningRoom" -msgstr "餐厅" +msgid "editor.panels.roomPanel.height" +msgstr "高度" -# Source-Hash: 5efd0185e89ee84e +# Source-Hash: 2d89c1638aa8dd7e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dressing room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide code" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.dressingRoom" -msgstr "更衣室" +msgid "editor.panels.roomPanel.hideCode" +msgstr "隐藏代码" -# Source-Hash: f45768e27780dc72 +# Source-Hash: e93969f5a7cbb140 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "En-suite" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room · {level}" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.enSuite" -msgstr "套内卫生间" +msgid "editor.panels.roomPanel.kickerLevel" +msgstr "房间 · {level}" -# Source-Hash: 51c664d19e5ea703 +# Source-Hash: f4ad56b4e0c014b3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Entrance" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine · in {room}" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.entrance" -msgstr "入口" +msgid "editor.panels.roomPanel.kickerMezzanineIn" +msgstr "夹层 · 位于{room}" -# Source-Hash: 4b32a81a5abf006a +# Source-Hash: de37205633316011 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Family room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room · not enclosed" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.familyRoom" -msgstr "家庭活动室" +msgid "editor.panels.roomPanel.kickerNotEnclosed" +msgstr "房间 · 未封闭" -# Source-Hash: e87e6bd9a7d6d667 +# Source-Hash: 9e84d6d7b9885c4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gallery" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Loading…" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.gallery" -msgstr "回廊" +msgid "editor.panels.roomPanel.loading" +msgstr "加载中…" -# Source-Hash: cf7cc0ba06d5eea1 +# Source-Hash: 194a147d4618a994 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Games room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.gamesRoom" -msgstr "游戏室" +msgid "editor.panels.roomPanel.mezzanine" +msgstr "夹层" -# Source-Hash: 53aa825a4737190a +# Source-Hash: 97de3df03c4a0be6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Garage" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine name" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.garage" -msgstr "车库" +msgid "editor.panels.roomPanel.mezzanineName" +msgstr "夹层名称" -# Source-Hash: 5073b3c2989a626d +# Source-Hash: 42cfb1bcb80d09e7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Garden" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine names" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.garden" -msgstr "花园" +msgid "editor.panels.roomPanel.mezzanineNames" +msgstr "夹层名称" -# Source-Hash: 52fe13434cdb7b27 +# Source-Hash: 13b3e6a6afe319d1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Garden shed" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New unit" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.gardenShed" -msgstr "园艺棚" +msgid "editor.panels.roomPanel.newUnit" +msgstr "新建单元" -# Source-Hash: a2712156dcaec1ba +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guest room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.guestRoom" -msgstr "客房" +msgid "editor.panels.roomPanel.none" +msgstr "无" -# Source-Hash: a1128cf188432bb1 +# Source-Hash: e92d6108b57df9e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gym" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not enough headroom" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.gym" -msgstr "健身房" +msgid "editor.panels.roomPanel.notEnoughHeadroom" +msgstr "净空不足" -# Source-Hash: 18664ee5a1abd06d +# Source-Hash: 81a6770092b05d48 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hallway" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{doors, plural, one {{doorCount} door} other {{doorCount} doors}} · {windows, plural, one {{windowCount} window} other {{windowCount} windows}}" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.hallway" -msgstr "门厅" +msgid "editor.panels.roomPanel.openingCounts" +msgstr "{doors, plural, other {{doorCount} 扇门}} · {windows, plural, other {{windowCount} 扇窗}}" -# Source-Hash: 7dd957fc73d4d73a +# Source-Hash: a8cd9507ce472a48 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Home cinema" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} · Close its walls to build its floor and ceiling." +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.homeCinema" -msgstr "家庭影院" +msgid "editor.panels.roomPanel.openRoomArea" +msgstr "{area} · 围合其墙体以生成楼板和天花板。" -# Source-Hash: e1579515f44233ca +# Source-Hash: f8aa48ec39a15616 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kids' room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Over the mezzanine" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.kidsRoom" -msgstr "儿童房" +msgid "editor.panels.roomPanel.overTheMezzanine" +msgstr "位于夹层上方" -# Source-Hash: 1176d2568d093bf1 +# Source-Hash: ac87e14dabd5a256 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchen" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Perimeter" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.kitchen" -msgstr "厨房" +msgid "editor.panels.roomPanel.perimeter" +msgstr "周长" -# Source-Hash: 06eb4c431b9b09b6 +# Source-Hash: ed2aaf0a8d5a9b7b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchenette" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.kitchenette" -msgstr "小厨房" +msgid "editor.panels.roomPanel.pick" +msgstr "选择" -# Source-Hash: de9566487b17a73b +# Source-Hash: 7baaebbd411cc837 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picking it adds a number" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.landing" -msgstr "平台" +msgid "editor.panels.roomPanel.pickingItAddsANumber" +msgstr "选择后会添加编号" -# Source-Hash: 558bcafa2ec70ded +# Source-Hash: 9469a102f04ea196 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Laundry" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.laundry" -msgstr "洗衣房" +msgid "editor.panels.roomPanel.remove" +msgstr "移除" -# Source-Hash: 8d211c78417ed1b0 +# Source-Hash: 41ac9dd23bb558d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Library" -#: packages/editor/src/lib/room-name-messages.ts -#, fuzzy -msgid "editor.roomName.library" -msgstr "素材库" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove from unit" +#: packages/editor/src/components/ui/panels/room-panel.tsx +#, fuzzy +msgid "editor.panels.roomPanel.removeFromUnit" +msgstr "从单元中移除" -# Source-Hash: 2204538bab0e77ac +# Source-Hash: a11d13b92b3cefdb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Living room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove from {unit}" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.livingRoom" -msgstr "客厅" +msgid "editor.panels.roomPanel.removeFromUnitNamed" +msgstr "从{unit}中移除" -# Source-Hash: bb14c08f0c3db4ad +# Source-Hash: d6952b4e54d246dd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Loft" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rename" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.loft" -msgstr "阁楼" +msgid "editor.panels.roomPanel.rename" +msgstr "重命名" -# Source-Hash: a6a0e8bf816cbcb9 +# Source-Hash: 3562f9bea0a4a8f3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lounge" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{name} · Rename" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.lounge" -msgstr "休息室" +msgid "editor.panels.roomPanel.renameNamed" +msgstr "{name} · 重命名" -# Source-Hash: 194a147d4618a994 +# Source-Hash: d0d4e919bb58a977 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Revert" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.mezzanine" -msgstr "夹层" +msgid "editor.panels.roomPanel.revert" +msgstr "还原" -# Source-Hash: 6b2c82e5fbccb28b +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mudroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.mudroom" -msgstr "玄关储物间" +msgid "editor.panels.roomPanel.room" +msgstr "房间" -# Source-Hash: e3c3b9b917744680 +# Source-Hash: 15ae260fae44f42f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Nursery" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room colour — used in the plan and labels" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.nursery" -msgstr "婴儿房" +msgid "editor.panels.roomPanel.roomColourUsedInThePlan" +msgstr "房间颜色 — 用于平面图和标签" -# Source-Hash: c1f1fcd9cb418340 +# Source-Hash: bf75e739dd7e5877 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Office" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room name" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.office" -msgstr "办公室" +msgid "editor.panels.roomPanel.roomName" +msgstr "房间名称" -# Source-Hash: 5d98d41ec10bd05e +# Source-Hash: 2ecf8c059646873b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pantry" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room names" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.pantry" -msgstr "食品储藏室" +msgid "editor.panels.roomPanel.roomNames" +msgstr "房间名称" -# Source-Hash: 78dbe13192c0894b +# Source-Hash: e9a0a3688faba18b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Patio" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scripted finish" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.patio" -msgstr "露台" +msgid "editor.panels.roomPanel.scriptedFinish" +msgstr "脚本饰面" -# Source-Hash: c3cfcccc167b1c19 +# Source-Hash: 85ea1d3c8b749680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Playroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.playroom" -msgstr "游戏室" +msgid "editor.panels.roomPanel.shape" +msgstr "形状" -# Source-Hash: 2e6324beaed18dd5 +# Source-Hash: e51144ca1759a7bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pool area" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show mezzanine names" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.poolArea" -msgstr "泳池区" +msgid "editor.panels.roomPanel.showMezzanineNames" +msgstr "显示夹层名称" -# Source-Hash: 97d20e41044a3235 +# Source-Hash: 875b7303c47df33f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Porch" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show room names" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.porch" -msgstr "门廊" +msgid "editor.panels.roomPanel.showRoomNames" +msgstr "显示房间名称" -# Source-Hash: 04cb81f4a4ae4ff3 +# Source-Hash: f05bc67c57e4d530 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Powder room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stairs" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.powderRoom" -msgstr "客用卫生间" +msgid "editor.panels.roomPanel.stairs" +msgstr "楼梯" -# Source-Hash: 599c44d857832cd0 +# Source-Hash: 062cc0f1afef0c52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Primary bedroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unit" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.primaryBedroom" -msgstr "主卧" +msgid "editor.panels.roomPanel.unit" +msgstr "单元" -# Source-Hash: 9a6ac3f1cdd8de2b +# Source-Hash: 91436d6b374e8263 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reading nook" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.readingNook" -msgstr "阅读角" +msgid "editor.panels.roomPanel.use" +msgstr "使用" -# Source-Hash: 01f8cc22989822c4 +# Source-Hash: 61880aff6cd698c9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bathrooms" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{used} on this level" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.section.bathrooms" -msgstr "浴室" +msgid "editor.panels.roomPanel.usedOnThisLevel" +msgstr "此楼层已有 {used} 个" -# Source-Hash: 9ec82561de8cb788 +# Source-Hash: 611604740ed4549c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Circulation" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{use} “{name}”" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.section.circulation" -msgstr "交通空间" +msgid "editor.panels.roomPanel.useTyped" +msgstr "{use}“{name}”" -# Source-Hash: f74a48b6b49644d7 +# Source-Hash: 21242af83a2a6d17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Living" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "View code" +#: packages/editor/src/components/ui/panels/room-panel.tsx #, fuzzy -msgid "editor.roomName.section.living" -msgstr "起居" +msgid "editor.panels.roomPanel.viewCode" +msgstr "查看代码" -# Source-Hash: 194a147d4618a994 +# Source-Hash: ba15840e60ce672b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mezzanine" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The script could not be read." +#: packages/editor/src/components/ui/panels/room-panel.tsx +#: packages/nodes/src/wall/panel.tsx #, fuzzy -msgid "editor.roomName.section.mezzanine" -msgstr "夹层" +msgid "editor.panels.scriptUnreadable" +msgstr "无法读取脚本。" -# Source-Hash: a5a7af5e5fff1c81 +# Source-Hash: 4e186fc057733162 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Outdoor" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Polygon" +#: packages/editor/src/components/ui/panels/shape-choice.tsx #, fuzzy -msgid "editor.roomName.section.outdoor" -msgstr "室外" +msgid "editor.panels.shapeChoice.polygon" +msgstr "多边形" -# Source-Hash: 5df703d5b5e6ef7e +# Source-Hash: 2c2c20272b0370cc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sleeping" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangle" +#: packages/editor/src/components/ui/panels/shape-choice.tsx #, fuzzy -msgid "editor.roomName.section.sleeping" -msgstr "睡眠" +msgid "editor.panels.shapeChoice.rectangle" +msgstr "矩形" -# Source-Hash: c9d15ec19f814524 +# Source-Hash: 5dc88f90e6aa4129 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Utility & storage" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete region" +#: packages/editor/src/components/ui/panels/wall-region-list.tsx #, fuzzy -msgid "editor.roomName.section.utility" -msgstr "杂物与储藏" +msgid "editor.panels.wallRegionList.deleteRegion" +msgstr "删除区域" -# Source-Hash: fbe13f7ab45e4cca +# Source-Hash: d81d8cbadf5d4f33 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Work & hobbies" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paint regions" +#: packages/editor/src/components/ui/panels/wall-region-list.tsx #, fuzzy -msgid "editor.roomName.section.work" -msgstr "工作与爱好" +msgid "editor.panels.wallRegionList.paintRegions" +msgstr "涂刷区域" -# Source-Hash: 10ccb6591f6ad207 +# Source-Hash: 89ee318aad485f83 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shower room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Adjust design" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.showerRoom" -msgstr "淋浴间" +msgid "editor.proceduralItems.inspector.adjustDesign" +msgstr "调整设计" -# Source-Hash: 5254168cc5712cb2 +# Source-Hash: 7ceade8f25b58fe9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stairwell" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.stairwell" -msgstr "楼梯间" +msgid "editor.proceduralItems.inspector.back" +msgstr "返回" -# Source-Hash: d1596647cd84ade3 +# Source-Hash: ba9b68175315e177 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Storage" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit parts" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.storage" -msgstr "储藏" +msgid "editor.proceduralItems.inspector.editParts" +msgstr "编辑部件" -# Source-Hash: 7abc2dc6e39b1747 +# Source-Hash: 07c62820f014ed6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Studio" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid attachment" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.studio" -msgstr "影棚" +msgid "editor.proceduralItems.inspector.invalidAttachment" +msgstr "附着无效" -# Source-Hash: ebe68e83e73021ae +# Source-Hash: f862aea8d7957c55 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Study" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid edit" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.study" -msgstr "书房" +msgid "editor.proceduralItems.inspector.invalidEdit" +msgstr "编辑无效" -# Source-Hash: d69a0244649771ef +# Source-Hash: 190cf30b8edd8dd1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sunroom" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid placement" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.sunroom" -msgstr "阳光房" +msgid "editor.proceduralItems.inspector.invalidPlacement" +msgstr "放置无效" -# Source-Hash: 96281876ce53ba08 +# Source-Hash: 45bd2ec690cc48dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terrace" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid position" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.terrace" -msgstr "露台" +msgid "editor.proceduralItems.inspector.invalidPosition" +msgstr "位置无效" -# Source-Hash: a0cb3e6f5cf4fbec +# Source-Hash: faccab895717c598 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Toilet" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Invalid reset" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.toilet" -msgstr "卫生间" +msgid "editor.proceduralItems.inspector.invalidReset" +msgstr "重置无效" -# Source-Hash: 6c01526f89f3106b +# Source-Hash: 28fe6e9deddde6e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Utility room" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "pos" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.utilityRoom" -msgstr "杂物间" +msgid "editor.proceduralItems.inspector.pos" +msgstr "位置" -# Source-Hash: fc42d89621ae7bac +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Veranda" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.veranda" -msgstr "游廊" +msgid "editor.proceduralItems.inspector.position" +msgstr "位置" -# Source-Hash: b45d7730e896fd99 +# Source-Hash: 3fce677837d5a876 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walk-in closet" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset this part" +#: packages/editor/src/components/procedural-items/inspector.tsx #, fuzzy -msgid "editor.roomName.walkInCloset" -msgstr "步入式衣帽间" +msgid "editor.proceduralItems.inspector.resetThisPart" +msgstr "重置此部件" -# Source-Hash: 399f27253ef956cb +# Source-Hash: 5eab376947d29a50 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Workshop" -#: packages/editor/src/lib/room-name-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reload editor" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.roomName.workshop" -msgstr "工作间" +msgid "editor.reloadEditor" +msgstr "重新加载编辑器" -# Source-Hash: 83909f82446ee9c3 +# Source-Hash: 1063f1e315258b20 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Settings" -#: packages/editor/src/components/ui/sidebar/icon-rail.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close riser diagram" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.sidebar.iconRail.settings" -msgstr "设置" +msgid "editor.riserDiagramPanel.close" +msgstr "关闭立管图" -# Source-Hash: 91f90818d42a984e +# Source-Hash: c2d59ee62035974c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Site" -#: packages/editor/src/components/ui/sidebar/icon-rail.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV plumbing isometric" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.sidebar.iconRail.site" -msgstr "场地" +msgid "editor.riserDiagramPanel.dwvPlumbingIsometric" +msgstr "排水与通气管道轴测图" -# Source-Hash: 663175a9c461a96d +# Source-Hash: 3501a7c8a93d3b19 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV riser diagram" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.all" -msgstr "全部" +msgid "editor.riserDiagramPanel.dwvRiserDiagram" +msgstr "排水通气立管图" -# Source-Hash: fce9814c289e6b71 +# Source-Hash: 225e3e3dc3bb01ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Community" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No drain, waste, or vent pipes yet. Draw plumbing to see the riser diagram." +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.community" -msgstr "社区" +msgid "editor.riserDiagramPanel.noDrainWasteOrVentPipes" +msgstr "尚无排水、污水或通气管道。绘制管道后即可查看立管图。" -# Source-Hash: 663175a9c461a96d +# Source-Hash: bc8e172ba55160ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Riser Diagram" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.all" -msgstr "全部" +msgid "editor.riserDiagramPanel.riserDiagram" +msgstr "立管图" -# Source-Hash: fce9814c289e6b71 +# Source-Hash: 6a1132961f17f320 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Community" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{diameter}\" P-trap" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.community" -msgstr "社区" +msgid "editor.riserDiagramPanel.trap" +msgstr "{diameter}\" 存水弯" -# Source-Hash: 8d211c78417ed1b0 +# Source-Hash: 04bc0909a133a7e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Library" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vent" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.library" -msgstr "素材库" +msgid "editor.riserDiagramPanel.vent" +msgstr "通风口" -# Source-Hash: a0b7adfdfdec7307 +# Source-Hash: 02f3eef9f0fb6d9e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mine" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{diameter}\" VTR" +#. Vent through roof: where a plumbing vent stack exits the roof. +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.mine" -msgstr "我的" +msgid "editor.riserDiagramPanel.ventTermination" +msgstr "{diameter}\" 出屋面通气口" -# Source-Hash: 6024b7778b392ec3 +# Source-Hash: 29d8590334492601 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No results for “{search}”" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waste" +#: packages/editor/src/components/editor/riser-diagram-panel.tsx #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.noResultsForSearch" -msgstr "没有“{search}”的结果" +msgid "editor.riserDiagramPanel.waste" +msgstr "排污" -# Source-Hash: 4ceb6dcb7827db7f +# Source-Hash: 0f8d128255bf4afa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Search..." -#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{current} · {distance} above {shared}" +#: packages/editor/src/lib/room-built-on.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.search" -msgstr "搜索..." +msgid "editor.room.builtOn.above" +msgstr "{current} · 高于{shared} {distance}" -# Source-Hash: 8d211c78417ed1b0 +# Source-Hash: 8416f433385a2936 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Library" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{current} · {distance} below {shared}" +#: packages/editor/src/lib/room-built-on.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.library" -msgstr "素材库" +msgid "editor.room.builtOn.below" +msgstr "{current} · 低于{shared} {distance}" -# Source-Hash: a0b7adfdfdec7307 +# Source-Hash: 6dc18e9fada391f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mine" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{current} · level with {shared}" +#: packages/editor/src/lib/room-built-on.ts #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.mine" -msgstr "我的" +msgid "editor.room.builtOn.levelWith" +msgstr "{current} · 与{shared}齐平" -# Source-Hash: 6024b7778b392ec3 +# Source-Hash: 782bc47cb30d5c66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No results for “{search}”" -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cannot read \"{input}\"" +#: packages/editor/src/components/editor/room-handles.tsx #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.noResultsForSearch" -msgstr "没有“{search}”的结果" +msgid "editor.roomHandles.cannotReadInput" +msgstr "无法识别“{input}”" -# Source-Hash: 4ceb6dcb7827db7f +# Source-Hash: 70ca08939d758332 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Search..." -#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimension value" +#: packages/editor/src/components/editor/room-handles.tsx #, fuzzy -msgid "editor.sidebar.panels.itemsPanel.search" -msgstr "搜索..." +msgid "editor.roomHandles.dimensionValue" +msgstr "尺寸值" -# Source-Hash: 3c67cde0578ac829 +# Source-Hash: d7148fa065bc709b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/editor/src/components/editor/room-handles.tsx #, fuzzy -msgid "editor.sidebar.panels.sitePanel.addLevel" -msgstr "添加楼层" +msgid "editor.roomHandles.floor" +msgstr "楼面" -# Source-Hash: 9a56d90d461b4bca +# Source-Hash: de281c37906e7d14 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add point" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type a size to move the wall" +#: packages/editor/src/components/editor/room-handles.tsx #, fuzzy -msgid "editor.sidebar.panels.sitePanel.addPoint" -msgstr "添加点" +msgid "editor.roomHandles.typeASizeToMoveThe" +msgstr "输入尺寸以移动墙体" -# Source-Hash: fedccec504a9ae33 +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Area:" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/editor/room-labels.tsx +#: packages/editor/src/lib/viewer-selection.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.area" -msgstr "面积:" +msgid "editor.roomLabel.room" +msgstr "房间" -# Source-Hash: 87b6880f6de7a45a +# Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base elevation" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone" +#: packages/editor/src/components/editor/room-labels.tsx +#: packages/editor/src/lib/viewer-selection.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.baseElevation" -msgstr "基准标高" +msgid "editor.roomLabel.zone" +msgstr "区域" -# Source-Hash: d42f7d29e3fc4af7 +# Source-Hash: 7da15e7c88dab485 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Building" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Attic" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.building" -msgstr "建筑" +msgid "editor.roomName.attic" +msgstr "阁楼" -# Source-Hash: 7c90f458259d5cd8 +# Source-Hash: 52adf6ccf54fd772 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add new level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Balcony" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.buildingTreeNode.addNewLevel" -msgstr "添加新楼层" +msgid "editor.roomName.balcony" +msgstr "阳台" -# Source-Hash: d42f7d29e3fc4af7 +# Source-Hash: 8caa959c0ae800c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Building" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Basement" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.buildingTreeNode.building" -msgstr "建筑" +msgid "editor.roomName.basement" +msgstr "地下层" -# Source-Hash: bbc65c039ae86e11 +# Source-Hash: 0655333424a8b6fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Camera snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bathroom" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.cameraSnapshot" -msgstr "相机快照" +msgid "editor.roomName.bathroom" +msgstr "浴室" -# Source-Hash: 3a0701ebcb9f26cb +# Source-Hash: f25239fe3891ea8f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Capture" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bedroom" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.capture" -msgstr "采集" +msgid "editor.roomName.bedroom" +msgstr "卧室" -# Source-Hash: 71f2343818c55e0c +# Source-Hash: 77d15570e2eba719 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear selection" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Boiler room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.clearSelection" -msgstr "清除选择" +msgid "editor.roomName.boilerRoom" +msgstr "锅炉房" -# Source-Hash: 67d29724469fa8d3 +# Source-Hash: 5fbe77592f8f0ca9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx -#, fuzzy -msgid "editor.sidebar.panels.sitePanel.clearSnapshot" -msgstr "清除快照" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Carport" +#: packages/editor/src/lib/room-name-messages.ts +#, fuzzy +msgid "editor.roomName.carport" +msgstr "车棚" -# Source-Hash: def517c77fda49ea +# Source-Hash: f31dc305ce3a803a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close walls around a space to make a room." -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cellar" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.closeWallsAroundASpaceTo" -msgstr "用墙体围合一个空间即可创建房间。" +msgid "editor.roomName.cellar" +msgstr "地窖" -# Source-Hash: 2b9af8da4b34cbfa +# Source-Hash: e9af4141e3f8bdd1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collection colour" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Closet" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.collectionColour" -msgstr "集合颜色" +msgid "editor.roomName.closet" +msgstr "壁橱" -# Source-Hash: 135af27a14a4cda7 +# Source-Hash: 388530b7b9c6647d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Collections" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corridor" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.collections" -msgstr "集合" +msgid "editor.roomName.corridor" +msgstr "走廊" -# Source-Hash: 6f4751c26f12aef9 +# Source-Hash: 4d4a23b87e911d2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete collection" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Courtyard" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.deleteCollection" -msgstr "删除集合" +msgid "editor.roomName.courtyard" +msgstr "庭院" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: f3aa561772702108 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.delete" -msgstr "删除" +msgid "editor.roomName.deck" +msgstr "平台" -# Source-Hash: 8e29375893d63408 +# Source-Hash: 18d7f85ff03c43c9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Den" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.deleteLevel" -msgstr "删除楼层" +msgid "editor.roomName.den" +msgstr "书房" -# Source-Hash: 6552e45eecc0a227 +# Source-Hash: 4424343cad1f08b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw a zone" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dining room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.drawAZone" -msgstr "绘制区域" +msgid "editor.roomName.diningRoom" +msgstr "餐厅" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 5efd0185e89ee84e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dressing room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.duplicate" -msgstr "复制" +msgid "editor.roomName.dressingRoom" +msgstr "更衣室" -# Source-Hash: 933177338f5a03ed +# Source-Hash: f45768e27780dc72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "En-suite" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.duplicateLevel" -msgstr "复制楼层" +msgid "editor.roomName.enSuite" +msgstr "套内卫生间" -# Source-Hash: c038947f317cabba +# Source-Hash: 51c664d19e5ea703 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate level with options" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Entrance" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.duplicateLevelWithOptions" -msgstr "带选项复制楼层" +msgid "editor.roomName.entrance" +msgstr "入口" -# Source-Hash: 9614c6825a7c67bf +# Source-Hash: 4b32a81a5abf006a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate with options..." -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Family room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.duplicateWithOptions" -msgstr "带选项复制..." +msgid "editor.roomName.familyRoom" +msgstr "家庭活动室" -# Source-Hash: 7c4196b9e791c195 +# Source-Hash: e87e6bd9a7d6d667 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elements" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gallery" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.elements" -msgstr "元素" +msgid "editor.roomName.gallery" +msgstr "回廊" -# Source-Hash: 1344ea2602e3aa9e +# Source-Hash: cf7cc0ba06d5eea1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guide" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Games room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.guide" -msgstr "参考图" +msgid "editor.roomName.gamesRoom" +msgstr "游戏室" -# Source-Hash: 591087ea83a48ead +# Source-Hash: 53aa825a4737190a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Garage" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.hide" -msgstr "隐藏" +msgid "editor.roomName.garage" +msgstr "车库" -# Source-Hash: 0608743fc1736d86 +# Source-Hash: 5073b3c2989a626d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Garden" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.level" -msgstr "楼层" +msgid "editor.roomName.garden" +msgstr "花园" -# Source-Hash: 13b3e6a6afe319d1 +# Source-Hash: 52fe13434cdb7b27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "New unit" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Garden shed" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.newUnit" -msgstr "新建单元" +msgid "editor.roomName.gardenShed" +msgstr "园艺棚" -# Source-Hash: 0192748d50f0e5f7 +# Source-Hash: a2712156dcaec1ba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No buildings yet" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guest room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.noBuildingsYet" -msgstr "暂无建筑" +msgid "editor.roomName.guestRoom" +msgstr "客房" -# Source-Hash: 1be310702a12e433 +# Source-Hash: a1128cf188432bb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No elements on this level" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gym" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.noElementsOnThisLevel" -msgstr "此楼层上没有元素" +msgid "editor.roomName.gym" +msgstr "健身房" -# Source-Hash: 0956af88ced36992 +# Source-Hash: 18664ee5a1abd06d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No levels yet" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hallway" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.noLevelsYet" -msgstr "暂无楼层" +msgid "editor.roomName.hallway" +msgstr "门厅" -# Source-Hash: 45c41bfb2ae19627 +# Source-Hash: 7dd957fc73d4d73a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {# object selected} other {# objects selected}}" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Home cinema" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.objectsSelected" -msgstr "{count, plural, other {已选择 # 个对象}}" +msgid "editor.roomName.homeCinema" +msgstr "家庭影院" -# Source-Hash: a5434e26e5cb1b26 +# Source-Hash: e1579515f44233ca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Other zones" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kids' room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.otherZones" -msgstr "其他区域" +msgid "editor.roomName.kidsRoom" +msgstr "儿童房" -# Source-Hash: 2aa38d84079d4dba +# Source-Hash: 1176d2568d093bf1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Perimeter:" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchen" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.perimeter" -msgstr "周长:" +msgid "editor.roomName.kitchen" +msgstr "厨房" -# Source-Hash: 4004b9a8e4f8c9d0 +# Source-Hash: 06eb4c431b9b09b6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Property Line" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchenette" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.propertyLine" -msgstr "地界线" +msgid "editor.roomName.kitchenette" +msgstr "小厨房" -# Source-Hash: 3e7408ed44676176 +# Source-Hash: de9566487b17a73b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rooms" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.rooms" -msgstr "房间" +msgid "editor.roomName.landing" +msgstr "平台" -# Source-Hash: ca39c0581c7318e6 +# Source-Hash: 558bcafa2ec70ded # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select a level to view content" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Laundry" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.selectALevelToViewContent" -msgstr "选择楼层以查看内容" +msgid "editor.roomName.laundry" +msgstr "洗衣房" -# Source-Hash: 827e0c6ac9936b69 +# Source-Hash: 8d211c78417ed1b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Library" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.show" -msgstr "显示" +msgid "editor.roomName.library" +msgstr "素材库" -# Source-Hash: 91f90818d42a984e +# Source-Hash: 2204538bab0e77ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Site" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Living room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.site" -msgstr "场地" +msgid "editor.roomName.livingRoom" +msgstr "客厅" -# Source-Hash: c40163620df24a76 +# Source-Hash: bb14c08f0c3db4ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Take snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Loft" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.takeSnapshot" -msgstr "拍摄快照" +msgid "editor.roomName.loft" +msgstr "阁楼" -# Source-Hash: d6b381247066a7aa +# Source-Hash: a6a0e8bf816cbcb9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The ground level cannot be deleted" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lounge" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.theGroundLevelCannotBeDeleted" -msgstr "无法删除首层楼层" +msgid "editor.roomName.lounge" +msgstr "休息室" -# Source-Hash: bbc65c039ae86e11 +# Source-Hash: 194a147d4618a994 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Camera snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.cameraSnapshot" -msgstr "相机快照" +msgid "editor.roomName.mezzanine" +msgstr "夹层" -# Source-Hash: 67d29724469fa8d3 +# Source-Hash: 6b2c82e5fbccb28b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mudroom" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.clearSnapshot" -msgstr "清除快照" +msgid "editor.roomName.mudroom" +msgstr "玄关储物间" -# Source-Hash: 591087ea83a48ead +# Source-Hash: e3c3b9b917744680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hide" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Nursery" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.hide" -msgstr "隐藏" +msgid "editor.roomName.nursery" +msgstr "婴儿房" -# Source-Hash: 827e0c6ac9936b69 +# Source-Hash: c1f1fcd9cb418340 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Office" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.show" -msgstr "显示" +msgid "editor.roomName.office" +msgstr "办公室" -# Source-Hash: c40163620df24a76 +# Source-Hash: 5d98d41ec10bd05e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Take snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pantry" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.takeSnapshot" -msgstr "拍摄快照" +msgid "editor.roomName.pantry" +msgstr "食品储藏室" -# Source-Hash: faecab10b69d4863 +# Source-Hash: 78dbe13192c0894b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Update snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Patio" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.updateSnapshot" -msgstr "更新快照" +msgid "editor.roomName.patio" +msgstr "露台" -# Source-Hash: 8a1fd8827a68f236 +# Source-Hash: c3cfcccc167b1c19 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "View snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Playroom" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.treeNodeActions.viewSnapshot" -msgstr "查看快照" +msgid "editor.roomName.playroom" +msgstr "游戏室" -# Source-Hash: b404dded35241274 +# Source-Hash: 2e6324beaed18dd5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Units" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pool area" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.units" -msgstr "单位" +msgid "editor.roomName.poolArea" +msgstr "泳池区" -# Source-Hash: 149fec3fd1f08042 +# Source-Hash: 97d20e41044a3235 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete unit" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Porch" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.deleteUnit" -msgstr "删除单元" +msgid "editor.roomName.porch" +msgstr "门廊" -# Source-Hash: 930399d3fb247a7c +# Source-Hash: 04cb81f4a4ae4ff3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Focused" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Powder room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.focused" -msgstr "已聚焦" +msgid "editor.roomName.powderRoom" +msgstr "客用卫生间" -# Source-Hash: 41ac9dd23bb558d7 +# Source-Hash: 599c44d857832cd0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove from unit" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Primary bedroom" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.removeFromUnit" -msgstr "从单元中移除" +msgid "editor.roomName.primaryBedroom" +msgstr "主卧" -# Source-Hash: 612dcd5bf06a79c4 +# Source-Hash: 9a6ac3f1cdd8de2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reading nook" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.room" -msgstr "房间" +msgid "editor.roomName.readingNook" +msgstr "阅读角" -# Source-Hash: a107b4d76d6972e3 +# Source-Hash: 01f8cc22989822c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bathrooms" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.unitTreeNode.zone" -msgstr "区域" +msgid "editor.roomName.section.bathrooms" +msgstr "浴室" -# Source-Hash: faecab10b69d4863 +# Source-Hash: 9ec82561de8cb788 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Update snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Circulation" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.updateSnapshot" -msgstr "更新快照" +msgid "editor.roomName.section.circulation" +msgstr "交通空间" -# Source-Hash: 28a12e6806c091b0 +# Source-Hash: f74a48b6b49644d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{assetType, select, guide {Uploading guide... {progress}%} other {Uploading scan... {progress}%}}" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Living" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.uploadingProgress" -msgstr "{assetType, select, guide {正在上传参考底图... {progress}%} other {正在上传扫描模型... {progress}%}}" +msgid "editor.roomName.section.living" +msgstr "起居" -# Source-Hash: de389a2a46d53384 +# Source-Hash: 194a147d4618a994 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Upload scan/floorplan" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mezzanine" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.uploadScanFloorplan" -msgstr "上传扫描模型/平面图" +msgid "editor.roomName.section.mezzanine" +msgstr "夹层" -# Source-Hash: 8a1fd8827a68f236 +# Source-Hash: a5a7af5e5fff1c81 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "View snapshot" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outdoor" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.viewSnapshot" -msgstr "查看快照" +msgid "editor.roomName.section.outdoor" +msgstr "室外" -# Source-Hash: ba9f809cb032ee57 +# Source-Hash: 5df703d5b5e6ef7e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "In {unitName}" -#: packages/editor/src/components/ui/sidebar/panels/site-panel/zone-membership-checkbox.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sleeping" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.sitePanel.zoneMembershipCheckbox.inUnitname" -msgstr "在{unitName}中" +msgid "editor.roomName.section.sleeping" +msgstr "睡眠" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: c9d15ec19f814524 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Utility & storage" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.actions" -msgstr "操作" +msgid "editor.roomName.section.utility" +msgstr "杂物与储藏" -# Source-Hash: fcc43f22937d1536 +# Source-Hash: fbe13f7ab45e4cca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add one" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Work & hobbies" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.addOne" -msgstr "添加一个" +msgid "editor.roomName.section.work" +msgstr "工作与爱好" -# Source-Hash: bbc65c039ae86e11 +# Source-Hash: 10ccb6591f6ad207 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Camera snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shower room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.cameraSnapshot" -msgstr "相机快照" +msgid "editor.roomName.showerRoom" +msgstr "淋浴间" -# Source-Hash: 67d29724469fa8d3 +# Source-Hash: 5254168cc5712cb2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clear snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stairwell" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.clearSnapshot" -msgstr "清除快照" +msgid "editor.roomName.stairwell" +msgstr "楼梯间" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: d1596647cd84ade3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Storage" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.delete" -msgstr "删除" +msgid "editor.roomName.storage" +msgstr "储藏" -# Source-Hash: e2411929697b7ed4 +# Source-Hash: 7abc2dc6e39b1747 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete with contents" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Studio" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.deleteWithContents" -msgstr "连同内容一起删除" +msgid "editor.roomName.studio" +msgstr "影棚" -# Source-Hash: 22ca3935e8754072 +# Source-Hash: ebe68e83e73021ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No zones on this level." -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Study" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.noZonesOnThisLevel" -msgstr "此楼层上没有区域。" +msgid "editor.roomName.study" +msgstr "书房" -# Source-Hash: 941ea30f406dcfa2 +# Source-Hash: d69a0244649771ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Save to catalog" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sunroom" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.saveToCatalog" -msgstr "保存到目录" +msgid "editor.roomName.sunroom" +msgstr "阳光房" -# Source-Hash: 98662dfb371cac13 +# Source-Hash: 96281876ce53ba08 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Select a level to view and create zones" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terrace" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.selectALevelToViewAnd" -msgstr "选择楼层以查看和创建区域" +msgid "editor.roomName.terrace" +msgstr "露台" -# Source-Hash: c40163620df24a76 +# Source-Hash: a0cb3e6f5cf4fbec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Take snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Toilet" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.takeSnapshot" -msgstr "拍摄快照" +msgid "editor.roomName.toilet" +msgstr "卫生间" -# Source-Hash: faecab10b69d4863 +# Source-Hash: 6c01526f89f3106b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Update snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Utility room" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.updateSnapshot" -msgstr "更新快照" +msgid "editor.roomName.utilityRoom" +msgstr "杂物间" -# Source-Hash: 8a1fd8827a68f236 +# Source-Hash: fc42d89621ae7bac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "View snapshot" -#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Veranda" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.panels.zonePanel.viewSnapshot" -msgstr "查看快照" +msgid "editor.roomName.veranda" +msgstr "游廊" -# Source-Hash: 58b05af5b5724efb +# Source-Hash: b45d7730e896fd99 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "\"{label}\" plugin crashed" -#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walk-in closet" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.usePluginPanels.labelPluginCrashed" -msgstr "“{label}”插件已崩溃" +msgid "editor.roomName.walkInCloset" +msgstr "步入式衣帽间" -# Source-Hash: 9e84d6d7b9885c4f +# Source-Hash: 399f27253ef956cb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Loading…" -#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Workshop" +#: packages/editor/src/lib/room-name-messages.ts #, fuzzy -msgid "editor.sidebar.usePluginPanels.loading" -msgstr "加载中…" +msgid "editor.roomName.workshop" +msgstr "工作间" -# Source-Hash: 9fc7a39bc32f287a +# Source-Hash: 83909f82446ee9c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Plugins" -#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Settings" +#: packages/editor/src/components/ui/sidebar/icon-rail.tsx #, fuzzy -msgid "editor.sidebar.usePluginPanels.plugins" -msgstr "插件" +msgid "editor.sidebar.iconRail.settings" +msgstr "设置" -# Source-Hash: c6312309378aaaea +# Source-Hash: 91f90818d42a984e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "This panel hit an error and was unloaded for this session. The rest of the editor is unaffected — reload to try again." -#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Site" +#: packages/editor/src/components/ui/sidebar/icon-rail.tsx #, fuzzy -msgid "editor.sidebar.usePluginPanels.thisPanelHitAnErrorAnd" -msgstr "此面板发生错误,已在本次会话中卸载。编辑器的其余部分不受影响——重新加载即可重试。" +msgid "editor.sidebar.iconRail.site" +msgstr "场地" +# Source-Hash: 663175a9c461a96d # Review: required -# Source-Hash: 2ab3b6983e384ecc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling attachment" -#: packages/editor/src/components/ui/snap-target-badge.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx #, fuzzy -msgid "editor.snapTarget.ceiling" -msgstr "吸附到天花板" +msgid "editor.sidebar.panels.itemsPanel.all" +msgstr "全部" +# Source-Hash: fce9814c289e6b71 # Review: required -# Source-Hash: 54a00bbb699e3778 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof attachment" -#: packages/editor/src/components/ui/snap-target-badge.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Community" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx #, fuzzy -msgid "editor.snapTarget.roof" -msgstr "吸附到屋顶" +msgid "editor.sidebar.panels.itemsPanel.community" +msgstr "社区" +# Source-Hash: 663175a9c461a96d # Review: required -# Source-Hash: e45fee9c27f6ae69 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall attachment" -#: packages/editor/src/components/ui/snap-target-badge.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx #, fuzzy -msgid "editor.snapTarget.wall" -msgstr "吸附到墙面" +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.all" +msgstr "全部" -# Source-Hash: 834de1a7027c4da1 +# Source-Hash: fce9814c289e6b71 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The editor scene failed to render" -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Community" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx #, fuzzy -msgid "editor.theEditorSceneFailedToRender" -msgstr "编辑器场景渲染失败" +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.community" +msgstr "社区" -# Source-Hash: 151f7c7e4110016f +# Source-Hash: 8d211c78417ed1b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A curtain wall takes no corner window" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Library" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx #, fuzzy -msgid "editor.toolHint.aCurtainWallTakesNoCorner.1qxjv5i" -msgstr "幕墙不能设置转角窗" +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.library" +msgstr "素材库" -# Source-Hash: 97f5e044d46501fb +# Source-Hash: a0b7adfdfdec7307 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A curved wall takes no corner window" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mine" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx #, fuzzy -msgid "editor.toolHint.aCurvedWallTakesNoCorner.1vdnaw5" -msgstr "曲面墙体不能设置转角窗" +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.mine" +msgstr "我的" -# Source-Hash: 776d8ebece7fe1bb +# Source-Hash: 6024b7778b392ec3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add a corner · click the first to close" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No results for “{search}”" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx #, fuzzy -msgid "editor.toolHint.addACornerClickTheFirst.o4r67t" -msgstr "添加转角 · 点击第一个点闭合" +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.noResultsForSearch" +msgstr "没有“{search}”的结果" -# Source-Hash: 6a0745dd047b149a +# Source-Hash: 4ceb6dcb7827db7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Another opening is in the way at the corner" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Search..." +#: packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx #, fuzzy -msgid "editor.toolHint.anotherOpeningIsInTheWay.11l9dd0" -msgstr "转角处有另一个开口阻挡" +msgid "editor.sidebar.panels.itemsPanel.functionTreePanel.search" +msgstr "搜索..." -# Source-Hash: 441124187e7da2fc +# Source-Hash: 8d211c78417ed1b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Library" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx #, fuzzy -msgid "editor.toolHint.autoHangers.10554ka" -msgstr "自动吊架" +msgid "editor.sidebar.panels.itemsPanel.library" +msgstr "素材库" -# Source-Hash: 47a7f9a6a81156c3 +# Source-Hash: a0b7adfdfdec7307 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers - click or press H to toggle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mine" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx #, fuzzy -msgid "editor.toolHint.autoHangersClickOrPressH.rwa3ka" -msgstr "自动吊架 - 点击或按 H 切换" +msgid "editor.sidebar.panels.itemsPanel.mine" +msgstr "我的" -# Source-Hash: d7944f31cba90e26 +# Source-Hash: 6024b7778b392ec3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers: Off" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No results for “{search}”" +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx #, fuzzy -msgid "editor.toolHint.autoHangersOff.7yx01x" -msgstr "自动吊架:关" +msgid "editor.sidebar.panels.itemsPanel.noResultsForSearch" +msgstr "没有“{search}”的结果" -# Source-Hash: 295882d015d08742 +# Source-Hash: 4ceb6dcb7827db7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto hangers: On" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Search..." +#: packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx #, fuzzy -msgid "editor.toolHint.autoHangersOn.10b1umh" -msgstr "自动吊架:开" +msgid "editor.sidebar.panels.itemsPanel.search" +msgstr "搜索..." -# Source-Hash: 8c039e5182b01c4d +# Source-Hash: fb66c49eee49a3bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bypass snapping" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Build Tools" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.bypassSnapping.w5lmdv" -msgstr "绕过吸附" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.buildTools" +msgstr "建造工具" -# Source-Hash: c0774c185060fc13 +# Source-Hash: 14622745dbf93f4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.cancel.ew9em3" -msgstr "取消" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.camera" +msgstr "相机" -# Source-Hash: 5b33b576fd30b74e +# Source-Hash: 677783232bea72a2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel move" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Direct Manipulation" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.cancelMove.lvp31c" -msgstr "取消移动" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.directManipulation" +msgstr "直接操作" -# Source-Hash: 136fa29b9ae419bf +# Source-Hash: 8e67947d43b76596 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel run / exit" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawing Tools" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.cancelRunExit.zqjf3h" -msgstr "取消管段 / 退出" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.drawingTools" +msgstr "绘图工具" -# Source-Hash: 75b406824be91ac2 +# Source-Hash: 8cdda30f3be2bac2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel start point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Editor Navigation" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.cancelStartPoint.1xbq2lh" -msgstr "取消起点" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.editorNavigation" +msgstr "编辑器导航" -# Source-Hash: ffa5aaa1746303c4 +# Source-Hash: 9a996e3570d615ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner window" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Item Placement" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.cornerWindow.1avkzpo" -msgstr "转角窗" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.itemPlacement" +msgstr "物品放置" -# Source-Hash: b0afdd855a02e4a7 +# Source-Hash: fc18926f9bd9eebd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cuts" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keyboard shortcuts" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.cuts.1y0axps" -msgstr "切分" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.keyboardShortcuts" +msgstr "键盘快捷键" -# Source-Hash: dc9fe7601cc525f8 +# Source-Hash: cbb4c3e007d70aa0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cuts: {value}" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modes & History" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.cutsValue.ouzhvb" -msgstr "切分:{value}" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.modesHistory" +msgstr "模式与历史记录" -# Source-Hash: a2e13bc4dc82624c +# Source-Hash: 170b2049ef0f9131 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cuts: {value}, even" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selection" +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.cutsValueEven.1ngsz3" -msgstr "切分:{value},均分" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.selection" +msgstr "选择" -# Source-Hash: 04152b4cec726f34 +# Source-Hash: 0da1c4d163df2953 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cycle mono / gable / butterfly" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shortcuts are context-aware. Snapping is a visible mode: tap Shift to cycle it, hold Alt during a gesture to place freely." +#: packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx #, fuzzy -msgid "editor.toolHint.cycleMonoGableButterfly.1poga3m" -msgstr "切换单坡 / 双坡 / 蝶形" +msgid "editor.sidebar.panels.settingsPanel.keyboardShortcutsDialog.shortcutsAreContextAwareGuidedConstraints" +msgstr "快捷键随上下文而变化。吸附是可见的模式:轻按 Shift 切换,操作中按住 Alt 可自由放置。" -# Source-Hash: 4fb6c83edb6652b5 +# Source-Hash: 3c67cde0578ac829 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cycle snapping mode" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.cycleSnappingMode.1ct0gn6" -msgstr "切换吸附模式" +msgid "editor.sidebar.panels.sitePanel.addLevel" +msgstr "添加楼层" -# Source-Hash: 5d550a3ac76279de +# Source-Hash: 9a56d90d461b4bca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door style — click or press L to cycle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add point" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.doorStyleClickOrPressL.33pe65" -msgstr "门样式 — 点击或按 L 切换" +msgid "editor.sidebar.panels.sitePanel.addPoint" +msgstr "添加点" -# Source-Hash: 3272a7df5d7c6a9a +# Source-Hash: fedccec504a9ae33 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door type — click or press O to cycle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Area:" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.doorTypeClickOrPressO.1hhh8gt" -msgstr "门类型 — 点击或按 O 切换" +msgid "editor.sidebar.panels.sitePanel.area" +msgstr "面积:" -# Source-Hash: 366222b4435eefda +# Source-Hash: 87b6880f6de7a45a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drop downspout from outlet" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base elevation" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.dropDownspoutFromOutlet.1k4h1m4" -msgstr "从出水口引出落水管" +msgid "editor.sidebar.panels.sitePanel.baseElevation" +msgstr "基准标高" -# Source-Hash: 03f306371f345007 +# Source-Hash: d42f7d29e3fc4af7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct diameter down / up" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Building" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.ductDiameterDownUp.1wdz5vq" -msgstr "风管直径减小 / 增大" +msgid "editor.sidebar.panels.sitePanel.building" +msgstr "建筑" -# Source-Hash: 7b4137e27f8327d9 +# Source-Hash: 7c90f458259d5cd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End run / cancel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add new level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx #, fuzzy -msgid "editor.toolHint.endRunCancel.59dh2w" -msgstr "结束管段 / 取消" +msgid "editor.sidebar.panels.sitePanel.buildingTreeNode.addNewLevel" +msgstr "添加新楼层" -# Source-Hash: 938aacb119b29dc1 +# Source-Hash: d42f7d29e3fc4af7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Exit" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Building" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx #, fuzzy -msgid "editor.toolHint.exit.engmg5" -msgstr "退出" +msgid "editor.sidebar.panels.sitePanel.buildingTreeNode.building" +msgstr "建筑" -# Source-Hash: 7cb4e0688cabcb00 +# Source-Hash: bbc65c039ae86e11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Exit drawing" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.exitDrawing.9noxyb" -msgstr "退出绘制" +msgid "editor.sidebar.panels.sitePanel.cameraSnapshot" +msgstr "相机快照" -# Source-Hash: 47025a103c456125 +# Source-Hash: 3a0701ebcb9f26cb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish and continue" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Capture" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.finishAndContinue.1gpfsks" -msgstr "完成并继续" +msgid "editor.sidebar.panels.sitePanel.capture" +msgstr "采集" -# Source-Hash: 000918429b74128f +# Source-Hash: 71f2343818c55e0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish ceiling" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear selection" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.finishCeiling.1c1lfel" -msgstr "完成天花板" +msgid "editor.sidebar.panels.sitePanel.clearSelection" +msgstr "清除选择" -# Source-Hash: 51a80a0dba5a6f30 +# Source-Hash: 67d29724469fa8d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish grid axis" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.finishGridAxis.1wvrfhr" -msgstr "完成轴线" +msgid "editor.sidebar.panels.sitePanel.clearSnapshot" +msgstr "清除快照" -# Source-Hash: 87c7b98fc2e010e1 +# Source-Hash: def517c77fda49ea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish measurement" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close walls around a space to make a room." +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.finishMeasurement.1e4gv16" -msgstr "完成测量" +msgid "editor.sidebar.panels.sitePanel.closeWallsAroundASpaceTo" +msgstr "用墙体围合一个空间即可创建房间。" -# Source-Hash: 5e1a0af7dc506826 +# Source-Hash: 2b9af8da4b34cbfa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish multi-point witnesses" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collection colour" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx #, fuzzy -msgid "editor.toolHint.finishMultiPointWitnesses.8wzskz" -msgstr "完成多点参照" +msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.collectionColour" +msgstr "集合颜色" -# Source-Hash: 30fc0862501ba2e8 +# Source-Hash: 135af27a14a4cda7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish slab" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Collections" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx #, fuzzy -msgid "editor.toolHint.finishSlab.xmnm8e" -msgstr "完成楼板" +msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.collections" +msgstr "集合" -# Source-Hash: 66ed7c7598d3aa29 +# Source-Hash: 6f4751c26f12aef9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip side" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete collection" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx #, fuzzy -msgid "editor.toolHint.flipSide.172xku9" -msgstr "翻转方向" +msgid "editor.sidebar.panels.sitePanel.collectionTreeNode.deleteCollection" +msgstr "删除集合" -# Source-Hash: f5717f6a0905ffab +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follow: trace a lineset" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.followTraceALineset.mgquwe" -msgstr "跟随:沿冷媒管组布线" +msgid "editor.sidebar.panels.sitePanel.delete" +msgstr "删除" -# Source-Hash: ed7f3d8417a3e074 +# Source-Hash: 8e29375893d63408 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Force place" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.forcePlace.1hq1nr" -msgstr "强制放置" +msgid "editor.sidebar.panels.sitePanel.deleteLevel" +msgstr "删除楼层" -# Source-Hash: cc0c14065951444d +# Source-Hash: 6552e45eecc0a227 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Free placement" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw a zone" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.freePlacement.1nztdac" -msgstr "自由放置" +msgid "editor.sidebar.panels.sitePanel.drawAZone" +msgstr "绘制区域" -# Source-Hash: f098a27096a9c1ea +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Go vertical ↕, click to place" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.goVerticalClickToPlace.dg8g6m" -msgstr "切换为竖向 ↕,点击放置" +msgid "editor.sidebar.panels.sitePanel.duplicate" +msgstr "复制" -# Source-Hash: fd47f1820d8799c8 +# Source-Hash: 933177338f5a03ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Highlight outlet" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.highlightOutlet.65hoq8" -msgstr "高亮出水口" +msgid "editor.sidebar.panels.sitePanel.duplicateLevel" +msgstr "复制楼层" -# Source-Hash: eb90058d0f856f67 +# Source-Hash: c038947f317cabba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Join as a corner window" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate level with options" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.joinAsACornerWindow.jvdp4j" -msgstr "连接为转角窗" +msgid "editor.sidebar.panels.sitePanel.duplicateLevelWithOptions" +msgstr "带选项复制楼层" -# Source-Hash: 225b3161f2e59757 +# Source-Hash: 9614c6825a7c67bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Alt + drag" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate with options..." +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.altDrag.ai3wn9" -msgstr "Alt + 拖动" +msgid "editor.sidebar.panels.sitePanel.duplicateWithOptions" +msgstr "带选项复制..." -# Source-Hash: dd66f883b173fc72 +# Source-Hash: 7c4196b9e791c195 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Backspace" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elements" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.backspace.qy6qx8" -msgstr "退格键" +msgid "editor.sidebar.panels.sitePanel.elements" +msgstr "元素" -# Source-Hash: a18387bc0be54c32 +# Source-Hash: 1344ea2602e3aa9e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guide" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.click.m8sun" -msgstr "点击" +msgid "editor.sidebar.panels.sitePanel.guide" +msgstr "参考图" -# Source-Hash: db9e60c1d30b8499 +# Source-Hash: 591087ea83a48ead # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click again" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.clickAgain.190ws9j" -msgstr "再次点击" +msgid "editor.sidebar.panels.sitePanel.hide" +msgstr "隐藏" -# Source-Hash: f400330b9c9c12e8 +# Source-Hash: 0608743fc1736d86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Command" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.command.1j2mkia" -msgstr "Command" +msgid "editor.sidebar.panels.sitePanel.level" +msgstr "楼层" -# Source-Hash: 976c63285a510b09 +# Source-Hash: 13b3e6a6afe319d1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Control" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "New unit" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.control.10fbl8e" -msgstr "Ctrl" +msgid "editor.sidebar.panels.sitePanel.newUnit" +msgstr "新建单元" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 0192748d50f0e5f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No buildings yet" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.delete.oay2cq" -msgstr "删除" +msgid "editor.sidebar.panels.sitePanel.noBuildingsYet" +msgstr "暂无建筑" -# Source-Hash: 88888c9d2719fa92 +# Source-Hash: 1be310702a12e433 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double click" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No elements on this level" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.doubleClick.vlma6o" -msgstr "双击" +msgid "editor.sidebar.panels.sitePanel.noElementsOnThisLevel" +msgstr "此楼层上没有元素" -# Source-Hash: dfb85b2addb7b9fa +# Source-Hash: 0956af88ced36992 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No levels yet" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.drag.8pwtpf" -msgstr "拖动" +msgid "editor.sidebar.panels.sitePanel.noLevelsYet" +msgstr "暂无楼层" -# Source-Hash: ed9140d42148c99b +# Source-Hash: 45c41bfb2ae19627 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Enter" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# object selected} other {# objects selected}}" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.enter.1ctpui5" -msgstr "回车键" +msgid "editor.sidebar.panels.sitePanel.objectsSelected" +msgstr "{count, plural, other {已选择 # 个对象}}" -# Source-Hash: 9195fa8b9c8ebdfb +# Source-Hash: a5434e26e5cb1b26 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Other zones" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.hover.6xw79p" -msgstr "悬停" +msgid "editor.sidebar.panels.sitePanel.otherZones" +msgstr "其他区域" -# Source-Hash: 2d78441b741bc562 +# Source-Hash: 2aa38d84079d4dba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a duct end" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Perimeter:" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.hoverADuctEnd.19axr3b" -msgstr "悬停在风管端部" +msgid "editor.sidebar.panels.sitePanel.perimeter" +msgstr "周长:" -# Source-Hash: 6083405086f61c76 +# Source-Hash: 4004b9a8e4f8c9d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a pipe end" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Property Line" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.hoverAPipeEnd.1jbum5f" -msgstr "悬停在管道端部" +msgid "editor.sidebar.panels.sitePanel.propertyLine" +msgstr "地界线" -# Source-Hash: a5a337eb76fdb066 +# Source-Hash: 3e7408ed44676176 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover gutter" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rooms" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.hoverGutter.1dwcsno" -msgstr "悬停在檐沟上" +msgid "editor.sidebar.panels.sitePanel.rooms" +msgstr "房间" -# Source-Hash: a58533594411e088 +# Source-Hash: ca39c0581c7318e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left click" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select a level to view content" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.leftClick.s4gwfc" -msgstr "左键单击" - -# Source-Hash: bc4ab608ec3d3b4f +msgid "editor.sidebar.panels.sitePanel.selectALevelToViewContent" +msgstr "选择楼层以查看内容" + +# Source-Hash: 827e0c6ac9936b69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Middle click" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.middleClick.1jbaan4" -msgstr "中键单击" +msgid "editor.sidebar.panels.sitePanel.show" +msgstr "显示" -# Source-Hash: 6791879c651108c7 +# Source-Hash: 91f90818d42a984e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right click" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Site" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.rightClick.1ovld0h" -msgstr "右键单击" +msgid "editor.sidebar.panels.sitePanel.site" +msgstr "场地" -# Source-Hash: c836b21b42198868 +# Source-Hash: c40163620df24a76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R / Shift+R" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Take snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.rShiftR.13bnobh" -msgstr "R / Shift+R" +msgid "editor.sidebar.panels.sitePanel.takeSnapshot" +msgstr "拍摄快照" -# Source-Hash: 9812aa06d8bb7544 +# Source-Hash: d6b381247066a7aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scroll" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The ground level cannot be deleted" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.key.scroll.ai6wr0" -msgstr "滚动" +msgid "editor.sidebar.panels.sitePanel.theGroundLevelCannotBeDeleted" +msgstr "无法删除首层楼层" -# Source-Hash: f2174536230657c8 +# Source-Hash: bbc65c039ae86e11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scroll wheel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.toolHint.key.scrollWheel.18j0ix7" -msgstr "滚轮" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.cameraSnapshot" +msgstr "相机快照" -# Source-Hash: 82dd231086d87f3b +# Source-Hash: 67d29724469fa8d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Space" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.toolHint.key.space.1hrh82t" -msgstr "空格键" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.clearSnapshot" +msgstr "清除快照" -# Source-Hash: 9e68aa2f472cad56 +# Source-Hash: 591087ea83a48ead # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tab" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hide" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.toolHint.key.tab.1xsal0s" -msgstr "Tab 键" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.hide" +msgstr "隐藏" -# Source-Hash: 4b221b73f9496a49 +# Source-Hash: 827e0c6ac9936b69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mount: floor / ceiling / wall" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.toolHint.mountFloorCeilingWall.32dxpv" -msgstr "安装位置:地面 / 天花板 / 墙体" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.show" +msgstr "显示" -# Source-Hash: 225edfb1e45aed95 +# Source-Hash: c40163620df24a76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No room for the matching window on the other wall" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Take snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.toolHint.noRoomForTheMatchingWindow.1755948" -msgstr "另一面墙上没有空间放置对应的窗" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.takeSnapshot" +msgstr "拍摄快照" -# Source-Hash: a7045d6b678bcd13 +# Source-Hash: faecab10b69d4863 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No wall meets here" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Update snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.toolHint.noWallMeetsHere.19n99yc" -msgstr "此处没有相交的墙体" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.updateSnapshot" +msgstr "更新快照" -# Source-Hash: a639341dc21fed2c +# Source-Hash: 8a1fd8827a68f236 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Number of cuts — scroll or click to change" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "View snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx #, fuzzy -msgid "editor.toolHint.numberOfCutsScrollOrClick.1kqe84b" -msgstr "切分数量 — 滚动或点击更改" +msgid "editor.sidebar.panels.sitePanel.treeNodeActions.viewSnapshot" +msgstr "查看快照" -# Source-Hash: af01bde3ae4b7e59 +# Source-Hash: b404dded35241274 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pick witness point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Units" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.pickWitnessPoint.k3hgh1" -msgstr "拾取参照点" +msgid "editor.sidebar.panels.sitePanel.units" +msgstr "单位" -# Source-Hash: ecfd58576b28a9f6 +# Source-Hash: 149fec3fd1f08042 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pipe size down / up" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete unit" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.toolHint.pipeSizeDownUp.wp04og" -msgstr "管径减小 / 增大" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.deleteUnit" +msgstr "删除单元" -# Source-Hash: 7a1eb7b64f06bad0 +# Source-Hash: 930399d3fb247a7c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place and continue" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Focused" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.toolHint.placeAndContinue.qfwkrq" -msgstr "放置并继续" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.focused" +msgstr "已聚焦" -# Source-Hash: c6cda39e2e4b5d3a +# Source-Hash: 41ac9dd23bb558d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place block" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove from unit" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.toolHint.placeBlock.1aylwrx" -msgstr "放置体块" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.removeFromUnit" +msgstr "从单元中移除" -# Source-Hash: 45a743c52a1d72de +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place box vent on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.toolHint.placeBoxVentOnRoof.kf88e5" -msgstr "在屋顶上放置箱式通风口" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.room" +msgstr "房间" -# Source-Hash: 75142dd1d557efe2 +# Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place cabinet" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx #, fuzzy -msgid "editor.toolHint.placeCabinet.b0ouyk" -msgstr "放置橱柜" +msgid "editor.sidebar.panels.sitePanel.unitTreeNode.zone" +msgstr "区域" -# Source-Hash: da603a713d4c9909 +# Source-Hash: faecab10b69d4863 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place canopy or set the next run point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Update snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeCanopyOrSetTheNext.12l7zf8" -msgstr "放置雨棚或设置下一个连续点" +msgid "editor.sidebar.panels.sitePanel.updateSnapshot" +msgstr "更新快照" -# Source-Hash: 8b3a30c6b7a5612d +# Source-Hash: 28a12e6806c091b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place chimney on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{assetType, select, guide {Uploading guide... {progress}%} other {Uploading scan... {progress}%}}" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeChimneyOnRoof.19dbqu" -msgstr "在屋顶上放置烟囱" +msgid "editor.sidebar.panels.sitePanel.uploadingProgress" +msgstr "{assetType, select, guide {正在上传参考底图... {progress}%} other {正在上传扫描模型... {progress}%}}" -# Source-Hash: 710d41e4e2f259fa +# Source-Hash: de389a2a46d53384 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place column" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Upload scan/floorplan" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeColumn.1w2vq86" -msgstr "放置柱" +msgid "editor.sidebar.panels.sitePanel.uploadScanFloorplan" +msgstr "上传扫描模型/平面图" -# Source-Hash: ee1da4e12a71d9a9 +# Source-Hash: 8a1fd8827a68f236 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place cupola on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "View snapshot" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeCupolaOnRoof.ofx3bn" -msgstr "在屋顶上放置穹顶亭" +msgid "editor.sidebar.panels.sitePanel.viewSnapshot" +msgstr "查看快照" -# Source-Hash: 19c1fe8c46d213a5 +# Source-Hash: ba9f809cb032ee57 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place dimension line when needed" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "In {unitName}" +#: packages/editor/src/components/ui/sidebar/panels/site-panel/zone-membership-checkbox.tsx #, fuzzy -msgid "editor.toolHint.placeDimensionLineWhenNeeded.bjw2cj" -msgstr "需要时放置尺寸线" +msgid "editor.sidebar.panels.sitePanel.zoneMembershipCheckbox.inUnitname" +msgstr "在{unitName}中" -# Source-Hash: 58f3e7efb6ea120b +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place door on wall" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeDoorOnWall.1jwadf" -msgstr "在墙体上放置门" +msgid "editor.sidebar.panels.zonePanel.actions" +msgstr "操作" -# Source-Hash: de04e9d03d937c97 +# Source-Hash: fcc43f22937d1536 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place dormer on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add one" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeDormerOnRoof.1w518a6" -msgstr "在屋顶上放置老虎窗" +msgid "editor.sidebar.panels.zonePanel.addOne" +msgstr "添加一个" -# Source-Hash: c581645f2ee447c2 +# Source-Hash: bbc65c039ae86e11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place elevator" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Camera snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeElevator.1f65zva" -msgstr "放置电梯" +msgid "editor.sidebar.panels.zonePanel.cameraSnapshot" +msgstr "相机快照" -# Source-Hash: 096b8d6482717358 +# Source-Hash: 67d29724469fa8d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place eyebrow vent on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clear snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeEyebrowVentOnRoof.1h1tqxn" -msgstr "在屋顶上放置眉形通风口" +msgid "editor.sidebar.panels.zonePanel.clearSnapshot" +msgstr "清除快照" -# Source-Hash: e8d42c1c8370773f +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place fitting" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeFitting.1pmx3vn" -msgstr "放置管件" +msgid "editor.sidebar.panels.zonePanel.delete" +msgstr "删除" -# Source-Hash: 2340a4b70cb0d9ad +# Source-Hash: e2411929697b7ed4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place gutter on roof eave" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete with contents" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeGutterOnRoofEave.llwzf9" -msgstr "在屋檐上放置檐沟" +msgid "editor.sidebar.panels.zonePanel.deleteWithContents" +msgstr "连同内容一起删除" -# Source-Hash: 706a8eafb6212833 +# Source-Hash: 22ca3935e8754072 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place item" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No zones on this level." +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeItem.teynf" -msgstr "放置物品" +msgid "editor.sidebar.panels.zonePanel.noZonesOnThisLevel" +msgstr "此楼层上没有区域。" -# Source-Hash: 1815c482e249932e +# Source-Hash: 941ea30f406dcfa2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place it (locked to 45°)" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Save to catalog" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeItLockedTo45.16e4csk" -msgstr "放置(锁定为 45°)" +msgid "editor.sidebar.panels.zonePanel.saveToCatalog" +msgstr "保存到目录" -# Source-Hash: 4a14340657532838 +# Source-Hash: 98662dfb371cac13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place measurement point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Select a level to view and create zones" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placeMeasurementPoint.bsatli" -msgstr "放置测量点" +msgid "editor.sidebar.panels.zonePanel.selectALevelToViewAnd" +msgstr "选择楼层以查看和创建区域" -# Source-Hash: b3be684ac62fbf53 +# Source-Hash: c40163620df24a76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Take snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placement.13lcvts" -msgstr "放置" +msgid "editor.sidebar.panels.zonePanel.takeSnapshot" +msgstr "拍摄快照" -# Source-Hash: 2bb2ce6276c69b1e +# Source-Hash: faecab10b69d4863 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement: Auto" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Update snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placementAuto.1caa52d" -msgstr "放置:自动" +msgid "editor.sidebar.panels.zonePanel.updateSnapshot" +msgstr "更新快照" -# Source-Hash: ed78ac5354a1dcd8 +# Source-Hash: 8a1fd8827a68f236 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement: Ground" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "View snapshot" +#: packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx #, fuzzy -msgid "editor.toolHint.placementGround.1ruz145" -msgstr "放置:地面" +msgid "editor.sidebar.panels.zonePanel.viewSnapshot" +msgstr "查看快照" -# Source-Hash: a066a2c9d5e65a1a +# Source-Hash: 58b05af5b5724efb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement: Roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "\"{label}\" plugin crashed" +#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx #, fuzzy -msgid "editor.toolHint.placementRoof.renkw8" -msgstr "放置:屋顶" +msgid "editor.sidebar.usePluginPanels.labelPluginCrashed" +msgstr "“{label}”插件已崩溃" -# Source-Hash: 8f74dbe5064c4c66 +# Source-Hash: 9e84d6d7b9885c4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement surface - click or press P to cycle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Loading…" +#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx #, fuzzy -msgid "editor.toolHint.placementSurfaceClickOrPressP.w56h19" -msgstr "放置面 - 点击或按 P 切换" +msgid "editor.sidebar.usePluginPanels.loading" +msgstr "加载中…" -# Source-Hash: fe119955c925feaf +# Source-Hash: 9fc7a39bc32f287a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement type" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plugins" +#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx #, fuzzy -msgid "editor.toolHint.placementType.1mdpl60" -msgstr "放置类型" +msgid "editor.sidebar.usePluginPanels.plugins" +msgstr "插件" -# Source-Hash: 33043a35500168f5 +# Source-Hash: c6312309378aaaea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Placement type — click or press I to toggle" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This panel hit an error and was unloaded for this session. The rest of the editor is unaffected — reload to try again." +#: packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx #, fuzzy -msgid "editor.toolHint.placementTypeClickOrPressI.10cgxh2" -msgstr "放置类型 — 点击或按 I 切换" +msgid "editor.sidebar.usePluginPanels.thisPanelHitAnErrorAnd" +msgstr "此面板发生错误,已在本次会话中卸载。编辑器的其余部分不受影响——重新加载即可重试。" -# Source-Hash: 9945f412e6a9a446 +# Source-Hash: 2ab3b6983e384ecc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place on a fence" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling attachment" +#: packages/editor/src/components/ui/snap-target-badge.tsx #, fuzzy -msgid "editor.toolHint.placeOnAFence.1dptstr" -msgstr "放置在围栏上" +msgid "editor.snapTarget.ceiling" +msgstr "吸附到天花板" -# Source-Hash: 6708118775a7da7f +# Source-Hash: 54a00bbb699e3778 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place register" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof attachment" +#: packages/editor/src/components/ui/snap-target-badge.tsx #, fuzzy -msgid "editor.toolHint.placeRegister.1uebycd" -msgstr "放置风口" +msgid "editor.snapTarget.roof" +msgstr "吸附到屋顶" -# Source-Hash: ebd2731f5c79306e +# Source-Hash: e45fee9c27f6ae69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place ridge vent on roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall attachment" +#: packages/editor/src/components/ui/snap-target-badge.tsx #, fuzzy -msgid "editor.toolHint.placeRidgeVentOnRoof.2tpd8r" -msgstr "在屋顶上放置屋脊通风口" +msgid "editor.snapTarget.wall" +msgstr "吸附到墙面" -# Source-Hash: 9b3c66a867c23326 +# Source-Hash: 834de1a7027c4da1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place shelf" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The editor scene failed to render" +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "editor.toolHint.placeShelf.y4l3iw" -msgstr "放置置物架" +msgid "editor.theEditorSceneFailedToRender" +msgstr "编辑器场景渲染失败" -# Source-Hash: f11cf5c1c9fe862d +# Source-Hash: 151f7c7e4110016f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place skylight on roof" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A curtain wall takes no corner window" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeSkylightOnRoof.e215pe" -msgstr "在屋顶上放置天窗" +msgid "editor.toolHint.aCurtainWallTakesNoCorner.1qxjv5i" +msgstr "幕墙不能设置转角窗" -# Source-Hash: e989a58d6709cc16 +# Source-Hash: 97f5e044d46501fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place solar panel array on roof" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A curved wall takes no corner window" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeSolarPanelArrayOnRoof.kk11fn" -msgstr "在屋顶上放置光伏板阵列" +msgid "editor.toolHint.aCurvedWallTakesNoCorner.1vdnaw5" +msgstr "曲面墙体不能设置转角窗" -# Source-Hash: b67f7036d5180cf5 +# Source-Hash: 776d8ebece7fe1bb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place spawn point" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add a corner · click the first to close" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeSpawnPoint.205o25" -msgstr "放置出生点" +msgid "editor.toolHint.addACornerClickTheFirst.o4r67t" +msgstr "添加转角 · 点击第一个点闭合" -# Source-Hash: 6c7f32a17e5636c3 +# Source-Hash: 6a0745dd047b149a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place stairs" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Another opening is in the way at the corner" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeStairs.zwxxu2" -msgstr "放置楼梯" +msgid "editor.toolHint.anotherOpeningIsInTheWay.11l9dd0" +msgstr "转角处有另一个开口阻挡" -# Source-Hash: 641c0d3debd798a8 +# Source-Hash: 441124187e7da2fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place trap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeTrap.1gxemn3" -msgstr "放置存水弯" +msgid "editor.toolHint.autoHangers.10554ka" +msgstr "自动吊架" -# Source-Hash: 6f0a6f6c4b7588a0 +# Source-Hash: 47a7f9a6a81156c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place turbine vent on roof" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers - click or press H to toggle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeTurbineVentOnRoof.1iqeluf" -msgstr "在屋顶上放置涡轮通风器" +msgid "editor.toolHint.autoHangersClickOrPressH.rwa3ka" +msgstr "自动吊架 - 点击或按 H 切换" -# Source-Hash: e65cf5edb4f51ed5 +# Source-Hash: d7944f31cba90e26 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place unit" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers: Off" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeUnit.8zkx4q" -msgstr "放置设备" +msgid "editor.toolHint.autoHangersOff.7yx01x" +msgstr "自动吊架:关" -# Source-Hash: 86ce1c730154f68b +# Source-Hash: 295882d015d08742 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place window on wall" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto hangers: On" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeWindowOnWall.1k3qnfb" -msgstr "在墙体上放置窗" +msgid "editor.toolHint.autoHangersOn.10b1umh" +msgstr "自动吊架:开" -# Source-Hash: 2b612180a7617901 +# Source-Hash: 8c039e5182b01c4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place without the corner snap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bypass snapping" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.placeWithoutTheCornerSnap.1nifqew" -msgstr "不使用转角吸附放置" +msgid "editor.toolHint.bypassSnapping.w5lmdv" +msgstr "绕过吸附" -# Source-Hash: 0dc6d121791696f7 +# Source-Hash: c0774c185060fc13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove last point" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.removeLastPoint.2dmdcx" -msgstr "移除最后一个点" +msgid "editor.toolHint.cancel.ew9em3" +msgstr "取消" -# Source-Hash: 8b74b1d962be10fc +# Source-Hash: 5b33b576fd30b74e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove last witness" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel move" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.removeLastWitness.1b6vvzw" -msgstr "移除最后一个参照" +msgid "editor.toolHint.cancelMove.lvp31c" +msgstr "取消移动" -# Source-Hash: 306d409f8a1cf480 +# Source-Hash: 136fa29b9ae419bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel run / exit" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.rotate.1thqa0a" -msgstr "旋转" +msgid "editor.toolHint.cancelRunExit.zqjf3h" +msgstr "取消管段 / 退出" -# Source-Hash: 8a665ecaeffa9308 +# Source-Hash: 75b406824be91ac2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ±45°" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel start point" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.rotate45.9zq68u" -msgstr "旋转 ±45°" +msgid "editor.toolHint.cancelStartPoint.1xbq2lh" +msgstr "取消起点" -# Source-Hash: be2240289aa74df5 +# Source-Hash: ffa5aaa1746303c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ±45° (floor / ceiling)" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner window" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.rotate45FloorCeiling.m9t57d" -msgstr "旋转 ±45°(地面 / 天花板)" +msgid "editor.toolHint.cornerWindow.1avkzpo" +msgstr "转角窗" -# Source-Hash: d5fb78b07c0f8138 +# Source-Hash: b0afdd855a02e4a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate ghost ±15°" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cuts" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.rotateGhost15.rsa52c" -msgstr "旋转预览 ±15°" +msgid "editor.toolHint.cuts.1y0axps" +msgstr "切分" -# Source-Hash: 912d340cd16e27fa +# Source-Hash: dc9fe7601cc525f8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate or flip the run side" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cuts: {value}" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.rotateOrFlipTheRunSide.t5ior7" -msgstr "旋转或翻转排布方向" +msgid "editor.toolHint.cutsValue.ouzhvb" +msgstr "切分:{value}" -# Source-Hash: ad1dc0b5536cceef +# Source-Hash: a2e13bc4dc82624c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate roof direction 90°" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cuts: {value}, even" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.rotateRoofDirection90.tvbji2" -msgstr "将屋顶方向旋转 90°" +msgid "editor.toolHint.cutsValueEven.1ngsz3" +msgstr "切分:{value},均分" -# Source-Hash: fa24651e9e5f595a +# Source-Hash: 04152b4cec726f34 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotate spawn point" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cycle mono / gable / butterfly" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.rotateSpawnPoint.1opcuu7" -msgstr "旋转出生点" +msgid "editor.toolHint.cycleMonoGableButterfly.1poga3m" +msgstr "切换单坡 / 双坡 / 蝶形" -# Source-Hash: 2d693d87fe9b59e6 +# Source-Hash: 4fb6c83edb6652b5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round / rectangular / oval" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cycle snapping mode" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.roundRectangularOval.e4nh6x" -msgstr "圆形 / 矩形 / 椭圆" +msgid "editor.toolHint.cycleSnappingMode.1ct0gn6" +msgstr "切换吸附模式" -# Source-Hash: f7d2c9cdcc637c97 +# Source-Hash: 5d550a3ac76279de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set fence start / end" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door style — click or press L to cycle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.setFenceStartEnd.1phbwsq" -msgstr "设置围栏起点 / 终点" +msgid "editor.toolHint.doorStyleClickOrPressL.33pe65" +msgstr "门样式 — 点击或按 L 切换" -# Source-Hash: c93ae898b4d59f6f +# Source-Hash: 3272a7df5d7c6a9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set one corner, then the opposite" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door type — click or press O to cycle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.setOneCornerThenTheOpposite.8tsl49" -msgstr "设置一个角,再设置对角" +msgid "editor.toolHint.doorTypeClickOrPressO.1hhh8gt" +msgstr "门类型 — 点击或按 O 切换" -# Source-Hash: 4f55171f10c6ceeb +# Source-Hash: 366222b4435eefda # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set roof footprint" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drop downspout from outlet" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.setRoofFootprint.p50n0o" -msgstr "设置屋顶轮廓" +msgid "editor.toolHint.dropDownspoutFromOutlet.1k4h1m4" +msgstr "从出水口引出落水管" -# Source-Hash: 0243859b1d64c21e +# Source-Hash: 03f306371f345007 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set wall start / end" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct diameter down / up" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.setWallStartEnd.1r8ubcx" -msgstr "设置墙体起点 / 终点" +msgid "editor.toolHint.ductDiameterDownUp.1wdz5vq" +msgstr "风管直径减小 / 增大" -# Source-Hash: c2806cce9612fa50 +# Source-Hash: 7b4137e27f8327d9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slope / level" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End run / cancel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.slopeLevel.ftqp67" -msgstr "坡度 / 水平" +msgid "editor.toolHint.endRunCancel.59dh2w" +msgstr "结束管段 / 取消" -# Source-Hash: 06c0ec40606db679 +# Source-Hash: b714e91c31108a71 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snap onto the run" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End the run" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.snapOntoTheRun.86yhmp" -msgstr "吸附到管段上" +msgid "editor.toolHint.endTheRun.1c1raig" +msgstr "结束连续绘制" -# Source-Hash: e214cccbac9c4fd2 +# Source-Hash: 938aacb119b29dc1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Split at the marks" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Exit" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.splitAtTheMarks.x5tpdd" -msgstr "在标记处分割" +msgid "editor.toolHint.exit.engmg5" +msgstr "退出" -# Source-Hash: 94455c35bfeac6b4 +# Source-Hash: 7cb4e0688cabcb00 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start grid axis" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Exit drawing" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.startGridAxis.k92yza" -msgstr "开始轴线" +msgid "editor.toolHint.exitDrawing.9noxyb" +msgstr "退出绘制" -# Source-Hash: 2edb4c29bbe7c513 +# Source-Hash: 47025a103c456125 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start lineset" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish and continue" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.startLineset.23q8dh" -msgstr "开始冷媒管组" +msgid "editor.toolHint.finishAndContinue.1gpfsks" +msgstr "完成并继续" -# Source-Hash: 9e50f1b30e325208 +# Source-Hash: 000918429b74128f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start liquid line" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish ceiling" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.startLiquidLine.1rlxsgd" -msgstr "开始液管" +msgid "editor.toolHint.finishCeiling.1c1lfel" +msgstr "完成天花板" -# Source-Hash: 877ddcb778c211cc +# Source-Hash: 51a80a0dba5a6f30 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start run" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish grid axis" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.startRun.r6fc5u" -msgstr "开始管段" +msgid "editor.toolHint.finishGridAxis.1wvrfhr" +msgstr "完成轴线" -# Source-Hash: 8a62bee64174bbc0 +# Source-Hash: 87c7b98fc2e010e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start segment" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish measurement" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.startSegment.rolym6" -msgstr "开始分段" +msgid "editor.toolHint.finishMeasurement.1e4gv16" +msgstr "完成测量" -# Source-Hash: 6cc5dc51a8e66779 +# Source-Hash: 5e1a0af7dc506826 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Step back or cancel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish multi-point witnesses" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.stepBackOrCancel.zbfdkn" -msgstr "后退一步或取消" +msgid "editor.toolHint.finishMultiPointWitnesses.8wzskz" +msgstr "完成多点参照" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: 30fc0862501ba2e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish slab" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.style.nf3vcm" -msgstr "样式" +msgid "editor.toolHint.finishSlab.xmnm8e" +msgstr "完成楼板" -# Source-Hash: 81f595b1c47c0080 +# Source-Hash: 66ed7c7598d3aa29 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Barn" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip side" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleBarn.k9n1x" -msgstr "样式:谷仓门" +msgid "editor.toolHint.flipSide.172xku9" +msgstr "翻转方向" -# Source-Hash: 3a82c718fe215273 +# Source-Hash: f5717f6a0905ffab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Casement" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow: trace a lineset" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleCasement.ziklec" -msgstr "样式:平开" +msgid "editor.toolHint.followTraceALineset.mgquwe" +msgstr "跟随:沿冷媒管组布线" -# Source-Hash: 072e3331d1d105c0 +# Source-Hash: ed7f3d8417a3e074 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Craftsman" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Force place" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleCraftsman.52e6a9" -msgstr "样式:工匠" +msgid "editor.toolHint.forcePlace.1hq1nr" +msgstr "强制放置" -# Source-Hash: b64d07557dec1714 +# Source-Hash: 64b4ac6d3da25183 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Double-hung" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free angle" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleDoubleHung.1lg8pkg" -msgstr "样式:双悬" +msgid "editor.toolHint.freeAngle.1ptblho" +msgstr "自由角度" -# Source-Hash: 55ef8761a537637f +# Source-Hash: 446b8aac1e5e8422 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: French" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free place" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleFrench.1ue3j64" -msgstr "样式:法式" +msgid "editor.toolHint.freePlace.1s1uusw" +msgstr "自由放置" -# Source-Hash: bc8a751d87536dc3 +# Source-Hash: cc0c14065951444d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Glass" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Free placement" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleGlass.qudnb4" -msgstr "样式:玻璃" +msgid "editor.toolHint.freePlacement.1nztdac" +msgstr "自由放置" -# Source-Hash: 40c1eb0bc83e207d +# Source-Hash: f098a27096a9c1ea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Grid" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Go vertical ↕, click to place" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleGrid.1vuq4po" -msgstr "样式:格栅" +msgid "editor.toolHint.goVerticalClickToPlace.dg8g6m" +msgstr "切换为竖向 ↕,点击放置" -# Source-Hash: f516886bab2e7f10 +# Source-Hash: fd47f1820d8799c8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Half-louvered" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Highlight outlet" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleHalfLouvered.13b1few" -msgstr "样式:半百叶" +msgid "editor.toolHint.highlightOutlet.65hoq8" +msgstr "高亮出水口" -# Source-Hash: 64e4389a695371a2 +# Source-Hash: eb90058d0f856f67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Horizontal bands" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Join as a corner window" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleHorizontalBands.12ethxk" -msgstr "样式:横向条纹" +msgid "editor.toolHint.joinAsACornerWindow.jvdp4j" +msgstr "连接为转角窗" -# Source-Hash: ff6d226a425b00c0 +# Source-Hash: 225b3161f2e59757 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Modern" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Alt + drag" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleModern.1fh8hhn" -msgstr "样式:现代" +msgid "editor.toolHint.key.altDrag.ai3wn9" +msgstr "Alt + 拖动" -# Source-Hash: c6d17ba078ff47e7 +# Source-Hash: dd66f883b173fc72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Backspace" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.stylePanel.922jze" -msgstr "样式:镶板" +msgid "editor.toolHint.key.backspace.qy6qx8" +msgstr "退格键" -# Source-Hash: 5e6baad0d2ce3a62 +# Source-Hash: a18387bc0be54c32 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Paneled glass" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.stylePaneledGlass.17a17en" -msgstr "样式:镶板玻璃" +msgid "editor.toolHint.key.click.m8sun" +msgstr "点击" -# Source-Hash: 6314388e6832c252 +# Source-Hash: db9e60c1d30b8499 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Shaker" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click again" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleShaker.49z17k" -msgstr "样式:震颤派" +msgid "editor.toolHint.key.clickAgain.190ws9j" +msgstr "再次点击" -# Source-Hash: a0f8e524f3ca121f +# Source-Hash: f400330b9c9c12e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Single" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Command" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleSingle.6f3cm0" -msgstr "样式:单扇" +msgid "editor.toolHint.key.command.1j2mkia" +msgstr "Command" -# Source-Hash: 368279df3a472c86 +# Source-Hash: 976c63285a510b09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Six-panel" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Control" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleSixPanel.u49laj" -msgstr "样式:六镶板" +msgid "editor.toolHint.key.control.10fbl8e" +msgstr "Ctrl" -# Source-Hash: 8f3c2571d8168fee +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Sliding" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleSliding.q81s0i" -msgstr "样式:推拉" +msgid "editor.toolHint.key.delete.oay2cq" +msgstr "删除" -# Source-Hash: aa9d9eb137ca38d4 +# Source-Hash: 88888c9d2719fa92 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Tall grid" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double click" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleTallGrid.1eotg3x" -msgstr "样式:高格栅" +msgid "editor.toolHint.key.doubleClick.vlma6o" +msgstr "双击" -# Source-Hash: bc164648722b63e5 +# Source-Hash: dfb85b2addb7b9fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Transom" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleTransom.kb9bh6" -msgstr "样式:带亮子" +msgid "editor.toolHint.key.drag.8pwtpf" +msgstr "拖动" -# Source-Hash: 9a218f0c9ceb4697 +# Source-Hash: ed9140d42148c99b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Triple-hung" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Enter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleTripleHung.pxnqi3" -msgstr "样式:三悬" +msgid "editor.toolHint.key.enter.1ctpui5" +msgstr "回车键" -# Source-Hash: 9f6df1344bd3d694 +# Source-Hash: 9195fa8b9c8ebdfb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style: Wide grid" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.styleWideGrid.12n27et" -msgstr "样式:宽格栅" +msgid "editor.toolHint.key.hover.6xw79p" +msgstr "悬停" -# Source-Hash: 711d4050c0cb95d7 +# Source-Hash: 2d78441b741bc562 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Switch rotation axis (Y → X → Z)" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a duct end" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.switchRotationAxisYXZ.15lohm6" -msgstr "切换旋转轴(Y → X → Z)" +msgid "editor.toolHint.key.hoverADuctEnd.19axr3b" +msgstr "悬停在风管端部" -# Source-Hash: d650c71e042c2598 +# Source-Hash: 6083405086f61c76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The walls meet at too sharp or too flat an angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a pipe end" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.theWallsMeetAtTooSharp.kh3wi3" -msgstr "墙体相交的角度过尖或过平" +msgid "editor.toolHint.key.hoverAPipeEnd.1jbum5f" +msgstr "悬停在管道端部" -# Source-Hash: ab206ac56e65f190 +# Source-Hash: a5a337eb76fdb066 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The window waiting there is taller than this wall" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover gutter" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.theWindowWaitingThereIsTaller.1tqwez4" -msgstr "该处待放置的窗比这面墙体更高" +msgid "editor.toolHint.key.hoverGutter.1dwcsno" +msgstr "悬停在檐沟上" -# Source-Hash: 9c1f47138ed5c7ee +# Source-Hash: a58533594411e088 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Three or more walls meet here" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left click" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.threeOrMoreWallsMeetHere.rgifif" -msgstr "此处有三面或更多墙体相交" +msgid "editor.toolHint.key.leftClick.s4gwfc" +msgstr "左键单击" -# Source-Hash: c3ca56fa28e15f07 +# Source-Hash: bc4ab608ec3d3b4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trace ceiling outline" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Middle click" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.traceCeilingOutline.1b639wv" -msgstr "描绘天花板轮廓" +msgid "editor.toolHint.key.middleClick.1jbaan4" +msgstr "中键单击" -# Source-Hash: bdf71499d30a29de +# Source-Hash: 6791879c651108c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trace slab outline" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right click" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.traceSlabOutline.z0j2lc" -msgstr "描绘楼板轮廓" +msgid "editor.toolHint.key.rightClick.1ovld0h" +msgstr "右键单击" -# Source-Hash: c44f7ab8bbd24858 +# Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.type.1m2zofh" -msgstr "类型" +msgid "editor.toolHint.key.room.1f3jkpm" +msgstr "房间" -# Source-Hash: b54eaaff3349dcb1 +# Source-Hash: c836b21b42198868 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Awning" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R / Shift+R" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeAwning.1cj59al" -msgstr "类型:上悬" +msgid "editor.toolHint.key.rShiftR.13bnobh" +msgstr "R / Shift+R" -# Source-Hash: f399572a27417c66 +# Source-Hash: 9812aa06d8bb7544 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Barn" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scroll" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeBarn.sbnygq" -msgstr "类型:谷仓门" +msgid "editor.toolHint.key.scroll.ai6wr0" +msgstr "滚动" -# Source-Hash: a1df9782200b5f1e +# Source-Hash: f2174536230657c8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Bay" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scroll wheel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeBay.1200hc1" -msgstr "类型:凸窗" +msgid "editor.toolHint.key.scrollWheel.18j0ix7" +msgstr "滚轮" -# Source-Hash: ff069a390e8e3f66 +# Source-Hash: 82dd231086d87f3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Bow" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Space" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeBow.14s2t9p" -msgstr "类型:弧形凸窗" +msgid "editor.toolHint.key.space.1hrh82t" +msgstr "空格键" -# Source-Hash: bdac5f3f2ea70fff +# Source-Hash: 9e68aa2f472cad56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Cabinet" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tab" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeCabinet.1r68je5" -msgstr "类型:柜门" +msgid "editor.toolHint.key.tab.1xsal0s" +msgstr "Tab 键" -# Source-Hash: e0754fc03997cbf9 +# Source-Hash: 4b221b73f9496a49 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Casement" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mount: floor / ceiling / wall" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeCasement.176uo9j" -msgstr "类型:平开" +msgid "editor.toolHint.mountFloorCeilingWall.32dxpv" +msgstr "安装位置:地面 / 天花板 / 墙体" -# Source-Hash: 47d873446d6e173b +# Source-Hash: 225edfb1e45aed95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Double" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No room for the matching window on the other wall" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeDouble.af7w4i" -msgstr "类型:双扇" +msgid "editor.toolHint.noRoomForTheMatchingWindow.1755948" +msgstr "另一面墙上没有空间放置对应的窗" -# Source-Hash: 5942e484513aaab5 +# Source-Hash: e367d28a655f1cca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Double Hung" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not a rectangle: draw this roof instead" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeDoubleHung.t482fu" -msgstr "类型:双悬" +msgid "editor.toolHint.notARectangleDrawThisRoof.100pa5g" +msgstr "非矩形:请改为绘制此屋顶" -# Source-Hash: f9497fbfceefda27 +# Source-Hash: a7045d6b678bcd13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Fixed" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No wall meets here" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeFixed.v1cjez" -msgstr "类型:固定" +msgid "editor.toolHint.noWallMeetsHere.19n99yc" +msgstr "此处没有相交的墙体" -# Source-Hash: 0dcf07acc9cbf000 +# Source-Hash: a639341dc21fed2c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Folding" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Number of cuts — scroll or click to change" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeFolding.sxxyng" -msgstr "类型:折叠" +msgid "editor.toolHint.numberOfCutsScrollOrClick.1kqe84b" +msgstr "切分数量 — 滚动或点击更改" -# Source-Hash: bff7331f87f279aa +# Source-Hash: af01bde3ae4b7e59 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: French" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pick witness point" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeFrench.1y57z1b" -msgstr "类型:法式" +msgid "editor.toolHint.pickWitnessPoint.k3hgh1" +msgstr "拾取参照点" -# Source-Hash: 9d2c3b82079eb769 +# Source-Hash: ecfd58576b28a9f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Hinged" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pipe size down / up" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeHinged.1xrcfju" -msgstr "类型:铰链" +msgid "editor.toolHint.pipeSizeDownUp.wp04og" +msgstr "管径减小 / 增大" -# Source-Hash: b8001b90ff522838 +# Source-Hash: 7a1eb7b64f06bad0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Island" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place and continue" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeIsland.ufr3ce" -msgstr "类型:岛台" +msgid "editor.toolHint.placeAndContinue.qfwkrq" +msgstr "放置并继续" -# Source-Hash: 516833c5160d412e +# Source-Hash: c6cda39e2e4b5d3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Louvered" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place block" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeLouvered.oxl1cz" -msgstr "类型:百叶" +msgid "editor.toolHint.placeBlock.1aylwrx" +msgstr "放置体块" -# Source-Hash: 291272bf848ad6ab +# Source-Hash: 45a743c52a1d72de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Pocket" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place box vent on roof" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typePocket.hc65x9" -msgstr "类型:内嵌推拉" +msgid "editor.toolHint.placeBoxVentOnRoof.kf88e5" +msgstr "在屋顶上放置箱式通风口" -# Source-Hash: 46d0e53d6ae07c72 +# Source-Hash: 75142dd1d557efe2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Single Hung" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place cabinet" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeSingleHung.p53pyl" -msgstr "类型:单悬" +msgid "editor.toolHint.placeCabinet.b0ouyk" +msgstr "放置橱柜" -# Source-Hash: b11115b50df8faac +# Source-Hash: da603a713d4c9909 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type: Sliding" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place canopy or set the next run point" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.typeSliding.nwmr3f" -msgstr "类型:推拉" +msgid "editor.toolHint.placeCanopyOrSetTheNext.12l7zf8" +msgstr "放置雨棚或设置下一个连续点" -# Source-Hash: bff0c1694ee0a37e +# Source-Hash: 8b3a30c6b7a5612d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical stack ↕, click to place" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place chimney on roof" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.verticalStackClickToPlace.ijcn4q" -msgstr "竖向立管 ↕,点击放置" +msgid "editor.toolHint.placeChimneyOnRoof.19dbqu" +msgstr "在屋顶上放置烟囱" -# Source-Hash: bac471ee67af6412 +# Source-Hash: 710d41e4e2f259fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waste / vent" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place column" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.wasteVent.1hvi3vj" -msgstr "污水 / 通气" +msgid "editor.toolHint.placeColumn.1w2vq86" +msgstr "放置柱" -# Source-Hash: 1c744b7e24fc786e +# Source-Hash: ee1da4e12a71d9a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Window style — click or press L to cycle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place cupola on roof" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.windowStyleClickOrPressL.ah7qm9" -msgstr "窗样式 — 点击或按 L 切换" +msgid "editor.toolHint.placeCupolaOnRoof.ofx3bn" +msgstr "在屋顶上放置穹顶亭" -# Source-Hash: dd6f0ab314fea26c +# Source-Hash: 19c1fe8c46d213a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Window type — click or press O to cycle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place dimension line when needed" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.toolHint.windowTypeClickOrPressO.wv4x35" -msgstr "窗类型 — 点击或按 O 切换" +msgid "editor.toolHint.placeDimensionLineWhenNeeded.bjw2cj" +msgstr "需要时放置尺寸线" +# Source-Hash: 58f3e7efb6ea120b # Review: required -# Source-Hash: a48c4b2e4d71b08d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length: {field} m" -#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place door on wall" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.tools.distribution.distributionRunTool.lengthField" -msgstr "长度:{field} m" +msgid "editor.toolHint.placeDoorOnWall.1jwadf" +msgstr "在墙体上放置门" +# Source-Hash: de04e9d03d937c97 # Review: required -# Source-Hash: e53695d6669245c7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tab: direction" -#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place dormer on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.tools.distribution.distributionRunTool.tabDirection" -msgstr "Tab:方向" +msgid "editor.toolHint.placeDormerOnRoof.1w518a6" +msgstr "在屋顶上放置老虎窗" +# Source-Hash: c581645f2ee447c2 # Review: required -# Source-Hash: abb1d8c8bfb41acf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "type a length" -#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place elevator" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.tools.distribution.distributionRunTool.typeALength" -msgstr "输入长度" +msgid "editor.toolHint.placeElevator.1f65zva" +msgstr "放置电梯" -# Source-Hash: 9fc7a39bc32f287a +# Source-Hash: 096b8d6482717358 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Plugins" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place eyebrow vent on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.plugins" -msgstr "插件" +msgid "editor.toolHint.placeEyebrowVentOnRoof.1h1tqxn" +msgstr "在屋顶上放置眉形通风口" -# Source-Hash: c54f9bac358893d8 +# Source-Hash: e8d42c1c8370773f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "2D" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place fitting" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.view2d" -msgstr "2D" +msgid "editor.toolHint.placeFitting.1pmx3vn" +msgstr "放置管件" -# Source-Hash: f78f2fa035f25f85 +# Source-Hash: 2340a4b70cb0d9ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "3D" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place gutter on roof eave" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.view3d" -msgstr "3D" +msgid "editor.toolHint.placeGutterOnRoofEave.llwzf9" +msgstr "在屋檐上放置檐沟" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: 706a8eafb6212833 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place item" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.auto" -msgstr "自动" +msgid "editor.toolHint.placeItem.teynf" +msgstr "放置物品" -# Source-Hash: 7890c110650ad1e5 +# Source-Hash: 1815c482e249932e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Browse plugins" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place it (locked to 45°)" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.browsePlugins" -msgstr "浏览插件" +msgid "editor.toolHint.placeItLockedTo45.16e4csk" +msgstr "放置(锁定为 45°)" -# Source-Hash: 3b11e7af681a9dcd +# Source-Hash: 4a14340657532838 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close {label}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place measurement point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.closeLabel" -msgstr "关闭{label}" +msgid "editor.toolHint.placeMeasurementPoint.bsatli" +msgstr "放置测量点" -# Source-Hash: 3f00e92517e3f4a5 +# Source-Hash: b3be684ac62fbf53 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close split (\\)" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.closeSplit" -msgstr "关闭分屏 (\\)" +msgid "editor.toolHint.placement.13lcvts" +msgstr "放置" -# Source-Hash: 94cc8e9f1ee16edb +# Source-Hash: 2bb2ce6276c69b1e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement: Auto" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.ground" -msgstr "地面" +msgid "editor.toolHint.placementAuto.1caa52d" +msgstr "放置:自动" -# Source-Hash: 0d472502a4d36e86 +# Source-Hash: ed78ac5354a1dcd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{standing, select, partly {Partly below grade · ground solid} below {Below grade · ground solid} other {Ground solid}}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement: Ground" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.groundSolid" -msgstr "{standing, select, partly {部分位于地坪以下 · 地面实体} below {位于地坪以下 · 地面实体} other {地面实体}}" +msgid "editor.toolHint.placementGround.1ruz145" +msgstr "放置:地面" -# Source-Hash: 1b6798c307ac1b96 +# Source-Hash: a066a2c9d5e65a1a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{standing, select, partly {Partly below grade · ground veiled} below {Below grade · ground veiled} other {Ground veiled}}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement: Roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.groundVeiled" -msgstr "{standing, select, partly {部分位于地坪以下 · 地面淡化} below {位于地坪以下 · 地面淡化} other {地面淡化}}" +msgid "editor.toolHint.placementRoof.renkw8" +msgstr "放置:屋顶" -# Source-Hash: ebdc976a98e82626 +# Source-Hash: 8f74dbe5064c4c66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Keep the ground solid" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement surface - click or press P to cycle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.keepTheGroundSolid" -msgstr "保持地面为实体" +msgid "editor.toolHint.placementSurfaceClickOrPressP.w56h19" +msgstr "放置面 - 点击或按 P 切换" -# Source-Hash: 5f827686a006d88c +# Source-Hash: fe119955c925feaf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "More views" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement type" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.moreViews" -msgstr "更多视图" +msgid "editor.toolHint.placementType.1mdpl60" +msgstr "放置类型" -# Source-Hash: f175bbcf457ab73c +# Source-Hash: 33043a35500168f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pane {pane} views" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement type — click or press I to toggle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.paneViews" -msgstr "窗格 {pane} 视图" +msgid "editor.toolHint.placementTypeClickOrPressI.10cgxh2" +msgstr "放置类型 — 点击或按 I 切换" -# Source-Hash: 33c20cc33dce9a9b +# Source-Hash: 9945f412e6a9a446 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pin {label}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place on a fence" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.pinLabel" -msgstr "固定{label}" +msgid "editor.toolHint.placeOnAFence.1dptstr" +msgstr "放置在围栏上" -# Source-Hash: 3f7231b1eb2f93f3 +# Source-Hash: 6708118775a7da7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pin to the view bar" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place register" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.pinToTheViewBar" -msgstr "固定到视图栏" +msgid "editor.toolHint.placeRegister.1uebycd" +msgstr "放置风口" -# Source-Hash: ef3e765e692faf4c +# Source-Hash: ebd2731f5c79306e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place ridge vent on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.solid" -msgstr "实体" +msgid "editor.toolHint.placeRidgeVentOnRoof.2tpd8r" +msgstr "在屋顶上放置屋脊通风口" -# Source-Hash: 98f22f3f89f17686 +# Source-Hash: 9b3c66a867c23326 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Split (\\)" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place shelf" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.split" -msgstr "分屏 (\\)" +msgid "editor.toolHint.placeShelf.y4l3iw" +msgstr "放置置物架" -# Source-Hash: e4cd64b1680ac0d2 +# Source-Hash: f11cf5c1c9fe862d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Split" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place skylight on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.split2" -msgstr "分屏" +msgid "editor.toolHint.placeSkylightOnRoof.e215pe" +msgstr "在屋顶上放置天窗" -# Source-Hash: 15b0adc705923a27 +# Source-Hash: e989a58d6709cc16 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swap panes" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place solar panel array on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.swapPanes" -msgstr "交换窗格" +msgid "editor.toolHint.placeSolarPanelArrayOnRoof.kk11fn" +msgstr "在屋顶上放置光伏板阵列" -# Source-Hash: 9781bcdb7a8549e2 +# Source-Hash: b67f7036d5180cf5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unpin from the view bar" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place spawn point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.unpinFromTheViewBar" -msgstr "从视图栏取消固定" +msgid "editor.toolHint.placeSpawnPoint.205o25" +msgstr "放置出生点" -# Source-Hash: f667358dec4abdea +# Source-Hash: 6c7f32a17e5636c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unpin {label}" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place stairs" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.unpinLabel" -msgstr "取消固定{label}" +msgid "editor.toolHint.placeStairs.zwxxu2" +msgstr "放置楼梯" -# Source-Hash: e96581f0bbf9fa91 +# Source-Hash: 641c0d3debd798a8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Veil the ground over a level below grade" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place trap" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.veilTheGroundOverALevel" -msgstr "在地坪以下的楼层上方淡化地面" +msgid "editor.toolHint.placeTrap.1gxemn3" +msgstr "放置存水弯" -# Source-Hash: fb82f09f8ed3059e +# Source-Hash: 6f0a6f6c4b7588a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Views" -#: packages/editor/src/components/editor/views/view-bar.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place turbine vent on roof" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.views.viewBar.views" -msgstr "视图" +msgid "editor.toolHint.placeTurbineVentOnRoof.1iqeluf" +msgstr "在屋顶上放置涡轮通风器" -# Source-Hash: fdece5c2158dfe88 +# Source-Hash: e65cf5edb4f51ed5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "You can retry the scene or return home without reloading the whole app shell." -#: packages/editor/src/components/editor/index.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place unit" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "editor.youCanRetryTheSceneOr" -msgstr "您可以重试场景,或在不重新加载整个应用的情况下返回首页。" +msgid "editor.toolHint.placeUnit.8zkx4q" +msgstr "放置设备" -# Source-Hash: a273dacdf51b26f2 +# Source-Hash: 86ce1c730154f68b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A topology-backed solid edited directly in the canvas." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place window on wall" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.block.description" -msgstr "基于拓扑、可直接在画布中编辑的实体。" +msgid "editor.toolHint.placeWindowOnWall.1k3qnfb" +msgstr "在墙体上放置窗" -# Source-Hash: 279f456ebb2f5da0 +# Source-Hash: 2b612180a7617901 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Block" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place without the corner snap" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.block.label" -msgstr "体块" +msgid "editor.toolHint.placeWithoutTheCornerSnap.1nifqew" +msgstr "不使用转角吸附放置" -# Source-Hash: b2a371b4041b5e38 +# Source-Hash: dd2ea442152dca5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Small louvered exhaust vent that sits on a roof slope." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Point inside a room, porch or deck" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.description" -msgstr "位于屋面坡上的小型百叶排气口。" +msgid "editor.toolHint.pointInsideARoomPorchOr.58w64l" +msgstr "指向房间、门廊或平台内部" -# Source-Hash: f736ca24e84825c3 +# Source-Hash: 0dc6d121791696f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box Vent" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove last point" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.label" -msgstr "箱式通风口" +msgid "editor.toolHint.removeLastPoint.2dmdcx" +msgstr "移除最后一个点" +# Source-Hash: 8b74b1d962be10fc # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove last witness" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.actions" -msgstr "操作" +msgid "editor.toolHint.removeLastWitness.1b6vvzw" +msgstr "移除最后一个参照" +# Source-Hash: 1185bd2407dd9172 # Review: required -# Source-Hash: c0e9837e67038e92 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base Flange" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge direction" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.baseFlange" -msgstr "底座法兰" +msgid "editor.toolHint.ridgeDirection.5m1369" +msgstr "屋脊方向" +# Source-Hash: 4352028e50450055 # Review: required -# Source-Hash: fa9118f6f4f020d7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base Height" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge direction - click or press R to turn it 90°" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.baseHeight" -msgstr "底座高度" +msgid "editor.toolHint.ridgeDirectionClickOrPressR.1t14dyk" +msgstr "屋脊方向 - 点击或按 R 旋转 90°" +# Source-Hash: 96c889f047db9de5 # Review: required -# Source-Hash: 0869f5a92dabb4e1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base Inset" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge: Long side" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.baseInset" -msgstr "底座内缩" +msgid "editor.toolHint.ridgeLongSide.ew0euv" +msgstr "屋脊:长边" +# Source-Hash: 58143198d3f2a265 # Review: required -# Source-Hash: e9a89a5e4ac8cd61 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge: Short side" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.box" -msgstr "盒形" +msgid "editor.toolHint.ridgeShortSide.gye8pb" +msgstr "屋脊:短边" +# Source-Hash: 306d409f8a1cf480 # Review: required -# Source-Hash: f736ca24e84825c3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box Vent" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.boxVent" -msgstr "箱式通风口" +msgid "editor.toolHint.rotate.1thqa0a" +msgstr "旋转" +# Source-Hash: 8a665ecaeffa9308 # Review: required -# Source-Hash: d52b53241789ee63 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ±45°" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.cap" -msgstr "顶盖" +msgid "editor.toolHint.rotate45.9zq68u" +msgstr "旋转 ±45°" +# Source-Hash: be2240289aa74df5 # Review: required -# Source-Hash: 0ce3b53766b550e7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap Height" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ±45° (floor / ceiling)" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.capHeight" -msgstr "顶盖高度" +msgid "editor.toolHint.rotate45FloorCeiling.m9t57d" +msgstr "旋转 ±45°(地面 / 天花板)" +# Source-Hash: d5fb78b07c0f8138 # Review: required -# Source-Hash: 89eba9f077fba348 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner Bevel" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate ghost ±15°" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.cornerBevel" -msgstr "转角倒角" +msgid "editor.toolHint.rotateGhost15.rsa52c" +msgstr "旋转预览 ±15°" +# Source-Hash: 912d340cd16e27fa # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate or flip the run side" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.delete" -msgstr "删除" +msgid "editor.toolHint.rotateOrFlipTheRunSide.t5ior7" +msgstr "旋转或翻转排布方向" +# Source-Hash: fa24651e9e5f595a # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotate spawn point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.depth" -msgstr "深度" +msgid "editor.toolHint.rotateSpawnPoint.1opcuu7" +msgstr "旋转出生点" +# Source-Hash: 2d693d87fe9b59e6 # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round / rectangular / oval" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.dimensions" -msgstr "尺寸" +msgid "editor.toolHint.roundRectangularOval.e4nh6x" +msgstr "圆形 / 矩形 / 椭圆" +# Source-Hash: ee4ca2612f1ea085 # Review: required -# Source-Hash: de47e23eb81efe02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dome" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set beam start / end; the next beam starts there" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.dome" -msgstr "穹顶" +msgid "editor.toolHint.setBeamStartEndTheNext.di3bzj" +msgstr "设置梁的起点 / 终点;下一根梁从该处开始" +# Source-Hash: f7d2c9cdcc637c97 # Review: required -# Source-Hash: 1c5c81aa21193d07 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dome Curvature" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set fence start / end" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.domeCurvature" -msgstr "穹顶曲率" +msgid "editor.toolHint.setFenceStartEnd.1phbwsq" +msgstr "设置围栏起点 / 终点" +# Source-Hash: c93ae898b4d59f6f # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set one corner, then the opposite" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.duplicate" -msgstr "复制" +msgid "editor.toolHint.setOneCornerThenTheOpposite.8tsl49" +msgstr "设置一个角,再设置对角" +# Source-Hash: 4f55171f10c6ceeb # Review: required -# Source-Hash: 8cac057f7ae6804d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap Height" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set roof footprint" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.gapHeight" -msgstr "缝隙高度" +msgid "editor.toolHint.setRoofFootprint.p50n0o" +msgstr "设置屋顶轮廓" +# Source-Hash: 0243859b1d64c21e # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set wall start / end" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.height" -msgstr "高度" +msgid "editor.toolHint.setWallStartEnd.1r8ubcx" +msgstr "设置墙体起点 / 终点" +# Source-Hash: c2806cce9612fa50 # Review: required -# Source-Hash: 8a9c2ea0783a0e53 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hood Overhang" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slope / level" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.hoodOverhang" -msgstr "罩檐悬挑" +msgid "editor.toolHint.slopeLevel.ftqp67" +msgstr "坡度 / 水平" +# Source-Hash: 06c0ec40606db679 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snap onto the run" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.move" -msgstr "移动" +msgid "editor.toolHint.snapOntoTheRun.86yhmp" +msgstr "吸附到管段上" +# Source-Hash: e214cccbac9c4fd2 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/box-vent/panel.tsx -#, fuzzy -msgid "node.boxVent.panel.position" -msgstr "位置" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Split at the marks" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "editor.toolHint.splitAtTheMarks.x5tpdd" +msgstr "在标记处分割" +# Source-Hash: 94455c35bfeac6b4 # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start grid axis" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.rotation" -msgstr "旋转" +msgid "editor.toolHint.startGridAxis.k92yza" +msgstr "开始轴线" +# Source-Hash: 2edb4c29bbe7c513 # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start lineset" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.style" -msgstr "样式" +msgid "editor.toolHint.startLineset.23q8dh" +msgstr "开始冷媒管组" +# Source-Hash: 9e50f1b30e325208 # Review: required -# Source-Hash: 71d82d47e11d2564 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Taper" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start liquid line" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.topTaper" -msgstr "顶部收分" +msgid "editor.toolHint.startLiquidLine.1rlxsgd" +msgstr "开始液管" +# Source-Hash: 877ddcb778c211cc # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/box-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start run" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.boxVent.panel.width" -msgstr "宽度" +msgid "editor.toolHint.startRun.r6fc5u" +msgstr "开始管段" -# Source-Hash: f49d8836ae037dde +# Source-Hash: 8a62bee64174bbc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A building container holding one or more levels." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start segment" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.building.description" -msgstr "包含一个或多个楼层的建筑容器。" +msgid "editor.toolHint.startSegment.rolym6" +msgstr "开始分段" -# Source-Hash: d42f7d29e3fc4af7 +# Source-Hash: 6cc5dc51a8e66779 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Building" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Step back or cancel" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.building.label" -msgstr "建筑" +msgid "editor.toolHint.stepBackOrCancel.zbfdkn" +msgstr "后退一步或取消" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: 5a8274cbe3034558 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Baskets" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.baskets" -msgstr "拉篮" +msgid "editor.toolHint.style.nf3vcm" +msgstr "样式" +# Source-Hash: 81f595b1c47c0080 # Review: required -# Source-Hash: b3a163b453896bef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Barn" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.bottom" -msgstr "底部" +msgid "editor.toolHint.styleBarn.k9n1x" +msgstr "样式:谷仓门" +# Source-Hash: 3a82c718fe215273 # Review: required -# Source-Hash: 486501f027037732 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Freezer" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Casement" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.bottomFreezer" -msgstr "下置冷冻" +msgid "editor.toolHint.styleCasement.ziklec" +msgstr "样式:平开" +# Source-Hash: 072e3331d1d105c0 # Review: required -# Source-Hash: 375acc0016b3aa14 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bowls" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Craftsman" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.bowls" -msgstr "水槽" +msgid "editor.toolHint.styleCraftsman.52e6a9" +msgstr "样式:工匠" +# Source-Hash: b64d07557dec1714 # Review: required -# Source-Hash: 8449b59bf054c27d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Burners on" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Double-hung" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.burnersOn" -msgstr "点火" +msgid "editor.toolHint.styleDoubleHung.1lg8pkg" +msgstr "样式:双悬" +# Source-Hash: 55ef8761a537637f # Review: required -# Source-Hash: 95169058fec6db14 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Chimney" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: French" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.chimney" -msgstr "烟囱" +msgid "editor.toolHint.styleFrench.1ue3j64" +msgstr "样式:法式" +# Source-Hash: bc8a751d87536dc3 # Review: required -# Source-Hash: a6b76187db231ae7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Decrease {label}" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Glass" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.decrease" -msgstr "减少{label}" +msgid "editor.toolHint.styleGlass.qudnb4" +msgstr "样式:玻璃" +# Source-Hash: 40c1eb0bc83e207d # Review: required -# Source-Hash: 787e10f5db16904e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Grid" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.door" -msgstr "门" +msgid "editor.toolHint.styleGrid.1vuq4po" +msgstr "样式:格栅" +# Source-Hash: f516886bab2e7f10 # Review: required -# Source-Hash: 3cd71355956a1821 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Half-louvered" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.double" -msgstr "双扇" +msgid "editor.toolHint.styleHalfLouvered.13b1few" +msgstr "样式:半百叶" +# Source-Hash: 64e4389a695371a2 # Review: required -# Source-Hash: 63fe49d73892aac8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawer" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Horizontal bands" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.drawer" -msgstr "抽屉" +msgid "editor.toolHint.styleHorizontalBands.12ethxk" +msgstr "样式:横向条纹" +# Source-Hash: ff6d226a425b00c0 # Review: required -# Source-Hash: f98242a5dacd33f3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawers" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Modern" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.drawers" -msgstr "抽屉" +msgid "editor.toolHint.styleModern.1fh8hhn" +msgstr "样式:现代" +# Source-Hash: c6d17ba078ff47e7 # Review: required -# Source-Hash: 3af5347c94ae6443 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip hinge" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Panel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.flipHinge" -msgstr "翻转铰链" +msgid "editor.toolHint.stylePanel.922jze" +msgstr "样式:镶板" +# Source-Hash: 5e6baad0d2ce3a62 # Review: required -# Source-Hash: c930f681e61c029c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip the door hinge to the opposite side" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Paneled glass" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.flipTheDoorHingeToThe" -msgstr "将门铰链翻转到另一侧" +msgid "editor.toolHint.stylePaneledGlass.17a17en" +msgstr "样式:镶板玻璃" +# Source-Hash: 6314388e6832c252 # Review: required -# Source-Hash: 85724031c91952a3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fridge" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Shaker" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.fridge" -msgstr "冰箱" +msgid "editor.toolHint.styleShaker.49z17k" +msgstr "样式:震颤派" +# Source-Hash: a0f8e524f3ca121f # Review: required -# Source-Hash: e67f11024d683ea9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gas" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Single" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.gas" -msgstr "燃气" +msgid "editor.toolHint.styleSingle.6f3cm0" +msgstr "样式:单扇" +# Source-Hash: 368279df3a472c86 # Review: required -# Source-Hash: 8ab91094cf650204 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Six-panel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.glass" -msgstr "玻璃" +msgid "editor.toolHint.styleSixPanel.u49laj" +msgstr "样式:六镶板" +# Source-Hash: 8f3c2571d8168fee # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Sliding" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.height" -msgstr "高度" +msgid "editor.toolHint.styleSliding.q81s0i" +msgstr "样式:推拉" +# Source-Hash: aa9d9eb137ca38d4 # Review: required -# Source-Hash: 6f434b84c8b59b8c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hob" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Tall grid" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.hob" -msgstr "灶台" +msgid "editor.toolHint.styleTallGrid.1eotg3x" +msgstr "样式:高格栅" +# Source-Hash: bc164648722b63e5 # Review: required -# Source-Hash: d52570d41b4df776 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Increase {label}" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Transom" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.increase" -msgstr "增加{label}" +msgid "editor.toolHint.styleTransom.kb9bh6" +msgstr "样式:带亮子" +# Source-Hash: 9a218f0c9ceb4697 # Review: required -# Source-Hash: d298f259163e868e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Induction" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Triple-hung" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.induction" -msgstr "电磁" +msgid "editor.toolHint.styleTripleHung.pxnqi3" +msgstr "样式:三悬" +# Source-Hash: 9f6df1344bd3d694 # Review: required -# Source-Hash: 54800340a0eeab23 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Layout" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style: Wide grid" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.layout" -msgstr "布局" +msgid "editor.toolHint.styleWideGrid.12n27et" +msgstr "样式:宽格栅" +# Source-Hash: 711d4050c0cb95d7 # Review: required -# Source-Hash: f365c6b6dd9ebab9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Switch rotation axis (Y → X → Z)" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.left" -msgstr "左" +msgid "editor.toolHint.switchRotationAxisYXZ.15lohm6" +msgstr "切换旋转轴(Y → X → Z)" +# Source-Hash: d650c71e042c2598 # Review: required -# Source-Hash: 12ade82be3830a0b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Micro" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The walls meet at too sharp or too flat an angle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.micro" -msgstr "微波炉" +msgid "editor.toolHint.theWallsMeetAtTooSharp.kh3wi3" +msgstr "墙体相交的角度过尖或过平" +# Source-Hash: ab206ac56e65f190 # Review: required -# Source-Hash: a06a50e63f0c240e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move down" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The window waiting there is taller than this wall" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.moveDown" -msgstr "下移" +msgid "editor.toolHint.theWindowWaitingThereIsTaller.1tqwez4" +msgstr "该处待放置的窗比这面墙体更高" +# Source-Hash: 9c1f47138ed5c7ee # Review: required -# Source-Hash: d49ea60a2312df2f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move up" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Three or more walls meet here" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.moveUp" -msgstr "上移" +msgid "editor.toolHint.threeOrMoreWallsMeetHere.rgifif" +msgstr "此处有三面或更多墙体相交" +# Source-Hash: c3ca56fa28e15f07 # Review: required -# Source-Hash: 596023c8b9a8f2e4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Oven" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trace ceiling outline" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.oven" -msgstr "烤箱" +msgid "editor.toolHint.traceCeilingOutline.1b639wv" +msgstr "描绘天花板轮廓" +# Source-Hash: bdf71499d30a29de # Review: required -# Source-Hash: 83b20797fb0a01a0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pullout" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trace slab outline" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.pullout" -msgstr "拉出式" +msgid "editor.toolHint.traceSlabOutline.z0j2lc" +msgstr "描绘楼板轮廓" +# Source-Hash: c44f7ab8bbd24858 # Review: required -# Source-Hash: 43c251f465b647ce -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rack" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.rack" -msgstr "置物架" +msgid "editor.toolHint.type.1m2zofh" +msgstr "类型" +# Source-Hash: b54eaaff3349dcb1 # Review: required -# Source-Hash: 3c2b3026d37cbcc2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove compartment" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Awning" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.removeCompartment" -msgstr "移除隔间" +msgid "editor.toolHint.typeAwning.1cj59al" +msgstr "类型:上悬" +# Source-Hash: f399572a27417c66 # Review: required -# Source-Hash: b34d5ee0f218221d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Barn" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.right" -msgstr "右" +msgid "editor.toolHint.typeBarn.sbnygq" +msgstr "类型:谷仓门" +# Source-Hash: a1df9782200b5f1e # Review: required -# Source-Hash: d7145f84f8e0e3fe -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shelf" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Bay" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.shelf" -msgstr "置物架" +msgid "editor.toolHint.typeBay.1200hc1" +msgstr "类型:凸窗" +# Source-Hash: ff069a390e8e3f66 # Review: required -# Source-Hash: 5fbb88f1f079b6db -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shelves" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Bow" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.shelves" -msgstr "层板" +msgid "editor.toolHint.typeBow.14s2t9p" +msgstr "类型:弧形凸窗" +# Source-Hash: bdac5f3f2ea70fff # Review: required -# Source-Hash: 47173085127029f0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shelves inside" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Cabinet" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.shelvesInside" -msgstr "内部层板" +msgid "editor.toolHint.typeCabinet.1r68je5" +msgstr "类型:柜门" +# Source-Hash: e0754fc03997cbf9 # Review: required -# Source-Hash: 62ab2eb3c775da95 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Casement" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.single" -msgstr "单扇" +msgid "editor.toolHint.typeCasement.176uo9j" +msgstr "类型:平开" +# Source-Hash: 47d873446d6e173b # Review: required -# Source-Hash: 522a7535fc93fb4f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sink" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Double" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.sink" -msgstr "水槽" +msgid "editor.toolHint.typeDouble.af7w4i" +msgstr "类型:双扇" +# Source-Hash: 5942e484513aaab5 # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Double Hung" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.style" -msgstr "样式" +msgid "editor.toolHint.typeDoubleHung.t482fu" +msgstr "类型:双悬" +# Source-Hash: f9497fbfceefda27 # Review: required -# Source-Hash: 78a454b7ac7a3cd9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Fixed" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.surface" -msgstr "表面" +msgid "editor.toolHint.typeFixed.v1cjez" +msgstr "类型:固定" +# Source-Hash: 0dcf07acc9cbf000 # Review: required -# Source-Hash: 27644f0497fd9849 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Folding" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.top" -msgstr "顶部" +msgid "editor.toolHint.typeFolding.sxxyng" +msgstr "类型:折叠" +# Source-Hash: bff7331f87f279aa # Review: required -# Source-Hash: eaadfd2d19b27d87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Freezer" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: French" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.topFreezer" -msgstr "上置冷冻" +msgid "editor.toolHint.typeFrench.1y57z1b" +msgstr "类型:法式" +# Source-Hash: 9d2c3b82079eb769 # Review: required -# Source-Hash: 04f3a3462ef5d247 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top grate" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Hinged" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.topGrate" -msgstr "顶部炉架" +msgid "editor.toolHint.typeHinged.1xrcfju" +msgstr "类型:铰链" +# Source-Hash: b8001b90ff522838 # Review: required -# Source-Hash: 4a616e1d2ca55bd5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tray" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Island" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.tray" -msgstr "托盘" +msgid "editor.toolHint.typeIsland.ufr3ce" +msgstr "类型:岛台" +# Source-Hash: 516833c5160d412e # Review: required -# Source-Hash: c44f7ab8bbd24858 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Louvered" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.type" -msgstr "类型" +msgid "editor.toolHint.typeLouvered.oxl1cz" +msgstr "类型:百叶" +# Source-Hash: 291272bf848ad6ab # Review: required -# Source-Hash: 6c4de540d19316ab -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Washer" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Pocket" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.washer" -msgstr "洗碗机" +msgid "editor.toolHint.typePocket.hc65x9" +msgstr "类型:内嵌推拉" +# Source-Hash: 46d0e53d6ae07c72 # Review: required -# Source-Hash: 5211a0caf3518125 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wire" -#: packages/nodes/src/cabinet/compartment-card.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Single Hung" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.compartmentCard.wire" -msgstr "金属丝" +msgid "editor.toolHint.typeSingleHung.p53pyl" +msgstr "类型:单悬" -# Source-Hash: 693a0d8896f5cc43 +# Source-Hash: b11115b50df8faac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A configurable parametric base cabinet." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type: Sliding" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.description" -msgstr "可配置的参数化地柜。" +msgid "editor.toolHint.typeSliding.nwmr3f" +msgstr "类型:推拉" +# Source-Hash: bff0c1694ee0a37e # Review: required -# Source-Hash: b0568ea943addd5b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom freezer" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical stack ↕, click to place" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.essentialControls.bottomFreezer" -msgstr "下置冷冻" +msgid "editor.toolHint.verticalStackClickToPlace.ijcn4q" +msgstr "竖向立管 ↕,点击放置" +# Source-Hash: bac471ee67af6412 # Review: required -# Source-Hash: da78819903ae0863 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cooktop type" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waste / vent" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.essentialControls.cooktopType" -msgstr "灶台类型" +msgid "editor.toolHint.wasteVent.1hvi3vj" +msgstr "污水 / 通气" +# Source-Hash: 1c744b7e24fc786e # Review: required -# Source-Hash: c608188f58ed1cfc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door direction" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Window style — click or press L to cycle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.essentialControls.doorDirection" -msgstr "开门方向" +msgid "editor.toolHint.windowStyleClickOrPressL.ah7qm9" +msgstr "窗样式 — 点击或按 L 切换" +# Source-Hash: dd6f0ab314fea26c # Review: required -# Source-Hash: 3cd71355956a1821 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Window type — click or press O to cycle" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.essentialControls.double" -msgstr "双扇" +msgid "editor.toolHint.windowTypeClickOrPressO.wv4x35" +msgstr "窗类型 — 点击或按 O 切换" +# Source-Hash: a48c4b2e4d71b08d # Review: required -# Source-Hash: f7fb8f6393cc4cfc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fridge type" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length: {field} m" +#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx #, fuzzy -msgid "node.cabinet.essentialControls.fridgeType" -msgstr "冰箱类型" +msgid "editor.tools.distribution.distributionRunTool.lengthField" +msgstr "长度:{field} m" +# Source-Hash: e53695d6669245c7 # Review: required -# Source-Hash: e67f11024d683ea9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gas" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tab: direction" +#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx #, fuzzy -msgid "node.cabinet.essentialControls.gas" -msgstr "燃气" +msgid "editor.tools.distribution.distributionRunTool.tabDirection" +msgstr "Tab:方向" +# Source-Hash: abb1d8c8bfb41acf # Review: required -# Source-Hash: 8ab91094cf650204 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "type a length" +#: packages/editor/src/components/tools/distribution/distribution-run-tool.tsx #, fuzzy -msgid "node.cabinet.essentialControls.glass" -msgstr "玻璃" +msgid "editor.tools.distribution.distributionRunTool.typeALength" +msgstr "输入长度" +# Source-Hash: 9fc7a39bc32f287a # Review: required -# Source-Hash: d298f259163e868e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Induction" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plugins" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.essentialControls.induction" -msgstr "电磁" +msgid "editor.views.plugins" +msgstr "插件" +# Source-Hash: c54f9bac358893d8 # Review: required -# Source-Hash: 76df477d42cec629 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Item options" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "2D" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.essentialControls.itemOptions" -msgstr "物品选项" +msgid "editor.views.view2d" +msgstr "2D" +# Source-Hash: f78f2fa035f25f85 # Review: required -# Source-Hash: bca1b184af1c0c4b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left hinge" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "3D" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.essentialControls.leftHinge" -msgstr "左铰链" +msgid "editor.views.view3d" +msgstr "3D" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: e32da7429c85f1a5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right hinge" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.essentialControls.rightHinge" -msgstr "右铰链" +msgid "editor.views.viewBar.auto" +msgstr "自动" +# Source-Hash: 7890c110650ad1e5 # Review: required -# Source-Hash: 62ab2eb3c775da95 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Browse plugins" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.essentialControls.single" -msgstr "单扇" +msgid "editor.views.viewBar.browsePlugins" +msgstr "浏览插件" +# Source-Hash: 3b11e7af681a9dcd # Review: required -# Source-Hash: 4bc3042055df1e85 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sink layout" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close {label}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.essentialControls.sinkLayout" -msgstr "水槽布局" +msgid "editor.views.viewBar.closeLabel" +msgstr "关闭{label}" +# Source-Hash: 3f00e92517e3f4a5 # Review: required -# Source-Hash: 29cffe75281dbea6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top freezer" -#: packages/nodes/src/cabinet/essential-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close split (\\)" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.essentialControls.topFreezer" -msgstr "上置冷冻" +msgid "editor.views.viewBar.closeSplit" +msgstr "关闭分屏 (\\)" +# Source-Hash: 94cc8e9f1ee16edb # Review: required -# Source-Hash: 09c2cb2ea7b1be3c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose {label}" -#: packages/nodes/src/cabinet/kitchen-collection.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenCollection.chooseLabel" -msgstr "选择{label}" +msgid "editor.views.viewBar.ground" +msgstr "地面" +# Source-Hash: 0d472502a4d36e86 # Review: required -# Source-Hash: 1dd2cac6488ddc30 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No kitchen items match. Try “fridge”, “sink”, or “cabinet”." -#: packages/nodes/src/cabinet/kitchen-collection.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{standing, select, partly {Partly below grade · ground solid} below {Below grade · ground solid} other {Ground solid}}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenCollection.noKitchenItemsMatchTryFridge" -msgstr "没有匹配的厨房物品。试试“冰箱”“水槽”或“橱柜”。" +msgid "editor.views.viewBar.groundSolid" +msgstr "{standing, select, partly {部分位于地坪以下 · 地面实体} below {位于地坪以下 · 地面实体} other {地面实体}}" +# Source-Hash: 1b6798c307ac1b96 # Review: required -# Source-Hash: 6752675ca6280ddd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Search fridge, sink, cabinets…" -#: packages/nodes/src/cabinet/kitchen-collection.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{standing, select, partly {Partly below grade · ground veiled} below {Below grade · ground veiled} other {Ground veiled}}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenCollection.searchFridgeSinkCabinets" -msgstr "搜索冰箱、水槽、橱柜…" +msgid "editor.views.viewBar.groundVeiled" +msgstr "{standing, select, partly {部分位于地坪以下 · 地面淡化} below {位于地坪以下 · 地面淡化} other {地面淡化}}" +# Source-Hash: ebdc976a98e82626 # Review: required -# Source-Hash: fe3c6d57a07c323d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Search kitchen items" -#: packages/nodes/src/cabinet/kitchen-collection.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keep the ground solid" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenCollection.searchKitchenItems" -msgstr "搜索厨房物品" +msgid "editor.views.viewBar.keepTheGroundSolid" +msgstr "保持地面为实体" +# Source-Hash: 5f827686a006d88c # Review: required -# Source-Hash: d44a46146db2e44c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Appliances & fixtures" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "More views" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenGroup.appliances" -msgstr "电器与设施" +msgid "editor.views.viewBar.moreViews" +msgstr "更多视图" +# Source-Hash: f175bbcf457ab73c # Review: required -# Source-Hash: d4d3ad7c099b6513 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinets" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pane {pane} views" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenGroup.cabinets" -msgstr "橱柜" +msgid "editor.views.viewBar.paneViews" +msgstr "窗格 {pane} 视图" +# Source-Hash: 33c20cc33dce9a9b # Review: required -# Source-Hash: 465db52f98c2d94f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add beside" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pin {label}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.addBeside" -msgstr "在旁边添加" +msgid "editor.views.viewBar.pinLabel" +msgstr "固定{label}" +# Source-Hash: 3f7231b1eb2f93f3 # Review: required -# Source-Hash: 9733e2ad85deb6d5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add beside selected item" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pin to the view bar" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.addBesideSelectedItem" -msgstr "在所选物品旁添加" +msgid "editor.views.viewBar.pinToTheViewBar" +msgstr "固定到视图栏" +# Source-Hash: ef3e765e692faf4c # Review: required -# Source-Hash: 4b2f676fb4c9ec63 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add {label}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.addLabel" -msgstr "添加{label}" +msgid "editor.views.viewBar.solid" +msgstr "实体" +# Source-Hash: 98f22f3f89f17686 # Review: required -# Source-Hash: 5122b8e9b4ec6a00 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "An upper cabinet attached to this item will be removed to make room." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Split (\\)" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.anUpperCabinetAttachedToThis" -msgstr "附着在此物品上的吊柜将被移除以腾出空间。" +msgid "editor.views.viewBar.split" +msgstr "分屏 (\\)" +# Source-Hash: e4cd64b1680ac0d2 # Review: required -# Source-Hash: 5737c4567e0f6863 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Split" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.cabinet" -msgstr "柜体" +msgid "editor.views.viewBar.split2" +msgstr "分屏" +# Source-Hash: 15b0adc705923a27 # Review: required -# Source-Hash: c0774c185060fc13 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cancel" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap panes" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.cancel" -msgstr "取消" +msgid "editor.views.viewBar.swapPanes" +msgstr "交换窗格" +# Source-Hash: 9781bcdb7a8549e2 # Review: required -# Source-Hash: f42912b116015f58 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "This {width} item cannot fit within the current run and its wall or corner limits. Move an end cabinet or free space, then try again." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unpin from the view bar" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.cannotFit" -msgstr "这个 {width} 的物品无法放入当前橱柜组及其墙体或转角限制内。请移动端部橱柜或腾出空间后重试。" +msgid "editor.views.viewBar.unpinFromTheViewBar" +msgstr "从视图栏取消固定" +# Source-Hash: f667358dec4abdea # Review: required -# Source-Hash: b7eeb26a356d03c3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{side, select, left {Inserts on the left of the selected item.} other {Inserts on the right of the selected item.}}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unpin {label}" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.insertsBeside" -msgstr "{side, select, left {插入到所选物品的左侧。} other {插入到所选物品的右侧。}}" +msgid "editor.views.viewBar.unpinLabel" +msgstr "取消固定{label}" +# Source-Hash: e96581f0bbf9fa91 # Review: required -# Source-Hash: f65332177316d11d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The kitchen changed. Select an item again to refresh the preview." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Veil the ground over a level below grade" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.kitchenChanged" -msgstr "厨房已更改。请重新选择物品以刷新预览。" +msgid "editor.views.viewBar.veilTheGroundOverALevel" +msgstr "在地坪以下的楼层上方淡化地面" +# Source-Hash: fb82f09f8ed3059e # Review: required -# Source-Hash: 5b6990b17111fd6b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchen run preview, highlighted item is the proposed change" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Views" +#: packages/editor/src/components/editor/views/view-bar.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.kitchenRunPreviewHighlightedItemIs" -msgstr "厨房橱柜组预览,高亮的物品为拟议更改" +msgid "editor.views.viewBar.views" +msgstr "视图" +# Source-Hash: 57c1428fe2d28745 # Review: required -# Source-Hash: cb59562ba7eb1d25 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left side" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "List the layers from the outside in, around one framing core. The type is saved with the project and applied to this wall; other walls keep their layers." +#: packages/editor/src/components/ui/wall-type/wall-type-editor-dialog.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.leftSide" -msgstr "左侧" +msgid "editor.wallTypeEditorDialog.listTheLayersAppliedToThisWall" +msgstr "围绕一个结构核心,从外到内列出各构造层。该类型随项目保存并应用于此墙,其他墙体保留各自的构造层。" +# Source-Hash: 9e9715d52410c86f # Review: required -# Source-Hash: 766354d53f17d78c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{name}: moves {distance}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.moved" -msgstr "{name}:移动 {distance}" +msgid "editor.wallTypeMenu.custom" +msgstr "自定义" +# Source-Hash: 0e2a2a8b90ba9c7e # Review: required -# Source-Hash: df1083d9ffc2c59d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{name}: {width}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall types: new, edit or duplicate {label}" +#: packages/editor/src/components/ui/wall-type/wall-type-menu.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.previewItem" -msgstr "{name}:{width}" +msgid "editor.wallTypeMenu.wallTypesOf" +msgstr "墙体类型:新建、编辑或复制 {label}" +# Source-Hash: fdece5c2158dfe88 # Review: required -# Source-Hash: ada7fbece9ca9e3c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace selected item" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "You can retry the scene or return home without reloading the whole app shell." +#: packages/editor/src/components/editor/index.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.replaceSelectedItem" -msgstr "替换所选物品" +msgid "editor.youCanRetryTheSceneOr" +msgstr "您可以重试场景,或在不重新加载整个应用的情况下返回首页。" +# Source-Hash: bafa390e07160f3c # Review: required -# Source-Hash: ab8b52d2704537d2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replaces only the selected item." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A framing beam drawn end to end: a porch header, a deck beam, a girder." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.kitchenModuleActions.replacesOnlyTheSelectedItem" -msgstr "仅替换所选物品。" +msgid "node.beam.description" +msgstr "从一端绘制到另一端的框架梁:门廊过梁、平台梁或主梁。" +# Source-Hash: e14858b33b6e2623 # Review: required -# Source-Hash: 03cb6dea6e4a4c5e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace with…" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.kitchenModuleActions.replaceWith" -msgstr "替换为…" +msgid "node.beam.label" +msgstr "梁" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 948fe657641f298c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace with {label}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.replaceWithLabel" -msgstr "替换为{label}" +msgid "node.beam.panel.actions" +msgstr "操作" +# Source-Hash: 59f845b250e0df6f # Review: required -# Source-Hash: 154f9fa86b7670ba -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{name}: {before} → {after}" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add posts" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.resized" -msgstr "{name}:{before} → {after}" +msgid "node.beam.panel.addPosts" +msgstr "添加立柱" +# Source-Hash: e14858b33b6e2623 # Review: required -# Source-Hash: 4ecc493400fb6aa2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right side" -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.rightSide" -msgstr "右侧" +msgid "node.beam.panel.beam" +msgstr "梁" +# Source-Hash: 26e977da636cc882 # Review: required -# Source-Hash: f2c30e7e21cf27e6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unable to update this kitchen." -#: packages/nodes/src/cabinet/kitchen-module-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Beam {size}" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.kitchenModuleActions.unableToUpdateThisKitchen" -msgstr "无法更新此厨房。" +msgid "node.beam.panel.beamSize" +msgstr "梁 {size}" -# Source-Hash: 2e6d8cda361c648d +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Modular Cabinet" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.label" -msgstr "组合橱柜" +msgid "node.beam.panel.delete" +msgstr "删除" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: 740e0a4e4afa78ea -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finished height extends {overflow} mm above the ceiling." -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.aboveCeiling" -msgstr "完成高度超出天花板 {overflow} mm。" +msgid "node.beam.panel.depth" +msgstr "高度" +# Source-Hash: 73694f3f45cf2ee1 # Review: required -# Source-Hash: e3b4d2ed4f6f5efb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add chimney" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dropped" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.addChimney" -msgstr "添加烟罩" +msgid "node.beam.panel.dropped" +msgstr "下挂" +# Source-Hash: eaaa20f3b603140f # Review: required -# Source-Hash: 90bdc92c0a91d060 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add compartment" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flush" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.addCompartment" -msgstr "添加隔间" +msgid "node.beam.panel.flush" +msgstr "齐平" +# Source-Hash: 0ee3edea19fd153e # Review: required -# Source-Hash: ece05d9b6f4b616d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add wall cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow the ceiling plane" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.addWallCabinet" -msgstr "添加吊柜" +msgid "node.beam.panel.followTheCeilingPlane" +msgstr "跟随天花板平面" +# Source-Hash: 193b75ac869c251d # Review: required -# Source-Hash: f571cb2d06ae01ae -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Advanced" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{length} long; its underside {underside} over the floor, the ceiling plane {plane}." +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.advanced" -msgstr "高级" +msgid "node.beam.panel.lengthLongItsUnderside" +msgstr "长 {length};梁底高出楼面 {underside},天花板平面 {plane}。" +# Source-Hash: 964b86ae1474ff98 # Review: required -# Source-Hash: 7f4dcb90defe1ac2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Appliance" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Material" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.appliance" -msgstr "电器" +msgid "node.beam.panel.material" +msgstr "材料" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: bd5e3f533412ff6a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Appliance front" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.applianceFront" -msgstr "电器面板" +msgid "node.beam.panel.move" +msgstr "移动" +# Source-Hash: fa876c632c284d81 # Review: required -# Source-Hash: 05b65242d8c48791 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "1 ply" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.auto" -msgstr "自动" +msgid "node.beam.panel.n1Ply" +msgstr "1 片" +# Source-Hash: b3be684ac62fbf53 # Review: required -# Source-Hash: 9cf3754f15467c50 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Placement" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.bar" -msgstr "拉手条" +msgid "node.beam.panel.placement" +msgstr "位置" +# Source-Hash: 6ac7987d650b9742 # Review: required -# Source-Hash: 133893b177bd05d6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base Cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{plies} plies" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.baseCabinet" -msgstr "地柜" +msgid "node.beam.panel.pliesPlies" +msgstr "{plies} 片" +# Source-Hash: 60bb3338e0ad558c # Review: required -# Source-Hash: d63f16df2c754126 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet construction, compartments, and opening preview." -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Size" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.cabinetConstructionCompartmentsAndOpeningPreview" -msgstr "橱柜构造、隔间和开启预览。" +msgid "node.beam.panel.size" +msgstr "尺寸" +# Source-Hash: 27644f0497fd9849 # Review: required -# Source-Hash: d62dc35dac835228 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet panel" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.cabinetPanel" -msgstr "橱柜面板" +msgid "node.beam.panel.top" +msgstr "顶部" +# Source-Hash: 5b4c960036b3d05b # Review: required -# Source-Hash: 81caf4809d58b5f5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet Type" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top elevation" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.cabinetType" -msgstr "橱柜类型" +msgid "node.beam.panel.topElevation" +msgstr "顶部标高" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: 5211341ed18f33f6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/beam/panel.tsx #, fuzzy -msgid "node.cabinet.panel.center" -msgstr "居中" +msgid "node.beam.panel.width" +msgstr "宽度" +# Source-Hash: a273dacdf51b26f2 # Review: required -# Source-Hash: d7cf5045c01b2eb9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A topology-backed solid edited directly in the canvas." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.panel.close" -msgstr "关闭" +msgid "node.block.description" +msgstr "基于拓扑、可直接在画布中编辑的实体。" +# Source-Hash: 279f456ebb2f5da0 # Review: required -# Source-Hash: cf29134333e47184 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Block" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.panel.closeCabinet" -msgstr "关闭橱柜" +msgid "node.block.label" +msgstr "体块" +# Source-Hash: b2a371b4041b5e38 # Review: required -# Source-Hash: b1ab1ba948bb77b0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Common wall-cabinet heights. Use the slider below for a custom height." -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Small louvered exhaust vent that sits on a roof slope." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.panel.commonWallCabinetHeightsUseThe" -msgstr "常用吊柜高度。如需自定义高度,请使用下方滑块。" +msgid "node.boxVent.description" +msgstr "位于屋面坡上的小型百叶排气口。" +# Source-Hash: f736ca24e84825c3 # Review: required -# Source-Hash: fe9e63d5c5087386 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Compartments" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box Vent" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.panel.compartments" -msgstr "隔间" +msgid "node.boxVent.label" +msgstr "箱式通风口" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 7984b1c42abd9c02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cutout" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.cutout" -msgstr "开槽" +msgid "node.boxVent.panel.actions" +msgstr "操作" +# Source-Hash: c0e9837e67038e92 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base Flange" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.depth" -msgstr "深度" +msgid "node.boxVent.panel.baseFlange" +msgstr "底座法兰" +# Source-Hash: fa9118f6f4f020d7 # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base Height" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.dimensions" -msgstr "尺寸" +msgid "node.boxVent.panel.baseHeight" +msgstr "底座高度" +# Source-Hash: 0869f5a92dabb4e1 # Review: required -# Source-Hash: 82c9ea6f403fc934 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit kitchen run" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base Inset" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.editKitchenRun" -msgstr "编辑厨房橱柜组" +msgid "node.boxVent.panel.baseInset" +msgstr "底座内缩" +# Source-Hash: e9a89a5e4ac8cd61 # Review: required -# Source-Hash: 7e9bbeb035fc73e2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fill to ceiling" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.fillToCeiling" -msgstr "填充至天花板" +msgid "node.boxVent.panel.box" +msgstr "盒形" +# Source-Hash: f736ca24e84825c3 # Review: required -# Source-Hash: b3907da0ad234f10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box Vent" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.finish" -msgstr "完成" +msgid "node.boxVent.panel.boxVent" +msgstr "箱式通风口" +# Source-Hash: d52b53241789ee63 # Review: required -# Source-Hash: c1796152935221ef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front construction" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.frontConstruction" -msgstr "面板构造" +msgid "node.boxVent.panel.cap" +msgstr "顶盖" +# Source-Hash: 0ce3b53766b550e7 # Review: required -# Source-Hash: 58884f99d64e6d00 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handles" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap Height" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.handles" -msgstr "拉手" +msgid "node.boxVent.panel.capHeight" +msgstr "顶盖高度" +# Source-Hash: 89eba9f077fba348 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner Bevel" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.height" -msgstr "高度" +msgid "node.boxVent.panel.cornerBevel" +msgstr "转角倒角" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: d73589d7c04b1121 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height preset" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.heightPreset" -msgstr "预设高度" +msgid "node.boxVent.panel.delete" +msgstr "删除" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: 590bfdd02dcdb857 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hole" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.hole" -msgstr "孔" +msgid "node.boxVent.panel.depth" +msgstr "深度" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: 3db1dea825785a30 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inset" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.inset" -msgstr "内嵌" +msgid "node.boxVent.panel.dimensions" +msgstr "尺寸" +# Source-Hash: de47e23eb81efe02 # Review: required -# Source-Hash: 1176d2568d093bf1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchen" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dome" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.kitchen" -msgstr "厨房" +msgid "node.boxVent.panel.dome" +msgstr "穹顶" +# Source-Hash: 1c5c81aa21193d07 # Review: required -# Source-Hash: a74f10dadc92c8bb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchen run" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dome Curvature" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.kitchenRun" -msgstr "厨房橱柜组" +msgid "node.boxVent.panel.domeCurvature" +msgstr "穹顶曲率" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: 103e15b39c909210 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Knob" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.knob" -msgstr "旋钮拉手" +msgid "node.boxVent.panel.duplicate" +msgstr "复制" +# Source-Hash: 8cac057f7ae6804d # Review: required -# Source-Hash: 81d365ccef73068c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap Height" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.mounting" -msgstr "安装方式" +msgid "node.boxVent.panel.gapHeight" +msgstr "缝隙高度" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: f2953d2931e36d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.none" -msgstr "无" +msgid "node.boxVent.panel.height" +msgstr "高度" +# Source-Hash: 8a9c2ea0783a0e53 # Review: required -# Source-Hash: 3e52f04f92e08070 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hood Overhang" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.open" -msgstr "打开" +msgid "node.boxVent.panel.hoodOverhang" +msgstr "罩檐悬挑" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: b8ecc16c07d66f42 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open Animation" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.openAnimation" -msgstr "开启动画" +msgid "node.boxVent.panel.move" +msgstr "移动" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: 2d4adbbd70c3ae6a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.openCabinet" -msgstr "打开橱柜" +msgid "node.boxVent.panel.position" +msgstr "位置" +# Source-Hash: 01989595ee7c1dc0 # Review: required -# Source-Hash: 9c215dc512e57fa4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overlay" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.overlay" -msgstr "盖门" +msgid "node.boxVent.panel.rotation" +msgstr "旋转" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: a35b7357943a5cae -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel-ready" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.panelReady" -msgstr "可装面板" +msgid "node.boxVent.panel.style" +msgstr "样式" +# Source-Hash: 71d82d47e11d2564 # Review: required -# Source-Hash: 3d0d4eee59177824 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Planning checks" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Taper" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.planningChecks" -msgstr "规划检查" +msgid "node.boxVent.panel.topTaper" +msgstr "顶部收分" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: c7b10382e01914ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Play" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/box-vent/panel.tsx #, fuzzy -msgid "node.cabinet.panel.play" -msgstr "播放" +msgid "node.boxVent.panel.width" +msgstr "宽度" +# Source-Hash: f49d8836ae037dde # Review: required -# Source-Hash: c530f8af9dfd846f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Play animation" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A building container holding one or more levels." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.panel.playAnimation" -msgstr "播放动画" +msgid "node.building.description" +msgstr "包含一个或多个楼层的建筑容器。" +# Source-Hash: d42f7d29e3fc4af7 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Building" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.panel.position" -msgstr "位置" +msgid "node.building.label" +msgstr "建筑" +# Source-Hash: 5a8274cbe3034558 # Review: required -# Source-Hash: efca749fc4463623 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised Arch" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Baskets" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.raisedArch" -msgstr "凸起拱形" +msgid "node.cabinet.compartmentCard.baskets" +msgstr "拉篮" +# Source-Hash: b3a163b453896bef # Review: required -# Source-Hash: a8639a97ab07cd59 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove wall cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.removeWallCabinet" -msgstr "移除吊柜" +msgid "node.cabinet.compartmentCard.bottom" +msgstr "底部" +# Source-Hash: 486501f027037732 # Review: required -# Source-Hash: 03cb6dea6e4a4c5e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Replace with…" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Freezer" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.replaceWith" -msgstr "替换为…" +msgid "node.cabinet.compartmentCard.bottomFreezer" +msgstr "下置冷冻" +# Source-Hash: 375acc0016b3aa14 # Review: required -# Source-Hash: 5d6956c21fde6418 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reveal gap" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bowls" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.revealGap" -msgstr "缝隙" +msgid "node.cabinet.compartmentCard.bowls" +msgstr "水槽" +# Source-Hash: 8449b59bf054c27d # Review: required -# Source-Hash: 5b68e435b7210876 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaker" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Burners on" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.shaker" -msgstr "夏克风" +msgid "node.cabinet.compartmentCard.burnersOn" +msgstr "点火" +# Source-Hash: 95169058fec6db14 # Review: required -# Source-Hash: c378ed346bf83375 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shared countertop, plinth, and finishes" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Chimney" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.sharedCountertopPlinthAndFinishes" -msgstr "共用台面、踢脚和饰面" +msgid "node.cabinet.compartmentCard.chimney" +msgstr "烟囱" +# Source-Hash: a6b76187db231ae7 # Review: required -# Source-Hash: 8775bc8dc9593964 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Decrease {label}" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.slab" -msgstr "楼板" +msgid "node.cabinet.compartmentCard.decrease" +msgstr "减少{label}" +# Source-Hash: 787e10f5db16904e # Review: required -# Source-Hash: 8606fe2c60764a95 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid matching front between the cabinet and wall. Countertop and toe-kick continue across this filler." -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.solidMatchingFrontBetweenTheCabinet" -msgstr "橱柜与墙之间的同款实心面板。台面和踢脚会延续到此填充板上。" +msgid "node.cabinet.compartmentCard.door" +msgstr "门" +# Source-Hash: 3cd71355956a1821 # Review: required -# Source-Hash: 5a4d5353cc496a63 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard width" -#: packages/nodes/src/cabinet/panel.tsx -#, fuzzy -msgid "node.cabinet.panel.standardWidth" -msgstr "标准宽度" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" +#: packages/nodes/src/cabinet/compartment-card.tsx +#, fuzzy +msgid "node.cabinet.compartmentCard.double" +msgstr "双扇" +# Source-Hash: 63fe49d73892aac8 # Review: required -# Source-Hash: 4a784e3e95a08715 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stop" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawer" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.stop" -msgstr "停止" +msgid "node.cabinet.compartmentCard.drawer" +msgstr "抽屉" +# Source-Hash: f98242a5dacd33f3 # Review: required -# Source-Hash: 72c9fcd7a0eb5380 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stop animation" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawers" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.stopAnimation" -msgstr "停止动画" +msgid "node.cabinet.compartmentCard.drawers" +msgstr "抽屉" +# Source-Hash: 3af5347c94ae6443 # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip hinge" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.style" -msgstr "样式" +msgid "node.cabinet.compartmentCard.flipHinge" +msgstr "翻转铰链" +# Source-Hash: c930f681e61c029c # Review: required -# Source-Hash: bfd618690e0c2f24 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tall Cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip the door hinge to the opposite side" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.tallCabinet" -msgstr "高柜" +msgid "node.cabinet.compartmentCard.flipTheDoorHingeToThe" +msgstr "将门铰链翻转到另一侧" +# Source-Hash: 85724031c91952a3 # Review: required -# Source-Hash: 27644f0497fd9849 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fridge" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.top" -msgstr "顶部" +msgid "node.cabinet.compartmentCard.fridge" +msgstr "冰箱" +# Source-Hash: e67f11024d683ea9 # Review: required -# Source-Hash: d09654ebd12a538a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Cabinet" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gas" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.topCabinet" -msgstr "顶柜" +msgid "node.cabinet.compartmentCard.gas" +msgstr "燃气" +# Source-Hash: 8ab91094cf650204 # Review: required -# Source-Hash: bc19e7805b3e3703 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top / Ceiling" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.topCeiling" -msgstr "顶部 / 天花板" +msgid "node.cabinet.compartmentCard.glass" +msgstr "玻璃" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 29ea8a68eed99925 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top depth" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.topDepth" -msgstr "顶部深度" +msgid "node.cabinet.compartmentCard.height" +msgstr "高度" +# Source-Hash: 6f434b84c8b59b8c # Review: required -# Source-Hash: 2d40f591e7dcbf5a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top height" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hob" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.topHeight" -msgstr "顶部高度" +msgid "node.cabinet.compartmentCard.hob" +msgstr "灶台" +# Source-Hash: d52570d41b4df776 # Review: required -# Source-Hash: 3b878d6015c03945 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trim / Soffit" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Increase {label}" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.trimSoffit" -msgstr "饰条 / 吊顶" +msgid "node.cabinet.compartmentCard.increase" +msgstr "增加{label}" +# Source-Hash: d298f259163e868e # Review: required -# Source-Hash: a6e5be20001e8d26 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Uses the cabinet front style, reveal, handle, and front material settings below." -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Induction" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.usesTheCabinetFrontStyleReveal" -msgstr "使用下方的橱柜面板样式、缝隙、拉手和面板材质设置。" +msgid "node.cabinet.compartmentCard.induction" +msgstr "电磁" +# Source-Hash: 54800340a0eeab23 # Review: required -# Source-Hash: cd55643590c64a42 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall filler" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layout" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.wallFiller" -msgstr "靠墙填充板" +msgid "node.cabinet.compartmentCard.layout" +msgstr "布局" +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/cabinet/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.panel.width" -msgstr "宽度" +msgid "node.cabinet.compartmentCard.left" +msgstr "左" +# Source-Hash: 12ade82be3830a0b # Review: required -# Source-Hash: 4ef03cfd6782316b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base cabinet" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Micro" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.preset.baseCabinet" -msgstr "地柜" +msgid "node.cabinet.compartmentCard.micro" +msgstr "微波炉" +# Source-Hash: a06a50e63f0c240e # Review: required -# Source-Hash: d353fff221a78228 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dishwasher" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move down" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.preset.dishwasher" -msgstr "洗碗机" +msgid "node.cabinet.compartmentCard.moveDown" +msgstr "下移" +# Source-Hash: d49ea60a2312df2f # Review: required -# Source-Hash: ecb596567b8b7179 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drawer cabinet" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move up" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.preset.drawerCabinet" -msgstr "抽屉柜" +msgid "node.cabinet.compartmentCard.moveUp" +msgstr "上移" +# Source-Hash: 596023c8b9a8f2e4 # Review: required -# Source-Hash: 85724031c91952a3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fridge" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Oven" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.preset.fridge" -msgstr "冰箱" +msgid "node.cabinet.compartmentCard.oven" +msgstr "烤箱" +# Source-Hash: 83b20797fb0a01a0 # Review: required -# Source-Hash: 72d587d58b645a81 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gas cooktop" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pullout" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.preset.gasCooktop" -msgstr "燃气灶" +msgid "node.cabinet.compartmentCard.pullout" +msgstr "拉出式" +# Source-Hash: 43c251f465b647ce # Review: required -# Source-Hash: 6b02c36e6aac2cd6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Induction cooktop" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rack" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.preset.inductionCooktop" -msgstr "电磁炉" +msgid "node.cabinet.compartmentCard.rack" +msgstr "置物架" +# Source-Hash: 3c2b3026d37cbcc2 # Review: required -# Source-Hash: d5fcb790aef707bf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Oven Tower" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove compartment" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.preset.ovenTower" -msgstr "烤箱高柜" +msgid "node.cabinet.compartmentCard.removeCompartment" +msgstr "移除隔间" +# Source-Hash: b34d5ee0f218221d # Review: required -# Source-Hash: edd4d1ab7525dcaa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sink cabinet" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.preset.sinkCabinet" -msgstr "水槽柜" +msgid "node.cabinet.compartmentCard.right" +msgstr "右" +# Source-Hash: d7145f84f8e0e3fe # Review: required -# Source-Hash: 9b7427a8954f618b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tall Pantry" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shelf" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.preset.tallPantry" -msgstr "高储物柜" +msgid "node.cabinet.compartmentCard.shelf" +msgstr "置物架" +# Source-Hash: 5fbb88f1f079b6db # Review: required -# Source-Hash: 3bd9629eb17cc572 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall cabinet" -#: packages/nodes/src/cabinet/kitchen-catalog.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shelves" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.preset.wallCabinet" -msgstr "吊柜" +msgid "node.cabinet.compartmentCard.shelves" +msgstr "层板" +# Source-Hash: 47173085127029f0 # Review: required -# Source-Hash: 7c40d26770eede82 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add left" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shelves inside" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.addLeft" -msgstr "向左添加" +msgid "node.cabinet.compartmentCard.shelvesInside" +msgstr "内部层板" +# Source-Hash: 62ab2eb3c775da95 # Review: required -# Source-Hash: 25082cdf77e219c3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add right" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.addRight" -msgstr "向右添加" +msgid "node.cabinet.compartmentCard.single" +msgstr "单扇" +# Source-Hash: 522a7535fc93fb4f # Review: required -# Source-Hash: 4b1204c1b706f618 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Align cabinets & handles" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sink" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.alignCabinetsHandles" -msgstr "对齐橱柜和拉手" +msgid "node.cabinet.compartmentCard.sink" +msgstr "水槽" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: 8c73c7a9406db5ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Applies depth, carcass, plinth, and countertop thickness to this run." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.appliesDepthCarcassPlinthAndCountertop" -msgstr "将深度、柜体、踢脚和台面厚度应用到此橱柜组。" +msgid "node.cabinet.compartmentCard.style" +msgstr "样式" +# Source-Hash: 78a454b7ac7a3cd9 # Review: required -# Source-Hash: ef576e6c8f9ebe5f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {Create {number} module copy} other {Create {number} module copies}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.arrayCreate" -msgstr "{count, plural, other {创建 {number} 个模块副本}}" +msgid "node.cabinet.compartmentCard.surface" +msgstr "表面" +# Source-Hash: 27644f0497fd9849 # Review: required -# Source-Hash: 0eec3888096306a1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {Create {number} {name} copy} other {Create {number} {name} copies}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.arrayCreateNamed" -msgstr "{count, plural, other {创建 {number} 个{name}副本}}" +msgid "node.cabinet.compartmentCard.top" +msgstr "顶部" +# Source-Hash: eaadfd2d19b27d87 # Review: required -# Source-Hash: 8cdc0b808b551d3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a copy count from 1 to 20 and spacing from 0 to 2 m" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Freezer" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.arrayInvalidOptions" -msgstr "请选择 1 到 20 的副本数量和 0 到 2 m 的间距" +msgid "node.cabinet.compartmentCard.topFreezer" +msgstr "上置冷冻" +# Source-Hash: 04f3a3462ef5d247 # Review: required -# Source-Hash: cb89fe4161e87d68 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "There is not enough room in this run for the requested array" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top grate" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.arrayNoRoom" -msgstr "此橱柜组空间不足以容纳所需阵列" +msgid "node.cabinet.compartmentCard.topGrate" +msgstr "顶部炉架" +# Source-Hash: 4a616e1d2ca55bd5 # Review: required -# Source-Hash: 075d027345689724 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a standard or appliance module as the source" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tray" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.arrayNoSource" -msgstr "请选择一个标准模块或电器模块作为源" +msgid "node.cabinet.compartmentCard.tray" +msgstr "托盘" +# Source-Hash: c44f7ab8bbd24858 # Review: required -# Source-Hash: 05b65242d8c48791 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.auto" -msgstr "自动" +msgid "node.cabinet.compartmentCard.type" +msgstr "类型" +# Source-Hash: 6c4de540d19316ab # Review: required -# Source-Hash: 7ceade8f25b58fe9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Washer" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.back" -msgstr "返回" +msgid "node.cabinet.compartmentCard.washer" +msgstr "洗碗机" +# Source-Hash: 5211a0caf3518125 # Review: required -# Source-Hash: b2c3a03bf67a97a7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Balances standard base cabinets while keeping appliance and corner-filler widths fixed." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wire" +#: packages/nodes/src/cabinet/compartment-card.tsx #, fuzzy -msgid "node.cabinet.runPanel.balancesStandardBaseCabinetsWhileKeeping" -msgstr "平衡标准地柜宽度,同时保持电器和转角填充板宽度不变。" +msgid "node.cabinet.compartmentCard.wire" +msgstr "金属丝" +# Source-Hash: 693a0d8896f5cc43 # Review: required -# Source-Hash: 9cf3754f15467c50 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A configurable parametric base cabinet." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.runPanel.bar" -msgstr "拉手条" +msgid "node.cabinet.description" +msgstr "可配置的参数化地柜。" +# Source-Hash: b0568ea943addd5b # Review: required -# Source-Hash: ccec5da17ca39eee -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar counter" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom freezer" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.barCounter" -msgstr "吧台" +msgid "node.cabinet.essentialControls.bottomFreezer" +msgstr "下置冷冻" +# Source-Hash: da78819903ae0863 # Review: required -# Source-Hash: 97c1605fff221752 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar depth" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cooktop type" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.barDepth" -msgstr "吧台深度" +msgid "node.cabinet.essentialControls.cooktopType" +msgstr "灶台类型" +# Source-Hash: c608188f58ed1cfc # Review: required -# Source-Hash: 9514a6ddebdca34e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar height" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door direction" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.barHeight" -msgstr "吧台高度" +msgid "node.cabinet.essentialControls.doorDirection" +msgstr "开门方向" +# Source-Hash: 3cd71355956a1821 # Review: required -# Source-Hash: 7af3b69b4b5aeb19 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Carcass height" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.carcassHeight" -msgstr "柜体高度" +msgid "node.cabinet.essentialControls.double" +msgstr "双扇" +# Source-Hash: f7fb8f6393cc4cfc # Review: required -# Source-Hash: 5211341ed18f33f6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fridge type" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.center" -msgstr "居中" +msgid "node.cabinet.essentialControls.fridgeType" +msgstr "冰箱类型" +# Source-Hash: e67f11024d683ea9 # Review: required -# Source-Hash: b1ab1ba948bb77b0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Common wall-cabinet heights. Use the slider below for a custom height." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gas" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.commonWallCabinetHeightsUseThe" -msgstr "常用吊柜高度。如需自定义高度,请使用下方滑块。" +msgid "node.cabinet.essentialControls.gas" +msgstr "燃气" +# Source-Hash: 8ab91094cf650204 # Review: required -# Source-Hash: 88ccc87b9b45a464 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Copies" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.copies" -msgstr "副本" +msgid "node.cabinet.essentialControls.glass" +msgstr "玻璃" +# Source-Hash: d298f259163e868e # Review: required -# Source-Hash: d215c489b8385d9f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Copies include the source cabinet structure and any attached wall cabinet. Existing modules stay fixed; the requested array must fit in the available run space." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Induction" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.copiesIncludeTheSourceCabinetStructure" -msgstr "副本包含源橱柜结构及其附着的吊柜。现有模块保持不动;所需阵列必须能放入橱柜组的可用空间。" +msgid "node.cabinet.essentialControls.induction" +msgstr "电磁" +# Source-Hash: 76df477d42cec629 # Review: required -# Source-Hash: 221d1b64649b08f8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner fillers cannot be used as array sources" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Item options" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.cornerFillersCannotBeUsedAs" -msgstr "转角填充板不能用作阵列源" +msgid "node.cabinet.essentialControls.itemOptions" +msgstr "物品选项" +# Source-Hash: bca1b184af1c0c4b # Review: required -# Source-Hash: d8d1bc5a0f9fa0cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Countertop depth" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left hinge" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.countertopDepth" -msgstr "台面深度" +msgid "node.cabinet.essentialControls.leftHinge" +msgstr "左铰链" +# Source-Hash: e32da7429c85f1a5 # Review: required -# Source-Hash: 10bba4a11996c84b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Countertop height" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right hinge" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.countertopHeight" -msgstr "台面高度" +msgid "node.cabinet.essentialControls.rightHinge" +msgstr "右铰链" +# Source-Hash: 62ab2eb3c775da95 # Review: required -# Source-Hash: 8abdfbc1798d9eaa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Create array" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.createArray" -msgstr "创建阵列" +msgid "node.cabinet.essentialControls.single" +msgstr "单扇" +# Source-Hash: 4bc3042055df1e85 # Review: required -# Source-Hash: 7984b1c42abd9c02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cutout" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sink layout" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.cutout" -msgstr "开槽" +msgid "node.cabinet.essentialControls.sinkLayout" +msgstr "水槽布局" +# Source-Hash: 29cffe75281dbea6 # Review: required -# Source-Hash: 555240ffcca44233 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete {name}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top freezer" +#: packages/nodes/src/cabinet/essential-controls.tsx #, fuzzy -msgid "node.cabinet.runPanel.deleteModule" -msgstr "删除{name}" +msgid "node.cabinet.essentialControls.topFreezer" +msgstr "上置冷冻" +# Source-Hash: 09c2cb2ea7b1be3c # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose {label}" +#: packages/nodes/src/cabinet/kitchen-collection.tsx #, fuzzy -msgid "node.cabinet.runPanel.depth" -msgstr "深度" +msgid "node.cabinet.kitchenCollection.chooseLabel" +msgstr "选择{label}" +# Source-Hash: 1dd2cac6488ddc30 # Review: required -# Source-Hash: 76cd03300faa9b2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Direction" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No kitchen items match. Try “fridge”, “sink”, or “cabinet”." +#: packages/nodes/src/cabinet/kitchen-collection.tsx #, fuzzy -msgid "node.cabinet.runPanel.direction" -msgstr "方向" +msgid "node.cabinet.kitchenCollection.noKitchenItemsMatchTryFridge" +msgstr "没有匹配的厨房物品。试试“冰箱”“水槽”或“橱柜”。" +# Source-Hash: 6752675ca6280ddd # Review: required -# Source-Hash: 5ca5884d3ff7edf4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate along run" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Search fridge, sink, cabinets…" +#: packages/nodes/src/cabinet/kitchen-collection.tsx #, fuzzy -msgid "node.cabinet.runPanel.duplicateAlongRun" -msgstr "沿橱柜组复制" +msgid "node.cabinet.kitchenCollection.searchFridgeSinkCabinets" +msgstr "搜索冰箱、水槽、橱柜…" +# Source-Hash: fe3c6d57a07c323d # Review: required -# Source-Hash: a834f687290afc10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equalize all resizeable standard base cabinets in this run" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Search kitchen items" +#: packages/nodes/src/cabinet/kitchen-collection.tsx #, fuzzy -msgid "node.cabinet.runPanel.equalizeAll" -msgstr "均分此橱柜组中所有可调宽度的标准地柜" +msgid "node.cabinet.kitchenCollection.searchKitchenItems" +msgstr "搜索厨房物品" +# Source-Hash: d44a46146db2e44c # Review: required -# Source-Hash: 24da8a2de2c6e345 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The resizeable cabinet widths are already equal" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Appliances & fixtures" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.runPanel.equalizeAlreadyEqual" -msgstr "可调宽度的橱柜已经等宽" +msgid "node.cabinet.kitchenGroup.appliances" +msgstr "电器与设施" +# Source-Hash: d4d3ad7c099b6513 # Review: required -# Source-Hash: c38a4faef2097b73 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "At least two standard base cabinets are required" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinets" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.cabinet.runPanel.equalizeNeedsTwo" -msgstr "至少需要两个标准地柜" +msgid "node.cabinet.kitchenGroup.cabinets" +msgstr "橱柜" +# Source-Hash: 465db52f98c2d94f # Review: required -# Source-Hash: 61f15ae24419430c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The available run width cannot satisfy the cabinet width limits" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add beside" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.equalizeNoFit" -msgstr "橱柜组的可用宽度无法满足橱柜宽度限制" +msgid "node.cabinet.kitchenModuleActions.addBeside" +msgstr "在旁边添加" +# Source-Hash: 9733e2ad85deb6d5 # Review: required -# Source-Hash: 7617bb3b455dcdda -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equalize widths" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add beside selected item" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.equalizeWidths" -msgstr "均分宽度" +msgid "node.cabinet.kitchenModuleActions.addBesideSelectedItem" +msgstr "在所选物品旁添加" +# Source-Hash: 4b2f676fb4c9ec63 # Review: required -# Source-Hash: ad8c948d883a0c9d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{side, select, left {Left: {width} mm} other {Right: {width} mm}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add {label}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.fillerPlanSide" -msgstr "{side, select, left {左侧:{width} mm} other {右侧:{width} mm}}" +msgid "node.cabinet.kitchenModuleActions.addLabel" +msgstr "添加{label}" +# Source-Hash: 5122b8e9b4ec6a00 # Review: required -# Source-Hash: 47ccd8c8b04475cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finish & align" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An upper cabinet attached to this item will be removed to make room." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.finishAlign" -msgstr "饰面与对齐" +msgid "node.cabinet.kitchenModuleActions.anUpperCabinetAttachedToThis" +msgstr "附着在此物品上的吊柜将被移除以腾出空间。" +# Source-Hash: 5737c4567e0f6863 # Review: required -# Source-Hash: 855892e18c74153a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finished back" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.finishedBack" -msgstr "背面饰面" +msgid "node.cabinet.kitchenModuleActions.cabinet" +msgstr "柜体" +# Source-Hash: c0774c185060fc13 # Review: required -# Source-Hash: 7ab47aea30c73663 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finished exposed ends" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cancel" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.finishedExposedEnds" -msgstr "外露端饰面" +msgid "node.cabinet.kitchenModuleActions.cancel" +msgstr "取消" +# Source-Hash: f42912b116015f58 # Review: required -# Source-Hash: c9356f25caf33eec -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fits 50–150 mm gaps at run ends beside perpendicular walls." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This {width} item cannot fit within the current run and its wall or corner limits. Move an end cabinet or free space, then try again." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.fits50150MmGapsAt" -msgstr "填补橱柜组两端靠垂直墙处 50–150 mm 的缝隙。" +msgid "node.cabinet.kitchenModuleActions.cannotFit" +msgstr "这个 {width} 的物品无法放入当前橱柜组及其墙体或转角限制内。请移动端部橱柜或腾出空间后重试。" +# Source-Hash: b7eeb26a356d03c3 # Review: required -# Source-Hash: b6f541bc28e38d2f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fit wall fillers" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{side, select, left {Inserts on the left of the selected item.} other {Inserts on the right of the selected item.}}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.fitWallFillers" -msgstr "适配靠墙填充板" +msgid "node.cabinet.kitchenModuleActions.insertsBeside" +msgstr "{side, select, left {插入到所选物品的左侧。} other {插入到所选物品的右侧。}}" +# Source-Hash: f65332177316d11d # Review: required -# Source-Hash: 2af738f010ce28f0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fronts" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The kitchen changed. Select an item again to refresh the preview." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.fronts" -msgstr "面板" +msgid "node.cabinet.kitchenModuleActions.kitchenChanged" +msgstr "厨房已更改。请重新选择物品以刷新预览。" +# Source-Hash: 5b6990b17111fd6b # Review: required -# Source-Hash: 58884f99d64e6d00 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handles" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchen run preview, highlighted item is the proposed change" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.handles" -msgstr "拉手" +msgid "node.cabinet.kitchenModuleActions.kitchenRunPreviewHighlightedItemIs" +msgstr "厨房橱柜组预览,高亮的物品为拟议更改" +# Source-Hash: cb59562ba7eb1d25 # Review: required -# Source-Hash: d73589d7c04b1121 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height preset" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left side" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.heightPreset" -msgstr "预设高度" +msgid "node.cabinet.kitchenModuleActions.leftSide" +msgstr "左侧" +# Source-Hash: 766354d53f17d78c # Review: required -# Source-Hash: 590bfdd02dcdb857 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hole" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{name}: moves {distance}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.hole" -msgstr "孔" +msgid "node.cabinet.kitchenModuleActions.moved" +msgstr "{name}:移动 {distance}" +# Source-Hash: df1083d9ffc2c59d # Review: required -# Source-Hash: 3db1dea825785a30 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inset" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{name}: {width}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.inset" -msgstr "内嵌" +msgid "node.cabinet.kitchenModuleActions.previewItem" +msgstr "{name}:{width}" +# Source-Hash: ada7fbece9ca9e3c # Review: required -# Source-Hash: 2997c230c529590d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Island & Bar" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace selected item" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.islandBar" -msgstr "岛台与吧台" +msgid "node.cabinet.kitchenModuleActions.replaceSelectedItem" +msgstr "替换所选物品" +# Source-Hash: ab8b52d2704537d2 # Review: required -# Source-Hash: a74f10dadc92c8bb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kitchen run" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replaces only the selected item." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.kitchenRun" -msgstr "厨房橱柜组" +msgid "node.cabinet.kitchenModuleActions.replacesOnlyTheSelectedItem" +msgstr "仅替换所选物品。" +# Source-Hash: 03cb6dea6e4a4c5e # Review: required -# Source-Hash: 103e15b39c909210 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Knob" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace with…" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.knob" -msgstr "旋钮拉手" +msgid "node.cabinet.kitchenModuleActions.replaceWith" +msgstr "替换为…" +# Source-Hash: 948fe657641f298c # Review: required -# Source-Hash: f365c6b6dd9ebab9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace with {label}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.left" -msgstr "左" +msgid "node.cabinet.kitchenModuleActions.replaceWithLabel" +msgstr "替换为{label}" +# Source-Hash: 154f9fa86b7670ba # Review: required -# Source-Hash: 3c88a1840043e15a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match base heights, backs, reveals and handles. Align upper cabinets; preserve tall appliances and custom compartments." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{name}: {before} → {after}" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.matchBaseHeightsBacksRevealsAnd" -msgstr "统一地柜高度、背板、缝隙和拉手。对齐吊柜;保留高电器和自定义隔间。" +msgid "node.cabinet.kitchenModuleActions.resized" +msgstr "{name}:{before} → {after}" +# Source-Hash: 4ecc493400fb6aa2 # Review: required -# Source-Hash: b112e31fe44cc94b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Metric · 600 mm" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right side" +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.metricProfile" -msgstr "公制 · 600 mm" +msgid "node.cabinet.kitchenModuleActions.rightSide" +msgstr "右侧" +# Source-Hash: f2c30e7e21cf27e6 # Review: required -# Source-Hash: 4739f6315c5e8680 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Module {number}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unable to update this kitchen." +#: packages/nodes/src/cabinet/kitchen-module-actions.tsx #, fuzzy -msgid "node.cabinet.runPanel.moduleNumber" -msgstr "模块 {number}" +msgid "node.cabinet.kitchenModuleActions.unableToUpdateThisKitchen" +msgstr "无法更新此厨房。" +# Source-Hash: 2e6d8cda361c648d # Review: required -# Source-Hash: b8801184e07e4815 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Modules" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modular Cabinet" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.cabinet.runPanel.modules" -msgstr "模块" +msgid "node.cabinet.label" +msgstr "组合橱柜" +# Source-Hash: 740e0a4e4afa78ea # Review: required -# Source-Hash: 81d365ccef73068c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finished height extends {overflow} mm above the ceiling." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.mounting" -msgstr "安装方式" +msgid "node.cabinet.panel.aboveCeiling" +msgstr "完成高度超出天花板 {overflow} mm。" +# Source-Hash: e3b4d2ed4f6f5efb # Review: required -# Source-Hash: a3914bd96488175c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No eligible module" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add chimney" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.noEligibleModule" -msgstr "没有可用模块" +msgid "node.cabinet.panel.addChimney" +msgstr "添加烟罩" +# Source-Hash: 90bdc92c0a91d060 # Review: required -# Source-Hash: f2953d2931e36d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add compartment" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.none" -msgstr "无" +msgid "node.cabinet.panel.addCompartment" +msgstr "添加隔间" +# Source-Hash: ece05d9b6f4b616d # Review: required -# Source-Hash: 9c215dc512e57fa4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overlay" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add wall cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.overlay" -msgstr "盖门" +msgid "node.cabinet.panel.addWallCabinet" +msgstr "添加吊柜" +# Source-Hash: f571cb2d06ae01ae # Review: required -# Source-Hash: 49fb05dfafd6001d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Plinth height" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Advanced" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.plinthHeight" -msgstr "踢脚高度" +msgid "node.cabinet.panel.advanced" +msgstr "高级" +# Source-Hash: 7f4dcb90defe1ac2 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Appliance" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.position" -msgstr "位置" +msgid "node.cabinet.panel.appliance" +msgstr "电器" +# Source-Hash: bd5e3f533412ff6a # Review: required -# Source-Hash: efca749fc4463623 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Raised Arch" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Appliance front" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.raisedArch" -msgstr "凸起拱形" +msgid "node.cabinet.panel.applianceFront" +msgstr "电器面板" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: 5d6956c21fde6418 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reveal gap" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.revealGap" -msgstr "缝隙" +msgid "node.cabinet.panel.auto" +msgstr "自动" +# Source-Hash: 9cf3754f15467c50 # Review: required -# Source-Hash: b34d5ee0f218221d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.right" -msgstr "右" +msgid "node.cabinet.panel.bar" +msgstr "拉手条" +# Source-Hash: 133893b177bd05d6 # Review: required -# Source-Hash: e022da49ae8b4aef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Seating overhang" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base Cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.seatingOverhang" -msgstr "座位悬挑" +msgid "node.cabinet.panel.baseCabinet" +msgstr "地柜" +# Source-Hash: d63f16df2c754126 # Review: required -# Source-Hash: 5b68e435b7210876 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaker" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet construction, compartments, and opening preview." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.shaker" -msgstr "夏克风" +msgid "node.cabinet.panel.cabinetConstructionCompartmentsAndOpeningPreview" +msgstr "橱柜构造、隔间和开启预览。" +# Source-Hash: d62dc35dac835228 # Review: required -# Source-Hash: cba29b18ce666b0a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shared Plinth & Countertop" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet panel" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.sharedPlinthCountertop" -msgstr "共用踢脚与台面" +msgid "node.cabinet.panel.cabinetPanel" +msgstr "橱柜面板" +# Source-Hash: 81caf4809d58b5f5 # Review: required -# Source-Hash: f7d577c4064c16ff -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show countertop" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet Type" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.showCountertop" -msgstr "显示台面" +msgid "node.cabinet.panel.cabinetType" +msgstr "橱柜类型" +# Source-Hash: 5211341ed18f33f6 # Review: required -# Source-Hash: 5d98e04dfd2e0a83 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show plinth" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.showPlinth" -msgstr "显示踢脚" +msgid "node.cabinet.panel.center" +msgstr "居中" +# Source-Hash: d7cf5045c01b2eb9 # Review: required -# Source-Hash: 8775bc8dc9593964 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.slab" -msgstr "楼板" +msgid "node.cabinet.panel.close" +msgstr "关闭" +# Source-Hash: cf29134333e47184 # Review: required -# Source-Hash: 5bdc0a959203c52e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Source module" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.sourceModule" -msgstr "源模块" +msgid "node.cabinet.panel.closeCabinet" +msgstr "关闭橱柜" +# Source-Hash: b1ab1ba948bb77b0 # Review: required -# Source-Hash: e4698e83d02beb6c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spacing" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Common wall-cabinet heights. Use the slider below for a custom height." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.spacing" -msgstr "间距" +msgid "node.cabinet.panel.commonWallCabinetHeightsUseThe" +msgstr "常用吊柜高度。如需自定义高度,请使用下方滑块。" +# Source-Hash: fe9e63d5c5087386 # Review: required -# Source-Hash: 40e3105cbe68d163 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard dimensions" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Compartments" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.standardDimensions" -msgstr "标准尺寸" +msgid "node.cabinet.panel.compartments" +msgstr "隔间" +# Source-Hash: 7984b1c42abd9c02 # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cutout" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.style" -msgstr "样式" +msgid "node.cabinet.panel.cutout" +msgstr "开槽" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: e9d7ad9851d476d9 +# Source-Hash: 99ac4d03c3061f3a # Review: required -# English: "{type, select, shelf {Shelf} drawer {Drawer} door {Door} oven {Oven} microwave {Microwave} dishwasher {Dishwasher} sink {Sink} cooktop_gas {Gas cooktop} cooktop_induction {Induction cooktop} pull_out_pantry {Pull-out pantry} fridge_single {Fridge} fridge_double {Double fridge} fridge_top_freezer {Top-freezer fridge} fridge_bottom_freezer {Bottom-freezer fridge} hood_pyramid {Pyramid hood} hood_curved_glass {Curved glass hood} other {{raw}}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.summaryCompartment" -msgstr "{type, select, shelf {层板} drawer {抽屉} door {柜门} oven {烤箱} microwave {微波炉} dishwasher {洗碗机} sink {水槽} cooktop_gas {燃气灶} cooktop_induction {电磁炉} pull_out_pantry {拉出式储物架} fridge_single {冰箱} fridge_double {双门冰箱} fridge_top_freezer {上置冷冻冰箱} fridge_bottom_freezer {下置冷冻冰箱} hood_pyramid {金字塔形烟罩} hood_curved_glass {弧形玻璃烟罩} other {{raw}}}" +msgid "node.cabinet.panel.depth" +msgstr "深度" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: 98582c257f149d44 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {{number} compartment} other {{number} compartments}}" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.summaryCompartments" -msgstr "{count, plural, other {{number} 个隔间}}" +msgid "node.cabinet.panel.dimensions" +msgstr "尺寸" +# Source-Hash: 82c9ea6f403fc934 # Review: required -# Source-Hash: 65b1cbba3b92c5b2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Empty" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit kitchen run" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.summaryEmpty" -msgstr "空" +msgid "node.cabinet.panel.editKitchenRun" +msgstr "编辑厨房橱柜组" +# Source-Hash: 7e9bbeb035fc73e2 # Review: required -# Source-Hash: 5db8b868684cf9f3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tall cabinet" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fill to ceiling" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.summaryTall" -msgstr "高柜" +msgid "node.cabinet.panel.fillToCeiling" +msgstr "填充至天花板" +# Source-Hash: b3907da0ad234f10 # Review: required -# Source-Hash: 27644f0497fd9849 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.top" -msgstr "顶部" +msgid "node.cabinet.panel.finish" +msgstr "完成" +# Source-Hash: c1796152935221ef # Review: required -# Source-Hash: 88c85283afe0c0bc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unable to finish this kitchen run." -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front construction" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.unableToFinish" -msgstr "无法完成此厨房橱柜组。" +msgid "node.cabinet.panel.frontConstruction" +msgstr "面板构造" +# Source-Hash: 58884f99d64e6d00 # Review: required -# Source-Hash: 8f668fb3e1a1696a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use {name} as array source" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handles" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.useAsArraySource" -msgstr "将{name}用作阵列源" +msgid "node.cabinet.panel.handles" +msgstr "拉手" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 9308a109d017dcd6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use this module as the array source" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.useThisModuleAsTheArray" -msgstr "将此模块用作阵列源" +msgid "node.cabinet.panel.height" +msgstr "高度" +# Source-Hash: d73589d7c04b1121 # Review: required -# Source-Hash: 1ce253a4d11bfa68 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "US · 24 in" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height preset" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.usProfile" -msgstr "美制 · 24 in" +msgid "node.cabinet.panel.heightPreset" +msgstr "预设高度" +# Source-Hash: 590bfdd02dcdb857 # Review: required -# Source-Hash: a2d852b2c5629796 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waterfall ends" -#: packages/nodes/src/cabinet/run-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hole" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinet.runPanel.waterfallEnds" -msgstr "瀑布式侧板" +msgid "node.cabinet.panel.hole" +msgstr "孔" -# Source-Hash: ffc8d80e438f40b7 +# Source-Hash: 3db1dea825785a30 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "An editable module inside a modular cabinet run." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inset" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinetModule.description" -msgstr "组合橱柜中的可编辑模块。" +msgid "node.cabinet.panel.inset" +msgstr "内嵌" -# Source-Hash: d5c19ec529e26a98 +# Source-Hash: 1176d2568d093bf1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cabinet Module" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchen" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.cabinetModule.label" -msgstr "橱柜模块" +msgid "node.cabinet.panel.kitchen" +msgstr "厨房" -# Source-Hash: 4d6d5e9439f40e9b +# Source-Hash: a74f10dadc92c8bb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A polygon-bounded ceiling surface that hosts ceiling-mounted items." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchen run" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.description" -msgstr "由多边形界定的天花板面,可安装吸顶物品。" +msgid "node.cabinet.panel.kitchenRun" +msgstr "厨房橱柜组" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: 103e15b39c909210 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Knob" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.label" -msgstr "天花板" +msgid "node.cabinet.panel.knob" +msgstr "旋钮拉手" -# Source-Hash: 659e6b799ad7c27d +# Source-Hash: 81d365ccef73068c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Hole" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.addHole" -msgstr "添加开洞" +msgid "node.cabinet.panel.mounting" +msgstr "安装方式" -# Source-Hash: 8332ab41e22958f1 +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Area" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.area" -msgstr "面积" +msgid "node.cabinet.panel.none" +msgstr "无" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.auto" -msgstr "自动" +msgid "node.cabinet.panel.open" +msgstr "打开" -# Source-Hash: 4275c05172abd7fb +# Source-Hash: b8ecc16c07d66f42 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ceiling" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open Animation" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.ceiling" -msgstr "天花板" +msgid "node.cabinet.panel.openAnimation" +msgstr "开启动画" -# Source-Hash: b2a1b3bc9676fe05 +# Source-Hash: 2d4adbbd70c3ae6a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom height" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.customHeight" -msgstr "自定义高度" +msgid "node.cabinet.panel.openCabinet" +msgstr "打开橱柜" -# Source-Hash: 4e4f1a24e4a9d61e +# Source-Hash: 9c215dc512e57fa4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut opening" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overlay" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.cutOpening" -msgstr "开洞" +msgid "node.cabinet.panel.overlay" +msgstr "盖门" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: a35b7357943a5cae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel-ready" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.done" -msgstr "完成" +msgid "node.cabinet.panel.panelReady" +msgstr "可装面板" -# Source-Hash: a5c2353769b603d5 +# Source-Hash: 3d0d4eee59177824 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows level" -#: packages/nodes/src/ceiling/panel.tsx -#, fuzzy -msgid "node.ceiling.panel.followsLevel" -msgstr "跟随楼层" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Planning checks" +#: packages/nodes/src/cabinet/panel.tsx +#, fuzzy +msgid "node.cabinet.panel.planningChecks" +msgstr "规划检查" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: c7b10382e01914ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Play" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.height" -msgstr "高度" +msgid "node.cabinet.panel.play" +msgstr "播放" -# Source-Hash: 703f56131ac45e60 +# Source-Hash: c530f8af9dfd846f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High (3.0m)" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Play animation" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.high30m" -msgstr "高(3.0m)" +msgid "node.cabinet.panel.playAnimation" +msgstr "播放动画" -# Source-Hash: 4ed40bdab397fe22 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "High (9'0\")" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.high90" -msgstr "高(9'0\")" +msgid "node.cabinet.panel.position" +msgstr "位置" -# Source-Hash: 34504c6ca6445e76 +# Source-Hash: efca749fc4463623 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Holes" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised Arch" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.holes" -msgstr "开洞" +msgid "node.cabinet.panel.raisedArch" +msgstr "凸起拱形" -# Source-Hash: 6e68b62d2aa611a4 +# Source-Hash: a8639a97ab07cd59 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Info" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove wall cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.info" -msgstr "信息" +msgid "node.cabinet.panel.removeWallCabinet" +msgstr "移除吊柜" -# Source-Hash: 6925a008b1924062 +# Source-Hash: 03cb6dea6e4a4c5e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Limited by the level to {height} — raise the level height for a taller ceiling." -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Replace with…" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.limitedByLevel" -msgstr "受楼层限制为 {height} — 提高楼层高度以获得更高的天花板。" +msgid "node.cabinet.panel.replaceWith" +msgstr "替换为…" -# Source-Hash: c7410ff087be3a61 +# Source-Hash: 5d6956c21fde6418 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low (2.4m)" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reveal gap" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.low24m" -msgstr "低(2.4m)" +msgid "node.cabinet.panel.revealGap" +msgstr "缝隙" -# Source-Hash: a59425761b7c9084 +# Source-Hash: 5b68e435b7210876 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low (8'0\")" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaker" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.low80" -msgstr "低(8'0\")" +msgid "node.cabinet.panel.shaker" +msgstr "夏克风" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: c378ed346bf83375 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shared countertop, plinth, and finishes" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.move" -msgstr "移动" +msgid "node.cabinet.panel.sharedCountertopPlinthAndFinishes" +msgstr "共用台面、踢脚和饰面" -# Source-Hash: 1d2dafb0d8f26ed5 +# Source-Hash: 8775bc8dc9593964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No holes" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.noHoles" -msgstr "无开洞" +msgid "node.cabinet.panel.slab" +msgstr "楼板" -# Source-Hash: 24f5fbd158798197 +# Source-Hash: 8606fe2c60764a95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard (2.5m)" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid matching front between the cabinet and wall. Countertop and toe-kick continue across this filler." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.standard25m" -msgstr "标准(2.5m)" +msgid "node.cabinet.panel.solidMatchingFrontBetweenTheCabinet" +msgstr "橱柜与墙之间的同款实心面板。台面和踢脚会延续到此填充板上。" -# Source-Hash: 73cf00cf1900c22b +# Source-Hash: 5a4d5353cc496a63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard (8'6\")" -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard width" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.standard86" -msgstr "标准(8'6\")" +msgid "node.cabinet.panel.standardWidth" +msgstr "标准宽度" -# Source-Hash: 065626498678bc5d +# Source-Hash: 4a784e3e95a08715 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Taller than this level ({available} available). Raise the level height first." -#: packages/nodes/src/ceiling/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stop" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.ceiling.panel.tallerThanLevel" -msgstr "高于此楼层(可用 {available})。请先提高楼层高度。" +msgid "node.cabinet.panel.stop" +msgstr "停止" -# Source-Hash: ea12ce3c2b3588e7 +# Source-Hash: 72c9fcd7a0eb5380 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical masonry stack on a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stop animation" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.description" -msgstr "屋面上的竖向砌体烟囱。" +msgid "node.cabinet.panel.stopAnimation" +msgstr "停止动画" -# Source-Hash: 95169058fec6db14 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Chimney" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.label" -msgstr "烟囱" +msgid "node.cabinet.panel.style" +msgstr "样式" +# Source-Hash: bfd618690e0c2f24 # Review: required -# Source-Hash: dc393661f0038c2d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Above Ridge" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tall Cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.panel.aboveRidge" -msgstr "高出屋脊" +msgid "node.cabinet.panel.tallCabinet" +msgstr "高柜" +# Source-Hash: 27644f0497fd9849 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.panel.actions" -msgstr "操作" +msgid "node.cabinet.panel.top" +msgstr "顶部" +# Source-Hash: d09654ebd12a538a # Review: required -# Source-Hash: 7ceade8f25b58fe9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Cabinet" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.panel.back" -msgstr "返回" +msgid "node.cabinet.panel.topCabinet" +msgstr "顶柜" +# Source-Hash: bc19e7805b3e3703 # Review: required -# Source-Hash: 0d42509b34b05dec -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bands" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top / Ceiling" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.panel.bands" -msgstr "腰线" +msgid "node.cabinet.panel.topCeiling" +msgstr "顶部 / 天花板" +# Source-Hash: 29ea8a68eed99925 # Review: required -# Source-Hash: d52b53241789ee63 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cap" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top depth" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.panel.cap" -msgstr "顶盖" +msgid "node.cabinet.panel.topDepth" +msgstr "顶部深度" +# Source-Hash: 2d40f591e7dcbf5a # Review: required -# Source-Hash: 95169058fec6db14 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Chimney" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top height" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.panel.chimney" -msgstr "烟囱" +msgid "node.cabinet.panel.topHeight" +msgstr "顶部高度" +# Source-Hash: 3b878d6015c03945 # Review: required -# Source-Hash: b619f366d2a1dfda -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Chimney Type" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trim / Soffit" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.panel.chimneyType" -msgstr "烟囱类型" +msgid "node.cabinet.panel.trimSoffit" +msgstr "饰条 / 吊顶" +# Source-Hash: a6e5be20001e8d26 # Review: required -# Source-Hash: 6786ac75cbe9af57 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corbeled" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Uses the cabinet front style, reveal, handle, and front material settings below." +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.panel.corbeled" -msgstr "叠涩" +msgid "node.cabinet.panel.usesTheCabinetFrontStyleReveal" +msgstr "使用下方的橱柜面板样式、缝隙、拉手和面板材质设置。" +# Source-Hash: cd55643590c64a42 # Review: required -# Source-Hash: 89eba9f077fba348 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner Bevel" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall filler" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.panel.cornerBevel" -msgstr "转角倒角" +msgid "node.cabinet.panel.wallFiller" +msgstr "靠墙填充板" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: 8a4beb9a57edc26e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Count" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/cabinet/panel.tsx #, fuzzy -msgid "node.chimney.panel.count" -msgstr "数量" +msgid "node.cabinet.panel.width" +msgstr "宽度" +# Source-Hash: 4ef03cfd6782316b # Review: required -# Source-Hash: f8ba7d73d3006d57 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cricket" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base cabinet" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.cricket" -msgstr "泛水坡" +msgid "node.cabinet.preset.baseCabinet" +msgstr "地柜" +# Source-Hash: d353fff221a78228 # Review: required -# Source-Hash: 14144df9e1364eea -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cutout Offset" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dishwasher" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.cutoutOffset" -msgstr "开洞偏移" +msgid "node.cabinet.preset.dishwasher" +msgstr "洗碗机" +# Source-Hash: ecb596567b8b7179 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drawer cabinet" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.delete" -msgstr "删除" +msgid "node.cabinet.preset.drawerCabinet" +msgstr "抽屉柜" +# Source-Hash: 85724031c91952a3 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fridge" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.depth" -msgstr "深度" +msgid "node.cabinet.preset.fridge" +msgstr "冰箱" +# Source-Hash: 72d587d58b645a81 # Review: required -# Source-Hash: 016d8e70618916d4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diameter" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gas cooktop" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.diameter" -msgstr "直径" +msgid "node.cabinet.preset.gasCooktop" +msgstr "燃气灶" +# Source-Hash: 6b02c36e6aac2cd6 # Review: required -# Source-Hash: 3cd71355956a1821 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Induction cooktop" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.double" -msgstr "双扇" +msgid "node.cabinet.preset.inductionCooktop" +msgstr "电磁炉" +# Source-Hash: d5fcb790aef707bf # Review: required -# Source-Hash: 150340cd05f4a6dd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Extent" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Oven Tower" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.extent" -msgstr "范围" +msgid "node.cabinet.preset.ovenTower" +msgstr "烤箱高柜" +# Source-Hash: edd4d1ab7525dcaa # Review: required -# Source-Hash: 9cab4d4c95f63cdd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sink cabinet" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.flat" -msgstr "平屋顶" +msgid "node.cabinet.preset.sinkCabinet" +msgstr "水槽柜" +# Source-Hash: 9b7427a8954f618b # Review: required -# Source-Hash: f817c09ef0bb6d69 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flues" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tall Pantry" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.flues" -msgstr "烟道" +msgid "node.cabinet.preset.tallPantry" +msgstr "高储物柜" +# Source-Hash: 3bd9629eb17cc572 # Review: required -# Source-Hash: a3c10560fa3c1612 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Footprint" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall cabinet" +#: packages/nodes/src/cabinet/kitchen-catalog.ts #, fuzzy -msgid "node.chimney.panel.footprint" -msgstr "基底" +msgid "node.cabinet.preset.wallCabinet" +msgstr "吊柜" +# Source-Hash: 7c40d26770eede82 # Review: required -# Source-Hash: e360f89d3c0ec456 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add left" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.front" -msgstr "前" +msgid "node.cabinet.runPanel.addLeft" +msgstr "向左添加" +# Source-Hash: 25082cdf77e219c3 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add right" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.height" -msgstr "高度" +msgid "node.cabinet.runPanel.addRight" +msgstr "向右添加" +# Source-Hash: 4b1204c1b706f618 # Review: required -# Source-Hash: 5b490bc19dddf201 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hollow Depth" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Align cabinets & handles" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.hollowDepth" -msgstr "凹槽深度" +msgid "node.cabinet.runPanel.alignCabinetsHandles" +msgstr "对齐橱柜和拉手" +# Source-Hash: 8c73c7a9406db5ad # Review: required -# Source-Hash: 643687bc3adaac76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Applies depth, carcass, plinth, and countertop thickness to this run." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.length" -msgstr "长度" +msgid "node.cabinet.runPanel.appliesDepthCarcassPlinthAndCountertop" +msgstr "将深度、柜体、踢脚和台面厚度应用到此橱柜组。" +# Source-Hash: ef576e6c8f9ebe5f # Review: required -# Source-Hash: f2953d2931e36d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {Create {number} module copy} other {Create {number} module copies}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.none" -msgstr "无" +msgid "node.cabinet.runPanel.arrayCreate" +msgstr "{count, plural, other {创建 {number} 个模块副本}}" +# Source-Hash: 0eec3888096306a1 # Review: required -# Source-Hash: 0f0e13abf9b2bb67 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Offset" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {Create {number} {name} copy} other {Create {number} {name} copies}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.offset" -msgstr "偏移" +msgid "node.cabinet.runPanel.arrayCreateNamed" +msgstr "{count, plural, other {创建 {number} 个{name}副本}}" +# Source-Hash: 8cdc0b808b551d3a # Review: required -# Source-Hash: 88540def2ce16ac5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overhang" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a copy count from 1 to 20 and spacing from 0 to 2 m" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.overhang" -msgstr "出挑" +msgid "node.cabinet.runPanel.arrayInvalidOptions" +msgstr "请选择 1 到 20 的副本数量和 0 到 2 m 的间距" +# Source-Hash: cb89fe4161e87d68 # Review: required -# Source-Hash: 6ce059aee1386f72 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panels" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "There is not enough room in this run for the requested array" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.panels" -msgstr "面板" +msgid "node.cabinet.runPanel.arrayNoRoom" +msgstr "此橱柜组空间不足以容纳所需阵列" +# Source-Hash: 075d027345689724 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a standard or appliance module as the source" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.position" -msgstr "位置" +msgid "node.cabinet.runPanel.arrayNoSource" +msgstr "请选择一个标准模块或电器模块作为源" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: f29fef1beeb25f22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangular" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.rectangular" -msgstr "矩形" +msgid "node.cabinet.runPanel.auto" +msgstr "自动" +# Source-Hash: 7ceade8f25b58fe9 # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.rotation" -msgstr "旋转" +msgid "node.cabinet.runPanel.back" +msgstr "返回" +# Source-Hash: b2c3a03bf67a97a7 # Review: required -# Source-Hash: ad0457800a1f0eb4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Balances standard base cabinets while keeping appliance and corner-filler widths fixed." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.round" -msgstr "圆形" +msgid "node.cabinet.runPanel.balancesStandardBaseCabinetsWhileKeeping" +msgstr "平衡标准地柜宽度,同时保持电器和转角填充板宽度不变。" +# Source-Hash: 9cf3754f15467c50 # Review: required -# Source-Hash: 8c6e3985459dacf9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shoulder" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.shoulder" -msgstr "肩部" +msgid "node.cabinet.runPanel.bar" +msgstr "拉手条" +# Source-Hash: ccec5da17ca39eee # Review: required -# Source-Hash: 84b9195c73dd7a67 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Side Margin" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar counter" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.sideMargin" -msgstr "侧边距" +msgid "node.cabinet.runPanel.barCounter" +msgstr "吧台" +# Source-Hash: 97c1605fff221752 # Review: required -# Source-Hash: a05a390ae205fdd8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Simple" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar depth" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.simple" -msgstr "简单" +msgid "node.cabinet.runPanel.barDepth" +msgstr "吧台深度" +# Source-Hash: 9514a6ddebdca34e # Review: required -# Source-Hash: 62ab2eb3c775da95 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar height" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.single" -msgstr "单扇" +msgid "node.cabinet.runPanel.barHeight" +msgstr "吧台高度" +# Source-Hash: 7af3b69b4b5aeb19 # Review: required -# Source-Hash: f6998707123fe72d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sloped" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Carcass height" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.sloped" -msgstr "倾斜" +msgid "node.cabinet.runPanel.carcassHeight" +msgstr "柜体高度" +# Source-Hash: 5211341ed18f33f6 # Review: required -# Source-Hash: e4698e83d02beb6c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spacing" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.spacing" -msgstr "间距" +msgid "node.cabinet.runPanel.center" +msgstr "居中" +# Source-Hash: b1ab1ba948bb77b0 # Review: required -# Source-Hash: 39287346366fc206 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Common wall-cabinet heights. Use the slider below for a custom height." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.square" -msgstr "方形" +msgid "node.cabinet.runPanel.commonWallCabinetHeightsUseThe" +msgstr "常用吊柜高度。如需自定义高度,请使用下方滑块。" +# Source-Hash: 88ccc87b9b45a464 # Review: required -# Source-Hash: 2c6b1cf17a973d67 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stepped" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Copies" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.stepped" -msgstr "阶梯式" +msgid "node.cabinet.runPanel.copies" +msgstr "副本" +# Source-Hash: d215c489b8385d9f # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Copies include the source cabinet structure and any attached wall cabinet. Existing modules stay fixed; the requested array must fit in the available run space." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.style" -msgstr "样式" +msgid "node.cabinet.runPanel.copiesIncludeTheSourceCabinetStructure" +msgstr "副本包含源橱柜结构及其附着的吊柜。现有模块保持不动;所需阵列必须能放入橱柜组的可用空间。" +# Source-Hash: 221d1b64649b08f8 # Review: required -# Source-Hash: f86f1f22230596b7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tapered" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner fillers cannot be used as array sources" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.tapered" -msgstr "锥形" +msgid "node.cabinet.runPanel.cornerFillersCannotBeUsedAs" +msgstr "转角填充板不能用作阵列源" +# Source-Hash: d8d1bc5a0f9fa0cd # Review: required -# Source-Hash: fdbb503f0941bd56 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Countertop depth" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.thickness" -msgstr "厚度" +msgid "node.cabinet.runPanel.countertopDepth" +msgstr "台面深度" +# Source-Hash: 10bba4a11996c84b # Review: required -# Source-Hash: 14b162761ce18fe9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Offset" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Countertop height" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.topOffset" -msgstr "顶部偏移" +msgid "node.cabinet.runPanel.countertopHeight" +msgstr "台面高度" +# Source-Hash: 8abdfbc1798d9eaa # Review: required -# Source-Hash: 1a5ccd607c400d76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Thickness" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Create array" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.wallThickness" -msgstr "壁厚" +msgid "node.cabinet.runPanel.createArray" +msgstr "创建阵列" +# Source-Hash: 7984b1c42abd9c02 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cutout" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.panel.width" -msgstr "宽度" +msgid "node.cabinet.runPanel.cutout" +msgstr "开槽" +# Source-Hash: 555240ffcca44233 # Review: required -# Source-Hash: abff67400a76e5eb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Brick" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete {name}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.preset.brick" -msgstr "砖砌" +msgid "node.cabinet.runPanel.deleteModule" +msgstr "删除{name}" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: f6cbdaa17e989b91 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Modern" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.preset.modern" -msgstr "现代" +msgid "node.cabinet.runPanel.depth" +msgstr "深度" +# Source-Hash: 76cd03300faa9b2b # Review: required -# Source-Hash: ad0457800a1f0eb4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round" -#: packages/nodes/src/chimney/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Direction" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.chimney.preset.round" -msgstr "圆形" +msgid "node.cabinet.runPanel.direction" +msgstr "方向" -# Source-Hash: 6a06e628257f3393 +# Source-Hash: 5ca5884d3ff7edf4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A parametric column with configurable cross-section, base, and capital." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate along run" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.description" -msgstr "截面、柱础和柱头可配置的参数化柱。" +msgid "node.cabinet.runPanel.duplicateAlongRun" +msgstr "沿橱柜组复制" -# Source-Hash: 3530ac1f4046cd22 +# Source-Hash: a834f687290afc10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Column" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equalize all resizeable standard base cabinets in this run" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.label" -msgstr "柱" +msgid "node.cabinet.runPanel.equalizeAll" +msgstr "均分此橱柜组中所有可调宽度的标准地柜" +# Source-Hash: 24da8a2de2c6e345 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The resizeable cabinet widths are already equal" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.actions" -msgstr "操作" +msgid "node.cabinet.runPanel.equalizeAlreadyEqual" +msgstr "可调宽度的橱柜已经等宽" +# Source-Hash: c38a4faef2097b73 # Review: required -# Source-Hash: 14b21685d375581a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A-Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "At least two standard base cabinets are required" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.aFrame" -msgstr "A 字架" +msgid "node.cabinet.runPanel.equalizeNeedsTwo" +msgstr "至少需要两个标准地柜" +# Source-Hash: 61f15ae24419430c # Review: required -# Source-Hash: 4007d88108e25c2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Apply preset..." -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The available run width cannot satisfy the cabinet width limits" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.applyPreset" -msgstr "应用预设…" +msgid "node.cabinet.runPanel.equalizeNoFit" +msgstr "橱柜组的可用宽度无法满足橱柜宽度限制" +# Source-Hash: 7617bb3b455dcdda # Review: required -# Source-Hash: dbfe7c561383c964 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Apply proportion..." -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equalize widths" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.applyProportion" -msgstr "应用比例…" +msgid "node.cabinet.runPanel.equalizeWidths" +msgstr "均分宽度" +# Source-Hash: ad8c948d883a0c9d # Review: required -# Source-Hash: 1f3fd938f0b26c9f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Depth" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{side, select, left {Left: {width} mm} other {Right: {width} mm}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.bottomDepth" -msgstr "底部深度" +msgid "node.cabinet.runPanel.fillerPlanSide" +msgstr "{side, select, left {左侧:{width} mm} other {右侧:{width} mm}}" +# Source-Hash: 47ccd8c8b04475cd # Review: required -# Source-Hash: 85576e19cd3da914 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Height" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish & align" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.bottomHeight" -msgstr "底部高度" +msgid "node.cabinet.runPanel.finishAlign" +msgstr "饰面与对齐" +# Source-Hash: 855892e18c74153a # Review: required -# Source-Hash: 4df0bbb04744a810 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finished back" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.bottomSpread" -msgstr "底部张开" +msgid "node.cabinet.runPanel.finishedBack" +msgstr "背面饰面" +# Source-Hash: 7ab47aea30c73663 # Review: required -# Source-Hash: 67479fecb980a441 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Step Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finished exposed ends" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.bottomStepSpread" -msgstr "底部台阶间距" +msgid "node.cabinet.runPanel.finishedExposedEnds" +msgstr "外露端饰面" +# Source-Hash: c9356f25caf33eec # Review: required -# Source-Hash: 6ea977c42202ca24 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Tiers" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fits 50–150 mm gaps at run ends beside perpendicular walls." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.bottomTiers" -msgstr "底部层数" +msgid "node.cabinet.runPanel.fits50150MmGapsAt" +msgstr "填补橱柜组两端靠垂直墙处 50–150 mm 的缝隙。" +# Source-Hash: b6f541bc28e38d2f # Review: required -# Source-Hash: 709ca788827f8a94 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit wall fillers" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.bottomWidth" -msgstr "底部宽度" +msgid "node.cabinet.runPanel.fitWallFillers" +msgstr "适配靠墙填充板" +# Source-Hash: 2af738f010ce28f0 # Review: required -# Source-Hash: 39d33008c81fc075 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fronts" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.boxFrame" -msgstr "箱形框架" +msgid "node.cabinet.runPanel.fronts" +msgstr "面板" +# Source-Hash: 58884f99d64e6d00 # Review: required -# Source-Hash: 381b1f481f747677 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Brace Depth" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handles" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.braceDepth" -msgstr "支撑深度" +msgid "node.cabinet.runPanel.handles" +msgstr "拉手" +# Source-Hash: d73589d7c04b1121 # Review: required -# Source-Hash: 8509b09b4ecdd6b6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Brace Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height preset" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.braceWidth" -msgstr "支撑宽度" +msgid "node.cabinet.runPanel.heightPreset" +msgstr "预设高度" +# Source-Hash: 590bfdd02dcdb857 # Review: required -# Source-Hash: 08558dd786f45281 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bulge" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hole" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.bulge" -msgstr "凸起" +msgid "node.cabinet.runPanel.hole" +msgstr "孔" +# Source-Hash: 3db1dea825785a30 # Review: required -# Source-Hash: 663b9a9e6a469b02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bulged" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inset" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.bulged" -msgstr "鼓形" +msgid "node.cabinet.runPanel.inset" +msgstr "内嵌" +# Source-Hash: 2997c230c529590d # Review: required -# Source-Hash: 3530ac1f4046cd22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Column" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Island & Bar" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.column" -msgstr "柱" +msgid "node.cabinet.runPanel.islandBar" +msgstr "岛台与吧台" +# Source-Hash: a74f10dadc92c8bb # Review: required -# Source-Hash: ca0a856f04460bd5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connector Plates" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kitchen run" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.connectorPlates" -msgstr "连接板" +msgid "node.cabinet.runPanel.kitchenRun" +msgstr "厨房橱柜组" +# Source-Hash: 103e15b39c909210 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Knob" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.delete" -msgstr "删除" +msgid "node.cabinet.runPanel.knob" +msgstr "旋钮拉手" +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.depth" -msgstr "深度" +msgid "node.cabinet.runPanel.left" +msgstr "左" +# Source-Hash: 3c88a1840043e15a # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match base heights, backs, reveals and handles. Align upper cabinets; preserve tall appliances and custom compartments." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.dimensions" -msgstr "尺寸" +msgid "node.cabinet.runPanel.matchBaseHeightsBacksRevealsAnd" +msgstr "统一地柜高度、背板、缝隙和拉手。对齐吊柜;保留高电器和自定义隔间。" +# Source-Hash: b112e31fe44cc94b # Review: required -# Source-Hash: b963a08f0d540014 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edge Softness" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Metric · 600 mm" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.edgeSoftness" -msgstr "边缘柔化" +msgid "node.cabinet.runPanel.metricProfile" +msgstr "公制 · 600 mm" +# Source-Hash: 4739f6315c5e8680 # Review: required -# Source-Hash: 82b3db356639ef92 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ends" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Module {number}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.ends" -msgstr "端部" +msgid "node.cabinet.runPanel.moduleNumber" +msgstr "模块 {number}" +# Source-Hash: b8801184e07e4815 # Review: required -# Source-Hash: 646c3cd99df3e285 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modules" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.endWidth" -msgstr "端部宽度" +msgid "node.cabinet.runPanel.modules" +msgstr "模块" +# Source-Hash: 81d365ccef73068c # Review: required -# Source-Hash: 02e229bca2a2b5f1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fork Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.forkSpread" -msgstr "分叉张开" +msgid "node.cabinet.runPanel.mounting" +msgstr "安装方式" +# Source-Hash: a3914bd96488175c # Review: required -# Source-Hash: fdebfac05413abcf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Heavy" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No eligible module" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.heavy" -msgstr "粗重" +msgid "node.cabinet.runPanel.noEligibleModule" +msgstr "没有可用模块" +# Source-Hash: f2953d2931e36d0c # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.height" -msgstr "高度" +msgid "node.cabinet.runPanel.none" +msgstr "无" +# Source-Hash: 9c215dc512e57fa4 # Review: required -# Source-Hash: 957fae84ed52a2e3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height and footprint are controlled by the lean-to extension. Rotate or change the support style here; resize from the parent lean-to." -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overlay" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.heightAndFootprintAreControlledBy" -msgstr "高度和占地由单坡扩建控制。可在此旋转或更改支撑样式;请在所属单坡扩建中调整尺寸。" +msgid "node.cabinet.runPanel.overlay" +msgstr "盖门" +# Source-Hash: 49fb05dfafd6001d # Review: required -# Source-Hash: bb851e93088b73a2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hourglass" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plinth height" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.hourglass" -msgstr "沙漏形" +msgid "node.cabinet.runPanel.plinthHeight" +msgstr "踢脚高度" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: 9cc75129edee59ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "K Brace" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.kBrace" -msgstr "K 形支撑" +msgid "node.cabinet.runPanel.position" +msgstr "位置" +# Source-Hash: efca749fc4463623 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Raised Arch" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.move" -msgstr "移动" +msgid "node.cabinet.runPanel.raisedArch" +msgstr "凸起拱形" +# Source-Hash: 5d6956c21fde6418 # Review: required -# Source-Hash: 6dc190abd3f22787 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Neck Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reveal gap" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.neckWidth" -msgstr "颈部宽度" +msgid "node.cabinet.runPanel.revealGap" +msgstr "缝隙" +# Source-Hash: b34d5ee0f218221d # Review: required -# Source-Hash: 7dba7ed55eeba18f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.noBottom" -msgstr "无底座" +msgid "node.cabinet.runPanel.right" +msgstr "右" +# Source-Hash: e022da49ae8b4aef # Review: required -# Source-Hash: 682d71815bb20e94 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No Top" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Seating overhang" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.noTop" -msgstr "无柱头" +msgid "node.cabinet.runPanel.seatingOverhang" +msgstr "座位悬挑" +# Source-Hash: 5b68e435b7210876 # Review: required -# Source-Hash: 4da8688437f64db8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Plinth Thickness" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaker" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.plinthThickness" -msgstr "柱基厚度" +msgid "node.cabinet.runPanel.shaker" +msgstr "夏克风" +# Source-Hash: cba29b18ce666b0a # Review: required -# Source-Hash: 0bf453b4882c663c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Portal Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shared Plinth & Countertop" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.portalFrame" -msgstr "门式框架" +msgid "node.cabinet.runPanel.sharedPlinthCountertop" +msgstr "共用踢脚与台面" +# Source-Hash: f7d577c4064c16ff # Review: required -# Source-Hash: 441f7f652ea6a0d8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preset" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show countertop" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.preset" -msgstr "预设" +msgid "node.cabinet.runPanel.showCountertop" +msgstr "显示台面" +# Source-Hash: 5d98e04dfd2e0a83 # Review: required -# Source-Hash: f29fef1beeb25f22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rectangular" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show plinth" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.rectangular" -msgstr "矩形" +msgid "node.cabinet.runPanel.showPlinth" +msgstr "显示踢脚" +# Source-Hash: 8775bc8dc9593964 # Review: required -# Source-Hash: 23b9d290b165cd49 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ring Pairs" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.ringPairs" -msgstr "环对数" +msgid "node.cabinet.runPanel.slab" +msgstr "楼板" +# Source-Hash: 5bdc0a959203c52e # Review: required -# Source-Hash: 8db82d731a19651e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ring Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Source module" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.ringSpread" -msgstr "环间距" +msgid "node.cabinet.runPanel.sourceModule" +msgstr "源模块" +# Source-Hash: e4698e83d02beb6c # Review: required -# Source-Hash: bdb524a15d9e1509 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ring Thickness" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spacing" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.ringThickness" -msgstr "环厚度" +msgid "node.cabinet.runPanel.spacing" +msgstr "间距" +# Source-Hash: 40e3105cbe68d163 # Review: required -# Source-Hash: ad0457800a1f0eb4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard dimensions" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.round" -msgstr "圆形" +msgid "node.cabinet.runPanel.standardDimensions" +msgstr "标准尺寸" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: baa84a2d17095dcf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Round Band Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.roundBandWidth" -msgstr "圆环带宽度" +msgid "node.cabinet.runPanel.style" +msgstr "样式" +# Source-Hash: e9d7ad9851d476d9 # Review: required -# Source-Hash: 5f1f67fb0ca59a6d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rounded Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{type, select, shelf {Shelf} drawer {Drawer} door {Door} oven {Oven} microwave {Microwave} dishwasher {Dishwasher} sink {Sink} cooktop_gas {Gas cooktop} cooktop_induction {Induction cooktop} pull_out_pantry {Pull-out pantry} fridge_single {Fridge} fridge_double {Double fridge} fridge_top_freezer {Top-freezer fridge} fridge_bottom_freezer {Bottom-freezer fridge} hood_pyramid {Pyramid hood} hood_curved_glass {Curved glass hood} other {{raw}}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.roundedBottom" -msgstr "圆形底座" +msgid "node.cabinet.runPanel.summaryCompartment" +msgstr "{type, select, shelf {层板} drawer {抽屉} door {柜门} oven {烤箱} microwave {微波炉} dishwasher {洗碗机} sink {水槽} cooktop_gas {燃气灶} cooktop_induction {电磁炉} pull_out_pantry {拉出式储物架} fridge_single {冰箱} fridge_double {双门冰箱} fridge_top_freezer {上置冷冻冰箱} fridge_bottom_freezer {下置冷冻冰箱} hood_pyramid {金字塔形烟罩} hood_curved_glass {弧形玻璃烟罩} other {{raw}}}" +# Source-Hash: 98582c257f149d44 # Review: required -# Source-Hash: 446816980ed0da27 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rounded Top" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {{number} compartment} other {{number} compartments}}" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.roundedTop" -msgstr "圆形柱头" +msgid "node.cabinet.runPanel.summaryCompartments" +msgstr "{count, plural, other {{number} 个隔间}}" +# Source-Hash: 65b1cbba3b92c5b2 # Review: required -# Source-Hash: 9e554c26be80f0d0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segment Twist" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Empty" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.segmentTwist" -msgstr "分段扭转" +msgid "node.cabinet.runPanel.summaryEmpty" +msgstr "空" +# Source-Hash: 5db8b868684cf9f3 # Review: required -# Source-Hash: 4fc63ad21de30103 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tall cabinet" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.shaft" -msgstr "井道" +msgid "node.cabinet.runPanel.summaryTall" +msgstr "高柜" +# Source-Hash: 27644f0497fd9849 # Review: required -# Source-Hash: 9bc3a704a9a96b3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Corner Radius" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.shaftCornerRadius" -msgstr "柱身圆角半径" +msgid "node.cabinet.runPanel.top" +msgstr "顶部" +# Source-Hash: 88c85283afe0c0bc # Review: required -# Source-Hash: 3dab61aeb47e504d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unable to finish this kitchen run." +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.shaftWidth" -msgstr "柱身宽度" +msgid "node.cabinet.runPanel.unableToFinish" +msgstr "无法完成此厨房橱柜组。" +# Source-Hash: 8f668fb3e1a1696a # Review: required -# Source-Hash: 85ea1d3c8b749680 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use {name} as array source" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.shape" -msgstr "形状" +msgid "node.cabinet.runPanel.useAsArraySource" +msgstr "将{name}用作阵列源" +# Source-Hash: 9308a109d017dcd6 # Review: required -# Source-Hash: 49a2ce13016d4073 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Short / Stout" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use this module as the array source" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.shortStout" -msgstr "短粗" +msgid "node.cabinet.runPanel.useThisModuleAsTheArray" +msgstr "将此模块用作阵列源" +# Source-Hash: 1ce253a4d11bfa68 # Review: required -# Source-Hash: 4637a9a61638cc66 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Simple Block Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "US · 24 in" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.simpleBlockBottom" -msgstr "简单块状底座" +msgid "node.cabinet.runPanel.usProfile" +msgstr "美制 · 24 in" +# Source-Hash: a2d852b2c5629796 # Review: required -# Source-Hash: 9278f9b4a48208b0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Simple Top" -#: packages/nodes/src/column/panel.tsx -#, fuzzy -msgid "node.column.panel.simpleTop" -msgstr "简单柱头" - -# Review: required -# Source-Hash: 9099890734ae1238 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single Strut" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waterfall ends" +#: packages/nodes/src/cabinet/run-panel.tsx #, fuzzy -msgid "node.column.panel.singleStrut" -msgstr "单撑杆" +msgid "node.cabinet.runPanel.waterfallEnds" +msgstr "瀑布式侧板" +# Source-Hash: ffc8d80e438f40b7 # Review: required -# Source-Hash: d87ce271009ce063 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slender" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An editable module inside a modular cabinet run." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.panel.slender" -msgstr "纤细" +msgid "node.cabinetModule.description" +msgstr "组合橱柜中的可编辑模块。" +# Source-Hash: d5c19ec529e26a98 # Review: required -# Source-Hash: 39287346366fc206 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cabinet Module" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.panel.square" -msgstr "方形" +msgid "node.cabinetModule.label" +msgstr "橱柜模块" +# Source-Hash: 25be6d614ec09df9 # Review: required -# Source-Hash: 2dc84759d8df709d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square Plinth Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom chord" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.squarePlinthBottom" -msgstr "方形柱基底座" +msgid "node.ceiling.buildUpSection.bottomChord" +msgstr "下弦" +# Source-Hash: a0c71abc0f146a2b # Review: required -# Source-Hash: d998c212030bc7c2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling joists" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.standard" -msgstr "标准" +msgid "node.ceiling.buildUpSection.ceilingJoists" +msgstr "天花板搁栅" +# Source-Hash: 7d286c87375d417e # Review: required -# Source-Hash: 01a6393135e0fb10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stepped Bottom" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Decking" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.steppedBottom" -msgstr "阶梯底座" +msgid "node.ceiling.buildUpSection.decking" +msgstr "铺板" +# Source-Hash: b3907da0ad234f10 # Review: required -# Source-Hash: 3d7e443797d4146e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stepped Top" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.steppedTop" -msgstr "阶梯柱头" +msgid "node.ceiling.buildUpSection.finish" +msgstr "饰面" +# Source-Hash: c7e72beff9fe4b37 # Review: required -# Source-Hash: 4ee35f740730ae87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framing" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.straight" -msgstr "直跑" +msgid "node.ceiling.buildUpSection.framing" +msgstr "框架" +# Source-Hash: c7aa596536ceeecb # Review: required -# Source-Hash: 6063ae2877faa35d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Taper" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Joists" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.taper" -msgstr "收分" +msgid "node.ceiling.buildUpSection.joists" +msgstr "搁栅" +# Source-Hash: 4ccd2fc1a471fca5 # Review: required -# Source-Hash: f86f1f22230596b7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tapered" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layers" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.tapered" -msgstr "锥形" +msgid "node.ceiling.buildUpSection.layers" +msgstr "构造层" +# Source-Hash: f2953d2931e36d0c # Review: required -# Source-Hash: 3e7ec47626ee3f22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Depth" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.topDepth" -msgstr "顶部深度" +msgid "node.ceiling.buildUpSection.none" +msgstr "无" +# Source-Hash: 441f7f652ea6a0d8 # Review: required -# Source-Hash: 0ca9047731784f56 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Height" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preset" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.topHeight" -msgstr "顶部高度" +msgid "node.ceiling.buildUpSection.preset" +msgstr "预设" +# Source-Hash: 2bc7b44c217cb8fb # Review: required -# Source-Hash: 3d8a2be83b5b536a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The height is the finished underside; the layers rise from it." +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.topSpread" -msgstr "顶部张开" +msgid "node.ceiling.buildUpSection.theHeightIsTheFinishedUnderside" +msgstr "高度以完成面底面为准;各层由此向上叠加。" +# Source-Hash: fdbb503f0941bd56 # Review: required -# Source-Hash: f4ae0dc639dbc220 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Step Spread" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.topStepSpread" -msgstr "顶部台阶间距" +msgid "node.ceiling.buildUpSection.thickness" +msgstr "厚度" +# Source-Hash: 2cf52770d658d006 # Review: required -# Source-Hash: 8acc4e843934b086 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Tiers" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Truss bottom chords" +#: packages/nodes/src/ceiling/build-up-section.tsx #, fuzzy -msgid "node.column.panel.topTiers" -msgstr "顶部层数" +msgid "node.ceiling.buildUpSection.trussBottomChords" +msgstr "桁架下弦" +# Source-Hash: 4d6d5e9439f40e9b # Review: required -# Source-Hash: a50eb6400611a57c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A polygon-bounded ceiling surface that hosts ceiling-mounted items." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.panel.topWidth" -msgstr "顶部宽度" +msgid "node.ceiling.description" +msgstr "由多边形界定的天花板面,可安装吸顶物品。" +# Source-Hash: 4275c05172abd7fb # Review: required -# Source-Hash: f425799b82e085ed -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Transform" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.panel.transform" -msgstr "变换" +msgid "node.ceiling.label" +msgstr "天花板" +# Source-Hash: 659e6b799ad7c27d # Review: required -# Source-Hash: 952fd1ef187c6646 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trestle" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Hole" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.trestle" -msgstr "支架" +msgid "node.ceiling.panel.addHole" +msgstr "添加开洞" +# Source-Hash: 8332ab41e22958f1 # Review: required -# Source-Hash: 7430dad59aaf98f4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tripod" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Area" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.tripod" -msgstr "三脚" +msgid "node.ceiling.panel.area" +msgstr "面积" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: 0db559f22647ec73 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Twist Segments" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.twistSegments" -msgstr "扭转分段" +msgid "node.ceiling.panel.auto" +msgstr "自动" +# Source-Hash: 4275c05172abd7fb # Review: required -# Source-Hash: 8038a34ffebf4932 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ceiling" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.vertical" -msgstr "垂直" +msgid "node.ceiling.panel.ceiling" +msgstr "天花板" +# Source-Hash: b2a1b3bc9676fe05 # Review: required -# Source-Hash: f24cc343d79acc10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "V Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom height" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.vSupport" -msgstr "V 形支撑" +msgid "node.ceiling.panel.customHeight" +msgstr "自定义高度" +# Source-Hash: 4e4f1a24e4a9d61e # Review: required -# Source-Hash: 44dda7136b93c8ee -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut opening" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.waist" -msgstr "板式" +msgid "node.ceiling.panel.cutOpening" +msgstr "开洞" +# Source-Hash: 16552c2580bbe8b8 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.width" -msgstr "宽度" +msgid "node.ceiling.panel.done" +msgstr "完成" +# Source-Hash: a5c2353769b603d5 # Review: required -# Source-Hash: 4e6640dfff42cea4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "X Brace" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows level" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.xBrace" -msgstr "X 形支撑" +msgid "node.ceiling.panel.followsLevel" +msgstr "跟随楼层" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: fefc9b1cfb26b5a8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Yaw" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.yaw" -msgstr "偏航" +msgid "node.ceiling.panel.height" +msgstr "高度" +# Source-Hash: 703f56131ac45e60 # Review: required -# Source-Hash: 86259690e332b66d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Y Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High (3.0m)" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.panel.ySupport" -msgstr "Y 形支撑" +msgid "node.ceiling.panel.high30m" +msgstr "高(3.0m)" +# Source-Hash: 4ed40bdab397fe22 # Review: required -# Source-Hash: bf2baf3d7b55f0df -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A-Frame Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "High (9'0\")" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.aFrameSupport" -msgstr "A 字支撑" +msgid "node.ceiling.panel.high90" +msgstr "高(9'0\")" +# Source-Hash: 34504c6ca6445e76 # Review: required -# Source-Hash: 51cf77bb359cee43 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight Round" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Holes" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.basicPillar" -msgstr "直圆柱" +msgid "node.ceiling.panel.holes" +msgstr "开洞" +# Source-Hash: 6e68b62d2aa611a4 # Review: required -# Source-Hash: 39d33008c81fc075 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Info" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.boxFrameSupport" -msgstr "箱形框架" +msgid "node.ceiling.panel.info" +msgstr "信息" +# Source-Hash: 6925a008b1924062 # Review: required -# Source-Hash: 4f22058e862d1f81 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Soft Bulged" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Limited by the level to {height} — raise the level height for a taller ceiling." +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.bulgedPillar" -msgstr "微鼓形" +msgid "node.ceiling.panel.limitedByLevel" +msgstr "受楼层限制为 {height} — 提高楼层高度以获得更高的天花板。" +# Source-Hash: c7410ff087be3a61 # Review: required -# Source-Hash: bb851e93088b73a2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hourglass" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low (2.4m)" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.hourglassPillar" -msgstr "沙漏形" +msgid "node.ceiling.panel.low24m" +msgstr "低(2.4m)" +# Source-Hash: a59425761b7c9084 # Review: required -# Source-Hash: 9cc75129edee59ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "K Brace" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low (8'0\")" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.kBraceSupport" -msgstr "K 形支撑" +msgid "node.ceiling.panel.low80" +msgstr "低(8'0\")" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: 0bf453b4882c663c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Portal Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.portalFrameSupport" -msgstr "门式框架" +msgid "node.ceiling.panel.move" +msgstr "移动" +# Source-Hash: 1d2dafb0d8f26ed5 # Review: required -# Source-Hash: 9099890734ae1238 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single Strut" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No holes" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.singleStrutSupport" -msgstr "单撑杆" +msgid "node.ceiling.panel.noHoles" +msgstr "无开洞" +# Source-Hash: 24f5fbd158798197 # Review: required -# Source-Hash: 0c13af329b9b57cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Square Block" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard (2.5m)" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.squarePillar" -msgstr "方柱" +msgid "node.ceiling.panel.standard25m" +msgstr "标准(2.5m)" +# Source-Hash: 73cf00cf1900c22b # Review: required -# Source-Hash: 4c294bad84924665 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tapered Round" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard (8'6\")" +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.taperedPillar" -msgstr "收分圆柱" +msgid "node.ceiling.panel.standard86" +msgstr "标准(8'6\")" +# Source-Hash: 065626498678bc5d # Review: required -# Source-Hash: 360e405bfd74a379 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trestle Frame" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Taller than this level ({available} available). Raise the level height first." +#: packages/nodes/src/ceiling/panel.tsx #, fuzzy -msgid "node.column.preset.trestleSupport" -msgstr "支架框架" +msgid "node.ceiling.panel.tallerThanLevel" +msgstr "高于此楼层(可用 {available})。请先提高楼层高度。" +# Source-Hash: ea12ce3c2b3588e7 # Review: required -# Source-Hash: 4589103259b4fc4d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tripod Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical masonry stack on a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.preset.tripodSupport" -msgstr "三脚支撑" +msgid "node.chimney.description" +msgstr "屋面上的竖向砌体烟囱。" +# Source-Hash: 95169058fec6db14 # Review: required -# Source-Hash: f24cc343d79acc10 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "V Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Chimney" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.column.preset.vFrameSupport" -msgstr "V 形支撑" +msgid "node.chimney.label" +msgstr "烟囱" +# Source-Hash: dc393661f0038c2d # Review: required -# Source-Hash: 4e6640dfff42cea4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "X Brace" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Above Ridge" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.column.preset.xBraceSupport" -msgstr "X 形支撑" +msgid "node.chimney.panel.aboveRidge" +msgstr "高出屋脊" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 86259690e332b66d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Y Support" -#: packages/nodes/src/column/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.column.preset.yFrameSupport" -msgstr "Y 形支撑" +msgid "node.chimney.panel.actions" +msgstr "操作" -# Source-Hash: 895766ad1b766c2e +# Source-Hash: 7ceade8f25b58fe9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Associative linear, curved, circular, angular, or coordinate plan dimension." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.constructionDimension.description" -msgstr "关联的线性、曲线、圆形、角度或坐标平面尺寸。" +msgid "node.chimney.panel.back" +msgstr "返回" -# Source-Hash: 6875b60ee8a7cc3b +# Source-Hash: 0d42509b34b05dec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Construction Dimension" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bands" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.constructionDimension.label" -msgstr "施工尺寸" +msgid "node.chimney.panel.bands" +msgstr "腰线" -# Source-Hash: 61a6c6b9bc29c4f8 +# Source-Hash: d52b53241789ee63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Left" -#: packages/nodes/src/window/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cap" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cornerRadius.bottomLeft" -msgstr "左下" +msgid "node.chimney.panel.cap" +msgstr "顶盖" -# Source-Hash: c5368accab136fa6 +# Source-Hash: 95169058fec6db14 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom Right" -#: packages/nodes/src/window/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Chimney" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cornerRadius.bottomRight" -msgstr "右下" +msgid "node.chimney.panel.chimney" +msgstr "烟囱" -# Source-Hash: c8f86af3f03af6c7 +# Source-Hash: b619f366d2a1dfda # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Left" -#: packages/nodes/src/door/panel.tsx -#: packages/nodes/src/window/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Chimney Type" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cornerRadius.topLeft" -msgstr "左上" +msgid "node.chimney.panel.chimneyType" +msgstr "烟囱类型" -# Source-Hash: 0ead7f1ffdbbd892 +# Source-Hash: 6786ac75cbe9af57 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Right" -#: packages/nodes/src/door/panel.tsx -#: packages/nodes/src/window/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corbeled" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cornerRadius.topRight" -msgstr "右上" +msgid "node.chimney.panel.corbeled" +msgstr "叠涩" -# Source-Hash: a276c9693f01dec7 +# Source-Hash: 89eba9f077fba348 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Louvered roof lantern with a dome or pyramid cap and optional finial." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner Bevel" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.description" -msgstr "带百叶的屋顶亭,配圆顶或金字塔顶,可选尖顶饰。" +msgid "node.chimney.panel.cornerBevel" +msgstr "转角倒角" -# Source-Hash: e679dd19f96eba0a +# Source-Hash: 8a4beb9a57edc26e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cupola" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Count" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.label" -msgstr "穹顶亭" +msgid "node.chimney.panel.count" +msgstr "数量" +# Source-Hash: f8ba7d73d3006d57 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cricket" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.actions" -msgstr "操作" +msgid "node.chimney.panel.cricket" +msgstr "泛水坡" +# Source-Hash: 14144df9e1364eea # Review: required -# Source-Hash: e679dd19f96eba0a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cupola" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cutout Offset" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.cupola" -msgstr "穹顶亭" +msgid "node.chimney.panel.cutoutOffset" +msgstr "开洞偏移" -# Review: required # Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" -#: packages/nodes/src/cupola/panel.tsx +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.delete" +msgid "node.chimney.panel.delete" msgstr "删除" -# Review: required # Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Depth" -#: packages/nodes/src/cupola/panel.tsx +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.depth" +msgid "node.chimney.panel.depth" msgstr "深度" +# Source-Hash: 016d8e70618916d4 # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diameter" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.dimensions" -msgstr "尺寸" +msgid "node.chimney.panel.diameter" +msgstr "直径" +# Source-Hash: 3cd71355956a1821 # Review: required -# Source-Hash: de47e23eb81efe02 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dome" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.dome" -msgstr "穹顶" +msgid "node.chimney.panel.double" +msgstr "双扇" +# Source-Hash: 150340cd05f4a6dd # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Extent" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.duplicate" -msgstr "复制" +msgid "node.chimney.panel.extent" +msgstr "范围" +# Source-Hash: 9cab4d4c95f63cdd # Review: required -# Source-Hash: 1cfe33235b30b1d8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finial" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.finial" -msgstr "尖顶饰" +msgid "node.chimney.panel.flat" +msgstr "平屋顶" +# Source-Hash: f817c09ef0bb6d69 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flues" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.height" -msgstr "高度" +msgid "node.chimney.panel.flues" +msgstr "烟道" +# Source-Hash: a3c10560fa3c1612 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Footprint" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.move" -msgstr "移动" +msgid "node.chimney.panel.footprint" +msgstr "基底" +# Source-Hash: e360f89d3c0ec456 # Review: required -# Source-Hash: b5e0cb318d484d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No Finial" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.noFinial" -msgstr "无尖顶饰" +msgid "node.chimney.panel.front" +msgstr "前" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.position" -msgstr "位置" +msgid "node.chimney.panel.height" +msgstr "高度" +# Source-Hash: 5b490bc19dddf201 # Review: required -# Source-Hash: 47587b825e9a696b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pyramid" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hollow Depth" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.pyramid" -msgstr "金字塔形" +msgid "node.chimney.panel.hollowDepth" +msgstr "凹槽深度" +# Source-Hash: 643687bc3adaac76 # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.rotation" -msgstr "旋转" +msgid "node.chimney.panel.length" +msgstr "长度" +# Source-Hash: f2953d2931e36d0c # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.style" -msgstr "样式" +msgid "node.chimney.panel.none" +msgstr "无" +# Source-Hash: 0f0e13abf9b2bb67 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/cupola/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Offset" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cupola.panel.width" -msgstr "宽度" +msgid "node.chimney.panel.offset" +msgstr "偏移" -# Source-Hash: 5d4ccdf13668fab4 +# Source-Hash: 88540def2ce16ac5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto elevator cutout" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overhang" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cutout.autoElevator" -msgstr "自动电梯开洞" +msgid "node.chimney.panel.overhang" +msgstr "出挑" -# Source-Hash: 78aa03576e02dda7 +# Source-Hash: 6ce059aee1386f72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto stair cutout" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panels" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cutout.autoStair" -msgstr "自动楼梯开洞" +msgid "node.chimney.panel.panels" +msgstr "面板" -# Source-Hash: e04298381837252f +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cutout.opening" -msgstr "开口" +msgid "node.chimney.panel.position" +msgstr "位置" -# Source-Hash: ce37dbd7a309940b +# Source-Hash: f29fef1beeb25f22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Room cutout" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangular" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.cutout.room" -msgstr "房间开洞" +msgid "node.chimney.panel.rectangular" +msgstr "矩形" -# Source-Hash: 6123b20edb9569de +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A door cut into a wall. Animated open/close state." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.description" -msgstr "开在墙体上的门,带开关动画。" +msgid "node.chimney.panel.rotation" +msgstr "旋转" -# Source-Hash: 787e10f5db16904e +# Source-Hash: ad0457800a1f0eb4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.label" -msgstr "门" +msgid "node.chimney.panel.round" +msgstr "圆形" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 8c6e3985459dacf9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shoulder" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.actions" -msgstr "操作" +msgid "node.chimney.panel.shoulder" +msgstr "肩部" -# Source-Hash: 8337b3213849faca +# Source-Hash: 84b9195c73dd7a67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "+ Add Segment" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Side Margin" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.addSegment" -msgstr "+ 添加分段" +msgid "node.chimney.panel.sideMargin" +msgstr "侧边距" -# Source-Hash: 663175a9c461a96d +# Source-Hash: a05a390ae205fdd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Simple" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.all" -msgstr "全部" +msgid "node.chimney.panel.simple" +msgstr "简单" -# Source-Hash: 710261f5ffb32617 +# Source-Hash: 62ab2eb3c775da95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arch" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.arch" -msgstr "拱形" +msgid "node.chimney.panel.single" +msgstr "单扇" -# Source-Hash: 3715cd54e4775087 +# Source-Hash: f6998707123fe72d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arch Height" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sloped" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.archHeight" -msgstr "拱高" +msgid "node.chimney.panel.sloped" +msgstr "倾斜" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: e4698e83d02beb6c # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 -# English: "Auto" -#: packages/nodes/src/door/panel.tsx +# AI-Model: claude-opus-5-5 +# English: "Spacing" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.auto" -msgstr "自动" +msgid "node.chimney.panel.spacing" +msgstr "间距" -# Source-Hash: 8a04486ba122ea7d +# Source-Hash: 39287346366fc206 # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 -# English: "Auto follows the wall" -#: packages/nodes/src/door/panel.tsx +# AI-Model: claude-opus-5-5 +# English: "Square" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.autoFollowsTheWall" -msgstr "自动跟随墙体" +msgid "node.chimney.panel.square" +msgstr "方形" -# Source-Hash: 387773c8aa2820a4 +# Source-Hash: 2c6b1cf17a973d67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bar Height" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stepped" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.barHeight" -msgstr "横档高度" +msgid "node.chimney.panel.stepped" +msgstr "阶梯式" -# Source-Hash: 30edd1c180aac9b4 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Columns" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.columns" -msgstr "列" +msgid "node.chimney.panel.style" +msgstr "样式" -# Source-Hash: f533584833a4a7bb +# Source-Hash: f86f1f22230596b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Content Padding" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tapered" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.contentPadding" -msgstr "内容边距" +msgid "node.chimney.panel.tapered" +msgstr "锥形" -# Source-Hash: 7a90a42b578f2435 +# Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner Radius" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.cornerRadius" -msgstr "圆角半径" +msgid "node.chimney.panel.thickness" +msgstr "厚度" -# Source-Hash: aa0e8e02212091e4 +# Source-Hash: 14b162761ce18fe9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom: the segments match no style." -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Offset" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.customTheSegmentsMatchNoStyle" -msgstr "自定义:分段不匹配任何样式。" +msgid "node.chimney.panel.topOffset" +msgstr "顶部偏移" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 1a5ccd607c400d76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall Thickness" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.delete" -msgstr "删除" +msgid "node.chimney.panel.wallThickness" +msgstr "壁厚" -# Source-Hash: 99ac4d03c3061f3a +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.depth" -msgstr "深度" +msgid "node.chimney.panel.width" +msgstr "宽度" -# Source-Hash: 12df69f42beb0643 +# Source-Hash: abff67400a76e5eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brick" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.dimensions" -msgstr "尺寸" +msgid "node.chimney.preset.brick" +msgstr "砖砌" -# Source-Hash: 76cd03300faa9b2b +# Source-Hash: f6cbdaa17e989b91 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Direction" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modern" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.direction" -msgstr "方向" +msgid "node.chimney.preset.modern" +msgstr "现代" -# Source-Hash: c53c3307e2a2a32a +# Source-Hash: ad0457800a1f0eb4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Divider" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round" +#: packages/nodes/src/chimney/panel.tsx #, fuzzy -msgid "node.door.panel.divider" -msgstr "分隔条" +msgid "node.chimney.preset.round" +msgstr "圆形" -# Source-Hash: 787e10f5db16904e +# Source-Hash: 6a06e628257f3393 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A parametric column with configurable cross-section, base, and capital." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.door" -msgstr "门" +msgid "node.column.description" +msgstr "截面、柱础和柱头可配置的参数化柱。" -# Source-Hash: 4a0aa7f647e6461b +# Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Closer" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Column" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.door.panel.doorCloser" -msgstr "闭门器" +msgid "node.column.label" +msgstr "柱" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.duplicate" -msgstr "复制" +msgid "node.column.panel.actions" +msgstr "操作" -# Source-Hash: 65b1cbba3b92c5b2 +# Source-Hash: 14b21685d375581a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Empty" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A-Frame" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.empty" -msgstr "空" +msgid "node.column.panel.aFrame" +msgstr "A 字架" -# Source-Hash: 6982301da2dbe186 +# Source-Hash: 4007d88108e25c2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Enable Handle" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Apply preset..." +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.enableHandle" -msgstr "启用把手" +msgid "node.column.panel.applyPreset" +msgstr "应用预设…" -# Source-Hash: 2e96ebf9c6e7fe49 +# Source-Hash: dbfe7c561383c964 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Enable Threshold" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Apply proportion..." +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.enableThreshold" -msgstr "启用门槛" +msgid "node.column.panel.applyProportion" +msgstr "应用比例…" -# Source-Hash: 61f9413d3bbabde7 +# Source-Hash: 1f3fd938f0b26c9f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip Side" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Depth" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.flipSide" -msgstr "翻转方向" +msgid "node.column.panel.bottomDepth" +msgstr "底部深度" -# Source-Hash: 7e8fdd28f9d54d1f +# Source-Hash: 85576e19cd3da914 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fold" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Height" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.fold" -msgstr "折叠" +msgid "node.column.panel.bottomHeight" +msgstr "底部高度" -# Source-Hash: ce3a6c03765dbbd8 +# Source-Hash: 4df0bbb04744a810 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.frame" -msgstr "框架" +msgid "node.column.panel.bottomSpread" +msgstr "底部张开" -# Source-Hash: 0cce8ae784f78478 +# Source-Hash: 67479fecb980a441 # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 -# English: "Depth (auto)" -#: packages/nodes/src/door/panel.tsx +# AI-Model: claude-opus-5-5 +# English: "Bottom Step Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.frameDepthAuto" -msgstr "深度(自动)" +msgid "node.column.panel.bottomStepSpread" +msgstr "底部台阶间距" -# Source-Hash: 53aa825a4737190a +# Source-Hash: 6ea977c42202ca24 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Garage" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Tiers" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.garage" -msgstr "车库" +msgid "node.column.panel.bottomTiers" +msgstr "底部层数" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: 709ca788827f8a94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.glass" -msgstr "玻璃" +msgid "node.column.panel.bottomWidth" +msgstr "底部宽度" -# Source-Hash: 41483b645efc0c65 +# Source-Hash: 39d33008c81fc075 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handle" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box Frame" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.handle" -msgstr "把手" +msgid "node.column.panel.boxFrame" +msgstr "箱形框架" -# Source-Hash: b4a496a904640583 +# Source-Hash: 381b1f481f747677 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handle Side" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brace Depth" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.handleSide" -msgstr "把手侧" +msgid "node.column.panel.braceDepth" +msgstr "支撑深度" -# Source-Hash: 8c1bc3a078056ff7 +# Source-Hash: 8509b09b4ecdd6b6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hardware" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Brace Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.hardware" -msgstr "五金件" +msgid "node.column.panel.braceWidth" +msgstr "支撑宽度" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: 08558dd786f45281 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bulge" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.height" -msgstr "高度" +msgid "node.column.panel.bulge" +msgstr "凸起" -# Source-Hash: 7c8f079bbefe86c9 +# Source-Hash: 663b9a9e6a469b02 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hinges Side" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bulged" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.hingesSide" -msgstr "铰链侧" +msgid "node.column.panel.bulged" +msgstr "鼓形" -# Source-Hash: ac9c79f08ef130a1 +# Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Horizontal" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Column" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.horizontal" -msgstr "水平" +msgid "node.column.panel.column" +msgstr "柱" -# Source-Hash: 42824e50de26bc14 +# Source-Hash: ca0a856f04460bd5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Individual" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connector Plates" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.individual" -msgstr "单独" +msgid "node.column.panel.connectorPlates" +msgstr "连接板" -# Source-Hash: 3db1dea825785a30 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inset" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.inset" -msgstr "内嵌" +msgid "node.column.panel.delete" +msgstr "删除" -# Source-Hash: 1f4ad5ad3e1be222 +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inward" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.inward" -msgstr "向内" +msgid "node.column.panel.depth" +msgstr "深度" -# Source-Hash: f365c6b6dd9ebab9 +# Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.left" -msgstr "左" +msgid "node.column.panel.dimensions" +msgstr "尺寸" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: b963a08f0d540014 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edge Softness" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.move" -msgstr "移动" +msgid "node.column.panel.edgeSoftness" +msgstr "边缘柔化" -# Source-Hash: 3e52f04f92e08070 +# Source-Hash: 82b3db356639ef92 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ends" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.open" -msgstr "打开" +msgid "node.column.panel.ends" +msgstr "端部" -# Source-Hash: e04298381837252f +# Source-Hash: 646c3cd99df3e285 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.opening" -msgstr "开口" +msgid "node.column.panel.endWidth" +msgstr "端部宽度" -# Source-Hash: ecb81bd3eefa6a47 +# Source-Hash: 02e229bca2a2b5f1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening Shape" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fork Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.openingShape" -msgstr "开洞形状" +msgid "node.column.panel.forkSpread" +msgstr "分叉张开" -# Source-Hash: ccd8f06b8f8d27c9 +# Source-Hash: fdebfac05413abcf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Outward" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Heavy" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.outward" -msgstr "向外" +msgid "node.column.panel.heavy" +msgstr "粗重" -# Source-Hash: 482469f5a0873f73 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.panel" -msgstr "面板" +msgid "node.column.panel.height" +msgstr "高度" -# Source-Hash: 6ce059aee1386f72 +# Source-Hash: 957fae84ed52a2e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panels" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height and footprint are controlled by the lean-to extension. Rotate or change the support style here; resize from the parent lean-to." +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.panels" -msgstr "面板" +msgid "node.column.panel.heightAndFootprintAreControlledBy" +msgstr "高度和占地由单坡扩建控制。可在此旋转或更改支撑样式;请在所属单坡扩建中调整尺寸。" -# Source-Hash: ad56a8ab82ff1a77 +# Source-Hash: bb851e93088b73a2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panic Bar" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hourglass" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.panicBar" -msgstr "推杠锁" +msgid "node.column.panel.hourglass" +msgstr "沙漏形" -# Source-Hash: ade6246634d93054 +# Source-Hash: 9cc75129edee59ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pocket" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "K Brace" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.pocket" -msgstr "暗藏推拉门" +msgid "node.column.panel.kBrace" +msgstr "K 形支撑" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.position" -msgstr "位置" +msgid "node.column.panel.move" +msgstr "移动" -# Source-Hash: 947eacd2689daced +# Source-Hash: 6dc190abd3f22787 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rail" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Neck Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.rail" -msgstr "横杆" +msgid "node.column.panel.neckWidth" +msgstr "颈部宽度" -# Source-Hash: 3b6f225112035fde +# Source-Hash: 7dba7ed55eeba18f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rect" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.rect" -msgstr "矩形" +msgid "node.column.panel.noBottom" +msgstr "无底座" -# Source-Hash: c05172113af5a2b8 +# Source-Hash: 682d71815bb20e94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "- Remove" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No Top" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.remove" -msgstr "- 移除" +msgid "node.column.panel.noTop" +msgstr "无柱头" -# Source-Hash: 59236bd016c6b904 +# Source-Hash: 4da8688437f64db8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reveal Radius" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plinth Thickness" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.revealRadius" -msgstr "洞口圆角半径" +msgid "node.column.panel.plinthThickness" +msgstr "柱基厚度" -# Source-Hash: b34d5ee0f218221d +# Source-Hash: 0bf453b4882c663c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Portal Frame" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.right" -msgstr "右" +msgid "node.column.panel.portalFrame" +msgstr "门式框架" -# Source-Hash: fc826da6c99303e6 +# Source-Hash: 441f7f652ea6a0d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rounded" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preset" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.rounded" -msgstr "圆角" +msgid "node.column.panel.preset" +msgstr "预设" -# Source-Hash: 505d8419cf4cc5e1 +# Source-Hash: f29fef1beeb25f22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segments" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rectangular" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.segments" -msgstr "分段" +msgid "node.column.panel.rectangular" +msgstr "矩形" -# Source-Hash: a8096eb4beaadeef +# Source-Hash: 23b9d290b165cd49 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Size is limited to the wall, including clearance for the opening frame." -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ring Pairs" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.sizeIsLimitedToTheWall" -msgstr "尺寸受墙体限制,包括洞口框的间隙。" +msgid "node.column.panel.ringPairs" +msgstr "环对数" -# Source-Hash: c00de0e2c9b0ddcb +# Source-Hash: 8db82d731a19651e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slide" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ring Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.slide" -msgstr "推拉" +msgid "node.column.panel.ringSpread" +msgstr "环间距" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: bdb524a15d9e1509 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ring Thickness" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.style" -msgstr "样式" +msgid "node.column.panel.ringThickness" +msgstr "环厚度" -# Source-Hash: e48604b5f7b2a5f4 +# Source-Hash: ad0457800a1f0eb4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swing" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.swing" -msgstr "平开" +msgid "node.column.panel.round" +msgstr "圆形" -# Source-Hash: fdbb503f0941bd56 +# Source-Hash: baa84a2d17095dcf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Round Band Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.thickness" -msgstr "厚度" +msgid "node.column.panel.roundBandWidth" +msgstr "圆环带宽度" -# Source-Hash: f165d6c05be2b651 +# Source-Hash: 5f1f67fb0ca59a6d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Threshold" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rounded Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.threshold" -msgstr "门槛" +msgid "node.column.panel.roundedBottom" +msgstr "圆形底座" -# Source-Hash: 7e2505dd1d5e3513 +# Source-Hash: 446816980ed0da27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Shape" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rounded Top" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.topShape" -msgstr "顶部形状" +msgid "node.column.panel.roundedTop" +msgstr "圆形柱头" -# Source-Hash: c44f7ab8bbd24858 +# Source-Hash: 9e554c26be80f0d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segment Twist" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.type" -msgstr "类型" +msgid "node.column.panel.segmentTwist" +msgstr "分段扭转" -# Source-Hash: 8038a34ffebf4932 +# Source-Hash: 4fc63ad21de30103 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.vertical" -msgstr "垂直" +msgid "node.column.panel.shaft" +msgstr "井道" -# Source-Hash: 63d6b766151965f9 +# Source-Hash: 9bc3a704a9a96b3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "wall" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Corner Radius" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.wall" -msgstr "墙体" +msgid "node.column.panel.shaftCornerRadius" +msgstr "柱身圆角半径" -# Source-Hash: 3a0ccd6c46877a87 +# Source-Hash: 3dab61aeb47e504d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.panel.width" -msgstr "宽度" +msgid "node.column.panel.shaftWidth" +msgstr "柱身宽度" -# Source-Hash: 8421deea35cb5afc +# Source-Hash: 85ea1d3c8b749680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Barn" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.barn" -msgstr "谷仓门" +msgid "node.column.panel.shape" +msgstr "形状" -# Source-Hash: f747fbe71717772e +# Source-Hash: 49a2ce13016d4073 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Craftsman" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Short / Stout" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.craftsman" -msgstr "工匠风" +msgid "node.column.panel.shortStout" +msgstr "短粗" -# Source-Hash: 092033938ca2debb +# Source-Hash: 4637a9a61638cc66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "French" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Simple Block Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.french" -msgstr "法式门" +msgid "node.column.panel.simpleBlockBottom" +msgstr "简单块状底座" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: 9278f9b4a48208b0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Simple Top" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.glass" -msgstr "玻璃" +msgid "node.column.panel.simpleTop" +msgstr "简单柱头" -# Source-Hash: 6ab8b98b38eb2e65 +# Source-Hash: 9099890734ae1238 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Half-louvered" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single Strut" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.halfLouvered" -msgstr "半百叶" +msgid "node.column.panel.singleStrut" +msgstr "单撑杆" -# Source-Hash: f6cbdaa17e989b91 +# Source-Hash: d87ce271009ce063 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Modern" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slender" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.modern" -msgstr "现代" +msgid "node.column.panel.slender" +msgstr "纤细" -# Source-Hash: 482469f5a0873f73 +# Source-Hash: 39287346366fc206 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.panel" -msgstr "面板" +msgid "node.column.panel.square" +msgstr "方形" -# Source-Hash: ac42c328610a0edd +# Source-Hash: 2dc84759d8df709d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Paneled glass" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square Plinth Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.paneledGlass" -msgstr "镶板玻璃" +msgid "node.column.panel.squarePlinthBottom" +msgstr "方形柱基底座" -# Source-Hash: 5b68e435b7210876 +# Source-Hash: d998c212030bc7c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaker" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.shaker" -msgstr "夏克风" +msgid "node.column.panel.standard" +msgstr "标准" -# Source-Hash: 9ad6ac42b4152b64 +# Source-Hash: 01a6393135e0fb10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Six-panel" -#: packages/nodes/src/shared/opening-labels.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stepped Bottom" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.style.sixPanel" -msgstr "六镶板" +msgid "node.column.panel.steppedBottom" +msgstr "阶梯底座" -# Source-Hash: 8421deea35cb5afc +# Source-Hash: 3d7e443797d4146e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Barn" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stepped Top" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.barn" -msgstr "谷仓门" +msgid "node.column.panel.steppedTop" +msgstr "阶梯柱头" -# Source-Hash: 3cd71355956a1821 +# Source-Hash: 4ee35f740730ae87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.double" -msgstr "双扇" +msgid "node.column.panel.straight" +msgstr "直跑" -# Source-Hash: 29ff60e662b789fb +# Source-Hash: 6063ae2877faa35d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Folding" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Taper" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.folding" -msgstr "折叠门" +msgid "node.column.panel.taper" +msgstr "收分" -# Source-Hash: 092033938ca2debb +# Source-Hash: f86f1f22230596b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "French" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tapered" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.french" -msgstr "法式门" +msgid "node.column.panel.tapered" +msgstr "锥形" -# Source-Hash: c86309fefe89699b +# Source-Hash: 3e7ec47626ee3f22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roll-up" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Depth" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.garageRollup" -msgstr "卷帘门" +msgid "node.column.panel.topDepth" +msgstr "顶部深度" -# Source-Hash: fb6a868430547544 +# Source-Hash: 0ca9047731784f56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sectional" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Height" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.garageSectional" -msgstr "分节门" +msgid "node.column.panel.topHeight" +msgstr "顶部高度" -# Source-Hash: 0b5eb64b569db837 +# Source-Hash: 3d8a2be83b5b536a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilt-up" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.garageTiltup" -msgstr "翻板门" +msgid "node.column.panel.topSpread" +msgstr "顶部张开" -# Source-Hash: e744be60baad6abc +# Source-Hash: f4ae0dc639dbc220 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hinged" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Step Spread" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.hinged" -msgstr "平开门" +msgid "node.column.panel.topStepSpread" +msgstr "顶部台阶间距" -# Source-Hash: ade6246634d93054 +# Source-Hash: 8acc4e843934b086 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pocket" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Tiers" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.pocket" -msgstr "暗藏推拉门" +msgid "node.column.panel.topTiers" +msgstr "顶部层数" -# Source-Hash: 18cbc73c5e1590aa +# Source-Hash: a50eb6400611a57c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sliding" -#: packages/nodes/src/door/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.door.type.sliding" -msgstr "推拉门" +msgid "node.column.panel.topWidth" +msgstr "顶部宽度" -# Source-Hash: 387e57242c8d110a +# Source-Hash: f425799b82e085ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "House-shaped protrusion on a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Transform" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.description" -msgstr "屋面上的房屋形凸出部分。" +msgid "node.column.panel.transform" +msgstr "变换" -# Source-Hash: 6b6f8068bbc4c902 +# Source-Hash: 952fd1ef187c6646 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dormer" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trestle" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.label" -msgstr "老虎窗" +msgid "node.column.panel.trestle" +msgstr "支架" +# Source-Hash: 7430dad59aaf98f4 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tripod" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.depth" -msgstr "深度" +msgid "node.column.panel.tripod" +msgstr "三脚" +# Source-Hash: 0db559f22647ec73 # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Twist Segments" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.dimensions" -msgstr "尺寸" +msgid "node.column.panel.twistSegments" +msgstr "扭转分段" +# Source-Hash: 8038a34ffebf4932 # Review: required -# Source-Hash: 6b6f8068bbc4c902 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dormer" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.dormer" -msgstr "老虎窗" +msgid "node.column.panel.vertical" +msgstr "垂直" +# Source-Hash: f24cc343d79acc10 # Review: required -# Source-Hash: 6949d667043bee0b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "V Support" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.dutch" -msgstr "荷兰式" +msgid "node.column.panel.vSupport" +msgstr "V 形支撑" +# Source-Hash: 44dda7136b93c8ee # Review: required -# Source-Hash: 9cab4d4c95f63cdd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.flat" -msgstr "平屋顶" +msgid "node.column.panel.waist" +msgstr "板式" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: deaffa095d126dfe -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.gable" -msgstr "双坡" +msgid "node.column.panel.width" +msgstr "宽度" +# Source-Hash: 4e6640dfff42cea4 # Review: required -# Source-Hash: 7f53d9ffca39984a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "X Brace" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.gambrel" -msgstr "复折式" +msgid "node.column.panel.xBrace" +msgstr "X 形支撑" +# Source-Hash: fefc9b1cfb26b5a8 # Review: required -# Source-Hash: 9eda0ea8d447066d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hip" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Yaw" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.hip" -msgstr "四坡" +msgid "node.column.panel.yaw" +msgstr "偏航" +# Source-Hash: 86259690e332b66d # Review: required -# Source-Hash: 7f7bb0e875af3260 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Y Support" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.mansard" -msgstr "孟莎式" +msgid "node.column.panel.ySupport" +msgstr "Y 形支撑" +# Source-Hash: 4d3a89de7073d38d # Review: required -# Source-Hash: 53af9efc7eca6594 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pitch Direction" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A {size} deck post stands no taller than {limit} (IRC Table R507.4, by species and the area it carries): check it, or use the next size up." +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.pitchDirection" -msgstr "坡向" +msgid "node.column.postSection.aSizeDeckPostStandsNo" +msgstr "{size} 平台立柱的高度不超过 {limit}(IRC Table R507.4,取决于树种及其承载面积):请复核,或改用大一号的尺寸。" +# Source-Hash: 9e9715d52410c86f # Review: required -# Source-Hash: 6c39ef7125494c4a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pitch Rise" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.pitchRise" -msgstr "坡度高差" +msgid "node.column.postSection.custom" +msgstr "自定义" +# Source-Hash: 31f74f6b8e7f077e # Review: required -# Source-Hash: 96336d4b0820b977 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rise Back" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit to the beam over it ({height})" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.riseBack" -msgstr "向后升高" +msgid "node.column.postSection.fitToTheBeamOverIt" +msgstr "贴合上方的梁({height})" +# Source-Hash: f09c0bf0ea50fc47 # Review: required -# Source-Hash: ee3d45f8b756d029 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rise Front" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit to the ceiling plane ({height})" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.riseFront" -msgstr "向前升高" +msgid "node.column.postSection.fitToTheCeilingPlane" +msgstr "贴合天花板平面({height})" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 5e0622f3b09c9326 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Height" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.roofHeight" -msgstr "屋顶高度" +msgid "node.column.postSection.height" +msgstr "高度" +# Source-Hash: b1778491849d76d6 # Review: required -# Source-Hash: 19ab9527ae7889f4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Type" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keep its shape and style it as a column" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.roofType" -msgstr "屋顶类型" +msgid "node.column.postSection.keepItsShapeAndStyleIt" +msgstr "保留其形状,并改用柱的样式" +# Source-Hash: 151f47e85cf7cc8b # Review: required -# Source-Hash: dba6a7b56cf7083f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Section" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Make it a column" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.section" -msgstr "部分" +msgid "node.column.postSection.makeItAColumn" +msgstr "转为柱" +# Source-Hash: 5cc981e79d737694 # Review: required -# Source-Hash: c8d0df27faa3feaa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.shed" -msgstr "单坡" +msgid "node.column.postSection.post" +msgstr "立柱" +# Source-Hash: 64ed304f3773f93d # Review: required -# Source-Hash: e0f973edce3e4ca8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Height" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Treated" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.wallHeight" -msgstr "墙高" +msgid "node.column.postSection.treated" +msgstr "防腐" +# Source-Hash: 5c362de43a2cbac1 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Untreated" +#: packages/nodes/src/column/post-section.tsx #, fuzzy -msgid "node.dormer.panel.width" -msgstr "宽度" +msgid "node.column.postSection.untreated" +msgstr "非防腐" +# Source-Hash: bf2baf3d7b55f0df # Review: required -# Source-Hash: 0b1d1e9a36456a50 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Windows" -#: packages/nodes/src/dormer/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A-Frame Support" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panel.windows" -msgstr "窗户" +msgid "node.column.preset.aFrameSupport" +msgstr "A 字支撑" +# Source-Hash: 51cf77bb359cee43 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/dormer/panel-actions-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight Round" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelActionsSection.actions" -msgstr "操作" +msgid "node.column.preset.basicPillar" +msgstr "直圆柱" +# Source-Hash: 39d33008c81fc075 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/dormer/panel-actions-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box Frame" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelActionsSection.delete" -msgstr "删除" +msgid "node.column.preset.boxFrameSupport" +msgstr "箱形框架" +# Source-Hash: 4f22058e862d1f81 # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/dormer/panel-actions-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Soft Bulged" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelActionsSection.duplicate" -msgstr "复制" +msgid "node.column.preset.bulgedPillar" +msgstr "微鼓形" +# Source-Hash: bb851e93088b73a2 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/dormer/panel-actions-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hourglass" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelActionsSection.move" -msgstr "移动" - +msgid "node.column.preset.hourglassPillar" +msgstr "沙漏形" + +# Source-Hash: 9cc75129edee59ad # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/dormer/panel-position-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "K Brace" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelPositionSection.position" -msgstr "位置" +msgid "node.column.preset.kBraceSupport" +msgstr "K 形支撑" +# Source-Hash: 0bf453b4882c663c # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/dormer/panel-position-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Portal Frame" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelPositionSection.rotation" -msgstr "旋转" +msgid "node.column.preset.portalFrameSupport" +msgstr "门式框架" +# Source-Hash: 9099890734ae1238 # Review: required -# Source-Hash: 7b19d21b9ad868c7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Window" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single Strut" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.addWindow" -msgstr "添加窗户" +msgid "node.column.preset.singleStrutSupport" +msgstr "单撑杆" +# Source-Hash: 0c13af329b9b57cd # Review: required -# Source-Hash: 70d7cc5a6422feaa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit {name}" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square Block" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.editNamed" -msgstr "编辑{name}" +msgid "node.column.preset.squarePillar" +msgstr "方柱" +# Source-Hash: 4c294bad84924665 # Review: required -# Source-Hash: b6648f023e6c83dc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit window" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tapered Round" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.editWindow" -msgstr "编辑窗户" +msgid "node.column.preset.taperedPillar" +msgstr "收分圆柱" +# Source-Hash: 360e405bfd74a379 # Review: required -# Source-Hash: 4649baf9753aeb74 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Increase the dormer width to add another window." -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trestle Frame" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.increaseTheDormerWidthToAdd" -msgstr "增加老虎窗宽度才能再添加一扇窗。" +msgid "node.column.preset.trestleSupport" +msgstr "支架框架" +# Source-Hash: 4589103259b4fc4d # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tripod Support" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.move" -msgstr "移动" +msgid "node.column.preset.tripodSupport" +msgstr "三脚支撑" +# Source-Hash: f24cc343d79acc10 # Review: required -# Source-Hash: c24226954309d83e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move {name}" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "V Support" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.moveNamed" -msgstr "移动{name}" +msgid "node.column.preset.vFrameSupport" +msgstr "V 形支撑" +# Source-Hash: 4e6640dfff42cea4 # Review: required -# Source-Hash: f07faaf0d5e43eef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move window" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "X Brace" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.moveWindow" -msgstr "移动窗户" +msgid "node.column.preset.xBraceSupport" +msgstr "X 形支撑" +# Source-Hash: 86259690e332b66d # Review: required -# Source-Hash: d2816490ea93d363 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No windows" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Y Support" +#: packages/nodes/src/column/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.noWindows" -msgstr "没有窗户" +msgid "node.column.preset.yFrameSupport" +msgstr "Y 形支撑" +# Source-Hash: 895766ad1b766c2e # Review: required -# Source-Hash: 5cbb24f8b1ce7fb7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Window {number}" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Associative linear, curved, circular, angular, or coordinate plan dimension." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.dormer.panelWindowsSection.windowNumber" -msgstr "窗户 {number}" +msgid "node.constructionDimension.description" +msgstr "关联的线性、曲线、圆形、角度或坐标平面尺寸。" +# Source-Hash: 6875b60ee8a7cc3b # Review: required -# Source-Hash: 9ca7d951240907cd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Windows ({length})" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Construction Dimension" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.dormer.panelWindowsSection.windowsLength" -msgstr "窗户({length})" +msgid "node.constructionDimension.label" +msgstr "施工尺寸" +# Source-Hash: 61a6c6b9bc29c4f8 # Review: required -# Source-Hash: f975c4759607806a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{face, select, back {Back} left {Left} right {Right} other {Front}} · {width} × {height} m" -#: packages/nodes/src/dormer/panel-windows-section.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Left" +#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.dormer.panelWindowsSection.windowSummary" -msgstr "{face, select, back {背面} left {左侧} right {右侧} other {正面}} · {width} × {height} m" +msgid "node.cornerRadius.bottomLeft" +msgstr "左下" -# Source-Hash: b46392d2ea865760 +# Source-Hash: c5368accab136fa6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical drop pipe from a gutter outlet to the ground." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom Right" +#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.downspout.description" -msgstr "从檐沟出水口到地面的竖向落水管。" +msgid "node.cornerRadius.bottomRight" +msgstr "右下" +# Source-Hash: c8f86af3f03af6c7 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/downspout/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Left" +#: packages/nodes/src/door/panel.tsx +#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.downspout.inspectorEditors.position" -msgstr "位置" +msgid "node.cornerRadius.topLeft" +msgstr "左上" -# Source-Hash: 1a1ec08a311f1b35 +# Source-Hash: 0ead7f1ffdbbd892 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspout" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Right" +#: packages/nodes/src/door/panel.tsx +#: packages/nodes/src/window/panel.tsx #, fuzzy -msgid "node.downspout.label" -msgstr "落水管" +msgid "node.cornerRadius.topRight" +msgstr "右上" -# Source-Hash: 29eadb8c84ae9632 +# Source-Hash: a276c9693f01dec7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elbow, tee, reducer, or square-to-round transition connecting duct runs." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Louvered roof lantern with a dome or pyramid cap and optional finial." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.ductFitting.description" -msgstr "连接风管的弯头、三通、变径或方圆变径。" +msgid "node.cupola.description" +msgstr "带百叶的屋顶亭,配圆顶或金字塔顶,可选尖顶饰。" +# Source-Hash: e679dd19f96eba0a # Review: required -# Source-Hash: 7323a0fc9efb077f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swap W/H" -#: packages/nodes/src/duct-fitting/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cupola" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.ductFitting.inspectorEditors.swapWH" -msgstr "交换宽/高" +msgid "node.cupola.label" +msgstr "穹顶亭" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 064b36c4fc5deb87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swap width and height" -#: packages/nodes/src/duct-fitting/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductFitting.inspectorEditors.swapWidthAndHeight" -msgstr "交换宽度和高度" +msgid "node.cupola.panel.actions" +msgstr "操作" -# Source-Hash: 6d0c3833d87535e4 +# Source-Hash: e679dd19f96eba0a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct Fitting" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cupola" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductFitting.label" -msgstr "风管配件" +msgid "node.cupola.panel.cupola" +msgstr "穹顶亭" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: dd86efcab72fc5c7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Axis" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductFitting.tool.axis" -msgstr "轴" +msgid "node.cupola.panel.delete" +msgstr "删除" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: 5232a826549f915e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "⌥ axis" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductFitting.tool.axis2" -msgstr "⌥ 轴" +msgid "node.cupola.panel.depth" +msgstr "深度" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: 880b34f6fc0ae854 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hover a duct face that fits the door" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductFitting.tool.hoverADuctFaceThatFits" -msgstr "悬停到可容纳检修门的风管面上" +msgid "node.cupola.panel.dimensions" +msgstr "尺寸" +# Source-Hash: de47e23eb81efe02 # Review: required -# Source-Hash: 706f5b43a1d4a84a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Place access door" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dome" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductFitting.tool.placeAccessDoor" -msgstr "放置检修门" +msgid "node.cupola.panel.dome" +msgstr "穹顶" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/duct-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductFitting.tool.rTRotate" -msgstr "R/T 旋转" +msgid "node.cupola.panel.duplicate" +msgstr "复制" -# Source-Hash: 09eb45a9b35d1a9f +# Source-Hash: 1cfe33235b30b1d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "HVAC duct run — polyline of round, rect, or flat-oval sections." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finial" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductSegment.description" -msgstr "暖通风管 — 由圆形、矩形或扁椭圆截面组成的折线。" +msgid "node.cupola.panel.finial" +msgstr "尖顶饰" -# Source-Hash: e971d82044e2f48e +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductSegment.label" -msgstr "风管" +msgid "node.cupola.panel.height" +msgstr "高度" -# Source-Hash: 33181d0f42421013 +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duct terminal — supply register, ceiling diffuser, or return grille. Duct runs end at its collar." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductTerminal.description" -msgstr "风口 — 送风口、散流器或回风格栅。风管在其接口处终止。" +msgid "node.cupola.panel.move" +msgstr "移动" -# Source-Hash: 161e5386b939e1bc +# Source-Hash: b5e0cb318d484d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Register" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No Finial" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductTerminal.label" -msgstr "风口" +msgid "node.cupola.panel.noFinial" +msgstr "无尖顶饰" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: 83c665eafcf43a68 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{mount, select, floor {Mount Floor} ceiling {Mount Ceiling} wall {Mount Wall} other {Mount {label}}}" -#: packages/nodes/src/duct-terminal/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductTerminal.tool.mount" -msgstr "{mount, select, floor {安装:地面} ceiling {安装:天花板} wall {安装:墙面} other {安装:{label}}}" +msgid "node.cupola.panel.position" +msgstr "位置" +# Source-Hash: 47587b825e9a696b # Review: required -# Source-Hash: f067dd52ea051385 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "M surface" -#. Key hint: pressing M switches the mounting surface. -#: packages/nodes/src/duct-terminal/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pyramid" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductTerminal.tool.mSurface" -msgstr "M 表面" +msgid "node.cupola.panel.pyramid" +msgstr "金字塔形" +# Source-Hash: 01989595ee7c1dc0 # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/duct-terminal/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductTerminal.tool.rTRotate" -msgstr "R/T 旋转" +msgid "node.cupola.panel.rotation" +msgstr "旋转" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: 98446855908ee71d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snapped to duct" -#: packages/nodes/src/duct-terminal/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.ductTerminal.tool.snappedToDuct" -msgstr "已吸附到风管" +msgid "node.cupola.panel.style" +msgstr "样式" -# Source-Hash: d0afa386e65cd3a4 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A multi-level elevator shaft with configurable openings per level." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/cupola/panel.tsx #, fuzzy -msgid "node.elevator.description" -msgstr "跨多个楼层的电梯井,每层开口可配置。" +msgid "node.cupola.panel.width" +msgstr "宽度" -# Source-Hash: ab5cbab7be160a1c +# Source-Hash: 5d4ccdf13668fab4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevator" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto elevator cutout" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.elevator.label" -msgstr "电梯" +msgid "node.cutout.autoElevator" +msgstr "自动电梯开洞" +# Source-Hash: 78aa03576e02dda7 # Review: required -# Source-Hash: 7e6d5f138e315bdb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Access" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto stair cutout" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.elevator.panel.access" -msgstr "通行" +msgid "node.cutout.autoStair" +msgstr "自动楼梯开洞" +# Source-Hash: e04298381837252f # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.elevator.panel.actions" -msgstr "操作" +msgid "node.cutout.opening" +msgstr "开口" +# Source-Hash: ce37dbd7a309940b # Review: required -# Source-Hash: fdf7108a011bd94b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cab" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Room cutout" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.elevator.panel.cab" -msgstr "轿厢" +msgid "node.cutout.room" +msgstr "房间开洞" +# Source-Hash: b1757d76048706b7 # Review: required -# Source-Hash: 2d0ab44f3820f22c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cab Height" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap hinge side" +#: packages/nodes/src/door/actions.tsx #, fuzzy -msgid "node.elevator.panel.cabHeight" -msgstr "轿厢高度" +msgid "node.door.actions.swapHingeSide" +msgstr "切换铰链侧" +# Source-Hash: d8bbb9fdf69726ca # Review: required -# Source-Hash: 65f410261609060b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center opening" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap swing side" +#: packages/nodes/src/door/actions.tsx #, fuzzy -msgid "node.elevator.panel.centerOpening" -msgstr "中开" +msgid "node.door.actions.swapSwingSide" +msgstr "切换开启方向" +# Source-Hash: 6123b20edb9569de # Review: required -# Source-Hash: c5433f4d3ea8a8a7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default Floor" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A door cut into a wall. Animated open/close state." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.elevator.panel.defaultFloor" -msgstr "默认楼层" +msgid "node.door.description" +msgstr "开在墙体上的门,带开关动画。" +# Source-Hash: 787e10f5db16904e # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.elevator.panel.delete" -msgstr "删除" +msgid "node.door.label" +msgstr "门" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.depth" -msgstr "深度" +msgid "node.door.panel.actions" +msgstr "操作" +# Source-Hash: 8337b3213849faca # Review: required -# Source-Hash: 748877ae309c313c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Destination" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "+ Add Segment" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.destination" -msgstr "目标" +msgid "node.door.panel.addSegment" +msgstr "+ 添加分段" +# Source-Hash: 663175a9c461a96d # Review: required -# Source-Hash: 3bff69bd74544339 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Disabled" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.disabled" -msgstr "已停用" +msgid "node.door.panel.all" +msgstr "全部" +# Source-Hash: 710261f5ffb32617 # Review: required -# Source-Hash: d8baf402fa9c52f0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Height" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arch" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.doorHeight" -msgstr "门高度" +msgid "node.door.panel.arch" +msgstr "拱形" +# Source-Hash: 3715cd54e4775087 # Review: required -# Source-Hash: 20f60b98de67849b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Doors" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arch Height" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.doors" -msgstr "门" +msgid "node.door.panel.archHeight" +msgstr "拱高" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: eb0d4023a513b16c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Time" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.doorTime" -msgstr "开门时间" +msgid "node.door.panel.auto" +msgstr "自动" +# Source-Hash: 8a04486ba122ea7d # Review: required -# Source-Hash: b3e001acdb1f869d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Type" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto follows the wall" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.doorType" -msgstr "门类型" +msgid "node.door.panel.autoFollowsTheWall" +msgstr "自动跟随墙体" +# Source-Hash: 387773c8aa2820a4 # Review: required -# Source-Hash: c6203a69fdf44065 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Door Width" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bar Height" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.doorWidth" -msgstr "门宽度" +msgid "node.door.panel.barHeight" +msgstr "横档高度" +# Source-Hash: 30edd1c180aac9b4 # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Columns" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.duplicate" -msgstr "复制" +msgid "node.door.panel.columns" +msgstr "列" +# Source-Hash: f533584833a4a7bb # Review: required -# Source-Hash: eb3abe5340b26138 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dwell" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Content Padding" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.dwell" -msgstr "停靠时间" +msgid "node.door.panel.contentPadding" +msgstr "内容边距" +# Source-Hash: 7a90a42b578f2435 # Review: required -# Source-Hash: ab5cbab7be160a1c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevator" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner Radius" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.elevator" -msgstr "电梯" +msgid "node.door.panel.cornerRadius" +msgstr "圆角半径" +# Source-Hash: aa0e8e02212091e4 # Review: required -# Source-Hash: 702140636ff3977a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "From" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom: the segments match no style." +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.from" -msgstr "起始" +msgid "node.door.panel.customTheSegmentsMatchNoStyle" +msgstr "自定义:分段不匹配任何样式。" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: 8ab91094cf650204 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.glass" -msgstr "玻璃" +msgid "node.door.panel.delete" +msgstr "删除" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: 88810658a2b97bc6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass frame" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.glassFrame" -msgstr "玻璃框" +msgid "node.door.panel.depth" +msgstr "深度" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: c0ff16d77ebc9593 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Motion" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.motion" -msgstr "运动" +msgid "node.door.panel.dimensions" +msgstr "尺寸" +# Source-Hash: 76cd03300faa9b2b # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Direction" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.move" -msgstr "移动" +msgid "node.door.panel.direction" +msgstr "方向" +# Source-Hash: c53c3307e2a2a32a # Review: required -# Source-Hash: 825ac8855353a4e1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening Style" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divider" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.openingStyle" -msgstr "开门方式" +msgid "node.door.panel.divider" +msgstr "分隔条" +# Source-Hash: 787e10f5db16904e # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.position" -msgstr "位置" +msgid "node.door.panel.door" +msgstr "门" +# Source-Hash: 4a0aa7f647e6461b # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Closer" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.rotation" -msgstr "旋转" +msgid "node.door.panel.doorCloser" +msgstr "闭门器" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: f9a95d8407fafda4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segmented panel" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.segmentedPanel" -msgstr "分段面板" +msgid "node.door.panel.duplicate" +msgstr "复制" +# Source-Hash: 65b1cbba3b92c5b2 # Review: required -# Source-Hash: aa7b49b13f96057f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Service" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Empty" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.service" -msgstr "服务" +msgid "node.door.panel.empty" +msgstr "空" +# Source-Hash: 6982301da2dbe186 # Review: required -# Source-Hash: 4fc63ad21de30103 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Enable Handle" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.shaft" -msgstr "井道" +msgid "node.door.panel.enableHandle" +msgstr "启用把手" +# Source-Hash: 2e96ebf9c6e7fe49 # Review: required -# Source-Hash: 6605ade39317cd42 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Depth" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Enable Threshold" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.shaftDepth" -msgstr "井道深度" +msgid "node.door.panel.enableThreshold" +msgstr "启用门槛" +# Source-Hash: 61f9413d3bbabde7 # Review: required -# Source-Hash: b28db5a3a48fe52e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Style" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip Side" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.shaftStyle" -msgstr "井道样式" +msgid "node.door.panel.flipSide" +msgstr "翻转方向" +# Source-Hash: 7e8fdd28f9d54d1f # Review: required -# Source-Hash: 3dab61aeb47e504d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shaft Width" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fold" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.shaftWidth" -msgstr "井道宽度" +msgid "node.door.panel.fold" +msgstr "折叠" +# Source-Hash: ce3a6c03765dbbd8 # Review: required -# Source-Hash: aee3b2bd78c87d0b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single left" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.singleLeft" -msgstr "单扇左开" +msgid "node.door.panel.frame" +msgstr "框架" +# Source-Hash: 0cce8ae784f78478 # Review: required -# Source-Hash: cc43ffbef4ac7ae0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single right" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth (auto)" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.singleRight" -msgstr "单扇右开" +msgid "node.door.panel.frameDepthAuto" +msgstr "深度(自动)" +# Source-Hash: 53aa825a4737190a # Review: required -# Source-Hash: ef3e765e692faf4c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Garage" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.solid" -msgstr "实体" +msgid "node.door.panel.garage" +msgstr "车库" +# Source-Hash: 8ab91094cf650204 # Review: required -# Source-Hash: 8008b6f17089beaf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid panel" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.solidPanel" -msgstr "实板" +msgid "node.door.panel.glass" +msgstr "玻璃" +# Source-Hash: 41483b645efc0c65 # Review: required -# Source-Hash: 3b006be0b1f0493f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Speed" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handle" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.speed" -msgstr "速度" +msgid "node.door.panel.handle" +msgstr "把手" +# Source-Hash: b4a496a904640583 # Review: required -# Source-Hash: 6d37a1679fa3708e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stop {stopOrder}" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handle Side" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.stopStoporder" -msgstr "停靠站 {stopOrder}" +msgid "node.door.panel.handleSide" +msgstr "把手侧" +# Source-Hash: 8c1bc3a078056ff7 # Review: required -# Source-Hash: b3214a20e45a7aed -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "To" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hardware" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.to" -msgstr "至" +msgid "node.door.panel.hardware" +msgstr "五金件" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: 1a5ccd607c400d76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Thickness" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.wallThickness" -msgstr "壁厚" +msgid "node.door.panel.height" +msgstr "高度" +# Source-Hash: 7c8f079bbefe86c9 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hinges Side" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.width" -msgstr "宽度" +msgid "node.door.panel.hingesSide" +msgstr "铰链侧" +# Source-Hash: ac9c79f08ef130a1 # Review: required -# Source-Hash: fefc9b1cfb26b5a8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Yaw" -#: packages/nodes/src/elevator/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Horizontal" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.elevator.panel.yaw" -msgstr "偏航" +msgid "node.door.panel.horizontal" +msgstr "水平" -# Source-Hash: 7b22c91cf520e161 +# Source-Hash: 42824e50de26bc14 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Low curved lens-shaped roof vent with a louvered front." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Individual" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.eyebrowVent.description" -msgstr "低矮的弧形透镜状屋顶通风口,前部带百叶。" +msgid "node.door.panel.individual" +msgstr "单独" -# Source-Hash: 654b29319185ac66 +# Source-Hash: 3db1dea825785a30 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Eyebrow Vent" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inset" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.eyebrowVent.label" -msgstr "眉形通风口" +msgid "node.door.panel.inset" +msgstr "内嵌" +# Source-Hash: 1f4ad5ad3e1be222 # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inward" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.actions" -msgstr "操作" +msgid "node.door.panel.inward" +msgstr "向内" +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# Source-Hash: abc97377800a8333 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back height" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.backHeight" -msgstr "后部高度" +msgid "node.door.panel.left" +msgstr "左" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.delete" -msgstr "删除" +msgid "node.door.panel.move" +msgstr "移动" +# Source-Hash: 3e52f04f92e08070 # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.depth" -msgstr "深度" +msgid "node.door.panel.open" +msgstr "打开" +# Source-Hash: e04298381837252f # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.dimensions" -msgstr "尺寸" +msgid "node.door.panel.opening" +msgstr "开口" +# Source-Hash: ecb81bd3eefa6a47 # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening Shape" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.duplicate" -msgstr "复制" +msgid "node.door.panel.openingShape" +msgstr "开洞形状" +# Source-Hash: ccd8f06b8f8d27c9 # Review: required -# Source-Hash: 654b29319185ac66 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Eyebrow Vent" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outward" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.eyebrowVent" -msgstr "眉形通风口" +msgid "node.door.panel.outward" +msgstr "向外" +# Source-Hash: 482469f5a0873f73 # Review: required -# Source-Hash: a2d107a5deaa01f4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Half-round" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.halfRound" -msgstr "半圆" +msgid "node.door.panel.panel" +msgstr "面板" +# Source-Hash: 6ce059aee1386f72 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panels" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.height" -msgstr "高度" +msgid "node.door.panel.panels" +msgstr "面板" +# Source-Hash: ad56a8ab82ff1a77 # Review: required -# Source-Hash: 318192f27a774fb7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Louvers" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panic Bar" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.louvers" -msgstr "百叶" +msgid "node.door.panel.panicBar" +msgstr "推杠锁" +# Source-Hash: ade6246634d93054 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pocket" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.move" -msgstr "移动" +msgid "node.door.panel.pocket" +msgstr "暗藏推拉门" -# Review: required # Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Position" -#: packages/nodes/src/eyebrow-vent/panel.tsx +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.position" +msgid "node.door.panel.position" msgstr "位置" +# Source-Hash: 947eacd2689daced # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rail" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.rotation" -msgstr "旋转" +msgid "node.door.panel.rail" +msgstr "横杆" +# Source-Hash: 3b6f225112035fde # Review: required -# Source-Hash: e16f85e4bebfefb1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scoop" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rect" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.scoop" -msgstr "勺形" +msgid "node.door.panel.rect" +msgstr "矩形" +# Source-Hash: c05172113af5a2b8 # Review: required -# Source-Hash: ec53d40877e11b62 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slant-box" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "- Remove" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.slantBox" -msgstr "斜箱" +msgid "node.door.panel.remove" +msgstr "- 移除" +# Source-Hash: 59236bd016c6b904 # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reveal Radius" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.style" -msgstr "样式" +msgid "node.door.panel.revealRadius" +msgstr "洞口圆角半径" +# Source-Hash: b34d5ee0f218221d # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/eyebrow-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.eyebrowVent.panel.width" -msgstr "宽度" +msgid "node.door.panel.right" +msgstr "右" -# Source-Hash: 20032fe9430f610d +# Source-Hash: fc826da6c99303e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A straight or curved fence segment with configurable posts and infill." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rounded" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fence.description" -msgstr "立柱和填充可配置的直线或曲线围栏段。" +msgid "node.door.panel.rounded" +msgstr "圆角" +# Source-Hash: 505d8419cf4cc5e1 # Review: required -# Source-Hash: 6f84b85097bc1ffc -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add point after" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segments" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.addPointAfter" -msgstr "在后面添加点" +msgid "node.door.panel.segments" +msgstr "分段" +# Source-Hash: a8096eb4beaadeef # Review: required -# Source-Hash: 1a15ab3101e2d166 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a slab or shaped surface on this level." -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Size is limited to the wall, including clearance for the opening frame." +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.chooseASlabOrShapedSurface" -msgstr "请在此楼层选择一块楼板或造型表面。" +msgid "node.door.panel.sizeIsLimitedToTheWall" +msgstr "尺寸受墙体限制,包括洞口框的间隙。" +# Source-Hash: c00de0e2c9b0ddcb # Review: required -# Source-Hash: 78a5625401384000 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a surface" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slide" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.chooseASurface" -msgstr "选择表面" +msgid "node.door.panel.slide" +msgstr "推拉" +# Source-Hash: 1a79a485d91f3f28 # Review: required -# Source-Hash: 2ee121dca87bb64a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Corner" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.corner" -msgstr "转角" +msgid "node.door.panel.style" +msgstr "样式" +# Source-Hash: e48604b5f7b2a5f4 # Review: required -# Source-Hash: f08fbb462e9afc0e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curve" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swing" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.curve" -msgstr "曲线" +msgid "node.door.panel.swing" +msgstr "平开" +# Source-Hash: fdbb503f0941bd56 # Review: required -# Source-Hash: a028e08962c388e0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curved" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.curved" -msgstr "弧形" +msgid "node.door.panel.thickness" +msgstr "厚度" +# Source-Hash: f165d6c05be2b651 # Review: required -# Source-Hash: 81b75058b7843a0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{style, select, picket {Distribution controls pickets in each bay between posts.} horizontal {Distribution controls posts along the full fence.} other {Distribution controls infill pieces between the two end posts.}} Spacing is measured between centers. The available width limits the count so pieces do not overlap." -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Threshold" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.distributionInfo" -msgstr "{style, select, picket {分布控制各柱间开间内的栅条。} horizontal {分布控制整段围栏上的立柱。} other {分布控制两端立柱之间的填充件。}}间距按中心计算。可用宽度会限制数量,避免构件重叠。" +msgid "node.door.panel.threshold" +msgstr "门槛" +# Source-Hash: 7e2505dd1d5e3513 # Review: required -# Source-Hash: fbc8f54b0e3fdeb1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit path" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Shape" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.editPath" -msgstr "编辑路径" +msgid "node.door.panel.topShape" +msgstr "顶部形状" +# Source-Hash: c44f7ab8bbd24858 # Review: required -# Source-Hash: 55686db44529c013 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Extend path" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.extendPath" -msgstr "延长路径" +msgid "node.door.panel.type" +msgstr "类型" +# Source-Hash: 8038a34ffebf4932 # Review: required -# Source-Hash: 0bf0f27e631aa98d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follow highest surface" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.followHighestSurface" -msgstr "跟随最高表面" +msgid "node.door.panel.vertical" +msgstr "垂直" +# Source-Hash: 63d6b766151965f9 # Review: required -# Source-Hash: e0b381fcb05a65c4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follow selected surface" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "wall" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.followSelectedSurface" -msgstr "跟随所选表面" +msgid "node.door.panel.wall" +msgstr "墙体" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: c418d97f803af8dd -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hold starting height" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.holdStartingHeight" -msgstr "保持起始高度" +msgid "node.door.panel.width" +msgstr "宽度" +# Source-Hash: 8421deea35cb5afc # Review: required -# Source-Hash: 295ca9336dc1935b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Join" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Barn" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.fence.inspectorEditors.join" -msgstr "连接" +msgid "node.door.style.barn" +msgstr "谷仓门" +# Source-Hash: f747fbe71717772e # Review: required -# Source-Hash: 643687bc3adaac76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Craftsman" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.fence.inspectorEditors.length" -msgstr "长度" +msgid "node.door.style.craftsman" +msgstr "工匠风" +# Source-Hash: 092033938ca2debb # Review: required -# Source-Hash: 1fedc8a2f2ea6887 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{count, plural, one {{number} point} other {{number} points}} · {length} m" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "French" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.fence.inspectorEditors.pathSummary" -msgstr "{count, plural, other {{number} 个点}} · {length} m" +msgid "node.door.style.french" +msgstr "法式门" +# Source-Hash: 8ab91094cf650204 # Review: required -# Source-Hash: c96d499e11181429 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket rail projection" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.fence.inspectorEditors.picketRailProjection" -msgstr "栅条相对横杆的凸出" +msgid "node.door.style.glass" +msgstr "玻璃" +# Source-Hash: 6ab8b98b38eb2e65 # Review: required -# Source-Hash: a1880fca8372d06f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Point" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Half-louvered" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.fence.inspectorEditors.point" -msgstr "点" +msgid "node.door.style.halfLouvered" +msgstr "半百叶" +# Source-Hash: f6cbdaa17e989b91 # Review: required -# Source-Hash: 39bc6254b5307f53 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove point" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Modern" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.fence.inspectorEditors.removePoint" -msgstr "移除点" +msgid "node.door.style.modern" +msgstr "现代" +# Source-Hash: 482469f5a0873f73 # Review: required -# Source-Hash: ea56af3a0d7a65e4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set each span to straight or curved, then drag its points and curve handles in either view." -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.fence.inspectorEditors.setEachSpanToStraightOr" -msgstr "将每段设为直线或曲线,然后在任一视图中拖动其点和曲线控制柄。" +msgid "node.door.style.panel" +msgstr "面板" +# Source-Hash: ac42c328610a0edd # Review: required -# Source-Hash: 354c8bc5c8da5a6e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Smooth" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Paneled glass" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.fence.inspectorEditors.smooth" -msgstr "平滑" +msgid "node.door.style.paneledGlass" +msgstr "镶板玻璃" +# Source-Hash: 5b68e435b7210876 # Review: required -# Source-Hash: 3c700cc1299a150f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Span to point {number}" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaker" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.fence.inspectorEditors.spanToPointNumber" -msgstr "至点 {number} 的分段" +msgid "node.door.style.shaker" +msgstr "夏克风" +# Source-Hash: 9ad6ac42b4152b64 # Review: required -# Source-Hash: 4ee35f740730ae87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Six-panel" +#: packages/nodes/src/shared/opening-labels.ts #, fuzzy -msgid "node.fence.inspectorEditors.straight" -msgstr "直跑" +msgid "node.door.style.sixPanel" +msgstr "六镶板" +# Source-Hash: 8421deea35cb5afc # Review: required -# Source-Hash: 78a454b7ac7a3cd9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Barn" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.surface" -msgstr "表面" +msgid "node.door.type.barn" +msgstr "谷仓门" +# Source-Hash: 3cd71355956a1821 # Review: required -# Source-Hash: ab2de0428c093018 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface behavior" -#: packages/nodes/src/fence/inspector-editors.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fence.inspectorEditors.surfaceBehavior" -msgstr "表面行为" +msgid "node.door.type.double" +msgstr "双扇" -# Source-Hash: 02042fde61b5aa11 +# Source-Hash: 29ff60e662b789fb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fence" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Folding" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fence.label" -msgstr "围栏" +msgid "node.door.type.folding" +msgstr "折叠门" +# Source-Hash: 092033938ca2debb # Review: required -# Source-Hash: 3e07a9889c1bd7f9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Detach endpoint" -#: packages/nodes/src/fence/move-endpoint-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "French" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fence.moveEndpointTool.detachEndpoint" -msgstr "分离端点" +msgid "node.door.type.french" +msgstr "法式门" +# Source-Hash: c86309fefe89699b # Review: required -# Source-Hash: 7a3ce9fec6370e3e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag endpoint" -#: packages/nodes/src/fence/move-endpoint-tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roll-up" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fence.moveEndpointTool.dragEndpoint" -msgstr "拖动端点" +msgid "node.door.type.garageRollup" +msgstr "卷帘门" +# Source-Hash: fb6a868430547544 # Review: required -# Source-Hash: d7cf5045c01b2eb9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close" -#: packages/nodes/src/fence-feature/actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sectional" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fenceFeature.actions.close" -msgstr "关闭" +msgid "node.door.type.garageSectional" +msgstr "分节门" +# Source-Hash: 0b5eb64b569db837 # Review: required -# Source-Hash: 3e52f04f92e08070 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/fence-feature/actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilt-up" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fenceFeature.actions.open" -msgstr "打开" +msgid "node.door.type.garageTiltup" +msgstr "翻板门" +# Source-Hash: e744be60baad6abc # Review: required -# Source-Hash: fc4cf2bc034fc547 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Board width" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hinged" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.boardWidth" -msgstr "板宽" +msgid "node.door.type.hinged" +msgstr "平开门" +# Source-Hash: ade6246634d93054 # Review: required -# Source-Hash: f3b11e5b2dd3b25f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bracing" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pocket" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.bracing" -msgstr "斜撑" +msgid "node.door.type.pocket" +msgstr "暗藏推拉门" +# Source-Hash: 18cbc73c5e1590aa # Review: required -# Source-Hash: d09ec3d9565734c3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Distance from start" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sliding" +#: packages/nodes/src/door/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.distanceFromStart" -msgstr "距起点距离" +msgid "node.door.type.sliding" +msgstr "推拉门" +# Source-Hash: 387e57242c8d110a # Review: required -# Source-Hash: dcd803eaf3796298 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fence unavailable." -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "House-shaped protrusion on a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.fenceUnavailable" -msgstr "围栏不可用。" +msgid "node.dormer.description" +msgstr "屋面上的房屋形凸出部分。" +# Source-Hash: 6b6f8068bbc4c902 # Review: required -# Source-Hash: 3519d91b7bda18a5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame width" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dormer" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.fenceFeature.inspector.frameWidth" -msgstr "框架宽度" +msgid "node.dormer.label" +msgstr "老虎窗" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: cb18554b2420e700 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gate height" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.gateHeight" -msgstr "门高度" +msgid "node.dormer.panel.depth" +msgstr "深度" +# Source-Hash: 12df69f42beb0643 # Review: required -# Source-Hash: 54098b5ee574737a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gate style" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.gateStyle" -msgstr "大门样式" +msgid "node.dormer.panel.dimensions" +msgstr "尺寸" +# Source-Hash: 6b6f8068bbc4c902 # Review: required -# Source-Hash: 4fc3e60be28f60d5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ground clearance" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dormer" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.groundClearance" -msgstr "离地间隙" +msgid "node.dormer.panel.dormer" +msgstr "老虎窗" +# Source-Hash: 6949d667043bee0b # Review: required -# Source-Hash: 916f2e07bf082795 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hinges and latch" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.hingesAndLatch" -msgstr "铰链与门闩" +msgid "node.dormer.panel.dutch" +msgstr "荷兰式" +# Source-Hash: 9cab4d4c95f63cdd # Review: required -# Source-Hash: 5bd2e597fbb2a2c9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hinge side" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.hingeSide" -msgstr "铰链侧" +msgid "node.dormer.panel.flat" +msgstr "平屋顶" +# Source-Hash: deaffa095d126dfe # Review: required -# Source-Hash: 8fec7e969045a8e7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Horizontal boards" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.horizontalBoards" -msgstr "横向板条" +msgid "node.dormer.panel.gable" +msgstr "双坡" +# Source-Hash: 7f53d9ffca39984a # Review: required -# Source-Hash: f4addad87cc4223e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Infill spacing" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.infillSpacing" -msgstr "填充间距" +msgid "node.dormer.panel.gambrel" +msgstr "复折式" +# Source-Hash: 9eda0ea8d447066d # Review: required -# Source-Hash: cdec08b292742b20 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Jamb posts" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hip" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.jambPosts" -msgstr "门框立柱" +msgid "node.dormer.panel.hip" +msgstr "四坡" +# Source-Hash: 7f7bb0e875af3260 # Review: required -# Source-Hash: ef88410453ee7414 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Keep the opening inside the fence and clear of other gates or passages." -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.keepTheOpeningInsideTheFence" -msgstr "请将开口保持在围栏内,并避开其他门或通道。" +msgid "node.dormer.panel.mansard" +msgstr "孟莎式" +# Source-Hash: 53af9efc7eca6594 # Review: required -# Source-Hash: 67cd0171b226fedb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Leaf thickness" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pitch Direction" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.leafThickness" -msgstr "门扇厚度" +msgid "node.dormer.panel.pitchDirection" +msgstr "坡向" +# Source-Hash: 6c39ef7125494c4a # Review: required -# Source-Hash: c390ba248e629b9e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Leaves" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pitch Rise" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.leaves" -msgstr "门扇" +msgid "node.dormer.panel.pitchRise" +msgstr "坡度高差" +# Source-Hash: 96336d4b0820b977 # Review: required -# Source-Hash: d7bb934589475512 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left leaf proportion" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rise Back" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.leftLeafProportion" -msgstr "左门扇比例" +msgid "node.dormer.panel.riseBack" +msgstr "向后升高" +# Source-Hash: ee3d45f8b756d029 # Review: required -# Source-Hash: aa9fe0ebace8957d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match fence height" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rise Front" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.matchFenceHeight" -msgstr "与围栏同高" +msgid "node.dormer.panel.riseFront" +msgstr "向前升高" +# Source-Hash: 5e0622f3b09c9326 # Review: required -# Source-Hash: c15c1af69ec5c1eb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Match fence style" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Height" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.matchFenceStyle" -msgstr "匹配围栏样式" +msgid "node.dormer.panel.roofHeight" +msgstr "屋顶高度" +# Source-Hash: 19ab9527ae7889f4 # Review: required -# Source-Hash: 51b7ab6a0a78d90a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening angle" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Type" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.openingAngle" -msgstr "开启角度" +msgid "node.dormer.panel.roofType" +msgstr "屋顶类型" +# Source-Hash: dba6a7b56cf7083f # Review: required -# Source-Hash: d2e20300c07aa722 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening width" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Section" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.openingWidth" -msgstr "开口宽度" +msgid "node.dormer.panel.section" +msgstr "部分" +# Source-Hash: c8d0df27faa3feaa # Review: required -# Source-Hash: 6b108fb1d0eb8f9d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open rails" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.openRails" -msgstr "开放栏杆" +msgid "node.dormer.panel.shed" +msgstr "单坡" +# Source-Hash: e0f973edce3e4ca8 # Review: required -# Source-Hash: d500c4b7827d3390 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cross" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall Height" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.cross" -msgstr "十字" +msgid "node.dormer.panel.wallHeight" +msgstr "墙高" +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# Source-Hash: 7420c0d2caee1c22 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diagonal" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.diagonal" -msgstr "斜撑" +msgid "node.dormer.panel.width" +msgstr "宽度" +# Source-Hash: 0b1d1e9a36456a50 # Review: required -# Source-Hash: 7308869944020839 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Double gate" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Windows" +#: packages/nodes/src/dormer/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.doubleGate" -msgstr "双开大门" +msgid "node.dormer.panel.windows" +msgstr "窗户" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 1f4ad5ad3e1be222 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inward" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/dormer/panel-actions-section.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.inward" -msgstr "向内" +msgid "node.dormer.panelActionsSection.actions" +msgstr "操作" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: f365c6b6dd9ebab9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/dormer/panel-actions-section.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.left" -msgstr "左" +msgid "node.dormer.panelActionsSection.delete" +msgstr "删除" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: f2953d2931e36d0c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/dormer/panel-actions-section.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.none" -msgstr "无" +msgid "node.dormer.panelActionsSection.duplicate" +msgstr "复制" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: ccd8f06b8f8d27c9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Outward" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/dormer/panel-actions-section.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.outward" -msgstr "向外" +msgid "node.dormer.panelActionsSection.move" +msgstr "移动" +# Source-Hash: 9da0cbfad144d737 # Review: required -# Source-Hash: b34d5ee0f218221d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/dormer/panel-position-section.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.right" -msgstr "右" +msgid "node.dormer.panelPositionSection.position" +msgstr "位置" +# Source-Hash: 01989595ee7c1dc0 # Review: required -# Source-Hash: d327097d9ac1099f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Single gate" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/dormer/panel-position-section.tsx #, fuzzy -msgid "node.fenceFeature.inspector.option.singleGate" -msgstr "单开大门" +msgid "node.dormer.panelPositionSection.rotation" +msgstr "旋转" +# Source-Hash: 7b19d21b9ad868c7 # Review: required -# Source-Hash: 9295ddc2805b21e2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Picket" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Window" +#: packages/nodes/src/dormer/panel-windows-section.tsx #, fuzzy -msgid "node.fenceFeature.inspector.picket" -msgstr "尖桩" +msgid "node.dormer.panelWindowsSection.addWindow" +msgstr "添加窗户" +# Source-Hash: 70d7cc5a6422feaa # Review: required -# Source-Hash: 8dd5999b235f60ab -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit {name}" +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.editNamed" +msgstr "编辑{name}" + +# Source-Hash: b6648f023e6c83dc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit window" +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.editWindow" +msgstr "编辑窗户" + +# Source-Hash: 4649baf9753aeb74 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Increase the dormer width to add another window." +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.increaseTheDormerWidthToAdd" +msgstr "增加老虎窗宽度才能再添加一扇窗。" + +# Source-Hash: bd02c614454fbd2b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.move" +msgstr "移动" + +# Source-Hash: c24226954309d83e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move {name}" +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.moveNamed" +msgstr "移动{name}" + +# Source-Hash: f07faaf0d5e43eef +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move window" +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.moveWindow" +msgstr "移动窗户" + +# Source-Hash: d2816490ea93d363 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No windows" +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.noWindows" +msgstr "没有窗户" + +# Source-Hash: 5cbb24f8b1ce7fb7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Window {number}" +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.windowNumber" +msgstr "窗户 {number}" + +# Source-Hash: 9ca7d951240907cd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Windows ({length})" +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.windowsLength" +msgstr "窗户({length})" + +# Source-Hash: f975c4759607806a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{face, select, back {Back} left {Left} right {Right} other {Front}} · {width} × {height} m" +#: packages/nodes/src/dormer/panel-windows-section.tsx +#, fuzzy +msgid "node.dormer.panelWindowsSection.windowSummary" +msgstr "{face, select, back {背面} left {左侧} right {右侧} other {正面}} · {width} × {height} m" + +# Source-Hash: b46392d2ea865760 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical drop pipe from a gutter outlet to the ground." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.downspout.description" +msgstr "从檐沟出水口到地面的竖向落水管。" + +# Source-Hash: 9da0cbfad144d737 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/downspout/inspector-editors.tsx +#, fuzzy +msgid "node.downspout.inspectorEditors.position" +msgstr "位置" + +# Source-Hash: 1a1ec08a311f1b35 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspout" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.downspout.label" +msgstr "落水管" + +# Source-Hash: 29eadb8c84ae9632 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elbow, tee, reducer, or square-to-round transition connecting duct runs." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.ductFitting.description" +msgstr "连接风管的弯头、三通、变径或方圆变径。" + +# Source-Hash: 7323a0fc9efb077f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap W/H" +#: packages/nodes/src/duct-fitting/inspector-editors.tsx +#, fuzzy +msgid "node.ductFitting.inspectorEditors.swapWH" +msgstr "交换宽/高" + +# Source-Hash: 064b36c4fc5deb87 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap width and height" +#: packages/nodes/src/duct-fitting/inspector-editors.tsx +#, fuzzy +msgid "node.ductFitting.inspectorEditors.swapWidthAndHeight" +msgstr "交换宽度和高度" + +# Source-Hash: 6d0c3833d87535e4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct Fitting" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.ductFitting.label" +msgstr "风管配件" + +# Source-Hash: dd86efcab72fc5c7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Axis" +#: packages/nodes/src/duct-fitting/tool.tsx +#, fuzzy +msgid "node.ductFitting.tool.axis" +msgstr "轴" + +# Source-Hash: 5232a826549f915e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "⌥ axis" +#: packages/nodes/src/duct-fitting/tool.tsx +#, fuzzy +msgid "node.ductFitting.tool.axis2" +msgstr "⌥ 轴" + +# Source-Hash: 880b34f6fc0ae854 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hover a duct face that fits the door" +#: packages/nodes/src/duct-fitting/tool.tsx +#, fuzzy +msgid "node.ductFitting.tool.hoverADuctFaceThatFits" +msgstr "悬停到可容纳检修门的风管面上" + +# Source-Hash: 706f5b43a1d4a84a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Place access door" +#: packages/nodes/src/duct-fitting/tool.tsx +#, fuzzy +msgid "node.ductFitting.tool.placeAccessDoor" +msgstr "放置检修门" + +# Source-Hash: 8fb180251a321cef +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/duct-fitting/tool.tsx +#, fuzzy +msgid "node.ductFitting.tool.rTRotate" +msgstr "R/T 旋转" + +# Source-Hash: 09eb45a9b35d1a9f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "HVAC duct run — polyline of round, rect, or flat-oval sections." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.ductSegment.description" +msgstr "暖通风管 — 由圆形、矩形或扁椭圆截面组成的折线。" + +# Source-Hash: e971d82044e2f48e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.ductSegment.label" +msgstr "风管" + +# Source-Hash: 33181d0f42421013 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duct terminal — supply register, ceiling diffuser, or return grille. Duct runs end at its collar." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.ductTerminal.description" +msgstr "风口 — 送风口、散流器或回风格栅。风管在其接口处终止。" + +# Source-Hash: 161e5386b939e1bc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Register" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.ductTerminal.label" +msgstr "风口" + +# Source-Hash: 83c665eafcf43a68 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{mount, select, floor {Mount Floor} ceiling {Mount Ceiling} wall {Mount Wall} other {Mount {label}}}" +#: packages/nodes/src/duct-terminal/tool.tsx +#, fuzzy +msgid "node.ductTerminal.tool.mount" +msgstr "{mount, select, floor {安装:地面} ceiling {安装:天花板} wall {安装:墙面} other {安装:{label}}}" + +# Source-Hash: f067dd52ea051385 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "M surface" +#. Key hint: pressing M switches the mounting surface. +#: packages/nodes/src/duct-terminal/tool.tsx +#, fuzzy +msgid "node.ductTerminal.tool.mSurface" +msgstr "M 表面" + +# Source-Hash: 8fb180251a321cef +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/duct-terminal/tool.tsx +#, fuzzy +msgid "node.ductTerminal.tool.rTRotate" +msgstr "R/T 旋转" + +# Source-Hash: 98446855908ee71d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snapped to duct" +#: packages/nodes/src/duct-terminal/tool.tsx +#, fuzzy +msgid "node.ductTerminal.tool.snappedToDuct" +msgstr "已吸附到风管" + +# Source-Hash: d0afa386e65cd3a4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A multi-level elevator shaft with configurable openings per level." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.elevator.description" +msgstr "跨多个楼层的电梯井,每层开口可配置。" + +# Source-Hash: ab5cbab7be160a1c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevator" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.elevator.label" +msgstr "电梯" + +# Source-Hash: 7e6d5f138e315bdb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Access" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.access" +msgstr "通行" + +# Source-Hash: aa6d82bdb3cc1d9a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.actions" +msgstr "操作" + +# Source-Hash: fdf7108a011bd94b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cab" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.cab" +msgstr "轿厢" + +# Source-Hash: 2d0ab44f3820f22c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cab Height" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.cabHeight" +msgstr "轿厢高度" + +# Source-Hash: 65f410261609060b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center opening" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.centerOpening" +msgstr "中开" + +# Source-Hash: c5433f4d3ea8a8a7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default Floor" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.defaultFloor" +msgstr "默认楼层" + +# Source-Hash: b26de372b4b0eaac +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.delete" +msgstr "删除" + +# Source-Hash: 99ac4d03c3061f3a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.depth" +msgstr "深度" + +# Source-Hash: 748877ae309c313c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Destination" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.destination" +msgstr "目标" + +# Source-Hash: 3bff69bd74544339 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Disabled" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.disabled" +msgstr "已停用" + +# Source-Hash: d8baf402fa9c52f0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Height" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.doorHeight" +msgstr "门高度" + +# Source-Hash: 20f60b98de67849b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Doors" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.doors" +msgstr "门" + +# Source-Hash: eb0d4023a513b16c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Time" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.doorTime" +msgstr "开门时间" + +# Source-Hash: b3e001acdb1f869d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Type" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.doorType" +msgstr "门类型" + +# Source-Hash: c6203a69fdf44065 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Door Width" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.doorWidth" +msgstr "门宽度" + +# Source-Hash: 34dc96fe77a31e51 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.duplicate" +msgstr "复制" + +# Source-Hash: eb3abe5340b26138 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dwell" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.dwell" +msgstr "停靠时间" + +# Source-Hash: ab5cbab7be160a1c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevator" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.elevator" +msgstr "电梯" + +# Source-Hash: 702140636ff3977a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "From" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.from" +msgstr "起始" + +# Source-Hash: 8ab91094cf650204 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.glass" +msgstr "玻璃" + +# Source-Hash: 88810658a2b97bc6 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass frame" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.glassFrame" +msgstr "玻璃框" + +# Source-Hash: c0ff16d77ebc9593 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Motion" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.motion" +msgstr "运动" + +# Source-Hash: bd02c614454fbd2b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.move" +msgstr "移动" + +# Source-Hash: 825ac8855353a4e1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening Style" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.openingStyle" +msgstr "开门方式" + +# Source-Hash: 9da0cbfad144d737 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.position" +msgstr "位置" + +# Source-Hash: 01989595ee7c1dc0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.rotation" +msgstr "旋转" + +# Source-Hash: f9a95d8407fafda4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segmented panel" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.segmentedPanel" +msgstr "分段面板" + +# Source-Hash: aa7b49b13f96057f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Service" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.service" +msgstr "服务" + +# Source-Hash: 4fc63ad21de30103 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.shaft" +msgstr "井道" + +# Source-Hash: 6605ade39317cd42 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Depth" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.shaftDepth" +msgstr "井道深度" + +# Source-Hash: b28db5a3a48fe52e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Style" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.shaftStyle" +msgstr "井道样式" + +# Source-Hash: 3dab61aeb47e504d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shaft Width" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.shaftWidth" +msgstr "井道宽度" + +# Source-Hash: aee3b2bd78c87d0b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single left" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.singleLeft" +msgstr "单扇左开" + +# Source-Hash: cc43ffbef4ac7ae0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single right" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.singleRight" +msgstr "单扇右开" + +# Source-Hash: ef3e765e692faf4c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.solid" +msgstr "实体" + +# Source-Hash: 8008b6f17089beaf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid panel" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.solidPanel" +msgstr "实板" + +# Source-Hash: 3b006be0b1f0493f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Speed" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.speed" +msgstr "速度" + +# Source-Hash: 6d37a1679fa3708e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stop {stopOrder}" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.stopStoporder" +msgstr "停靠站 {stopOrder}" + +# Source-Hash: b3214a20e45a7aed +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "To" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.to" +msgstr "至" + +# Source-Hash: 1a5ccd607c400d76 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall Thickness" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.wallThickness" +msgstr "壁厚" + +# Source-Hash: 3a0ccd6c46877a87 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.width" +msgstr "宽度" + +# Source-Hash: fefc9b1cfb26b5a8 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Yaw" +#: packages/nodes/src/elevator/panel.tsx +#, fuzzy +msgid "node.elevator.panel.yaw" +msgstr "偏航" + +# Source-Hash: 7b22c91cf520e161 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Low curved lens-shaped roof vent with a louvered front." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.eyebrowVent.description" +msgstr "低矮的弧形透镜状屋顶通风口,前部带百叶。" + +# Source-Hash: 654b29319185ac66 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eyebrow Vent" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.eyebrowVent.label" +msgstr "眉形通风口" + +# Source-Hash: aa6d82bdb3cc1d9a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.actions" +msgstr "操作" + +# Source-Hash: abc97377800a8333 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back height" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.backHeight" +msgstr "后部高度" + +# Source-Hash: b26de372b4b0eaac +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.delete" +msgstr "删除" + +# Source-Hash: 99ac4d03c3061f3a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.depth" +msgstr "深度" + +# Source-Hash: 12df69f42beb0643 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.dimensions" +msgstr "尺寸" + +# Source-Hash: 34dc96fe77a31e51 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.duplicate" +msgstr "复制" + +# Source-Hash: 654b29319185ac66 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eyebrow Vent" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.eyebrowVent" +msgstr "眉形通风口" + +# Source-Hash: a2d107a5deaa01f4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Half-round" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.halfRound" +msgstr "半圆" + +# Source-Hash: 646ef0fbcbc58edf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.height" +msgstr "高度" + +# Source-Hash: 318192f27a774fb7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Louvers" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.louvers" +msgstr "百叶" + +# Source-Hash: bd02c614454fbd2b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.move" +msgstr "移动" + +# Source-Hash: 9da0cbfad144d737 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.position" +msgstr "位置" + +# Source-Hash: 01989595ee7c1dc0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.rotation" +msgstr "旋转" + +# Source-Hash: e16f85e4bebfefb1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scoop" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.scoop" +msgstr "勺形" + +# Source-Hash: ec53d40877e11b62 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slant-box" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.slantBox" +msgstr "斜箱" + +# Source-Hash: 1a79a485d91f3f28 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.style" +msgstr "样式" + +# Source-Hash: 3a0ccd6c46877a87 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/eyebrow-vent/panel.tsx +#, fuzzy +msgid "node.eyebrowVent.panel.width" +msgstr "宽度" + +# Source-Hash: 20032fe9430f610d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A straight or curved fence segment with configurable posts and infill." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.fence.description" +msgstr "立柱和填充可配置的直线或曲线围栏段。" + +# Source-Hash: 6f84b85097bc1ffc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add point after" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.addPointAfter" +msgstr "在后面添加点" + +# Source-Hash: 1a15ab3101e2d166 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a slab or shaped surface on this level." +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.chooseASlabOrShapedSurface" +msgstr "请在此楼层选择一块楼板或造型表面。" + +# Source-Hash: 78a5625401384000 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a surface" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.chooseASurface" +msgstr "选择表面" + +# Source-Hash: 2ee121dca87bb64a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Corner" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.corner" +msgstr "转角" + +# Source-Hash: f08fbb462e9afc0e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curve" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.curve" +msgstr "曲线" + +# Source-Hash: a028e08962c388e0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curved" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.curved" +msgstr "弧形" + +# Source-Hash: 81b75058b7843a0c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{style, select, picket {Distribution controls pickets in each bay between posts.} horizontal {Distribution controls posts along the full fence.} other {Distribution controls infill pieces between the two end posts.}} Spacing is measured between centers. The available width limits the count so pieces do not overlap." +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.distributionInfo" +msgstr "{style, select, picket {分布控制各柱间开间内的栅条。} horizontal {分布控制整段围栏上的立柱。} other {分布控制两端立柱之间的填充件。}}间距按中心计算。可用宽度会限制数量,避免构件重叠。" + +# Source-Hash: fbc8f54b0e3fdeb1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit path" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.editPath" +msgstr "编辑路径" + +# Source-Hash: 55686db44529c013 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Extend path" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.extendPath" +msgstr "延长路径" + +# Source-Hash: 0bf0f27e631aa98d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow highest surface" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.followHighestSurface" +msgstr "跟随最高表面" + +# Source-Hash: e0b381fcb05a65c4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow selected surface" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.followSelectedSurface" +msgstr "跟随所选表面" + +# Source-Hash: c418d97f803af8dd +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hold starting height" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.holdStartingHeight" +msgstr "保持起始高度" + +# Source-Hash: 295ca9336dc1935b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Join" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.join" +msgstr "连接" + +# Source-Hash: 643687bc3adaac76 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.length" +msgstr "长度" + +# Source-Hash: 1fedc8a2f2ea6887 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {{number} point} other {{number} points}} · {length} m" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.pathSummary" +msgstr "{count, plural, other {{number} 个点}} · {length} m" + +# Source-Hash: c96d499e11181429 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket rail projection" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.picketRailProjection" +msgstr "栅条相对横杆的凸出" + +# Source-Hash: a1880fca8372d06f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Point" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.point" +msgstr "点" + +# Source-Hash: 39bc6254b5307f53 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove point" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.removePoint" +msgstr "移除点" + +# Source-Hash: ea56af3a0d7a65e4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set each span to straight or curved, then drag its points and curve handles in either view." +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.setEachSpanToStraightOr" +msgstr "将每段设为直线或曲线,然后在任一视图中拖动其点和曲线控制柄。" + +# Source-Hash: 354c8bc5c8da5a6e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Smooth" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.smooth" +msgstr "平滑" + +# Source-Hash: 3c700cc1299a150f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Span to point {number}" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.spanToPointNumber" +msgstr "至点 {number} 的分段" + +# Source-Hash: 4ee35f740730ae87 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.straight" +msgstr "直跑" + +# Source-Hash: 78a454b7ac7a3cd9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.surface" +msgstr "表面" + +# Source-Hash: ab2de0428c093018 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface behavior" +#: packages/nodes/src/fence/inspector-editors.tsx +#, fuzzy +msgid "node.fence.inspectorEditors.surfaceBehavior" +msgstr "表面行为" + +# Source-Hash: 02042fde61b5aa11 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fence" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.fence.label" +msgstr "围栏" + +# Source-Hash: 3e07a9889c1bd7f9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Detach endpoint" +#: packages/nodes/src/fence/move-endpoint-tool.tsx +#, fuzzy +msgid "node.fence.moveEndpointTool.detachEndpoint" +msgstr "分离端点" + +# Source-Hash: 7a3ce9fec6370e3e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag endpoint" +#: packages/nodes/src/fence/move-endpoint-tool.tsx +#, fuzzy +msgid "node.fence.moveEndpointTool.dragEndpoint" +msgstr "拖动端点" + +# Source-Hash: d7cf5045c01b2eb9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close" +#: packages/nodes/src/fence-feature/actions.tsx +#, fuzzy +msgid "node.fenceFeature.actions.close" +msgstr "关闭" + +# Source-Hash: 3e52f04f92e08070 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/fence-feature/actions.tsx +#, fuzzy +msgid "node.fenceFeature.actions.open" +msgstr "打开" + +# Source-Hash: fc4cf2bc034fc547 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Board width" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.boardWidth" +msgstr "板宽" + +# Source-Hash: f3b11e5b2dd3b25f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bracing" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.bracing" +msgstr "斜撑" + +# Source-Hash: d09ec3d9565734c3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Distance from start" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.distanceFromStart" +msgstr "距起点距离" + +# Source-Hash: dcd803eaf3796298 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fence unavailable." +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.fenceUnavailable" +msgstr "围栏不可用。" + +# Source-Hash: 3519d91b7bda18a5 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame width" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.frameWidth" +msgstr "框架宽度" + +# Source-Hash: cb18554b2420e700 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gate height" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.gateHeight" +msgstr "门高度" + +# Source-Hash: 54098b5ee574737a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gate style" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.gateStyle" +msgstr "大门样式" + +# Source-Hash: 4fc3e60be28f60d5 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ground clearance" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.groundClearance" +msgstr "离地间隙" + +# Source-Hash: 916f2e07bf082795 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hinges and latch" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.hingesAndLatch" +msgstr "铰链与门闩" + +# Source-Hash: 5bd2e597fbb2a2c9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hinge side" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.hingeSide" +msgstr "铰链侧" + +# Source-Hash: 8fec7e969045a8e7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Horizontal boards" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.horizontalBoards" +msgstr "横向板条" + +# Source-Hash: f4addad87cc4223e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Infill spacing" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.infillSpacing" +msgstr "填充间距" + +# Source-Hash: cdec08b292742b20 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Jamb posts" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.jambPosts" +msgstr "门框立柱" + +# Source-Hash: ef88410453ee7414 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Keep the opening inside the fence and clear of other gates or passages." +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.keepTheOpeningInsideTheFence" +msgstr "请将开口保持在围栏内,并避开其他门或通道。" + +# Source-Hash: 67cd0171b226fedb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Leaf thickness" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.leafThickness" +msgstr "门扇厚度" + +# Source-Hash: c390ba248e629b9e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Leaves" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.leaves" +msgstr "门扇" + +# Source-Hash: d7bb934589475512 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left leaf proportion" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.leftLeafProportion" +msgstr "左门扇比例" + +# Source-Hash: aa9fe0ebace8957d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match fence height" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.matchFenceHeight" +msgstr "与围栏同高" + +# Source-Hash: c15c1af69ec5c1eb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Match fence style" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.matchFenceStyle" +msgstr "匹配围栏样式" + +# Source-Hash: 51b7ab6a0a78d90a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening angle" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.openingAngle" +msgstr "开启角度" + +# Source-Hash: d2e20300c07aa722 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening width" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.openingWidth" +msgstr "开口宽度" + +# Source-Hash: 6b108fb1d0eb8f9d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open rails" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.openRails" +msgstr "开放栏杆" + +# Source-Hash: d500c4b7827d3390 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cross" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.option.cross" +msgstr "十字" + +# Source-Hash: 7420c0d2caee1c22 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diagonal" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.option.diagonal" +msgstr "斜撑" + +# Source-Hash: 7308869944020839 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Double gate" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.option.doubleGate" +msgstr "双开大门" + +# Source-Hash: 1f4ad5ad3e1be222 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inward" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.option.inward" +msgstr "向内" + +# Source-Hash: f365c6b6dd9ebab9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.option.left" +msgstr "左" + +# Source-Hash: f2953d2931e36d0c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.option.none" +msgstr "无" + +# Source-Hash: ccd8f06b8f8d27c9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Outward" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.option.outward" +msgstr "向外" + +# Source-Hash: b34d5ee0f218221d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.option.right" +msgstr "右" + +# Source-Hash: d327097d9ac1099f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Single gate" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.option.singleGate" +msgstr "单开大门" + +# Source-Hash: 9295ddc2805b21e2 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Picket" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.picket" +msgstr "尖桩" + +# Source-Hash: 8dd5999b235f60ab +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Post height" #: packages/nodes/src/fence-feature/inspector.tsx #, fuzzy -msgid "node.fenceFeature.inspector.postHeight" -msgstr "立柱高度" +msgid "node.fenceFeature.inspector.postHeight" +msgstr "立柱高度" + +# Source-Hash: 90bcd7a8123ec343 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove gate" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.removeGate" +msgstr "移除大门" + +# Source-Hash: 7e3505710613543f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove opening" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.removeOpening" +msgstr "移除开口" + +# Source-Hash: af6f8885fe0fa4e9 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid privacy" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.solidPrivacy" +msgstr "实心遮挡" + +# Source-Hash: 1a7048255c3bdfcb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swing direction" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.swingDirection" +msgstr "开启方向" + +# Source-Hash: eba3df14a2de0812 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Vertical slats" +#: packages/nodes/src/fence-feature/inspector.tsx +#, fuzzy +msgid "node.fenceFeature.inspector.verticalSlats" +msgstr "竖向板条" + +# Source-Hash: df61821ed00852d8 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A gate hosted by a fence." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.fenceGate.description" +msgstr "安装在围栏上的大门。" + +# Source-Hash: 4a479aa23542d766 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gate" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.fenceGate.label" +msgstr "大门" + +# Source-Hash: 8f9c927d79796c26 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An intentional opening in a fence." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.fenceOpening.description" +msgstr "围栏上的预留开口。" + +# Source-Hash: ab67bb47e647d594 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open Passage" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.fenceOpening.label" +msgstr "通道" + +# Source-Hash: dc3adf0c2d50dba6 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor opening" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.floorOpening.label" +msgstr "楼板开洞" + +# Source-Hash: 2f4fac2b1d39fdb1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A measurement / reference annotation (linear, area, or arc)." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.guide.description" +msgstr "测量 / 参考标注(线性、面积或弧长)。" + +# Source-Hash: 1344ea2602e3aa9e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Guide" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.guide.label" +msgstr "参考图" + +# Source-Hash: 5402d634f40b2f97 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rain-water channel running along the eave of a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.gutter.description" +msgstr "沿屋面檐口布置的雨水槽。" + +# Source-Hash: fc7d4ecf973db135 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Downspout" +#: packages/nodes/src/gutter/downspouts-panel.tsx +#, fuzzy +msgid "node.gutter.downspoutsPanel.addDownspout" +msgstr "添加落水管" + +# Source-Hash: 9b9929bac2c39bca +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspout {number}" +#: packages/nodes/src/gutter/downspouts-panel.tsx +#, fuzzy +msgid "node.gutter.downspoutsPanel.downspoutNumber" +msgstr "落水管 {number}" + +# Source-Hash: fc34d45725838141 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Downspouts" +#: packages/nodes/src/gutter/downspouts-panel.tsx +#, fuzzy +msgid "node.gutter.downspoutsPanel.downspouts" +msgstr "落水管" + +# Source-Hash: ac329c74056f0616 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Remove downspout" +#: packages/nodes/src/gutter/downspouts-panel.tsx +#, fuzzy +msgid "node.gutter.downspoutsPanel.removeDownspout" +msgstr "移除落水管" + +# Source-Hash: 14ba981da3627ae2 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gutter" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.gutter.label" +msgstr "檐沟" + +# Source-Hash: 387082cd5f118bed +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Manual" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx +#, fuzzy +msgid "node.hole.manual" +msgstr "手动" + +# Source-Hash: fffde6fa82e65ffc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hole {number} (Editing)" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx +#, fuzzy +msgid "node.holeEditing" +msgstr "开洞 {number}(编辑中)" + +# Source-Hash: 0fe446c72451e4a5 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hole {number}" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx +#, fuzzy +msgid "node.holeNumber" +msgstr "开洞 {number}" + +# Source-Hash: 8eeeb79ff4221939 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{area} {unit} · {count, plural, one {{points} pt} other {{points} pts}} · {source}" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/slab/panel.tsx +#, fuzzy +msgid "node.holeSummary" +msgstr "{area} {unit} · {count, plural, other {{points} 个点}} · {source}" + +# Source-Hash: 50e9252d30f3fb4d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Furnace, air handler, or condenser — duct runs connect to its supply/return collars." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.hvacEquipment.description" +msgstr "暖风炉、空气处理机或冷凝机组 — 风管连接到其送风 / 回风接口。" + +# Source-Hash: 3bf1c1a8dbb93743 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "HVAC Unit" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.hvacEquipment.label" +msgstr "暖通设备" + +# Source-Hash: 8fb180251a321cef +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/hvac-equipment/tool.tsx +#, fuzzy +msgid "node.hvacEquipment.tool.rTRotate" +msgstr "R/T 旋转" + +# Source-Hash: f24a1089d9256460 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Geometry preserved from an imported model when no native Pascal shape exists." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.importedMesh.description" +msgstr "当没有对应的 Pascal 原生形体时,保留自导入模型的几何体。" + +# Source-Hash: 9f9d11f287f722d7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Imported Mesh" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.importedMesh.label" +msgstr "导入网格" + +# Source-Hash: 9cce89f94c673821 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Couldn't rebuild with these values." +#: packages/nodes/src/item/authored-params.tsx +#, fuzzy +msgid "node.item.authoredParams.couldnTRebuildWithTheseValues" +msgstr "无法使用这些值重建。" + +# Source-Hash: 373b929318436fe3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Parameters" +#: packages/nodes/src/item/authored-params.tsx +#, fuzzy +msgid "node.item.authoredParams.parameters" +msgstr "参数" + +# Source-Hash: 558cb886dbe0babe +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rebuilding…" +#: packages/nodes/src/item/authored-params.tsx +#, fuzzy +msgid "node.item.authoredParams.rebuilding" +msgstr "重建中…" + +# Source-Hash: a094c99dc8ad29a3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rebuilding in Blender…" +#: packages/nodes/src/item/authored-params.tsx +#, fuzzy +msgid "node.item.authoredParams.rebuildingInBlender" +msgstr "正在 Blender 中重建…" + +# Source-Hash: 1778f93ee143cd95 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset {param}" +#: packages/nodes/src/item/authored-params.tsx +#, fuzzy +msgid "node.item.authoredParams.resetParam" +msgstr "重置{param}" + +# Source-Hash: 5a28cf5f2402dd7a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset parameters" +#: packages/nodes/src/item/authored-params.tsx +#, fuzzy +msgid "node.item.authoredParams.resetParameters" +msgstr "重置参数" + +# Source-Hash: 6eb8025c60d6d3ca +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset to default" +#: packages/nodes/src/item/authored-params.tsx +#, fuzzy +msgid "node.item.authoredParams.resetToDefault" +msgstr "恢复默认" + +# Source-Hash: 63f79b3c467177b3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A catalog-backed item (furniture, fixtures, decorations)." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.item.description" +msgstr "来自目录的物品(家具、设施、装饰)。" + +# Source-Hash: 2743a0e9d2743807 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Item" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.item.label" +msgstr "物品" + +# Source-Hash: aa6d82bdb3cc1d9a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/item/panel.tsx +#, fuzzy +msgid "node.item.panel.actions" +msgstr "操作" + +# Source-Hash: b26de372b4b0eaac +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/item/panel.tsx +#, fuzzy +msgid "node.item.panel.delete" +msgstr "删除" + +# Source-Hash: 12df69f42beb0643 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/item/panel.tsx +#, fuzzy +msgid "node.item.panel.dimensions" +msgstr "尺寸" + +# Source-Hash: 34dc96fe77a31e51 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/item/panel.tsx +#, fuzzy +msgid "node.item.panel.duplicate" +msgstr "复制" + +# Source-Hash: 6e68b62d2aa611a4 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Info" +#: packages/nodes/src/item/panel.tsx +#, fuzzy +msgid "node.item.panel.info" +msgstr "信息" + +# Source-Hash: bd02c614454fbd2b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/item/panel.tsx +#, fuzzy +msgid "node.item.panel.move" +msgstr "移动" + +# Source-Hash: 28fe6e9deddde6e8 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "pos" +#: packages/nodes/src/item/panel.tsx +#, fuzzy +msgid "node.item.panel.pos" +msgstr "位置" + +# Source-Hash: 9da0cbfad144d737 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/item/panel.tsx +#, fuzzy +msgid "node.item.panel.position" +msgstr "位置" + +# Source-Hash: 5f433581c8f404fa +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "rot" +#: packages/nodes/src/item/panel.tsx +#, fuzzy +msgid "node.item.panel.rot" +msgstr "旋转" + +# Source-Hash: 01989595ee7c1dc0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/item/panel.tsx +#, fuzzy +msgid "node.item.panel.rotation" +msgstr "旋转" + +# Source-Hash: 8210f376c0d29acc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Scale" +#: packages/nodes/src/item/panel.tsx +#, fuzzy +msgid "node.item.panel.scale" +msgstr "比例" + +# Source-Hash: 58fee802997c811c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "scale" +#: packages/nodes/src/item/panel.tsx +#, fuzzy +msgid "node.item.panel.scale2" +msgstr "比例" + +# Source-Hash: b0d264950558d50e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Uniform Scale" +#: packages/nodes/src/item/panel.tsx +#, fuzzy +msgid "node.item.panel.uniformScale" +msgstr "等比缩放" + +# Source-Hash: 4b8d7e52013d1691 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "XYZ" +#: packages/nodes/src/item/panel.tsx +#, fuzzy +msgid "node.item.panel.xyz" +msgstr "XYZ" + +# Source-Hash: a9e2d7b215696e2a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "An attached mono-pitch or freestanding mono, gable, or butterfly canopy with managed structure and drainage." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.leanToExtension.description" +msgstr "附墙单坡或独立式单坡、双坡、蝶形雨棚,自动处理结构与排水。" + +# Source-Hash: 8503bedfbafde9a3 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Canopy" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.leanToExtension.label" +msgstr "雨棚" + +# Source-Hash: 45673462f914d3df +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A single floor of a building, holding walls / slabs / ceilings / items." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.level.description" +msgstr "建筑的一个楼层,包含墙体、楼板、天花板和物品。" + +# Source-Hash: 0608743fc1736d86 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.level.label" +msgstr "楼层" + +# Source-Hash: 156bdee8fee5bec6 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Refrigerant lineset — copper suction + liquid pair joining a condenser to the indoor coil." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.lineset.description" +msgstr "冷媒管组 — 连接冷凝机组与室内盘管的铜质吸气管和液管。" + +# Source-Hash: 362b03eba9d8234c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lineset" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.lineset.label" +msgstr "冷媒管组" +# Source-Hash: 2bd4a85bed158269 # Review: required -# Source-Hash: 90bcd7a8123ec343 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove gate" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standalone refrigerant liquid line — a thin bare-copper run; Follow mode traces an existing lineset." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.liquidLine.description" +msgstr "独立冷媒液管 — 细的裸铜管;跟随模式会沿现有冷媒管组布线。" + +# Source-Hash: c34c9b36492c6e21 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Liquid Line" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.liquidLine.label" +msgstr "液管" + +# Source-Hash: 601aaf23ce5a9279 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Click to trace this lineset run" +#: packages/nodes/src/liquid-line/tool.tsx +#, fuzzy +msgid "node.liquidLine.tool.clickToTraceThisLinesetRun" +msgstr "点击以追踪此冷媒管段" + +# Source-Hash: 77df017af9260468 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follow: hover a lineset" +#: packages/nodes/src/liquid-line/tool.tsx +#, fuzzy +msgid "node.liquidLine.tool.followHoverALineset" +msgstr "跟随:悬停到冷媒管上" + +# Source-Hash: ff4e3bb72267859e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A persistent distance, angle, area, perimeter, or volume annotation." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.measurement.description" +msgstr "持久的距离、角度、面积、周长或体积标注。" + +# Source-Hash: ec3567fd058bab7c +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Measurement" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.measurement.label" +msgstr "测量" + +# Source-Hash: d71b38e990539364 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{kind} {number}" +#: packages/nodes/src/roof/panel.tsx +#, fuzzy +msgid "node.numberedName" +msgstr "{kind} {number}" + +# Source-Hash: 09865d8781ef8699 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Currently {value}" +#: packages/nodes/src/ceiling/panel.tsx +#: packages/nodes/src/roof/panel.tsx +#: packages/nodes/src/stair/panel.tsx +#: packages/nodes/src/wall/panel.tsx +#, fuzzy +msgid "node.panel.currently" +msgstr "当前为 {value}" + +# Source-Hash: 7764b50334e9f71d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV joint — elbow bend, 45° wye, or sanitary tee." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.pipeFitting.description" +msgstr "排水管件 — 弯头、45° 斜三通或卫生三通。" + +# Source-Hash: c040baa6ed4c7aa5 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pipe Fitting" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.pipeFitting.label" +msgstr "管件" + +# Source-Hash: dd86efcab72fc5c7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Axis" +#: packages/nodes/src/pipe-fitting/tool.tsx +#, fuzzy +msgid "node.pipeFitting.tool.axis" +msgstr "轴" + +# Source-Hash: 5232a826549f915e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "⌥ axis" +#: packages/nodes/src/pipe-fitting/tool.tsx +#, fuzzy +msgid "node.pipeFitting.tool.axis2" +msgstr "⌥ 轴" + +# Source-Hash: 8fb180251a321cef +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/pipe-fitting/tool.tsx +#, fuzzy +msgid "node.pipeFitting.tool.rTRotate" +msgstr "R/T 旋转" + +# Source-Hash: a0bb4762aa66fa3e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drain / waste / vent pipe run — draw level or toggle a ¼″ per foot fall with S." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.pipeSegment.description" +msgstr "排水 / 污水 / 通气管 — 水平绘制,或按 S 切换每英尺 ¼″ 坡度。" + +# Source-Hash: 457155657704f7cc +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV Pipe" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.pipeSegment.label" +msgstr "排水管" + +# Source-Hash: 6d0cdd14d0675e05 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "DWV P-trap — water seal on the waste line. The trap arm runs to the vent." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.pipeTrap.description" +msgstr "排水 P 型存水弯 — 污水管上的水封。存水弯臂通向通气管。" + +# Source-Hash: b778a315e82065a0 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trap" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.pipeTrap.label" +msgstr "存水弯" + +# Source-Hash: 73078bc0f5d686fa +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{diameter}\" Trap" +#: packages/nodes/src/pipe-trap/tool.tsx +#, fuzzy +msgid "node.pipeTrap.tool.diameterTrap" +msgstr "{diameter}\" 存水弯" + +# Source-Hash: 8fb180251a321cef +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "R/T rotate" +#: packages/nodes/src/pipe-trap/tool.tsx +#, fuzzy +msgid "node.pipeTrap.tool.rTRotate" +msgstr "R/T 旋转" + +# Source-Hash: 0efe82436b915f6d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Experimental editable recipe" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.proceduralItem.description" +msgstr "实验性可编辑配方" + +# Source-Hash: c8bbcc888cce7b8a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Procedural item" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.proceduralItem.label" +msgstr "程序化物品" + +# Source-Hash: 356aa0ed69cb8ec5 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ventilation strip running along the ridge of a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.ridgeVent.description" +msgstr "沿屋面屋脊布置的通风条。" + +# Source-Hash: 54b74080f33c8c4e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge Vent" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.ridgeVent.label" +msgstr "屋脊通风口" + +# Source-Hash: aa6d82bdb3cc1d9a +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/ridge-vent/panel.tsx +#, fuzzy +msgid "node.ridgeVent.panel.actions" +msgstr "操作" + +# Source-Hash: b26de372b4b0eaac +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/ridge-vent/panel.tsx +#, fuzzy +msgid "node.ridgeVent.panel.delete" +msgstr "删除" + +# Source-Hash: 12df69f42beb0643 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/ridge-vent/panel.tsx +#, fuzzy +msgid "node.ridgeVent.panel.dimensions" +msgstr "尺寸" + +# Source-Hash: 34dc96fe77a31e51 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/ridge-vent/panel.tsx +#, fuzzy +msgid "node.ridgeVent.panel.duplicate" +msgstr "复制" + +# Source-Hash: 18bf817325c1c537 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End Caps" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.removeGate" -msgstr "移除大门" +msgid "node.ridgeVent.panel.endCaps" +msgstr "端盖" +# Source-Hash: 466f817a0102d4a5 # Review: required -# Source-Hash: 7e3505710613543f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove opening" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flanged" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.removeOpening" -msgstr "移除开口" +msgid "node.ridgeVent.panel.flanged" +msgstr "带法兰" +# Source-Hash: 646ef0fbcbc58edf # Review: required -# Source-Hash: af6f8885fe0fa4e9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid privacy" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.solidPrivacy" -msgstr "实心遮挡" +msgid "node.ridgeVent.panel.height" +msgstr "高度" +# Source-Hash: 643687bc3adaac76 # Review: required -# Source-Hash: 1a7048255c3bdfcb -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Swing direction" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.swingDirection" -msgstr "开启方向" +msgid "node.ridgeVent.panel.length" +msgstr "长度" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: eba3df14a2de0812 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Vertical slats" -#: packages/nodes/src/fence-feature/inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceFeature.inspector.verticalSlats" -msgstr "竖向板条" +msgid "node.ridgeVent.panel.move" +msgstr "移动" -# Source-Hash: df61821ed00852d8 +# Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A gate hosted by a fence." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceGate.description" -msgstr "安装在围栏上的大门。" +msgid "node.ridgeVent.panel.open" +msgstr "打开" -# Source-Hash: 4a479aa23542d766 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gate" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceGate.label" -msgstr "大门" +msgid "node.ridgeVent.panel.position" +msgstr "位置" -# Source-Hash: 8f9c927d79796c26 +# Source-Hash: 54b74080f33c8c4e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "An intentional opening in a fence." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge Vent" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceOpening.description" -msgstr "围栏上的预留开口。" +msgid "node.ridgeVent.panel.ridgeVent" +msgstr "屋脊通风口" -# Source-Hash: ab67bb47e647d594 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open Passage" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.fenceOpening.label" -msgstr "通道" +msgid "node.ridgeVent.panel.rotation" +msgstr "旋转" -# Source-Hash: dc3adf0c2d50dba6 +# Source-Hash: e9046e9823b400a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor opening" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingled" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.floorOpening.label" -msgstr "楼板开洞" +msgid "node.ridgeVent.panel.shingled" +msgstr "瓦片铺设" -# Source-Hash: 2f4fac2b1d39fdb1 +# Source-Hash: d998c212030bc7c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A measurement / reference annotation (linear, area, or arc)." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.guide.description" -msgstr "测量 / 参考标注(线性、面积或弧长)。" +msgid "node.ridgeVent.panel.standard" +msgstr "标准" -# Source-Hash: 1344ea2602e3aa9e +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Guide" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.guide.label" -msgstr "参考图" +msgid "node.ridgeVent.panel.style" +msgstr "样式" -# Source-Hash: 5402d634f40b2f97 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rain-water channel running along the eave of a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/ridge-vent/panel.tsx #, fuzzy -msgid "node.gutter.description" -msgstr "沿屋面檐口布置的雨水槽。" +msgid "node.ridgeVent.panel.width" +msgstr "宽度" +# Source-Hash: c6d3976b4eb80586 # Review: required -# Source-Hash: fc7d4ecf973db135 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Downspout" -#: packages/nodes/src/gutter/downspouts-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arch bays" +#: packages/nodes/src/roof/barrel-panel.tsx #, fuzzy -msgid "node.gutter.downspoutsPanel.addDownspout" -msgstr "添加落水管" +msgid "node.roof.barrelPanel.archBays" +msgstr "拱跨" +# Source-Hash: 1cfdd5affedf153c # Review: required -# Source-Hash: 9b9929bac2c39bca -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspout {number}" -#: packages/nodes/src/gutter/downspouts-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Barrel arch" +#: packages/nodes/src/roof/barrel-panel.tsx #, fuzzy -msgid "node.gutter.downspoutsPanel.downspoutNumber" -msgstr "落水管 {number}" +msgid "node.roof.barrelPanel.barrelArch" +msgstr "筒形拱" +# Source-Hash: b3e8929750d18f7b # Review: required -# Source-Hash: fc34d45725838141 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Downspouts" -#: packages/nodes/src/gutter/downspouts-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat panes follow a circular arch. Rise is measured from the eaves." +#: packages/nodes/src/roof/barrel-panel.tsx #, fuzzy -msgid "node.gutter.downspoutsPanel.downspouts" -msgstr "落水管" +msgid "node.roof.barrelPanel.flatPanesFollowACircularArch" +msgstr "平板窗格沿圆弧排列。矢高从檐口算起。" +# Source-Hash: fe8c5b735495eb00 # Review: required -# Source-Hash: ac329c74056f0616 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Remove downspout" -#: packages/nodes/src/gutter/downspouts-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rise" +#: packages/nodes/src/roof/barrel-panel.tsx #, fuzzy -msgid "node.gutter.downspoutsPanel.removeDownspout" -msgstr "移除落水管" +msgid "node.roof.barrelPanel.rise" +msgstr "总高" -# Source-Hash: 14ba981da3627ae2 +# Source-Hash: 6afeec8de7ed618d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gutter" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A pitched / hip / gable roof composed of one or more segments." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.gutter.label" -msgstr "檐沟" +msgid "node.roof.description" +msgstr "由一个或多个坡面组成的坡屋顶 / 四坡屋顶 / 双坡屋顶。" -# Source-Hash: 387082cd5f118bed +# Source-Hash: b5be04471fd3fb7a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Manual" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arch bay {number}" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.hole.manual" -msgstr "手动" +msgid "node.roof.glazing.face.archBay" +msgstr "拱跨 {number}" -# Source-Hash: fffde6fa82e65ffc +# Source-Hash: 93381b9024a75a99 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hole {number} (Editing)" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Back slope" +#: packages/nodes/src/roof/glazing-panel-editor.tsx +#, fuzzy +msgid "node.roof.glazing.face.back" +msgstr "后坡" + +# Source-Hash: 08b00107b635e11d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left end" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.holeEditing" -msgstr "开洞 {number}(编辑中)" +msgid "node.roof.glazing.face.endLeft" +msgstr "左端" -# Source-Hash: 0fe446c72451e4a5 +# Source-Hash: 821734ea5d17a693 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hole {number}" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right end" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.holeNumber" -msgstr "开洞 {number}" +msgid "node.roof.glazing.face.endRight" +msgstr "右端" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: fd26f8df9d087c6b +# Source-Hash: 40c9ef62055067e1 # Review: required -# English: "{area} m² · {count, plural, one {{points} pt} other {{points} pts}} · {source}" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front slope" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.holeSummary" -msgstr "{area} m² · {count, plural, other {{points} 个点}} · {source}" +msgid "node.roof.glazing.face.front" +msgstr "前坡" -# Source-Hash: 50e9252d30f3fb4d +# Source-Hash: 1a88da71d5e5f0d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Furnace, air handler, or condenser — duct runs connect to its supply/return collars." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed slope" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.hvacEquipment.description" -msgstr "暖风炉、空气处理机或冷凝机组 — 风管连接到其送风 / 回风接口。" +msgid "node.roof.glazing.face.slope" +msgstr "单坡面" -# Source-Hash: 3bf1c1a8dbb93743 +# Source-Hash: 3bcc542295b4c61e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "HVAC Unit" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Alignment" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.hvacEquipment.label" -msgstr "暖通设备" +msgid "node.roof.glazingControls.alignment" +msgstr "对齐" +# Source-Hash: 5211341ed18f33f6 # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/hvac-equipment/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.hvacEquipment.tool.rTRotate" -msgstr "R/T 旋转" +msgid "node.roof.glazingControls.center" +msgstr "居中" -# Source-Hash: f24a1089d9256460 +# Source-Hash: 512e47607a37af46 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Geometry preserved from an imported model when no native Pascal shape exists." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a layout to edit the grid." +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.importedMesh.description" -msgstr "当没有对应的 Pascal 原生形体时,保留自导入模型的几何体。" +msgid "node.roof.glazingControls.chooseALayoutToEditThe" +msgstr "选择一种布局以编辑网格。" -# Source-Hash: 9f9d11f287f722d7 +# Source-Hash: 65b1cbba3b92c5b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Imported Mesh" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Empty" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.importedMesh.label" -msgstr "导入网格" +msgid "node.roof.glazingControls.empty" +msgstr "空" -# Source-Hash: 9cce89f94c673821 +# Source-Hash: 135874d189176d13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Couldn't rebuild with these values." -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.couldnTRebuildWithTheseValues" -msgstr "无法使用这些值重建。" +msgid "node.roof.glazingControls.end" +msgstr "终点" -# Source-Hash: 373b929318436fe3 +# Source-Hash: 4fb65101d0b1a222 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Parameters" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fixed spacing" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.parameters" -msgstr "参数" +msgid "node.roof.glazingControls.fixedSpacing" +msgstr "固定间距" -# Source-Hash: 558cb886dbe0babe +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rebuilding…" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.rebuilding" -msgstr "重建中…" +msgid "node.roof.glazingControls.glass" +msgstr "玻璃" -# Source-Hash: a094c99dc8ad29a3 +# Source-Hash: 54800340a0eeab23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rebuilding in Blender…" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layout" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.rebuildingInBlender" -msgstr "正在 Blender 中重建…" +msgid "node.roof.glazingControls.layout" +msgstr "布局" -# Source-Hash: 1778f93ee143cd95 +# Source-Hash: 321ca5101ab61db7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset {param}" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Maximum spacing" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.resetParam" -msgstr "重置{param}" +msgid "node.roof.glazingControls.maximumSpacing" +msgstr "最大间距" -# Source-Hash: 5a28cf5f2402dd7a +# Source-Hash: d10743fce478d9f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset parameters" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Max spacing" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.resetParameters" -msgstr "重置参数" +msgid "node.roof.glazingControls.maxSpacing" +msgstr "最大间距" -# Source-Hash: 6eb8025c60d6d3ca +# Source-Hash: 37d9f63758abdb67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset to default" -#: packages/nodes/src/item/authored-params.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mixed" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.authoredParams.resetToDefault" -msgstr "恢复默认" +msgid "node.roof.glazingControls.mixed" +msgstr "混合" -# Source-Hash: 63f79b3c467177b3 +# Source-Hash: b91302bf741c9fd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A catalog-backed item (furniture, fixtures, decorations)." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel count" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.description" -msgstr "来自目录的物品(家具、设施、装饰)。" +msgid "node.roof.glazingControls.panelCount" +msgstr "面板数量" -# Source-Hash: 2743a0e9d2743807 +# Source-Hash: 6ce059aee1386f72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Item" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panels" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.label" -msgstr "物品" +msgid "node.roof.glazingControls.panels" +msgstr "面板" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: ef3e765e692faf4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.actions" -msgstr "操作" +msgid "node.roof.glazingControls.solid" +msgstr "实体" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: e4698e83d02beb6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spacing" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.delete" -msgstr "删除" +msgid "node.roof.glazingControls.spacing" +msgstr "间距" -# Source-Hash: 12df69f42beb0643 +# Source-Hash: 0a26a1e61c825660 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.dimensions" -msgstr "尺寸" +msgid "node.roof.glazingControls.start" +msgstr "起点" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 095237e9e2df4d9c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{title} alignment" +#: packages/nodes/src/roof/glazing-controls.tsx #, fuzzy -msgid "node.item.panel.duplicate" -msgstr "复制" +msgid "node.roof.glazingControls.titleAlignment" +msgstr "{title}对齐" -# Source-Hash: 6e68b62d2aa611a4 +# Source-Hash: c98a4e6b28f05e0f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Info" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Changes apply to all {length} roof segments." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.info" -msgstr "信息" +msgid "node.roof.glazingPanel.changesApplyToAllLengthRoof" +msgstr "更改将应用于全部 {length} 个屋顶分段。" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: c5d2ff7fda4787cd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose one roof system to edit settings for all selected segments." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.move" -msgstr "移动" +msgid "node.roof.glazingPanel.chooseOneRoofSystemToEdit" +msgstr "选择一种屋顶系统以编辑所有选中分段的设置。" -# Source-Hash: 28fe6e9deddde6e8 +# Source-Hash: 80e07a119b63187c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "pos" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Close the roof ends" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.pos" -msgstr "位置" +msgid "node.roof.glazingPanel.closeTheRoofEnds" +msgstr "封闭屋顶端部" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: e28dd27d54aaa7ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default panel infill" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.position" -msgstr "位置" +msgid "node.roof.glazingPanel.defaultPanelInfill" +msgstr "默认面板填充" -# Source-Hash: 5f433581c8f404fa +# Source-Hash: 134d33e2465937e7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "rot" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divides each roof face into columns." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.rot" -msgstr "旋转" +msgid "node.roof.glazingPanel.dividesEachRoofFaceIntoColumns" +msgstr "将每个屋面划分为列。" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: 896a6e4da3357c39 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Divides the length of each arch bay into columns." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.rotation" -msgstr "旋转" +msgid "node.roof.glazingPanel.dividesTheLengthOfEachArch" +msgstr "将每个拱跨的长度划分为列。" -# Source-Hash: 8210f376c0d29acc +# Source-Hash: be9c810d28d1feb9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Scale" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End infill fills the space above the walls. Edit room walls and ceilings separately." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.scale" -msgstr "比例" +msgid "node.roof.glazingPanel.endInfillFillsTheSpaceAbove" +msgstr "端部填充会填满墙体上方的空间。请分别编辑房间的墙体和天花板。" -# Source-Hash: 58fee802997c811c +# Source-Hash: 0b8b27dbc57cca44 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "scale" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame color" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.scale2" -msgstr "比例" +msgid "node.roof.glazingPanel.frameColor" +msgstr "框架颜色" -# Source-Hash: b0d264950558d50e +# Source-Hash: fd413477f1a9e5ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Uniform Scale" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame depth" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.uniformScale" -msgstr "等比缩放" +msgid "node.roof.glazingPanel.frameDepth" +msgstr "框架深度" -# Source-Hash: 4b8d7e52013d1691 +# Source-Hash: 3519d91b7bda18a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "XYZ" -#: packages/nodes/src/item/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame width" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.item.panel.xyz" -msgstr "XYZ" +msgid "node.roof.glazingPanel.frameWidth" +msgstr "框架宽度" -# Source-Hash: a9e2d7b215696e2a +# Source-Hash: c7e72beff9fe4b37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "An attached mono-pitch or freestanding mono, gable, or butterfly canopy with managed structure and drainage." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framing" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.leanToExtension.description" -msgstr "附墙单坡或独立式单坡、双坡、蝶形雨棚,自动处理结构与排水。" +msgid "node.roof.glazingPanel.framing" +msgstr "龙骨" -# Source-Hash: 8503bedfbafde9a3 +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Canopy" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.leanToExtension.label" -msgstr "雨棚" +msgid "node.roof.glazingPanel.glass" +msgstr "玻璃" -# Source-Hash: 45673462f914d3df +# Source-Hash: 9c38875c310547ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A single floor of a building, holding walls / slabs / ceilings / items." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass tint" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.level.description" -msgstr "建筑的一个楼层,包含墙体、楼板、天花板和物品。" +msgid "node.roof.glazingPanel.glassTint" +msgstr "玻璃色调" -# Source-Hash: 0608743fc1736d86 +# Source-Hash: dd330a94b3f7a65a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glazed" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.level.label" -msgstr "楼层" +msgid "node.roof.glazingPanel.glazed" +msgstr "玻璃" -# Source-Hash: 156bdee8fee5bec6 +# Source-Hash: e6be52df9197243a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Refrigerant lineset — copper suction + liquid pair joining a condenser to the indoor coil." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glazing is available for gable, straight shed, and barrel roofs." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.lineset.description" -msgstr "冷媒管组 — 连接冷凝机组与室内盘管的铜质吸气管和液管。" +msgid "node.roof.glazingPanel.glazingIsAvailableForGableStraight" +msgstr "双坡、直单坡和筒形屋顶可使用玻璃。" -# Source-Hash: 362b03eba9d8234c +# Source-Hash: a4e7ef2e31d7220b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lineset" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid across the roof" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.lineset.label" -msgstr "冷媒管组" +msgid "node.roof.glazingPanel.gridAcrossTheRoof" +msgstr "沿屋顶横向网格" -# Source-Hash: 2bd4a85bed158269 +# Source-Hash: 2f28a3b33fccf56b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standalone refrigerant liquid line — a thin bare-copper run; Follow mode traces an existing lineset." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid along the length" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.liquidLine.description" -msgstr "独立冷媒液管 — 细的裸铜管;跟随模式会沿现有冷媒管组布线。" +msgid "node.roof.glazingPanel.gridAlongTheLength" +msgstr "沿长度方向网格" -# Source-Hash: c34c9b36492c6e21 +# Source-Hash: 1f701893dbf9d72b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Liquid Line" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid along the slope" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.liquidLine.label" -msgstr "液管" +msgid "node.roof.glazingPanel.gridAlongTheSlope" +msgstr "沿坡度方向网格" +# Source-Hash: 20c8dfbadda20e3b # Review: required -# Source-Hash: 601aaf23ce5a9279 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Click to trace this lineset run" -#: packages/nodes/src/liquid-line/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid within each arch bay" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.liquidLine.tool.clickToTraceThisLinesetRun" -msgstr "点击以追踪此冷媒管段" +msgid "node.roof.glazingPanel.gridWithinEachArchBay" +msgstr "每个拱跨内的网格" +# Source-Hash: 7c339a5fae55681d # Review: required -# Source-Hash: 77df017af9260468 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follow: hover a lineset" -#: packages/nodes/src/liquid-line/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Infill" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.liquidLine.tool.followHoverALineset" -msgstr "跟随:悬停到冷媒管上" +msgid "node.roof.glazingPanel.infill" +msgstr "填充" -# Source-Hash: ff4e3bb72267859e +# Source-Hash: 1c0b8a5503c5daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A persistent distance, angle, area, perimeter, or volume annotation." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opacity" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.measurement.description" -msgstr "持久的距离、角度、面积、周长或体积标注。" +msgid "node.roof.glazingPanel.opacity" +msgstr "不透明度" -# Source-Hash: ec3567fd058bab7c +# Source-Hash: 4d412746658f2faf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Measurement" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pane thickness" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.measurement.label" -msgstr "测量" +msgid "node.roof.glazingPanel.paneThickness" +msgstr "窗格厚度" -# Source-Hash: d71b38e990539364 +# Source-Hash: 570136e723cb7d99 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{kind} {number}" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof system" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.numberedName" -msgstr "{kind} {number}" +msgid "node.roof.glazingPanel.roofSystem" +msgstr "屋顶系统" -# Source-Hash: 09865d8781ef8699 +# Source-Hash: a6a7a36d982b4911 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Currently {value}" -#: packages/nodes/src/ceiling/panel.tsx -#: packages/nodes/src/roof/panel.tsx -#: packages/nodes/src/stair/panel.tsx -#: packages/nodes/src/wall/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roughness" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.panel.currently" -msgstr "当前为 {value}" +msgid "node.roof.glazingPanel.roughness" +msgstr "粗糙度" -# Source-Hash: 7764b50334e9f71d +# Source-Hash: 2fa6fbeda5d45949 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV joint — elbow bend, 45° wye, or sanitary tee." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spacing is measured on the slope, not its horizontal projection." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.pipeFitting.description" -msgstr "排水管件 — 弯头、45° 斜三通或卫生三通。" +msgid "node.roof.glazingPanel.spacingIsMeasuredOnTheSlope" +msgstr "间距沿坡面测量,而非其水平投影。" -# Source-Hash: c040baa6ed4c7aa5 +# Source-Hash: d998c212030bc7c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pipe Fitting" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard" +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.pipeFitting.label" -msgstr "管件" +msgid "node.roof.glazingPanel.standard" +msgstr "标准" +# Source-Hash: efbe1c4facf561f7 # Review: required -# Source-Hash: dd86efcab72fc5c7 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Axis" -#: packages/nodes/src/pipe-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Subdivides each flat arch bay. Arch bays controls the divisions around the curve." +#: packages/nodes/src/roof/glazing-panel.tsx #, fuzzy -msgid "node.pipeFitting.tool.axis" -msgstr "轴" +msgid "node.roof.glazingPanel.subdividesEachFlatArchBayArch" +msgstr "细分每个平板拱跨。拱跨数控制曲线上的分格。" +# Source-Hash: 1497eac9e4f63016 # Review: required -# Source-Hash: 5232a826549f915e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "⌥ axis" -#: packages/nodes/src/pipe-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Choose a panel to override its default infill." +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeFitting.tool.axis2" -msgstr "⌥ 轴" +msgid "node.roof.glazingPanelEditor.chooseAPanelToOverrideIts" +msgstr "选择一个面板以覆盖其默认填充。" +# Source-Hash: 3530ac1f4046cd22 # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/pipe-fitting/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Column" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeFitting.tool.rTRotate" -msgstr "R/T 旋转" +msgid "node.roof.glazingPanelEditor.column2" +msgstr "柱" -# Source-Hash: a0bb4762aa66fa3e +# Source-Hash: 9e9715d52410c86f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drain / waste / vent pipe run — draw level or toggle a ¼″ per foot fall with S." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeSegment.description" -msgstr "排水 / 污水 / 通气管 — 水平绘制,或按 S 切换每英尺 ¼″ 坡度。" +msgid "node.roof.glazingPanelEditor.custom" +msgstr "自定义" -# Source-Hash: 457155657704f7cc +# Source-Hash: 4ca0e0e73229540c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV Pipe" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Default" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeSegment.label" -msgstr "排水管" +msgid "node.roof.glazingPanelEditor.default" +msgstr "默认" -# Source-Hash: 6d0cdd14d0675e05 +# Source-Hash: 9ef92ad8ae49ed72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "DWV P-trap — water seal on the waste line. The trap arm runs to the vent." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{columns, plural, one {{columnCount} column} other {{columnCount} columns}} · {rows, plural, one {{rowCount} row} other {{rowCount} rows}}" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeTrap.description" -msgstr "排水 P 型存水弯 — 污水管上的水封。存水弯臂通向通气管。" +msgid "node.roof.glazingPanelEditor.grid" +msgstr "{columns, plural, other {{columnCount} 列}} · {rows, plural, other {{rowCount} 行}}" -# Source-Hash: b778a315e82065a0 +# Source-Hash: 11624abbcfdd5506 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trap" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Individual panels" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeTrap.label" -msgstr "存水弯" +msgid "node.roof.glazingPanelEditor.individualPanels" +msgstr "单个面板" +# Source-Hash: 3a019ce58d021431 # Review: required -# Source-Hash: 73078bc0f5d686fa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{diameter}\" Trap" -#: packages/nodes/src/pipe-trap/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel infill" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeTrap.tool.diameterTrap" -msgstr "{diameter}\" 存水弯" +msgid "node.roof.glazingPanelEditor.panelInfill" +msgstr "面板填充" +# Source-Hash: 6eb8025c60d6d3ca # Review: required -# Source-Hash: 8fb180251a321cef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "R/T rotate" -#: packages/nodes/src/pipe-trap/tool.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset to default" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.pipeTrap.tool.rTRotate" -msgstr "R/T 旋转" +msgid "node.roof.glazingPanelEditor.resetToDefault" +msgstr "恢复默认" -# Source-Hash: 0efe82436b915f6d +# Source-Hash: 6fba44f2bfd8af8e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Experimental editable recipe" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof face" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.proceduralItem.description" -msgstr "实验性可编辑配方" +msgid "node.roof.glazingPanelEditor.roofFace" +msgstr "屋面" -# Source-Hash: c8bbcc888cce7b8a +# Source-Hash: 03a22f6df69c47d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Procedural item" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Row" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.proceduralItem.label" -msgstr "程序化物品" +msgid "node.roof.glazingPanelEditor.row2" +msgstr "行" -# Source-Hash: 356aa0ed69cb8ec5 +# Source-Hash: 6c2cc2d9cd778998 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ventilation strip running along the ridge of a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selected panel infill" +#: packages/nodes/src/roof/glazing-panel-editor.tsx #, fuzzy -msgid "node.ridgeVent.description" -msgstr "沿屋面屋脊布置的通风条。" +msgid "node.roof.glazingPanelEditor.selectedPanelInfill" +msgstr "选中面板的填充" -# Source-Hash: 54b74080f33c8c4e +# Source-Hash: f5f730969df63d1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ridge Vent" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.ridgeVent.label" -msgstr "屋脊通风口" +msgid "node.roof.label" +msgstr "屋顶" -# Review: required # Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" -#: packages/nodes/src/ridge-vent/panel.tsx +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.actions" +msgid "node.roof.panel.actions" msgstr "操作" +# Source-Hash: d60471ce3cd45348 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Chimney" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.delete" -msgstr "删除" +msgid "node.roof.panel.addChimney" +msgstr "添加烟囱" +# Source-Hash: 1ca6a1cf9cc6e3ed # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Cupola" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.dimensions" -msgstr "尺寸" +msgid "node.roof.panel.addCupola" +msgstr "添加穹顶" +# Source-Hash: 94dea147eeaac52b # Review: required -# Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Dormer" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.duplicate" -msgstr "复制" +msgid "node.roof.panel.addDormer" +msgstr "添加老虎窗" +# Source-Hash: 5679acdd64484726 # Review: required -# Source-Hash: 18bf817325c1c537 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End Caps" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Eyebrow Vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.endCaps" -msgstr "端盖" +msgid "node.roof.panel.addEyebrowVent" +msgstr "添加眉形通风口" +# Source-Hash: 25a141dc0d7c4b44 # Review: required -# Source-Hash: 466f817a0102d4a5 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flanged" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Gutter" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.flanged" -msgstr "带法兰" +msgid "node.roof.panel.addGutter" +msgstr "添加檐沟" +# Source-Hash: 7230bdc8a2252626 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Skylight" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.height" -msgstr "高度" +msgid "node.roof.panel.addSkylight" +msgstr "添加天窗" +# Source-Hash: 0f220e2602b7ff24 # Review: required -# Source-Hash: 643687bc3adaac76 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Solar Panel" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.length" -msgstr "长度" +msgid "node.roof.panel.addSolarPanel" +msgstr "添加太阳能板" +# Source-Hash: 4d83a2e5a4d9e6b4 # Review: required -# Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.move" -msgstr "移动" +msgid "node.roof.panel.addVent" +msgstr "添加通风口" +# Source-Hash: e9a89a5e4ac8cd61 # Review: required -# Source-Hash: 3e52f04f92e08070 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Box" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.open" -msgstr "打开" +msgid "node.roof.panel.box" +msgstr "盒形" +# Source-Hash: 3bf078fe2560daca # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "box vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.position" -msgstr "位置" +msgid "node.roof.panel.boxVent" +msgstr "箱式通风口" +# Source-Hash: 4986740251121471 # Review: required -# Source-Hash: 54b74080f33c8c4e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ridge Vent" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "chimney" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.ridgeVent" -msgstr "屋脊通风口" +msgid "node.roof.panel.chimney" +msgstr "烟囱" +# Source-Hash: 9e9715d52410c86f # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.rotation" -msgstr "旋转" +msgid "node.roof.panel.custom" +msgstr "自定义" +# Source-Hash: b26de372b4b0eaac # Review: required -# Source-Hash: e9046e9823b400a0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingled" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.shingled" -msgstr "瓦片铺设" +msgid "node.roof.panel.delete" +msgstr "删除" +# Source-Hash: 5169968a4b0c1840 # Review: required -# Source-Hash: d998c212030bc7c2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "dormer" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.standard" -msgstr "标准" +msgid "node.roof.panel.dormer" +msgstr "老虎窗" +# Source-Hash: 72e51c6e5e9c6c26 # Review: required -# Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Draw Segment" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.style" -msgstr "样式" +msgid "node.roof.panel.drawSegment" +msgstr "绘制分段" +# Source-Hash: 34dc96fe77a31e51 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/ridge-vent/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.ridgeVent.panel.width" -msgstr "宽度" +msgid "node.roof.panel.duplicate" +msgstr "复制" -# Source-Hash: c6d3976b4eb80586 +# Source-Hash: 5c99a67253bfc02a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arch bays" -#: packages/nodes/src/roof/barrel-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eave overhang" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.barrelPanel.archBays" -msgstr "拱跨" +msgid "node.roof.panel.eaveOverhang" +msgstr "檐口出挑" -# Source-Hash: 1cfdd5affedf153c +# Source-Hash: 34756c5ea718ccb5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Barrel arch" -#: packages/nodes/src/roof/barrel-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eaves" +#: packages/nodes/src/roof/panel.tsx +#, fuzzy +msgid "node.roof.panel.eaves" +msgstr "檐口" + +# Source-Hash: 7c4196b9e791c195 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elements" +#: packages/nodes/src/roof/panel.tsx +#, fuzzy +msgid "node.roof.panel.elements" +msgstr "元素" + +# Source-Hash: 6b8ba49aa355fe87 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows walls" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.barrelPanel.barrelArch" -msgstr "筒形拱" +msgid "node.roof.panel.followsWalls" +msgstr "跟随墙体" -# Source-Hash: b3e8929750d18f7b +# Source-Hash: dbd062efc7f4fd7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat panes follow a circular arch. Rise is measured from the eaves." -#: packages/nodes/src/roof/barrel-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable overhang" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.barrelPanel.flatPanesFollowACircularArch" -msgstr "平板窗格沿圆弧排列。矢高从檐口算起。" +msgid "node.roof.panel.gableOverhang" +msgstr "山墙出挑" -# Source-Hash: fe8c5b735495eb00 +# Source-Hash: 23b434461c990711 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rise" -#: packages/nodes/src/roof/barrel-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "gutter" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.barrelPanel.rise" -msgstr "总高" +msgid "node.roof.panel.gutter" +msgstr "檐沟" -# Source-Hash: 6afeec8de7ed618d +# Source-Hash: 0608743fc1736d86 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A pitched / hip / gable roof composed of one or more segments." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Level" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.description" -msgstr "由一个或多个坡面组成的坡屋顶 / 四坡屋顶 / 双坡屋顶。" +msgid "node.roof.panel.level" +msgstr "楼层" -# Source-Hash: b5be04471fd3fb7a +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arch bay {number}" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.archBay" -msgstr "拱跨 {number}" +msgid "node.roof.panel.move" +msgstr "移动" -# Source-Hash: 93381b9024a75a99 +# Source-Hash: 39661f4827b0f435 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Back slope" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move to {level}" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.back" -msgstr "后坡" +msgid "node.roof.panel.moveToLevel" +msgstr "移到{level}" -# Source-Hash: 08b00107b635e11d +# Source-Hash: c534093ff560a9f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left end" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move to the roof level" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.endLeft" -msgstr "左端" +msgid "node.roof.panel.moveToTheRoofLevel" +msgstr "移到屋顶楼层" -# Source-Hash: 821734ea5d17a693 +# Source-Hash: 0939fad1cb1831f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right end" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "On {storey} with its walls, so it hides that floor's plan in solo and exploded views.{roofs, plural, =0 {} =1 {} other { The floor's {roofCount} roofs move together.}}" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.endRight" -msgstr "右端" +msgid "node.roof.panel.onStoreyWalls" +msgstr "与其墙体同在{storey},因此在单独和分解视图中会遮挡该层平面。{roofs, plural, =0 {} =1 {} other { 该层的 {roofCount} 个屋顶会一起移动。}}" -# Source-Hash: 40c9ef62055067e1 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front slope" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.front" -msgstr "前坡" +msgid "node.roof.panel.position" +msgstr "位置" -# Source-Hash: 1a88da71d5e5f0d6 +# Source-Hash: e6ddc8a624465793 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed slope" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ridge" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazing.face.slope" -msgstr "单坡面" +msgid "node.roof.panel.ridge" +msgstr "屋脊" -# Source-Hash: 3bcc542295b4c61e +# Source-Hash: 83112cbc205e9972 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Alignment" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "ridge vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.alignment" -msgstr "对齐" +msgid "node.roof.panel.ridgeVent" +msgstr "屋脊通风口" -# Source-Hash: 5211341ed18f33f6 +# Source-Hash: f5f730969df63d1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.center" -msgstr "居中" +msgid "node.roof.panel.roof" +msgstr "屋顶" -# Source-Hash: 512e47607a37af46 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a layout to edit the grid." -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.chooseALayoutToEditThe" -msgstr "选择一种布局以编辑网格。" +msgid "node.roof.panel.rotation" +msgstr "旋转" -# Source-Hash: 65b1cbba3b92c5b2 +# Source-Hash: 505d8419cf4cc5e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Empty" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segments" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.empty" -msgstr "空" +msgid "node.roof.panel.segments" +msgstr "分段" -# Source-Hash: 135874d189176d13 +# Source-Hash: 0c084c517dbc153b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{roofType, select, hip {Hip} gable {Gable} shed {Shed} gambrel {Gambrel} dutch {Dutch} mansard {Mansard} flat {Flat} conical {Conical} barrel {Barrel} other {Roof}}" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.end" -msgstr "终点" +msgid "node.roof.panel.segmentType" +msgstr "{roofType, select, hip {四坡} gable {双坡} shed {单坡} gambrel {复折} dutch {歇山} mansard {孟莎} flat {平屋顶} conical {锥形} barrel {筒形} other {屋顶}}" -# Source-Hash: 4fb65101d0b1a222 +# Source-Hash: 0c4c82caccb4775c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fixed spacing" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "skylight" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.fixedSpacing" -msgstr "固定间距" +msgid "node.roof.panel.skylight" +msgstr "天窗" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: b9f931508dd6ec70 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "solar panel" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.glass" -msgstr "玻璃" +msgid "node.roof.panel.solarPanel" +msgstr "太阳能板" -# Source-Hash: 54800340a0eeab23 +# Source-Hash: d2428b22f1757a4e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Layout" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turbine" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.layout" -msgstr "布局" +msgid "node.roof.panel.turbine" +msgstr "涡轮" -# Source-Hash: 321ca5101ab61db7 +# Source-Hash: 86d02a3d3a3a7fa2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Maximum spacing" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "turbine vent" +#: packages/nodes/src/roof/panel.tsx #, fuzzy -msgid "node.roof.glazingControls.maximumSpacing" -msgstr "最大间距" +msgid "node.roof.panel.turbineVent" +msgstr "涡轮通风器" -# Source-Hash: d10743fce478d9f4 +# Source-Hash: 6df330bcfcaac604 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Max spacing" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Apply to all planes of this roof" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.maxSpacing" -msgstr "最大间距" +msgid "node.roofSegment.buildUpSection.applyToAllPlanesOfThis" +msgstr "应用到此屋顶的所有坡面" -# Source-Hash: 37d9f63758abdb67 +# Source-Hash: 7254a3eb47471b8a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mixed" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Architectural shingle" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.mixed" -msgstr "混合" +msgid "node.roofSegment.buildUpSection.architecturalShingle" +msgstr "叠层沥青瓦" -# Source-Hash: b91302bf741c9fd6 +# Source-Hash: afd23a6d653689c6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel count" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Asphalt 3-tab" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.panelCount" -msgstr "面板数量" +msgid "node.roofSegment.buildUpSection.asphalt3Tab" +msgstr "三片式沥青瓦" -# Source-Hash: 6ce059aee1386f72 +# Source-Hash: 2650e7c436297ef2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panels" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clay tile" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.panels" -msgstr "面板" +msgid "node.roofSegment.buildUpSection.clayTile" +msgstr "黏土瓦" -# Source-Hash: ef3e765e692faf4c +# Source-Hash: 92af091c56892f25 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Concrete tile" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.solid" -msgstr "实体" +msgid "node.roofSegment.buildUpSection.concreteTile" +msgstr "混凝土瓦" -# Source-Hash: e4698e83d02beb6c +# Source-Hash: 75168c15633cbad3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spacing" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Covering" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.spacing" -msgstr "间距" +msgid "node.roofSegment.buildUpSection.covering" +msgstr "覆盖层" -# Source-Hash: 0a26a1e61c825660 +# Source-Hash: f3aa561772702108 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.start" -msgstr "起点" +msgid "node.roofSegment.buildUpSection.deck" +msgstr "屋面板" -# Source-Hash: 095237e9e2df4d9c +# Source-Hash: 14187d972ce9e1de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{title} alignment" -#: packages/nodes/src/roof/glazing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit layers" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingControls.titleAlignment" -msgstr "{title}对齐" +msgid "node.roofSegment.buildUpSection.editLayers" +msgstr "编辑构造层" -# Source-Hash: c98a4e6b28f05e0f +# Source-Hash: 5aff5f630e4b18c3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Changes apply to all {length} roof segments." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finish name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.changesApplyToAllLengthRoof" -msgstr "更改将应用于全部 {length} 个屋顶分段。" +msgid "node.roofSegment.buildUpSection.finishName" +msgstr "饰面名称" -# Source-Hash: c5d2ff7fda4787cd +# Source-Hash: b9ed3f21665672eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose one roof system to edit settings for all selected segments." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Ice and water shield" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.chooseOneRoofSystemToEdit" -msgstr "选择一种屋顶系统以编辑所有选中分段的设置。" +msgid "node.roofSegment.buildUpSection.iceAndWaterShield" +msgstr "防冰防水卷材" -# Source-Hash: 80e07a119b63187c +# Source-Hash: 6d79431c0092abac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Close the roof ends" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.closeTheRoofEnds" -msgstr "封闭屋顶端部" +msgid "node.roofSegment.buildUpSection.insulationName" +msgstr "保温层名称" -# Source-Hash: e28dd27d54aaa7ae +# Source-Hash: e4e9305964238fda # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default panel infill" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Interior finish" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.defaultPanelInfill" -msgstr "默认面板填充" +msgid "node.roofSegment.buildUpSection.interiorFinish" +msgstr "内饰面" -# Source-Hash: 134d33e2465937e7 +# Source-Hash: 4ccd2fc1a471fca5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Divides each roof face into columns." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layers" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.dividesEachRoofFaceIntoColumns" -msgstr "将每个屋面划分为列。" +msgid "node.roofSegment.buildUpSection.layers" +msgstr "构造层" -# Source-Hash: 896a6e4da3357c39 +# Source-Hash: 8f343a87f121347e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Divides the length of each arch bay into columns." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "#15 felt" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.dividesTheLengthOfEachArch" -msgstr "将每个拱跨的长度划分为列。" +msgid "node.roofSegment.buildUpSection.n15Felt" +msgstr "#15 油毡" -# Source-Hash: be9c810d28d1feb9 +# Source-Hash: faa54521399dc5b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End infill fills the space above the walls. Edit room walls and ceilings separately." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "#30 felt" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.endInfillFillsTheSpaceAbove" -msgstr "端部填充会填满墙体上方的空间。请分别编辑房间的墙体和天花板。" +msgid "node.roofSegment.buildUpSection.n30Felt" +msgstr "#30 油毡" -# Source-Hash: 0b8b27dbc57cca44 +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame color" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.frameColor" -msgstr "框架颜色" +msgid "node.roofSegment.buildUpSection.none" +msgstr "无" -# Source-Hash: fd413477f1a9e5ed +# Source-Hash: 441f7f652ea6a0d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame depth" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preset" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.frameDepth" -msgstr "框架深度" +msgid "node.roofSegment.buildUpSection.preset" +msgstr "预设" -# Source-Hash: 3519d91b7bda18a5 +# Source-Hash: a9cb232546779779 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame width" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rafters" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.frameWidth" -msgstr "框架宽度" +msgid "node.roofSegment.buildUpSection.rafters" +msgstr "椽子" -# Source-Hash: c7e72beff9fe4b37 +# Source-Hash: 5c0d95afa820e706 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Framing" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roofing" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.framing" -msgstr "龙骨" +msgid "node.roofSegment.buildUpSection.roofing" +msgstr "屋面材料" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: 75a1bff32810894e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roofing name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.glass" -msgstr "玻璃" +msgid "node.roofSegment.buildUpSection.roofingName" +msgstr "屋面材料名称" -# Source-Hash: 9c38875c310547ae +# Source-Hash: 36a588e44085108c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass tint" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sheathing" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.glassTint" -msgstr "玻璃色调" +msgid "node.roofSegment.buildUpSection.sheathing" +msgstr "覆面板" -# Source-Hash: dd330a94b3f7a65a +# Source-Hash: abdad84e524e56e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glazed" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sheathing name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.glazed" -msgstr "玻璃" +msgid "node.roofSegment.buildUpSection.sheathingName" +msgstr "覆面板名称" -# Source-Hash: e6be52df9197243a +# Source-Hash: a7b5921026935493 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glazing is available for gable, straight shed, and barrel roofs." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slate" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.glazingIsAvailableForGableStraight" -msgstr "双坡、直单坡和筒形屋顶可使用玻璃。" +msgid "node.roofSegment.buildUpSection.slate" +msgstr "石板瓦" -# Source-Hash: a4e7ef2e31d7220b +# Source-Hash: c156b8bd7920b129 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid across the roof" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standing-seam metal" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.gridAcrossTheRoof" -msgstr "沿屋顶横向网格" +msgid "node.roofSegment.buildUpSection.standingSeamMetal" +msgstr "直立锁边金属板" -# Source-Hash: 2f28a3b33fccf56b +# Source-Hash: f5defb7d8a17154e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid along the length" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Synthetic" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.gridAlongTheLength" -msgstr "沿长度方向网格" +msgid "node.roofSegment.buildUpSection.synthetic" +msgstr "合成卷材" -# Source-Hash: 1f701893dbf9d72b +# Source-Hash: 472f395a8b6319a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid along the slope" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top chord" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.gridAlongTheSlope" -msgstr "沿坡度方向网格" +msgid "node.roofSegment.buildUpSection.topChord" +msgstr "上弦" -# Source-Hash: 20c8dfbadda20e3b +# Source-Hash: 4dd558e7eeec7acf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid within each arch bay" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trusses" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.gridWithinEachArchBay" -msgstr "每个拱跨内的网格" +msgid "node.roofSegment.buildUpSection.trusses" +msgstr "桁架" -# Source-Hash: 7c339a5fae55681d +# Source-Hash: 3909955f8a920be1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Infill" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Underlayment" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.infill" -msgstr "填充" +msgid "node.roofSegment.buildUpSection.underlayment" +msgstr "防水垫层" -# Source-Hash: 1c0b8a5503c5daeb +# Source-Hash: 0167cfd2ec25cf5d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opacity" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Underlayment name" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.opacity" -msgstr "不透明度" +msgid "node.roofSegment.buildUpSection.underlaymentName" +msgstr "防水垫层名称" -# Source-Hash: 4d412746658f2faf +# Source-Hash: 7095fa6e1c927c5e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pane thickness" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wood shake" +#: packages/nodes/src/roof-segment/build-up-section.tsx #, fuzzy -msgid "node.roof.glazingPanel.paneThickness" -msgstr "窗格厚度" +msgid "node.roofSegment.buildUpSection.woodShake" +msgstr "木瓦" -# Source-Hash: 570136e723cb7d99 +# Source-Hash: 99afd827dbe5d647 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof system" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A single pitched plane of a parent roof." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.roofSegment.description" +msgstr "所属屋顶的单个坡面。" + +# Source-Hash: e72a64b3e00aad98 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Segment" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.roof.glazingPanel.roofSystem" -msgstr "屋顶系统" +msgid "node.roofSegment.label" +msgstr "屋面" -# Source-Hash: a6a7a36d982b4911 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roughness" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanel.roughness" -msgstr "粗糙度" +msgid "node.roofSegment.panel.actions" +msgstr "操作" -# Source-Hash: 2fa6fbeda5d45949 +# Source-Hash: c69865ec5d9d1ac9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spacing is measured on the slope, not its horizontal projection." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Angle" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanel.spacingIsMeasuredOnTheSlope" -msgstr "间距沿坡面测量,而非其水平投影。" +msgid "node.roofSegment.panel.angle" +msgstr "角度" -# Source-Hash: d998c212030bc7c2 +# Source-Hash: eb8f344a3c137280 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard" -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Arc" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanel.standard" -msgstr "标准" +msgid "node.roofSegment.panel.arc" +msgstr "弧形" -# Source-Hash: efbe1c4facf561f7 +# Source-Hash: 1eb45f83eeaabfad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Subdivides each flat arch bay. Arch bays controls the divisions around the curve." -#: packages/nodes/src/roof/glazing-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto gutters" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanel.subdividesEachFlatArchBayArch" -msgstr "细分每个平板拱跨。拱跨数控制曲线上的分格。" +msgid "node.roofSegment.panel.autoGutters" +msgstr "自动檐沟" -# Source-Hash: 1497eac9e4f63016 +# Source-Hash: 0986c4933d2b5808 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Choose a panel to override its default infill." -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto ridge vent" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.chooseAPanelToOverrideIts" -msgstr "选择一个面板以覆盖其默认填充。" +msgid "node.roofSegment.panel.autoRidgeVent" +msgstr "自动屋脊通风" -# Source-Hash: 3530ac1f4046cd22 +# Source-Hash: 344fe9d407a233a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Column" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Barrel" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.column2" -msgstr "柱" +msgid "node.roofSegment.panel.barrel" +msgstr "筒形" -# Source-Hash: 9e9715d52410c86f +# Source-Hash: 6ca418a2ecab5984 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clipped version" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.custom" -msgstr "自定义" +msgid "node.roofSegment.panel.clippedVersion" +msgstr "截角版本" -# Source-Hash: 4ca0e0e73229540c +# Source-Hash: 3241ecabee8221a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Default" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Conical" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.default" -msgstr "默认" +msgid "node.roofSegment.panel.conical" +msgstr "圆锥" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 9ef92ad8ae49ed72 +# Source-Hash: a37cfbc4db93cfd3 # Review: required -# English: "{columns, plural, one {{columnCount} column} other {{columnCount} columns}} · {rows, plural, one {{rowCount} row} other {{rowCount} rows}}" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Conical Shape" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.grid" -msgstr "{columns, plural, other {{columnCount} 列}} · {rows, plural, other {{rowCount} 行}}" +msgid "node.roofSegment.panel.conicalShape" +msgstr "锥形" -# Source-Hash: 11624abbcfdd5506 +# Source-Hash: a10f29fcde60eea9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Individual panels" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck Thick." +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.individualPanels" -msgstr "单个面板" +msgid "node.roofSegment.panel.deckThick" +msgstr "平台厚" -# Source-Hash: 3a019ce58d021431 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel infill" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.panelInfill" -msgstr "面板填充" +msgid "node.roofSegment.panel.delete" +msgstr "删除" -# Source-Hash: 6eb8025c60d6d3ca +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset to default" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.resetToDefault" -msgstr "恢复默认" +msgid "node.roofSegment.panel.depth" +msgstr "深度" -# Source-Hash: 6fba44f2bfd8af8e +# Source-Hash: 016d8e70618916d4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof face" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Diameter" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.roofFace" -msgstr "屋面" +msgid "node.roofSegment.panel.diameter" +msgstr "直径" -# Source-Hash: 03a22f6df69c47d3 +# Source-Hash: e132bf88b9e4d75e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Row" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done editing" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.row2" -msgstr "行" +msgid "node.roofSegment.panel.doneEditing" +msgstr "完成编辑" -# Source-Hash: 6c2cc2d9cd778998 +# Source-Hash: 00a4416e0a33d856 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Selected panel infill" -#: packages/nodes/src/roof/glazing-panel-editor.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drainage" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.glazingPanelEditor.selectedPanelInfill" -msgstr "选中面板的填充" +msgid "node.roofSegment.panel.drainage" +msgstr "排水" -# Source-Hash: f5f730969df63d1d +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.label" -msgstr "屋顶" +msgid "node.roofSegment.panel.duplicate" +msgstr "复制" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 6949d667043bee0b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dutch" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.actions" -msgstr "操作" +msgid "node.roofSegment.panel.dutch" +msgstr "荷兰式" -# Source-Hash: d60471ce3cd45348 +# Source-Hash: 4c539865731d5d66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Chimney" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eave cut" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addChimney" -msgstr "添加烟囱" +msgid "node.roofSegment.panel.eaveCut" +msgstr "檐口切法" -# Source-Hash: 1ca6a1cf9cc6e3ed +# Source-Hash: 5c99a67253bfc02a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Cupola" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Eave overhang" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addCupola" -msgstr "添加穹顶" +msgid "node.roofSegment.panel.eaveOverhang" +msgstr "檐口出挑" -# Source-Hash: 94dea147eeaac52b +# Source-Hash: dc90862aafc9d287 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Dormer" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Edit footprint" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addDormer" -msgstr "添加老虎窗" +msgid "node.roofSegment.panel.editFootprint" +msgstr "编辑基底" -# Source-Hash: 5679acdd64484726 +# Source-Hash: 9532d5e73585ea62 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Eyebrow Vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "End overhang" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addEyebrowVent" -msgstr "添加眉形通风口" +msgid "node.roofSegment.panel.endOverhang" +msgstr "端部出挑" -# Source-Hash: 25a141dc0d7c4b44 +# Source-Hash: 74f4143cd02de4a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Gutter" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fascia" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addGutter" -msgstr "添加檐沟" +msgid "node.roofSegment.panel.fascia" +msgstr "封檐板" -# Source-Hash: 7230bdc8a2252626 +# Source-Hash: 45baed9dc8b8047a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Skylight" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fascia height" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addSkylight" -msgstr "添加天窗" +msgid "node.roofSegment.panel.fasciaHeight" +msgstr "封檐板高度" -# Source-Hash: 0f220e2602b7ff24 +# Source-Hash: 9cab4d4c95f63cdd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Solar Panel" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addSolarPanel" -msgstr "添加太阳能板" +msgid "node.roofSegment.panel.flat" +msgstr "平屋顶" -# Source-Hash: 4d83a2e5a4d9e6b4 +# Source-Hash: a3c10560fa3c1612 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Footprint" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.addVent" -msgstr "添加通风口" +msgid "node.roofSegment.panel.footprint" +msgstr "基底" -# Source-Hash: e9a89a5e4ac8cd61 +# Source-Hash: deaffa095d126dfe # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Box" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.box" -msgstr "盒形" +msgid "node.roofSegment.panel.gable" +msgstr "双坡" -# Source-Hash: 3bf078fe2560daca +# Source-Hash: dbd062efc7f4fd7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "box vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gable overhang" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.boxVent" -msgstr "箱式通风口" +msgid "node.roofSegment.panel.gableOverhang" +msgstr "山墙出挑" -# Source-Hash: 4986740251121471 +# Source-Hash: 7f53d9ffca39984a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "chimney" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gambrel" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.chimney" -msgstr "烟囱" +msgid "node.roofSegment.panel.gambrel" +msgstr "复折式" -# Source-Hash: 9e9715d52410c86f +# Source-Hash: 9eda0ea8d447066d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hip" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.custom" -msgstr "自定义" +msgid "node.roofSegment.panel.hip" +msgstr "四坡" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 7ae4179d0abd80f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kink Depth" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.delete" -msgstr "删除" +msgid "node.roofSegment.panel.kinkDepth" +msgstr "折点深度" -# Source-Hash: 5169968a4b0c1840 +# Source-Hash: e19b2bca70030855 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "dormer" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Kink Height" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.dormer" -msgstr "老虎窗" +msgid "node.roofSegment.panel.kinkHeight" +msgstr "折点高度" -# Source-Hash: 72e51c6e5e9c6c26 +# Source-Hash: 643687bc3adaac76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Draw Segment" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Length" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.drawSegment" -msgstr "绘制分段" +msgid "node.roofSegment.panel.length" +msgstr "长度" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: 7f7bb0e875af3260 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mansard" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.duplicate" -msgstr "复制" +msgid "node.roofSegment.panel.mansard" +msgstr "孟莎式" -# Source-Hash: 7c4196b9e791c195 +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elements" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.elements" -msgstr "元素" +msgid "node.roofSegment.panel.move" +msgstr "移动" -# Source-Hash: 6b8ba49aa355fe87 +# Source-Hash: 75e3449fc1776d09 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows walls" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pitch" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.followsWalls" -msgstr "跟随墙体" +msgid "node.roofSegment.panel.pitch" +msgstr "坡度" -# Source-Hash: 23b434461c990711 +# Source-Hash: 6ae4075a23bb4ec4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "gutter" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plumb" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.gutter" -msgstr "檐沟" +msgid "node.roofSegment.panel.plumb" +msgstr "垂直切" -# Source-Hash: 0608743fc1736d86 +# Source-Hash: 16d8ab5937d74bdb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Level" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plumb + level" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.level" -msgstr "楼层" +msgid "node.roofSegment.panel.plumbLevel" +msgstr "垂直切 + 水平切" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.move" -msgstr "移动" +msgid "node.roofSegment.panel.position" +msgstr "位置" -# Source-Hash: 39661f4827b0f435 +# Source-Hash: bf91b71a9aa76e94 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move to {level}" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reset" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.moveToLevel" -msgstr "移到{level}" +msgid "node.roofSegment.panel.reset" +msgstr "重置" -# Source-Hash: c534093ff560a9f0 +# Source-Hash: e72a64b3e00aad98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move to the roof level" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Segment" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.moveToTheRoofLevel" -msgstr "移到屋顶楼层" +msgid "node.roofSegment.panel.roofSegment" +msgstr "屋面" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 0939fad1cb1831f0 +# Source-Hash: 19ab9527ae7889f4 # Review: required -# English: "On {storey} with its walls, so it hides that floor's plan in solo and exploded views.{roofs, plural, =0 {} =1 {} other { The floor's {roofCount} roofs move together.}}" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof Type" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.onStoreyWalls" -msgstr "与其墙体同在{storey},因此在单独和分解视图中会遮挡该层平面。{roofs, plural, =0 {} =1 {} other { 该层的 {roofCount} 个屋顶会一起移动。}}" +msgid "node.roofSegment.panel.roofType" +msgstr "屋顶类型" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.position" -msgstr "位置" +msgid "node.roofSegment.panel.rotation" +msgstr "旋转" -# Source-Hash: e6ddc8a624465793 +# Source-Hash: 85ea1d3c8b749680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Ridge" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shape" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.ridge" -msgstr "屋脊" +msgid "node.roofSegment.panel.shape" +msgstr "形状" -# Source-Hash: 83112cbc205e9972 +# Source-Hash: c8d0df27faa3feaa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "ridge vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shed" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.ridgeVent" -msgstr "屋脊通风口" +msgid "node.roofSegment.panel.shed" +msgstr "单坡" -# Source-Hash: f5f730969df63d1d +# Source-Hash: 4d944a2393bbddb2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shingle Thick." +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.roof" -msgstr "屋顶" +msgid "node.roofSegment.panel.shingleThick" +msgstr "瓦片厚" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: 93b34a5b546664c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Span" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.rotation" -msgstr "旋转" +msgid "node.roofSegment.panel.span" +msgstr "跨度" -# Source-Hash: 505d8419cf4cc5e1 +# Source-Hash: 39287346366fc206 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segments" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Square" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.segments" -msgstr "分段" +msgid "node.roofSegment.panel.square" +msgstr "直角切" -# Source-Hash: 0c084c517dbc153b +# Source-Hash: e90aceedf4a6b183 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{roofType, select, hip {Hip} gable {Gable} shed {Shed} gambrel {Gambrel} dutch {Dutch} mansard {Mansard} flat {Flat} conical {Conical} barrel {Barrel} other {Roof}}" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Start Angle" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.segmentType" -msgstr "{roofType, select, hip {四坡} gable {双坡} shed {单坡} gambrel {复折} dutch {歇山} mansard {孟莎} flat {平屋顶} conical {锥形} barrel {筒形} other {屋顶}}" +msgid "node.roofSegment.panel.startAngle" +msgstr "起始角度" -# Source-Hash: 0c4c82caccb4775c +# Source-Hash: a20c89205a4448d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "skylight" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.skylight" -msgstr "天窗" +msgid "node.roofSegment.panel.structure" +msgstr "结构" -# Source-Hash: b9f931508dd6ec70 +# Source-Hash: a2db62c74fe2bcee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "solar panel" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Rake Length" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.solarPanel" -msgstr "太阳能板" +msgid "node.roofSegment.panel.topRakeLength" +msgstr "顶部檐口长度" -# Source-Hash: d2428b22f1757a4e +# Source-Hash: 913d9552030ac86a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Turbine" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Rake Thick." +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.turbine" -msgstr "涡轮" +msgid "node.roofSegment.panel.topRakeThick" +msgstr "顶部檐口厚" -# Source-Hash: 86d02a3d3a3a7fa2 +# Source-Hash: 3beb5eb35f0c5c17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "turbine vent" -#: packages/nodes/src/roof/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Trim" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roof.panel.turbineVent" -msgstr "涡轮通风器" +msgid "node.roofSegment.panel.trim" +msgstr "装饰线" -# Source-Hash: 99afd827dbe5d647 +# Source-Hash: e6c5009c0d31fca1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A single pitched plane of a parent roof." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist Height" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.description" -msgstr "所属屋顶的单个坡面。" +msgid "node.roofSegment.panel.waistHeight" +msgstr "腰部高度" -# Source-Hash: e72a64b3e00aad98 +# Source-Hash: 4a8caffd24b6ee02 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Segment" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist Length" +#: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.label" -msgstr "屋面" +msgid "node.roofSegment.panel.waistLength" +msgstr "腰部长度" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 71045af5c81a11e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist Width" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.actions" -msgstr "操作" +msgid "node.roofSegment.panel.waistWidth" +msgstr "腰部宽度" -# Source-Hash: c69865ec5d9d1ac9 +# Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.angle" -msgstr "角度" +msgid "node.roofSegment.panel.wall" +msgstr "墙体" -# Source-Hash: eb8f344a3c137280 +# Source-Hash: e0f973edce3e4ca8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Arc" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall Height" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.arc" -msgstr "弧形" +msgid "node.roofSegment.panel.wallHeight" +msgstr "墙高" -# Source-Hash: 1eb45f83eeaabfad +# Source-Hash: d0db6dee5fe2edbd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto gutters" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall Thick." #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.autoGutters" -msgstr "自动檐沟" +msgid "node.roofSegment.panel.wallThick" +msgstr "墙厚" -# Source-Hash: 0986c4933d2b5808 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto ridge vent" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" #: packages/nodes/src/roof-segment/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.autoRidgeVent" -msgstr "自动屋脊通风" +msgid "node.roofSegment.panel.width" +msgstr "宽度" -# Source-Hash: 344fe9d407a233a9 +# Source-Hash: 6600a850000b98ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Barrel" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A captured session with optional mesh, motion, media, and sensor data." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.roofSegment.panel.barrel" -msgstr "筒形" +msgid "node.scan.description" +msgstr "包含可选网格、运动、媒体和传感器数据的采集会话。" + +# Source-Hash: 3a0701ebcb9f26cb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Capture" +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.scan.label" +msgstr "采集" -# Source-Hash: 6ca418a2ecab5984 +# Source-Hash: 95b5307eefb187c6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clipped version" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segment {number}" +#: packages/nodes/src/door/panel.tsx +#: packages/nodes/src/roof/panel.tsx +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.roofSegment.panel.clippedVersion" -msgstr "截角版本" +msgid "node.segmentNumber" +msgstr "分段 {number}" -# Source-Hash: 3241ecabee8221a1 +# Source-Hash: acb8cb92b3674b50 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Conical" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Separator" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.roofSegment.panel.conical" -msgstr "圆锥" +msgid "node.separator.label" +msgstr "分隔线" -# Source-Hash: a37cfbc4db93cfd3 +# Source-Hash: e34eb5b5bfbfce7c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Conical Shape" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Batt" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.conicalShape" -msgstr "锥形" +msgid "node.shared.buildUpControls.batt" +msgstr "保温棉毡" -# Source-Hash: a10f29fcde60eea9 +# Source-Hash: 430cef5fa9bd2787 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Deck Thick." -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Blown" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.deckThick" -msgstr "平台厚" +msgid "node.shared.buildUpControls.blown" +msgstr "喷吹保温" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 4da800c75b9a6b23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drywall" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.delete" -msgstr "删除" +msgid "node.shared.buildUpControls.drywall" +msgstr "石膏板" -# Source-Hash: 99ac4d03c3061f3a +# Source-Hash: 4e8f119349fa2dd4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drywall thickness" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.depth" -msgstr "深度" +msgid "node.shared.buildUpControls.drywallThickness" +msgstr "石膏板厚度" -# Source-Hash: 016d8e70618916d4 +# Source-Hash: 7d6ed24c02ab0c5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Diameter" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.diameter" -msgstr "直径" +msgid "node.shared.buildUpControls.insulation" +msgstr "保温层" -# Source-Hash: e132bf88b9e4d75e +# Source-Hash: 4251fc1e9051a7db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done editing" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Insulation thickness" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.doneEditing" -msgstr "完成编辑" +msgid "node.shared.buildUpControls.insulationThickness" +msgstr "保温层厚度" -# Source-Hash: 00a4416e0a33d856 +# Source-Hash: f567133879529366 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drainage" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{label} thickness" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.drainage" -msgstr "排水" +msgid "node.shared.buildUpControls.labelThickness" +msgstr "{label}厚度" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.duplicate" -msgstr "复制" +msgid "node.shared.buildUpControls.none" +msgstr "无" -# Source-Hash: 6949d667043bee0b +# Source-Hash: 4f7f8af75bf8e914 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dutch" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "OSB" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.dutch" -msgstr "荷兰式" +msgid "node.shared.buildUpControls.osb" +msgstr "定向刨花板" -# Source-Hash: 5c99a67253bfc02a +# Source-Hash: a6fd2cbf5c2154e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Eave overhang" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plaster" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.eaveOverhang" -msgstr "檐口出挑" +msgid "node.shared.buildUpControls.plaster" +msgstr "灰泥" -# Source-Hash: dc90862aafc9d287 +# Source-Hash: e669c2c08bd80e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Edit footprint" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plywood" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.editFootprint" -msgstr "编辑基底" +msgid "node.shared.buildUpControls.plywood" +msgstr "胶合板" -# Source-Hash: 9532d5e73585ea62 +# Source-Hash: 3d153fa2037159f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "End overhang" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rigid board" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.endOverhang" -msgstr "端部出挑" +msgid "node.shared.buildUpControls.rigidBoard" +msgstr "硬质保温板" -# Source-Hash: 74f4143cd02de4a6 +# Source-Hash: e4698e83d02beb6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fascia" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spacing" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.fascia" -msgstr "封檐板" +msgid "node.shared.buildUpControls.spacing" +msgstr "间距" -# Source-Hash: 45baed9dc8b8047a +# Source-Hash: bb2a1cccfd0bd194 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fascia height" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{spacing} o.c." +#. A framing spacing on centre (centre of one member to the next), e.g. 16" o.c. +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.fasciaHeight" -msgstr "封檐板高度" +msgid "node.shared.buildUpControls.spacingOC" +msgstr "中距 {spacing}" -# Source-Hash: 9cab4d4c95f63cdd +# Source-Hash: ab62afff8ba3f37f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wood plank" +#: packages/nodes/src/shared/build-up-controls.tsx #, fuzzy -msgid "node.roofSegment.panel.flat" -msgstr "平屋顶" +msgid "node.shared.buildUpControls.woodPlank" +msgstr "木板" -# Source-Hash: a3c10560fa3c1612 +# Source-Hash: e7512c891d8da7d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Footprint" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turn light off" +#: packages/nodes/src/shared/item-interaction-actions.tsx #, fuzzy -msgid "node.roofSegment.panel.footprint" -msgstr "基底" +msgid "node.shared.itemInteractionActions.turnLightOff" +msgstr "关灯" -# Source-Hash: deaffa095d126dfe +# Source-Hash: d47ec95e14909fe5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Turn light on" +#: packages/nodes/src/shared/item-interaction-actions.tsx #, fuzzy -msgid "node.roofSegment.panel.gable" -msgstr "双坡" +msgid "node.shared.itemInteractionActions.turnLightOn" +msgstr "开灯" -# Source-Hash: dbd062efc7f4fd7f +# Source-Hash: 18bf48fbbe121ef0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gable overhang" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Casing" +#: packages/nodes/src/shared/opening-casing-section.tsx #, fuzzy -msgid "node.roofSegment.panel.gableOverhang" -msgstr "山墙出挑" +msgid "node.shared.openingCasingSection.casing" +msgstr "门窗套" -# Source-Hash: 7f53d9ffca39984a +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gambrel" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/shared/opening-casing-section.tsx #, fuzzy -msgid "node.roofSegment.panel.gambrel" -msgstr "复折式" +msgid "node.shared.openingCasingSection.width" +msgstr "宽度" -# Source-Hash: 9eda0ea8d447066d +# Source-Hash: ee1c8bc3e27fb550 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hip" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Automatic support" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.hip" -msgstr "四坡" +msgid "node.shared.runHangerInspector.automaticSupport" +msgstr "自动支撑" -# Source-Hash: 7ae4179d0abd80f5 +# Source-Hash: 1353e40320c72a99 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kink Depth" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger {number} · segment {segment}" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.kinkDepth" -msgstr "折点深度" +msgid "node.shared.runHangerInspector.hangerOnSegment" +msgstr "吊架 {number} · 第 {segment} 段" -# Source-Hash: e19b2bca70030855 +# Source-Hash: 737ced90d0454197 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Kink Height" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Individual hangers" +#: packages/nodes/src/shared/run-hanger-inspector.tsx +#, fuzzy +msgid "node.shared.runHangerInspector.individualHangers" +msgstr "单个吊架" + +# Source-Hash: e6b17b09ed91c8c2 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Missing support" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.kinkHeight" -msgstr "折点高度" +msgid "node.shared.runHangerInspector.missingSupport" +msgstr "缺少支撑" -# Source-Hash: 643687bc3adaac76 +# Source-Hash: c895c3c603382ec9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Length" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No support within reach. Move the hanger or choose another host." +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.length" -msgstr "长度" +msgid "node.shared.runHangerInspector.noSupportWithinReachMoveThe" +msgstr "附近没有可用支撑。请移动吊架或选择其他承托构件。" -# Source-Hash: 7f7bb0e875af3260 +# Source-Hash: 6ce526cb7444be36 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mansard" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger {number} position in metres" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.mansard" -msgstr "孟莎式" +msgid "node.shared.runHangerInspector.positionLabel" +msgstr "吊架 {number} 的位置(米)" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: cbd36c4b82a55539 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position (m)" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.move" -msgstr "移动" +msgid "node.shared.runHangerInspector.positionM" +msgstr "位置(m)" -# Source-Hash: 75e3449fc1776d09 +# Source-Hash: b629c4f8388fd36f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Pitch" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Positions are measured along each path segment. Changing spacing regenerates the numbered slots." +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.pitch" -msgstr "坡度" +msgid "node.shared.runHangerInspector.positionsAreMeasuredAlongEachPath" +msgstr "位置沿各路径段测量。更改间距会重新生成编号位置。" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: c21cfbdb64e53388 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Reveal support" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.position" -msgstr "位置" +msgid "node.shared.runHangerInspector.revealSupport" +msgstr "显示支撑" -# Source-Hash: bf91b71a9aa76e94 +# Source-Hash: 9d5e4440db18e477 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reset" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Skip" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.reset" -msgstr "重置" +msgid "node.shared.runHangerInspector.skip" +msgstr "跳过" -# Source-Hash: e72a64b3e00aad98 +# Source-Hash: 1b184f78bf989931 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Segment" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hanger {number} support" +#: packages/nodes/src/shared/run-hanger-inspector.tsx #, fuzzy -msgid "node.roofSegment.panel.roofSegment" -msgstr "屋面" +msgid "node.shared.runHangerInspector.supportLabel" +msgstr "吊架 {number} 的支撑" -# Source-Hash: 19ab9527ae7889f4 +# Source-Hash: b2d703d283baf64a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof Type" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "About these checks" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.roofType" -msgstr "屋顶类型" +msgid "node.shared.systemCheckPanel.aboutTheseChecks" +msgstr "关于这些检查" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: 461cc26706956993 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All findings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.rotation" -msgstr "旋转" +msgid "node.shared.systemCheckPanel.allFindings" +msgstr "所有问题" -# Source-Hash: 85ea1d3c8b749680 +# Source-Hash: 7beeb4c4997f5edb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shape" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "All systems" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.shape" -msgstr "形状" +msgid "node.shared.systemCheckPanel.allSystems" +msgstr "所有系统" -# Source-Hash: c8d0df27faa3feaa +# Source-Hash: d613df280aa13b42 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shed" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connections" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.shed" -msgstr "单坡" +msgid "node.shared.systemCheckPanel.connections" +msgstr "连接" -# Source-Hash: 4d944a2393bbddb2 +# Source-Hash: 00a4416e0a33d856 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shingle Thick." -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drainage" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.shingleThick" -msgstr "瓦片厚" +msgid "node.shared.systemCheckPanel.drainage" +msgstr "排水" -# Source-Hash: 93b34a5b546664c4 +# Source-Hash: fc4ac19649f0ee8f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Span" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Error" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.span" -msgstr "跨度" +msgid "node.shared.systemCheckPanel.error" +msgstr "错误" -# Source-Hash: e90aceedf4a6b183 +# Source-Hash: b92720ff88a1bcfd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Start Angle" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Errors" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.startAngle" -msgstr "起始角度" +msgid "node.shared.systemCheckPanel.errors" +msgstr "错误" -# Source-Hash: a20c89205a4448d2 +# Source-Hash: d0e23bdbe1b380ff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Structure" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Filter system checks" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.structure" -msgstr "结构" +msgid "node.shared.systemCheckPanel.filterSystemChecks" +msgstr "筛选系统检查" -# Source-Hash: a2db62c74fe2bcee +# Source-Hash: 30d8dba84c42040e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Rake Length" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Hangers" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.topRakeLength" -msgstr "顶部檐口长度" +msgid "node.shared.systemCheckPanel.hangers" +msgstr "吊架" -# Source-Hash: 913d9552030ac86a +# Source-Hash: 8cd416ca57d969f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Rake Thick." -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Intersections" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.topRakeThick" -msgstr "顶部檐口厚" +msgid "node.shared.systemCheckPanel.intersections" +msgstr "交叉" -# Source-Hash: 3beb5eb35f0c5c17 +# Source-Hash: 18d652275a9a525c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Trim" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Locate {name} ({id})" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.trim" -msgstr "装饰线" +msgid "node.shared.systemCheckPanel.locate" +msgstr "定位{name}({id})" -# Source-Hash: e6c5009c0d31fca1 +# Source-Hash: 88546aa3a5987966 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist Height" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Missing item" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.waistHeight" -msgstr "腰部高度" +msgid "node.shared.systemCheckPanel.missingItem" +msgstr "缺失的物品" -# Source-Hash: 4a8caffd24b6ee02 +# Source-Hash: 2452d2922a7ecf4a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist Length" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No findings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.waistLength" -msgstr "腰部长度" +msgid "node.shared.systemCheckPanel.noFindings" +msgstr "没有问题" -# Source-Hash: 71045af5c81a11e4 +# Source-Hash: 995442fbfc786768 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist Width" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No findings in this category" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.waistWidth" -msgstr "腰部宽度" +msgid "node.shared.systemCheckPanel.noFindingsInThisCategory" +msgstr "此类别中没有问题" -# Source-Hash: 2210e5ee50b74dc9 +# Source-Hash: b5c58159b3eef89c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open ends" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.wall" -msgstr "墙体" +msgid "node.shared.systemCheckPanel.openEnds" +msgstr "开放端" -# Source-Hash: e0f973edce3e4ca8 +# Source-Hash: 3003dacc858d36ff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Height" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open ends and separate branches may be intentional. Intersection checks use bounding boxes; inspect openings and clearances." +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.wallHeight" -msgstr "墙高" +msgid "node.shared.systemCheckPanel.openEndsAndSeparateBranchesMay" +msgstr "开放端和独立分支可能是有意为之。交叉检查使用包围盒;请检查开口和间隙。" -# Source-Hash: d0db6dee5fe2edbd +# Source-Hash: c40c64562b6a1a91 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall Thick." -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selected connected system" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.wallThick" -msgstr "墙厚" +msgid "node.shared.systemCheckPanel.selectedConnectedSystem" +msgstr "选中的连接系统" -# Source-Hash: 3a0ccd6c46877a87 +# Source-Hash: 68355a98439229e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/roof-segment/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Selected: {count, plural, one {{number} run} other {{number} runs}} · {length} m" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.roofSegment.panel.width" -msgstr "宽度" +msgid "node.shared.systemCheckPanel.selectedRuns" +msgstr "已选:{count, plural, other {{number} 段管线}} · {length} m" -# Source-Hash: 6600a850000b98ad +# Source-Hash: e7a352627f8fcd45 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A captured session with optional mesh, motion, media, and sensor data." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Separate branches" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.scan.description" -msgstr "包含可选网格、运动、媒体和传感器数据的采集会话。" +msgid "node.shared.systemCheckPanel.separateBranches" +msgstr "独立分支" -# Source-Hash: 3a0701ebcb9f26cb +# Source-Hash: 910a5ee73f2ef8a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Capture" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show all findings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.scan.label" -msgstr "采集" +msgid "node.shared.systemCheckPanel.showAllFindings" +msgstr "显示所有问题" -# Source-Hash: 95b5307eefb187c6 +# Source-Hash: dda8887833d07390 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segment {number}" -#: packages/nodes/src/door/panel.tsx -#: packages/nodes/src/roof/panel.tsx -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System checks" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.segmentNumber" -msgstr "分段 {number}" +msgid "node.shared.systemCheckPanel.systemChecks" +msgstr "系统检查" -# Source-Hash: acb8cb92b3674b50 +# Source-Hash: 4dad0ed68e63d124 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Separator" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System finding" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.separator.label" -msgstr "分隔线" +msgid "node.shared.systemCheckPanel.systemFinding" +msgstr "系统问题" -# Source-Hash: e7512c891d8da7d8 +# Source-Hash: e37307a519466b38 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Turn light off" -#: packages/nodes/src/shared/item-interaction-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "System findings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.itemInteractionActions.turnLightOff" -msgstr "关灯" +msgid "node.shared.systemCheckPanel.systemFindings" +msgstr "系统问题" -# Source-Hash: d47ec95e14909fe5 +# Source-Hash: 5128de8b5a618339 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Turn light on" -#: packages/nodes/src/shared/item-interaction-actions.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Warning" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.itemInteractionActions.turnLightOn" -msgstr "开灯" +msgid "node.shared.systemCheckPanel.warning" +msgstr "警告" +# Source-Hash: 7e1647f9ce51509e # Review: required -# Source-Hash: ee1c8bc3e27fb550 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Automatic support" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Warnings" +#: packages/nodes/src/shared/system-check-panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.automaticSupport" -msgstr "自动支撑" +msgid "node.shared.systemCheckPanel.warnings" +msgstr "警告" +# Source-Hash: 26aff27b7284fc84 # Review: required -# Source-Hash: 1353e40320c72a99 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger {number} · segment {segment}" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A configurable shelving unit. Items host on each row." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.shared.runHangerInspector.hangerOnSegment" -msgstr "吊架 {number} · 第 {segment} 段" +msgid "node.shelf.description" +msgstr "可配置的置物架,每层都可放置物品。" +# Source-Hash: d7145f84f8e0e3fe # Review: required -# Source-Hash: 737ced90d0454197 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Individual hangers" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Shelf" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.shared.runHangerInspector.individualHangers" -msgstr "单个吊架" +msgid "node.shelf.label" +msgstr "置物架" +# Source-Hash: c52492c73312a922 # Review: required -# Source-Hash: e6b17b09ed91c8c2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Missing support" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The top-level container holding buildings, zones, and the property boundary." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.shared.runHangerInspector.missingSupport" -msgstr "缺少支撑" +msgid "node.site.description" +msgstr "包含建筑、区域和用地红线的顶层容器。" +# Source-Hash: 91f90818d42a984e # Review: required -# Source-Hash: c895c3c603382ec9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No support within reach. Move the hanger or choose another host." -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Site" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.shared.runHangerInspector.noSupportWithinReachMoveThe" -msgstr "附近没有可用支撑。请移动吊架或选择其他承托构件。" +msgid "node.site.label" +msgstr "场地" +# Source-Hash: 3b5a53b6d058a02a # Review: required -# Source-Hash: 6ce526cb7444be36 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger {number} position in metres" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Address" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.positionLabel" -msgstr "吊架 {number} 的位置(米)" +msgid "node.site.panel.address" +msgstr "地址" +# Source-Hash: ea03c49930137a0f # Review: required -# Source-Hash: cbd36c4b82a55539 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position (m)" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "APN" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.positionM" -msgstr "位置(m)" +msgid "node.site.panel.apn" +msgstr "地块编号" -# Review: required -# Source-Hash: b629c4f8388fd36f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Positions are measured along each path segment. Changing spacing regenerates the numbered slots." -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# Source-Hash: 8519c9ddf5e6b371 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto — most north-facing edge" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.positionsAreMeasuredAlongEachPath" -msgstr "位置沿各路径段测量。更改间距会重新生成编号位置。" +msgid "node.site.panel.autoMostNorthFacingEdge" +msgstr "自动 — 最朝北的边" +# Source-Hash: bc493d7655b3e3ad # Review: required -# Source-Hash: c21cfbdb64e53388 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Reveal support" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Contour interval (site plan and 3D)" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.revealSupport" -msgstr "显示支撑" +msgid "node.site.panel.contourIntervalSitePlanAnd3d" +msgstr "等高线间距(总平面与 3D)" +# Source-Hash: 99208d226da1315f # Review: required -# Source-Hash: 9d5e4440db18e477 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Skip" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "County" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.skip" -msgstr "跳过" +msgid "node.site.panel.county" +msgstr "县" +# Source-Hash: 0830cf0f95ad429d # Review: required -# Source-Hash: 1b184f78bf989931 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hanger {number} support" -#: packages/nodes/src/shared/run-hanger-inspector.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "e.g. RS-60" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.runHangerInspector.supportLabel" -msgstr "吊架 {number} 的支撑" +msgid "node.site.panel.eGRs60" +msgstr "例如 RS-60" -# Source-Hash: b2d703d283baf64a +# Source-Hash: b3e7e118266b5074 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "About these checks" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "e.g. Tampa LDC §27-156" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.aboutTheseChecks" -msgstr "关于这些检查" +msgid "node.site.panel.eGTampaLdc27156" +msgstr "例如 Tampa LDC §27-156" -# Source-Hash: 461cc26706956993 +# Source-Hash: 187e11889d08a2dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All findings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "every 12 in" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.allFindings" -msgstr "所有问题" +msgid "node.site.panel.every12In" +msgstr "每 12 in" -# Source-Hash: 7beeb4c4997f5edb +# Source-Hash: 17ee041f655085f8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "All systems" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "every 24 in" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.allSystems" -msgstr "所有系统" +msgid "node.site.panel.every24In" +msgstr "每 24 in" -# Source-Hash: d613df280aa13b42 +# Source-Hash: 40d7f9ddf5efcb7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connections" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "every 6 in" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.connections" -msgstr "连接" +msgid "node.site.panel.every6In" +msgstr "每 6 in" -# Source-Hash: 00a4416e0a33d856 +# Source-Hash: 442a3ce78ae6b462 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drainage" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Finding…" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.drainage" -msgstr "排水" +msgid "node.site.panel.finding" +msgstr "查找中…" -# Source-Hash: fc4ac19649f0ee8f +# Source-Hash: 734c1eac014adc69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Error" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Find parcel" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.error" -msgstr "错误" +msgid "node.site.panel.findParcel" +msgstr "查找地块" -# Source-Hash: b92720ff88a1bcfd +# Source-Hash: ccb70faaf91dbcb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Errors" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front (street) edge" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.errors" -msgstr "错误" +msgid "node.site.panel.frontStreetEdge" +msgstr "前侧(临街)边" -# Source-Hash: d0e23bdbe1b380ff +# Source-Hash: 4232218226616327 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Filter system checks" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Looking up the parcel and the streets around it…" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.filterSystemChecks" -msgstr "筛选系统检查" +msgid "node.site.panel.lookingUpTheParcel" +msgstr "正在查找地块及其周边街道…" -# Source-Hash: 30d8dba84c42040e +# Source-Hash: c39eb5933468a637 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Hangers" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lot area" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.hangers" -msgstr "吊架" +msgid "node.site.panel.lotArea" +msgstr "地块面积" -# Source-Hash: 8cd416ca57d969f5 +# Source-Hash: c8a874b339ff9696 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Intersections" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "1200 W Cass St, Tampa, FL" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.intersections" -msgstr "交叉" +msgid "node.site.panel.n1200WCassStTampaFl" +msgstr "1200 W Cass St, Tampa, FL" -# Source-Hash: 18d652275a9a525c +# Source-Hash: 30a0924a3360be68 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Locate {name} ({id})" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "none" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.locate" -msgstr "定位{name}({id})" +msgid "node.site.panel.none" +msgstr "无" -# Source-Hash: 88546aa3a5987966 +# Source-Hash: dd4e835cb90c5736 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Missing item" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "North rotation" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.missingItem" -msgstr "缺失的物品" +msgid "node.site.panel.northRotation" +msgstr "北向旋转" -# Source-Hash: 2452d2922a7ecf4a +# Source-Hash: a4bfb2891c820e2e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No findings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No surveyed lines — contours are drawn from the sculpted ground." +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.noFindings" -msgstr "没有问题" +msgid "node.site.panel.noSurveyedLinesContoursAreDrawn" +msgstr "无测量线 — 等高线根据塑形的地面绘制。" -# Source-Hash: 995442fbfc786768 +# Source-Hash: 1f0d024c0adbf0e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No findings in this category" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Orientation" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.noFindingsInThisCategory" -msgstr "此类别中没有问题" +msgid "node.site.panel.orientation" +msgstr "朝向" -# Source-Hash: b5c58159b3eef89c +# Source-Hash: 9a3961409e34bf66 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open ends" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Parcel" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.openEnds" -msgstr "开放端" +msgid "node.site.panel.parcel" +msgstr "地块" -# Source-Hash: 3003dacc858d36ff +# Source-Hash: 3aecc563cb9a2c68 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open ends and separate branches may be intentional. Intersection checks use bounding boxes; inspect openings and clearances." -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Parcel lookup failed." +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.openEndsAndSeparateBranchesMay" -msgstr "开放端和独立分支可能是有意为之。交叉检查使用包围盒;请检查开口和间隙。" +msgid "node.site.panel.parcelLookupFailed" +msgstr "地块查找失败。" -# Source-Hash: c40c64562b6a1a91 +# Source-Hash: 36696c4a8bede421 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Selected connected system" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Project look" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.selectedConnectedSystem" -msgstr "选中的连接系统" +msgid "node.site.panel.projectLook" +msgstr "项目外观" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 68355a98439229e2 +# Source-Hash: 5b50fc78ccdaf7aa # Review: required -# English: "Selected: {count, plural, one {{number} run} other {{number} runs}} · {length} m" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Save current look" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.selectedRuns" -msgstr "已选:{count, plural, other {{number} 段管线}} · {length} m" +msgid "node.site.panel.saveCurrentLook" +msgstr "保存当前外观" -# Source-Hash: e7a352627f8fcd45 +# Source-Hash: f06b316f421963d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Separate branches" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Save the current lighting and display as this project's default. Personal display changes stay in this browser." +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.separateBranches" -msgstr "独立分支" +msgid "node.site.panel.saveTheCurrentLightingAndDisplay" +msgstr "将当前照明和显示保存为此项目的默认设置。个人显示更改仅保留在此浏览器中。" -# Source-Hash: 910a5ee73f2ef8a6 +# Source-Hash: e87df48b61eda8ce # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show all findings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Setbacks" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.showAllFindings" -msgstr "显示所有问题" +msgid "node.site.panel.setbacks" +msgstr "退界" -# Source-Hash: dda8887833d07390 +# Source-Hash: 9ede31abea7ad545 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System checks" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show ground" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.systemChecks" -msgstr "系统检查" +msgid "node.site.panel.showGround" +msgstr "显示地面" -# Source-Hash: 4dad0ed68e63d124 +# Source-Hash: 1e16a47e5e10c83e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System finding" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Show the contour lines in 3D" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.systemFinding" -msgstr "系统问题" +msgid "node.site.panel.showTheContourLinesIn3d" +msgstr "在 3D 中显示等高线" -# Source-Hash: e37307a519466b38 +# Source-Hash: 464241679edcbdb4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "System findings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "side" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.systemFindings" -msgstr "系统问题" +msgid "node.site.panel.side" +msgstr "侧边" -# Source-Hash: 5128de8b5a618339 +# Source-Hash: 91f90818d42a984e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Warning" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Site" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.warning" -msgstr "警告" +msgid "node.site.panel.site" +msgstr "场地" -# Source-Hash: 7e1647f9ce51509e +# Source-Hash: 6165ee130f0082e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Warnings" -#: packages/nodes/src/shared/system-check-panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Source" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shared.systemCheckPanel.warnings" -msgstr "警告" +msgid "node.site.panel.source" +msgstr "来源" -# Source-Hash: 26aff27b7284fc84 +# Source-Hash: 5f3110d075c6a1a7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A configurable shelving unit. Items host on each row." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Source / citation" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shelf.description" -msgstr "可配置的置物架,每层都可放置物品。" +msgid "node.site.panel.sourceCitation" +msgstr "来源 / 引用" -# Source-Hash: d7145f84f8e0e3fe +# Source-Hash: 041cfc610fef830b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Shelf" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Street address" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.shelf.label" -msgstr "置物架" +msgid "node.site.panel.streetAddress" +msgstr "街道地址" -# Source-Hash: c52492c73312a922 +# Source-Hash: bdca51c5e6437075 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The top-level container holding buildings, zones, and the property boundary." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "survey" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.description" -msgstr "包含建筑、区域和用地红线的顶层容器。" +msgid "node.site.panel.survey" +msgstr "测量" -# Source-Hash: 91f90818d42a984e +# Source-Hash: 2177f21713b01a24 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Site" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {{lineCount} surveyed line} other {{lineCount} surveyed lines}} at {interval} ft ({datum}) — {source}" +#: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.label" -msgstr "场地" +msgid "node.site.panel.surveyedContours" +msgstr "{count, plural, other {{lineCount} 条测量线}},间距 {interval} ft({datum})— {source}" -# Source-Hash: 3b5a53b6d058a02a +# Source-Hash: d457508edd5bb8cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Address" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Terrain" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.address" -msgstr "地址" +msgid "node.site.panel.terrain" +msgstr "地形" -# Source-Hash: ea03c49930137a0f +# Source-Hash: 4c8601a0b7aeed3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "APN" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type an address first." #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.apn" -msgstr "地块编号" +msgid "node.site.panel.typeAnAddressFirst" +msgstr "请先输入地址。" -# Source-Hash: 8519c9ddf5e6b371 +# Source-Hash: dfe4cd35b3e0d5f5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto — most north-facing edge" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Use project look" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.autoMostNorthFacingEdge" -msgstr "自动 — 最朝北的边" +msgid "node.site.panel.useProjectLook" +msgstr "使用项目外观" -# Source-Hash: bc493d7655b3e3ad +# Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Contour interval (site plan and 3D)" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Zone" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.contourIntervalSitePlanAnd3d" -msgstr "等高线间距(总平面与 3D)" +msgid "node.site.panel.zone" +msgstr "区域" -# Source-Hash: 99208d226da1315f +# Source-Hash: e360f89d3c0ec456 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "County" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Front" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.county" -msgstr "县" +msgid "node.site.setback.front" +msgstr "前" -# Source-Hash: 0830cf0f95ad429d +# Source-Hash: ab1354f1aa520a54 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "e.g. RS-60" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left (override)" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.eGRs60" -msgstr "例如 RS-60" +msgid "node.site.setback.leftOverride" +msgstr "左(覆盖)" -# Source-Hash: b3e7e118266b5074 +# Source-Hash: 1a7e8e8f8e9232d7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "e.g. Tampa LDC §27-156" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rear" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.eGTampaLdc27156" -msgstr "例如 Tampa LDC §27-156" +msgid "node.site.setback.rear" +msgstr "后" -# Source-Hash: 187e11889d08a2dc +# Source-Hash: 8370146b38c30102 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "every 12 in" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right (override)" #: packages/nodes/src/site/panel.tsx -#, fuzzy -msgid "node.site.panel.every12In" -msgstr "每 12 in" +#, fuzzy +msgid "node.site.setback.rightOverride" +msgstr "右(覆盖)" -# Source-Hash: 17ee041f655085f8 +# Source-Hash: feefe9c7cb273e79 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "every 24 in" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Side" #: packages/nodes/src/site/panel.tsx #, fuzzy -msgid "node.site.panel.every24In" -msgstr "每 24 in" +msgid "node.site.setback.side" +msgstr "侧" -# Source-Hash: 40d7f9ddf5efcb7f +# Source-Hash: 67d903d7fe0c69c1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "every 6 in" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framed glass opening on a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.site.panel.every6In" -msgstr "每 6 in" +msgid "node.skylight.description" +msgstr "屋面上带框的玻璃开口。" -# Source-Hash: 442a3ce78ae6b462 +# Source-Hash: 358826fbdeaf72b9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Finding…" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Skylight" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.site.panel.finding" -msgstr "查找中…" +msgid "node.skylight.label" +msgstr "天窗" -# Source-Hash: 734c1eac014adc69 +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Find parcel" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.findParcel" -msgstr "查找地块" +msgid "node.skylight.panel.actions" +msgstr "操作" -# Source-Hash: ccb70faaf91dbcb1 +# Source-Hash: f1113261ad2797de # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front (street) edge" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Along X" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.frontStreetEdge" -msgstr "前侧(临街)边" +msgid "node.skylight.panel.alongX" +msgstr "沿 X" -# Source-Hash: 4232218226616327 +# Source-Hash: 5b84b1c644493370 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Looking up the parcel and the streets around it…" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Along Z" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.lookingUpTheParcel" -msgstr "正在查找地块及其周边街道…" +msgid "node.skylight.panel.alongZ" +msgstr "沿 Z" -# Source-Hash: c39eb5933468a637 +# Source-Hash: b3a163b453896bef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lot area" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.lotArea" -msgstr "地块面积" +msgid "node.skylight.panel.bottom" +msgstr "底部" -# Source-Hash: c8a874b339ff9696 +# Source-Hash: b8ff053666ee326b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "1200 W Cass St, Tampa, FL" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curb" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.n1200WCassStTampaFl" -msgstr "1200 W Cass St, Tampa, FL" +msgid "node.skylight.panel.curb" +msgstr "路缘" -# Source-Hash: 30a0924a3360be68 +# Source-Hash: 14144df9e1364eea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "none" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cutout Offset" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.none" -msgstr "无" +msgid "node.skylight.panel.cutoutOffset" +msgstr "开洞偏移" -# Source-Hash: dd4e835cb90c5736 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "North rotation" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.northRotation" -msgstr "北向旋转" +msgid "node.skylight.panel.delete" +msgstr "删除" -# Source-Hash: a4bfb2891c820e2e +# Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No surveyed lines — contours are drawn from the sculpted ground." -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.noSurveyedLinesContoursAreDrawn" -msgstr "无测量线 — 等高线根据塑形的地面绘制。" +msgid "node.skylight.panel.depth" +msgstr "深度" -# Source-Hash: 1f0d024c0adbf0e8 +# Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Orientation" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Dimensions" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.orientation" -msgstr "朝向" +msgid "node.skylight.panel.dimensions" +msgstr "尺寸" -# Source-Hash: 9a3961409e34bf66 +# Source-Hash: ce3a6c03765dbbd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Parcel" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.parcel" -msgstr "地块" +msgid "node.skylight.panel.frame" +msgstr "框架" -# Source-Hash: 3aecc563cb9a2c68 +# Source-Hash: 911ea36eb835f3a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Parcel lookup failed." -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass Thickness" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.parcelLookupFailed" -msgstr "地块查找失败。" +msgid "node.skylight.panel.glassThickness" +msgstr "玻璃厚度" -# Source-Hash: 36696c4a8bede421 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Project look" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.projectLook" -msgstr "项目外观" +msgid "node.skylight.panel.height" +msgstr "高度" -# Source-Hash: 5b50fc78ccdaf7aa +# Source-Hash: d56303913961984f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Save current look" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lantern Height" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.saveCurrentLook" -msgstr "保存当前外观" +msgid "node.skylight.panel.lanternHeight" +msgstr "采光亭高度" -# Source-Hash: f06b316f421963d7 +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Save the current lighting and display as this project's default. Personal display changes stay in this browser." -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.saveTheCurrentLightingAndDisplay" -msgstr "将当前照明和显示保存为此项目的默认设置。个人显示更改仅保留在此浏览器中。" +msgid "node.skylight.panel.left" +msgstr "左" -# Source-Hash: e87df48b61eda8ce +# Source-Hash: f3e9604e3b85510f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Setbacks" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Motor" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.setbacks" -msgstr "退界" +msgid "node.skylight.panel.motor" +msgstr "电机" -# Source-Hash: 9ede31abea7ad545 +# Source-Hash: a025444e0f500725 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show ground" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Motor Housing" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.showGround" -msgstr "显示地面" +msgid "node.skylight.panel.motorHousing" +msgstr "电机外壳" -# Source-Hash: 1e16a47e5e10c83e +# Source-Hash: b2cbc4e2e5545a6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Show the contour lines in 3D" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.showTheContourLinesIn3d" -msgstr "在 3D 中显示等高线" +msgid "node.skylight.panel.no" +msgstr "否" -# Source-Hash: 464241679edcbdb4 +# Source-Hash: a8e0b9fe5cfb4e3e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "side" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No Motor" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.side" -msgstr "侧边" +msgid "node.skylight.panel.noMotor" +msgstr "无电机" -# Source-Hash: 91f90818d42a984e +# Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Site" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.site" -msgstr "场地" +msgid "node.skylight.panel.open" +msgstr "打开" -# Source-Hash: 6165ee130f0082e8 +# Source-Hash: 9bfc55f879926fe6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Source" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening Angle" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.source" -msgstr "来源" +msgid "node.skylight.panel.openingAngle" +msgstr "开启角度" -# Source-Hash: 5f3110d075c6a1a7 +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Source / citation" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.sourceCitation" -msgstr "来源 / 引用" +msgid "node.skylight.panel.position" +msgstr "位置" -# Source-Hash: 041cfc610fef830b +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Street address" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.streetAddress" -msgstr "街道地址" +msgid "node.skylight.panel.right" +msgstr "右" -# Source-Hash: bdca51c5e6437075 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "survey" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.survey" -msgstr "测量" +msgid "node.skylight.panel.rotation" +msgstr "旋转" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 2177f21713b01a24 +# Source-Hash: 358826fbdeaf72b9 # Review: required -# English: "{count, plural, one {{lineCount} surveyed line} other {{lineCount} surveyed lines}} at {interval} ft ({datum}) — {source}" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Skylight" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.surveyedContours" -msgstr "{count, plural, other {{lineCount} 条测量线}},间距 {interval} ft({datum})— {source}" +msgid "node.skylight.panel.skylight" +msgstr "天窗" -# Source-Hash: d457508edd5bb8cf +# Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Terrain" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.terrain" -msgstr "地形" +msgid "node.skylight.panel.thickness" +msgstr "厚度" -# Source-Hash: 4c8601a0b7aeed3a +# Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type an address first." -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.typeAnAddressFirst" -msgstr "请先输入地址。" +msgid "node.skylight.panel.top" +msgstr "顶部" -# Source-Hash: dfe4cd35b3e0d5f5 +# Source-Hash: 75991d106eb93dae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Use project look" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Scale" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.useProjectLook" -msgstr "使用项目外观" +msgid "node.skylight.panel.topScale" +msgstr "顶部缩放" -# Source-Hash: a107b4d76d6972e3 +# Source-Hash: 3272a61417949895 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Zone" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Track Width" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.panel.zone" -msgstr "区域" +msgid "node.skylight.panel.trackWidth" +msgstr "轨道宽度" -# Source-Hash: e360f89d3c0ec456 +# Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Front" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.front" -msgstr "前" +msgid "node.skylight.panel.type" +msgstr "类型" -# Source-Hash: ab1354f1aa520a54 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left (override)" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.leftOverride" -msgstr "左(覆盖)" +msgid "node.skylight.panel.width" +msgstr "宽度" -# Source-Hash: 1a7e8e8f8e9232d7 +# Source-Hash: 184fda5c980b9d9c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rear" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Yes" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.rear" -msgstr "后" +msgid "node.skylight.panel.yes" +msgstr "是" -# Source-Hash: 8370146b38c30102 +# Source-Hash: 445aacf307de133d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right (override)" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flat roof skylight" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.rightOverride" -msgstr "右(覆盖)" +msgid "node.skylight.type.flat" +msgstr "平屋顶天窗" -# Source-Hash: feefe9c7cb273e79 +# Source-Hash: 446176b7c5d8b284 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Side" -#: packages/nodes/src/site/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Roof lantern" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.site.setback.side" -msgstr "侧" +msgid "node.skylight.type.lantern" +msgstr "屋顶采光亭" -# Source-Hash: 67d903d7fe0c69c1 +# Source-Hash: a6559387f108518f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Framed glass opening on a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening skylight" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.skylight.description" -msgstr "屋面上带框的玻璃开口。" +msgid "node.skylight.type.opening" +msgstr "可开启天窗" -# Source-Hash: 358826fbdeaf72b9 +# Source-Hash: 379436bb5a74867a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Skylight" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sliding skylight" +#: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.skylight.label" -msgstr "天窗" +msgid "node.skylight.type.sliding" +msgstr "推拉天窗" +# Source-Hash: d26ac61f593fe1bf # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walk-on rooflight" #: packages/nodes/src/skylight/panel.tsx #, fuzzy -msgid "node.skylight.panel.actions" -msgstr "操作" +msgid "node.skylight.type.walkOn" +msgstr "可上人天窗" + +# Source-Hash: ad8f8036d34f6cea +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A polygon-bounded floor surface that hosts items on top." +#: packages/nodes/src/i18n/definition-messages.ts +#, fuzzy +msgid "node.slab.description" +msgstr "由多边形界定的地面,可在其上放置物品。" +# Source-Hash: 8775bc8dc9593964 # Review: required -# Source-Hash: f1113261ad2797de -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Along X" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.skylight.panel.alongX" -msgstr "沿 X" +msgid "node.slab.label" +msgstr "楼板" +# Source-Hash: 659e6b799ad7c27d # Review: required -# Source-Hash: 5b84b1c644493370 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Along Z" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add Hole" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.alongZ" -msgstr "沿 Z" +msgid "node.slab.panel.addHole" +msgstr "添加开洞" +# Source-Hash: 8332ab41e22958f1 # Review: required -# Source-Hash: b3a163b453896bef -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Area" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.bottom" -msgstr "底部" +msgid "node.slab.panel.area" +msgstr "面积" +# Source-Hash: 05b65242d8c48791 # Review: required -# Source-Hash: b8ff053666ee326b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curb" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.curb" -msgstr "路缘" +msgid "node.slab.panel.auto" +msgstr "自动" +# Source-Hash: fadada809e27477c # Review: required -# Source-Hash: 14144df9e1364eea -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cutout Offset" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Base" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.cutoutOffset" -msgstr "开洞偏移" +msgid "node.slab.panel.base" +msgstr "底座" +# Source-Hash: 12195951bba19804 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut hatch" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.delete" -msgstr "删除" +msgid "node.slab.panel.cutHatch" +msgstr "开设检修口" +# Source-Hash: 4e4f1a24e4a9d61e # Review: required -# Source-Hash: 99ac4d03c3061f3a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut opening" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.depth" -msgstr "深度" +msgid "node.slab.panel.cutOpening" +msgstr "开洞" +# Source-Hash: 99ac4d03c3061f3a # Review: required -# Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Dimensions" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Depth" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.dimensions" -msgstr "尺寸" +msgid "node.slab.panel.depth" +msgstr "深度" +# Source-Hash: 16552c2580bbe8b8 # Review: required -# Source-Hash: ce3a6c03765dbbd8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Done" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.frame" -msgstr "框架" +msgid "node.slab.panel.done" +msgstr "完成" +# Source-Hash: 8a3bc5111b9e97f4 # Review: required -# Source-Hash: 911ea36eb835f3a6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass Thickness" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Elevation" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.glassThickness" -msgstr "玻璃厚度" +msgid "node.slab.panel.elevation" +msgstr "标高" +# Source-Hash: 201b720b76d79762 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Extends the perimeter down to terrain. The flat surface, base, and thickness stay unchanged." +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.height" -msgstr "高度" +msgid "node.slab.panel.extendsThePerimeterDownToTerrain" +msgstr "将周边向下延伸至地形。平面、底面和厚度保持不变。" +# Source-Hash: 387ce45ca2eb045f # Review: required -# Source-Hash: d56303913961984f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Lantern Height" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fixed" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.lanternHeight" -msgstr "采光亭高度" +msgid "node.slab.panel.fixed" +msgstr "固定" +# Source-Hash: d7148fa065bc709b # Review: required -# Source-Hash: f365c6b6dd9ebab9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.left" -msgstr "左" +msgid "node.slab.panel.floor" +msgstr "楼层" +# Source-Hash: 89b2cfd72a0a7e23 # Review: required -# Source-Hash: f3e9604e3b85510f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Motor" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows terrain" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.motor" -msgstr "电机" +msgid "node.slab.panel.followsTerrain" +msgstr "跟随地形" +# Source-Hash: 48c832c1fc389290 # Review: required -# Source-Hash: a025444e0f500725 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Motor Housing" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Foundation" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.motorHousing" -msgstr "电机外壳" +msgid "node.slab.panel.foundation" +msgstr "基础" +# Source-Hash: 34504c6ca6445e76 # Review: required -# Source-Hash: b2cbc4e2e5545a6c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Holes" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.no" -msgstr "否" +msgid "node.slab.panel.holes" +msgstr "开洞" +# Source-Hash: 6e68b62d2aa611a4 # Review: required -# Source-Hash: a8e0b9fe5cfb4e3e -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No Motor" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Info" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.noMotor" -msgstr "无电机" +msgid "node.slab.panel.info" +msgstr "信息" +# Source-Hash: bd02c614454fbd2b # Review: required -# Source-Hash: 3e52f04f92e08070 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.open" -msgstr "打开" +msgid "node.slab.panel.move" +msgstr "移动" +# Source-Hash: 1d2dafb0d8f26ed5 # Review: required -# Source-Hash: 9bfc55f879926fe6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening Angle" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No holes" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.openingAngle" -msgstr "开启角度" +msgid "node.slab.panel.noHoles" +msgstr "无开洞" +# Source-Hash: c6a29e75bf215488 # Review: required -# Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rim" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.position" -msgstr "位置" +msgid "node.slab.panel.rim" +msgstr "边沿" +# Source-Hash: 8775bc8dc9593964 # Review: required -# Source-Hash: b34d5ee0f218221d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Slab" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.right" -msgstr "右" +msgid "node.slab.panel.slab" +msgstr "楼板" +# Source-Hash: fb23c960abf5de23 # Review: required -# Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard (2\")" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.rotation" -msgstr "旋转" +msgid "node.slab.panel.standard2" +msgstr "标准(2\")" +# Source-Hash: 5f865b052c9b40eb # Review: required -# Source-Hash: 358826fbdeaf72b9 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Skylight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standard (5cm)" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.skylight" -msgstr "天窗" +msgid "node.slab.panel.standard5cm" +msgstr "标准(5cm)" +# Source-Hash: cff0e2e72cfab157 # Review: required -# Source-Hash: fdbb503f0941bd56 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sunken (15cm)" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.thickness" -msgstr "厚度" +msgid "node.slab.panel.sunken15cm" +msgstr "下沉(15cm)" +# Source-Hash: 8abc2aec4be98fe9 # Review: required -# Source-Hash: 27644f0497fd9849 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sunken (6\")" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.top" -msgstr "顶部" +msgid "node.slab.panel.sunken6" +msgstr "下沉(6\")" +# Source-Hash: 78a454b7ac7a3cd9 # Review: required -# Source-Hash: 75991d106eb93dae -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Scale" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.topScale" -msgstr "顶部缩放" +msgid "node.slab.panel.surface" +msgstr "表面" +# Source-Hash: 516636d85be919f0 # Review: required -# Source-Hash: 3272a61417949895 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Track Width" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thick (15cm)" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.trackWidth" -msgstr "轨道宽度" +msgid "node.slab.panel.thick15cm" +msgstr "厚(15cm)" +# Source-Hash: c84078f3560da233 # Review: required -# Source-Hash: c44f7ab8bbd24858 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thick (6\")" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.type" -msgstr "类型" +msgid "node.slab.panel.thick6" +msgstr "厚(6\")" +# Source-Hash: fdbb503f0941bd56 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.width" -msgstr "宽度" +msgid "node.slab.panel.thickness" +msgstr "厚度" +# Source-Hash: 61c191f6df40285b # Review: required -# Source-Hash: 184fda5c980b9d9c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Yes" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thin (1\")" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.panel.yes" -msgstr "是" +msgid "node.slab.panel.thin1" +msgstr "薄(1\")" +# Source-Hash: d345b1f707506fe7 # Review: required -# Source-Hash: 445aacf307de133d -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flat roof skylight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thin (2cm)" +#: packages/nodes/src/slab/panel.tsx #, fuzzy -msgid "node.skylight.type.flat" -msgstr "平屋顶天窗" +msgid "node.slab.panel.thin2cm" +msgstr "薄(2cm)" +# Source-Hash: 065ffaaf64ab479d # Review: required -# Source-Hash: 446176b7c5d8b284 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Roof lantern" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Grid of photovoltaic panels mounted on a roof segment." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.skylight.type.lantern" -msgstr "屋顶采光亭" +msgid "node.solarPanel.description" +msgstr "安装在屋面上的光伏板阵列。" +# Source-Hash: 4d18446ff8eaa680 # Review: required -# Source-Hash: a6559387f108518f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening skylight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solar Panel" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.skylight.type.opening" -msgstr "可开启天窗" +msgid "node.solarPanel.label" +msgstr "光伏板" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: 379436bb5a74867a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sliding skylight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.skylight.type.sliding" -msgstr "推拉天窗" +msgid "node.solarPanel.panel.actions" +msgstr "操作" +# Source-Hash: 2184867946897298 # Review: required -# Source-Hash: d26ac61f593fe1bf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walk-on rooflight" -#: packages/nodes/src/skylight/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Array" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.skylight.type.walkOn" -msgstr "可上人天窗" +msgid "node.solarPanel.panel.array" +msgstr "阵列" -# Source-Hash: ad8f8036d34f6cea +# Source-Hash: 6eaa0e2a78d44d59 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A polygon-bounded floor surface that hosts items on top." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto-fit to roof" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.description" -msgstr "由多边形界定的地面,可在其上放置物品。" +msgid "node.solarPanel.panel.autoFitToRoof" +msgstr "自动适配屋顶" -# Source-Hash: 8775bc8dc9593964 +# Source-Hash: 30edd1c180aac9b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Columns" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.label" -msgstr "楼板" +msgid "node.solarPanel.panel.columns" +msgstr "列" -# Source-Hash: 659e6b799ad7c27d +# Source-Hash: d1c6dd6335337cc1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add Hole" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom — dimensions don't match any preset" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.addHole" -msgstr "添加开洞" +msgid "node.solarPanel.panel.customDimensionsDonTMatchAny" +msgstr "自定义——尺寸与任何预设都不匹配" -# Source-Hash: 8332ab41e22958f1 +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Area" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.area" -msgstr "面积" +msgid "node.solarPanel.panel.delete" +msgstr "删除" -# Source-Hash: 05b65242d8c48791 +# Source-Hash: fe9356b1d0e0396b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flip orientation" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.auto" -msgstr "自动" +msgid "node.solarPanel.panel.flipOrientation" +msgstr "翻转方向" -# Source-Hash: fadada809e27477c +# Source-Hash: eaaa20f3b603140f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Base" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flush" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.base" -msgstr "底座" +msgid "node.solarPanel.panel.flush" +msgstr "齐平" -# Source-Hash: 12195951bba19804 +# Source-Hash: fd413477f1a9e5ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut hatch" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame depth" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.cutHatch" -msgstr "开设检修口" +msgid "node.solarPanel.panel.frameDepth" +msgstr "框架深度" -# Source-Hash: 4e4f1a24e4a9d61e +# Source-Hash: 6aa2318fa815e5f2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cut opening" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frame thickness" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.cutOpening" -msgstr "开洞" +msgid "node.solarPanel.panel.frameThickness" +msgstr "框架厚度" -# Source-Hash: 99ac4d03c3061f3a +# Source-Hash: c5657f721eae3dff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Depth" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap X" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.depth" -msgstr "深度" +msgid "node.solarPanel.panel.gapX" +msgstr "X 间距" -# Source-Hash: 16552c2580bbe8b8 +# Source-Hash: e6e3b393aa7c0d98 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Done" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Gap Y" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.done" -msgstr "完成" +msgid "node.solarPanel.panel.gapY" +msgstr "Y 间距" -# Source-Hash: 8a3bc5111b9e97f4 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Elevation" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.elevation" -msgstr "标高" +msgid "node.solarPanel.panel.height" +msgstr "高度" -# Source-Hash: 201b720b76d79762 +# Source-Hash: 81d365ccef73068c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Extends the perimeter down to terrain. The flat surface, base, and thickness stay unchanged." -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Mounting" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.extendsThePerimeterDownToTerrain" -msgstr "将周边向下延伸至地形。平面、底面和厚度保持不变。" +msgid "node.solarPanel.panel.mounting" +msgstr "安装方式" -# Source-Hash: 387ce45ca2eb045f +# Source-Hash: 482469f5a0873f73 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fixed" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Panel" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.fixed" -msgstr "固定" +msgid "node.solarPanel.panel.panel" +msgstr "面板" -# Source-Hash: d7148fa065bc709b +# Source-Hash: 441f7f652ea6a0d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Preset" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.floor" -msgstr "楼层" +msgid "node.solarPanel.panel.preset" +msgstr "预设" -# Source-Hash: 89b2cfd72a0a7e23 +# Source-Hash: c913b494c3901a17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows terrain" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rows" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.followsTerrain" -msgstr "跟随地形" +msgid "node.solarPanel.panel.rows" +msgstr "行" -# Source-Hash: 48c832c1fc389290 +# Source-Hash: a4dba2b2675dbba0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Foundation" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Setbacks too large to fit a panel." +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.foundation" -msgstr "基础" +msgid "node.solarPanel.panel.setbacksTooLarge" +msgstr "退界过大,无法放下面板。" -# Source-Hash: 34504c6ca6445e76 +# Source-Hash: 4d18446ff8eaa680 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Holes" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solar Panel" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.holes" -msgstr "开洞" +msgid "node.solarPanel.panel.solarPanel" +msgstr "光伏板" -# Source-Hash: 6e68b62d2aa611a4 +# Source-Hash: 0af6194a8b8d8be6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Info" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Standoff" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.info" -msgstr "信息" +msgid "node.solarPanel.panel.standoff" +msgstr "支脚" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 58cb60c14826f1d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilt angle" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.move" -msgstr "移动" +msgid "node.solarPanel.panel.tiltAngle" +msgstr "倾斜角度" -# Source-Hash: 1d2dafb0d8f26ed5 +# Source-Hash: 787005b26aec58a3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No holes" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tilted" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.noHoles" -msgstr "无开洞" +msgid "node.solarPanel.panel.tilted" +msgstr "倾斜" -# Source-Hash: c6a29e75bf215488 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rim" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.rim" -msgstr "边沿" +msgid "node.solarPanel.panel.width" +msgstr "宽度" -# Source-Hash: 8775bc8dc9593964 +# Source-Hash: cd53f16290b67f7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Slab" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Compact" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.slab" -msgstr "楼板" +msgid "node.solarPanel.preset.compact" +msgstr "紧凑型" -# Source-Hash: fb23c960abf5de23 +# Source-Hash: 317ebe2aa996af70 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard (2\")" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Frameless" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.standard2" -msgstr "标准(2\")" +msgid "node.solarPanel.preset.frameless" +msgstr "无边框" -# Source-Hash: 5f865b052c9b40eb +# Source-Hash: 46660ad432e19312 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standard (5cm)" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Residential" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.standard5cm" -msgstr "标准(5cm)" +msgid "node.solarPanel.preset.residential" +msgstr "住宅型" -# Source-Hash: cff0e2e72cfab157 +# Source-Hash: b33386b8fe3725fa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sunken (15cm)" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Residential Large" +#: packages/nodes/src/solar-panel/panel.tsx #, fuzzy -msgid "node.slab.panel.sunken15cm" -msgstr "下沉(15cm)" +msgid "node.solarPanel.preset.residentialLarge" +msgstr "大尺寸住宅型" -# Source-Hash: 8abc2aec4be98fe9 +# Source-Hash: 638f17c80f424dd3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sunken (6\")" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Player or camera origin within a level. One per level." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.slab.panel.sunken6" -msgstr "下沉(6\")" +msgid "node.spawn.description" +msgstr "楼层内的玩家或相机起点,每层一个。" -# Source-Hash: 78a454b7ac7a3cd9 +# Source-Hash: 3e2f6b4274f592c0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spawn Point" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.slab.panel.surface" -msgstr "表面" +msgid "node.spawn.label" +msgstr "出生点" -# Source-Hash: 516636d85be919f0 +# Source-Hash: faaa4f6b40001667 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thick (15cm)" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Body" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.slab.panel.thick15cm" -msgstr "厚(15cm)" +msgid "node.stair.constructionControls.body" +msgstr "主体" -# Source-Hash: c84078f3560da233 +# Source-Hash: 29b9fdb127a54435 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thick (6\")" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center stringer" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.slab.panel.thick6" -msgstr "厚(6\")" +msgid "node.stair.constructionControls.centerStringer" +msgstr "中间梯梁" -# Source-Hash: fdbb503f0941bd56 +# Source-Hash: b2b2383577835a61 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Closed risers" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.slab.panel.thickness" -msgstr "厚度" +msgid "node.stair.constructionControls.closedRisers" +msgstr "封闭踢面" -# Source-Hash: 61c191f6df40285b +# Source-Hash: 49a25acbaf33ee3d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thin (1\")" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "From structure" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.slab.panel.thin1" -msgstr "薄(1\")" +msgid "node.stair.constructionControls.fromStructure" +msgstr "随结构" -# Source-Hash: d345b1f707506fe7 +# Source-Hash: 6f6b188bff3c0223 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thin (2cm)" -#: packages/nodes/src/slab/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inherit" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.slab.panel.thin2cm" -msgstr "薄(2cm)" +msgid "node.stair.constructionControls.inherit" +msgstr "继承" -# Source-Hash: 065ffaaf64ab479d +# Source-Hash: ce25dc4a23f3ae10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Grid of photovoltaic panels mounted on a roof segment." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Nosing" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.description" -msgstr "安装在屋面上的光伏板阵列。" +msgid "node.stair.constructionControls.nosing" +msgstr "踏步前缘" -# Source-Hash: 4d18446ff8eaa680 +# Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solar Panel" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.label" -msgstr "光伏板" +msgid "node.stair.constructionControls.open" +msgstr "打开" +# Source-Hash: 7717e0464ad1e7df # Review: required -# Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Original" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.actions" -msgstr "操作" +msgid "node.stair.constructionControls.original" +msgstr "原始" +# Source-Hash: 8a6f6c6b0cca7460 # Review: required -# Source-Hash: 2184867946897298 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Array" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Riser thickness" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.array" -msgstr "阵列" +msgid "node.stair.constructionControls.riserThickness" +msgstr "踢面厚度" +# Source-Hash: 2fe058966023b542 # Review: required -# Source-Hash: 6eaa0e2a78d44d59 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto-fit to roof" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Side stringers" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.autoFitToRoof" -msgstr "自动适配屋顶" +msgid "node.stair.constructionControls.sideStringers" +msgstr "侧梯梁" +# Source-Hash: ef3e765e692faf4c # Review: required -# Source-Hash: 30edd1c180aac9b4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Columns" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Solid" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.columns" -msgstr "列" +msgid "node.stair.constructionControls.solid" +msgstr "实体" +# Source-Hash: 4c1489839e306865 # Review: required -# Source-Hash: d1c6dd6335337cc1 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom — dimensions don't match any preset" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringer depth" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.customDimensionsDonTMatchAny" -msgstr "自定义——尺寸与任何预设都不匹配" +msgid "node.stair.constructionControls.stringerDepth" +msgstr "梯梁高度" +# Source-Hash: 17e1a09c422d3660 # Review: required -# Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringer width" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.delete" -msgstr "删除" +msgid "node.stair.constructionControls.stringerWidth" +msgstr "梯梁宽度" +# Source-Hash: 146f8e61ff310dc5 # Review: required -# Source-Hash: fe9356b1d0e0396b -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flip orientation" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tread finish" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.flipOrientation" -msgstr "翻转方向" +msgid "node.stair.constructionControls.treadFinish" +msgstr "踏板饰面" +# Source-Hash: 9089f91f3fbbf4cd # Review: required -# Source-Hash: eaaa20f3b603140f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flush" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Tread thickness" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.flush" -msgstr "齐平" +msgid "node.stair.constructionControls.treadThickness" +msgstr "踏板厚度" +# Source-Hash: 44dda7136b93c8ee # Review: required -# Source-Hash: fd413477f1a9e5ed -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame depth" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.frameDepth" -msgstr "框架深度" +msgid "node.stair.constructionControls.waist" +msgstr "板式" +# Source-Hash: dfd6d2ff7a94f22e # Review: required -# Source-Hash: 6aa2318fa815e5f2 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frame thickness" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Waist thickness" +#: packages/nodes/src/stair/construction-controls.tsx #, fuzzy -msgid "node.solarPanel.panel.frameThickness" -msgstr "框架厚度" +msgid "node.stair.constructionControls.waistThickness" +msgstr "梯板厚度" +# Source-Hash: 8535b75637105412 # Review: required -# Source-Hash: c5657f721eae3dff -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap X" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A stair composed of one or more flights with configurable treads, risers, railings." +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.solarPanel.panel.gapX" -msgstr "X 间距" +msgid "node.stair.description" +msgstr "由一个或多个梯段组成的楼梯,踏板、踢板和栏杆可配置。" +# Source-Hash: c24b098693e1006d # Review: required -# Source-Hash: e6e3b393aa7c0d98 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Gap Y" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The flight chain does not reach the declared destination." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.gapY" -msgstr "Y 间距" +msgid "node.stair.diagnostic.arrivalMismatch" +msgstr "梯段链未到达指定的目标。" +# Source-Hash: 124ad1cd6bb00013 # Review: required -# Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Two risers plus going is outside the 0.60–0.65 m design range." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.height" -msgstr "高度" +msgid "node.stair.diagnostic.comfortTarget" +msgstr "两倍踢面高加踏面宽不在 0.60–0.65 m 的设计范围内。" +# Source-Hash: 7452fcd8370bef34 # Review: required -# Source-Hash: 81d365ccef73068c -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Mounting" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Going is below the design target." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.mounting" -msgstr "安装方式" +msgid "node.stair.diagnostic.goingTarget" +msgstr "踏面宽低于设计目标。" +# Source-Hash: 449683eb727091d5 # Review: required -# Source-Hash: 482469f5a0873f73 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Panel" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Overhead surfaces leave less than the target headroom." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.panel" -msgstr "面板" +msgid "node.stair.diagnostic.headroomTarget" +msgstr "上方表面留出的净空低于目标值。" +# Source-Hash: 9e9357408f6a0d08 # Review: required -# Source-Hash: 441f7f652ea6a0d8 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Preset" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Detailed headroom could not be evaluated: check riser counts and the surface query budget." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.preset" -msgstr "预设" +msgid "node.stair.diagnostic.headroomUnresolved" +msgstr "无法评估详细净空:请检查踢面数量和表面查询预算。" +# Source-Hash: 40fd019d72ff3835 # Review: required -# Source-Hash: c913b494c3901a17 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rows" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight dimensions and integer riser count must be positive." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.rows" -msgstr "行" +msgid "node.stair.diagnostic.invalidFlight" +msgstr "梯段尺寸和整数踢面数必须为正。" +# Source-Hash: 3d4b6f859bd8de50 # Review: required -# Source-Hash: a4dba2b2675dbba0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Setbacks too large to fit a panel." -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The destination must be above the stair base." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.setbacksTooLarge" -msgstr "退界过大,无法放下面板。" +msgid "node.stair.diagnostic.invalidRise" +msgstr "目标必须高于楼梯底部。" +# Source-Hash: 5f196b22e2c8296a # Review: required -# Source-Hash: 4d18446ff8eaa680 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solar Panel" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing depth exceeds a full circle at the walking line; the visible landing is limited to one circle." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.solarPanel" -msgstr "光伏板" +msgid "node.stair.diagnostic.landingOverlap" +msgstr "平台深度在行走线上超过一整圈;可见平台限制为一圈。" +# Source-Hash: 0122ec92b951a114 # Review: required -# Source-Hash: 0af6194a8b8d8be6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Standoff" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "The narrow end of a winder tread is below 0.10 m; check the intended stair use." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.standoff" -msgstr "支脚" +msgid "node.stair.diagnostic.narrowWinderEnd" +msgstr "扇形踏步窄端小于 0.10 m;请检查楼梯的预期用途。" +# Source-Hash: a664dc7f3b014af8 # Review: required -# Source-Hash: 58cb60c14826f1d0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilt angle" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight riser heights differ. Use uniform-riser repair only if this is a proposed design." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.tiltAngle" -msgstr "倾斜角度" +msgid "node.stair.diagnostic.nonuniformRisers" +msgstr "梯段踢面高度不一致。仅在此为方案设计时使用均匀踢面修复。" +# Source-Hash: cd140b519d37b01e # Review: required -# Source-Hash: 787005b26aec58a3 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tilted" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A landing has a stored rise; inspect its transition before repair." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.tilted" -msgstr "倾斜" +msgid "node.stair.diagnostic.raisedLanding" +msgstr "平台带有存储的高度;修复前请检查其过渡。" +# Source-Hash: a94cfa7b2a21cf14 # Review: required -# Source-Hash: 3a0ccd6c46877a87 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Riser height exceeds the design target." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.panel.width" -msgstr "宽度" +msgid "node.stair.diagnostic.riserTarget" +msgstr "踢面高度超过设计目标。" +# Source-Hash: 53d7084bc41c1ad6 # Review: required -# Source-Hash: cd53f16290b67f7f -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Compact" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stair" +#: packages/nodes/src/i18n/definition-messages.ts #, fuzzy -msgid "node.solarPanel.preset.compact" -msgstr "紧凑型" +msgid "node.stair.label" +msgstr "楼梯" +# Source-Hash: 4ee35f740730ae87 # Review: required -# Source-Hash: 317ebe2aa996af70 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Frameless" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.preset.frameless" -msgstr "无边框" +msgid "node.stair.layout.straight" +msgstr "直跑" +# Source-Hash: 1cda16cb49e6fb93 # Review: required -# Source-Hash: 46660ad432e19312 -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Residential" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{layout} turn" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.preset.residential" -msgstr "住宅型" +msgid "node.stair.layout.turn" +msgstr "{layout} 转折" +# Source-Hash: aa6d82bdb3cc1d9a # Review: required -# Source-Hash: b33386b8fe3725fa -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Residential Large" -#: packages/nodes/src/solar-panel/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Actions" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.solarPanel.preset.residentialLarge" -msgstr "大尺寸住宅型" +msgid "node.stair.panel.actions" +msgstr "操作" -# Source-Hash: 638f17c80f424dd3 +# Source-Hash: 15eaf25f306541f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Player or camera origin within a level. One per level." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add flight" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.spawn.description" -msgstr "楼层内的玩家或相机起点,每层一个。" +msgid "node.stair.panel.addFlight" +msgstr "添加梯段" -# Source-Hash: 3e2f6b4274f592c0 +# Source-Hash: 1fa37c346bffb8e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spawn Point" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Add landing" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.spawn.label" -msgstr "出生点" +msgid "node.stair.panel.addLanding" +msgstr "添加平台" -# Source-Hash: faaa4f6b40001667 +# Source-Hash: 9ccbd6c1785f1e73 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Body" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Apply {label} layout" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.body" -msgstr "主体" +msgid "node.stair.panel.applyLabelLayout" +msgstr "应用{label}布局" -# Source-Hash: 29b9fdb127a54435 +# Source-Hash: 7eb42ea0fc442b8d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center stringer" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto Cutout" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.centerStringer" -msgstr "中间梯梁" +msgid "node.stair.panel.autoCutout" +msgstr "自动开洞" -# Source-Hash: b2b2383577835a61 +# Source-Hash: 3eda29328f91485d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Closed risers" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Balusters" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.closedRisers" -msgstr "封闭踢面" +msgid "node.stair.panel.balusters" +msgstr "栏杆柱" -# Source-Hash: 6f6b188bff3c0223 +# Source-Hash: 19ae2360207ecf5a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inherit" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Boards" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.inherit" -msgstr "继承" +msgid "node.stair.panel.boards" +msgstr "木板" -# Source-Hash: ce25dc4a23f3ae10 +# Source-Hash: 69578b7dd7723fa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Nosing" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Both" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.nosing" -msgstr "踏步前缘" +msgid "node.stair.panel.both" +msgstr "两侧" -# Source-Hash: 3e52f04f92e08070 +# Source-Hash: 5e2429ced8144ab4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Open" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cable" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.open" -msgstr "打开" +msgid "node.stair.panel.cable" +msgstr "钢索" -# Source-Hash: 7717e0464ad1e7df +# Source-Hash: 11d6eec5d485488d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Original" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Center Column" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.original" -msgstr "原始" +msgid "node.stair.panel.centerColumn" +msgstr "中柱" -# Source-Hash: 8a6f6c6b0cca7460 +# Source-Hash: 5fbbf4ad24befa7f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Riser thickness" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Clockwise" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.riserThickness" -msgstr "踢面厚度" +msgid "node.stair.panel.clockwise" +msgstr "顺时针" -# Source-Hash: 2fe058966023b542 +# Source-Hash: 31028ca51b49018b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Side stringers" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connected to {surface}. Move the stair to connect to another edge." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.sideStringers" -msgstr "侧梯梁" +msgid "node.stair.panel.connectedTo" +msgstr "已连接到{surface}。移动楼梯可连接到其他边。" -# Source-Hash: ef3e765e692faf4c +# Source-Hash: 33133921e270509f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Solid" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Connected to a surface. Move the stair to connect to another edge." +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.solid" -msgstr "实体" +msgid "node.stair.panel.connectedToSurface" +msgstr "已连接到表面。移动楼梯可连接到其他边。" -# Source-Hash: 4c1489839e306865 +# Source-Hash: ce1429556f57d7ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stringer depth" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Construction" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.stringerDepth" -msgstr "梯梁高度" +msgid "node.stair.panel.construction" +msgstr "构造" -# Source-Hash: 17e1a09c422d3660 +# Source-Hash: 5e3e3ab7d91c2c4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stringer width" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Counterclockwise" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.stringerWidth" -msgstr "梯梁宽度" +msgid "node.stair.panel.counterclockwise" +msgstr "逆时针" -# Source-Hash: 146f8e61ff310dc5 +# Source-Hash: a028e08962c388e0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tread finish" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Curved" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.treadFinish" -msgstr "踏板饰面" +msgid "node.stair.panel.curved" +msgstr "弧形" -# Source-Hash: 9089f91f3fbbf4cd +# Source-Hash: 0bd4232a56d25366 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Tread thickness" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Custom rise" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.treadThickness" -msgstr "踏板厚度" +msgid "node.stair.panel.customRise" +msgstr "自定义踏步高" -# Source-Hash: 44dda7136b93c8ee +# Source-Hash: f3aa561772702108 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Deck" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.waist" -msgstr "板式" +msgid "node.stair.panel.deck" +msgstr "平台" -# Source-Hash: dfd6d2ff7a94f22e +# Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Waist thickness" -#: packages/nodes/src/stair/construction-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Delete" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.constructionControls.waistThickness" -msgstr "梯板厚度" +msgid "node.stair.panel.delete" +msgstr "删除" -# Source-Hash: 8535b75637105412 +# Source-Hash: 1c34e5cc37add163 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A stair composed of one or more flights with configurable treads, risers, railings." -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Design targets" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.description" -msgstr "由一个或多个梯段组成的楼梯,踏板、踢板和栏杆可配置。" +msgid "node.stair.panel.designTargets" +msgstr "设计目标" -# Source-Hash: c24b098693e1006d +# Source-Hash: 748877ae309c313c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The flight chain does not reach the declared destination." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Destination" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.arrivalMismatch" -msgstr "梯段链未到达指定的目标。" +msgid "node.stair.panel.destination" +msgstr "目标" -# Source-Hash: 124ad1cd6bb00013 +# Source-Hash: 1fa48e82752d1505 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Two risers plus going is outside the 0.60–0.65 m design range." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Drag near a deck, patio, concrete slab, or landing edge to fit the stair." #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.comfortTarget" -msgstr "两倍踢面高加踏面宽不在 0.60–0.65 m 的设计范围内。" +msgid "node.stair.panel.dragNearADeckPatioConcrete" +msgstr "拖到平台、露台、混凝土板或楼梯平台边缘附近以贴合楼梯。" -# Source-Hash: 7452fcd8370bef34 +# Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Going is below the design target." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Duplicate" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.goingTarget" -msgstr "踏面宽低于设计目标。" +msgid "node.stair.panel.duplicate" +msgstr "复制" -# Source-Hash: 449683eb727091d5 +# Source-Hash: 776903eb3756eea9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Overhead surfaces leave less than the target headroom." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equal angle" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.headroomTarget" -msgstr "上方表面留出的净空低于目标值。" +msgid "node.stair.panel.equalAngle" +msgstr "等角" -# Source-Hash: 9e9357408f6a0d08 +# Source-Hash: 8956a359d7cec0a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Detailed headroom could not be evaluated: check riser counts and the surface query budget." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Equal going" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.headroomUnresolved" -msgstr "无法评估详细净空:请检查踢面数量和表面查询预算。" +msgid "node.stair.panel.equalGoing" +msgstr "等踏步宽" -# Source-Hash: 40fd019d72ff3835 +# Source-Hash: 6ff728d5058c7e31 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flight dimensions and integer riser count must be positive." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit risers and going" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.invalidFlight" -msgstr "梯段尺寸和整数踢面数必须为正。" +msgid "node.stair.panel.fitRisersAndGoing" +msgstr "适配踢面和踏面" -# Source-Hash: 3d4b6f859bd8de50 +# Source-Hash: d60a4c7995bd2184 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The destination must be above the stair base." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit To Floor" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.invalidRise" -msgstr "目标必须高于楼梯底部。" +msgid "node.stair.panel.fitToFloor" +msgstr "贴合楼面" -# Source-Hash: 5f196b22e2c8296a +# Source-Hash: 0638614580661eb0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing depth exceeds a full circle at the walking line; the visible landing is limited to one circle." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Fit uniform risers" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.landingOverlap" -msgstr "平台深度在行走线上超过一整圈;可见平台限制为一圈。" +msgid "node.stair.panel.fitUniformRisers" +msgstr "适配均匀踢面" -# Source-Hash: 0122ec92b951a114 +# Source-Hash: 4d365dbc1fb92b90 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "The narrow end of a winder tread is below 0.10 m; check the intended stair use." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight {number}: {count, plural, one {{riserCount} riser} other {{riserCount} risers}} · R {riser} · T {going} · {slope}" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.narrowWinderEnd" -msgstr "扇形踏步窄端小于 0.10 m;请检查楼梯的预期用途。" +msgid "node.stair.panel.flightMeasurements" +msgstr "梯段 {number}:{count, plural, other {{riserCount} 级踢面}} · 踢面高 {riser} · 踏面宽 {going} · {slope}" -# Source-Hash: a664dc7f3b014af8 +# Source-Hash: 6e946bd1acd94637 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Flight riser heights differ. Use uniform-riser repair only if this is a proposed design." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floors, ceilings and stairs only." #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.nonuniformRisers" -msgstr "梯段踢面高度不一致。仅在此为方案设计时使用均匀踢面修复。" +msgid "node.stair.panel.floorsCeilingsAndStairsOnly" +msgstr "仅限楼板、天花板和楼梯。" -# Source-Hash: cd140b519d37b01e +# Source-Hash: fa10ea42944107a8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "A landing has a stored rise; inspect its transition before repair." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows deck" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.raisedLanding" -msgstr "平台带有存储的高度;修复前请检查其过渡。" +msgid "node.stair.panel.followsDeck" +msgstr "跟随平台" -# Source-Hash: a94cfa7b2a21cf14 +# Source-Hash: a5c2353769b603d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Riser height exceeds the design target." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Follows level" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.diagnostic.riserTarget" -msgstr "踢面高度超过设计目标。" +msgid "node.stair.panel.followsLevel" +msgstr "跟随楼层" -# Source-Hash: 53d7084bc41c1ad6 +# Source-Hash: b7fc627a965bc016 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Stair" -#: packages/nodes/src/i18n/definition-messages.ts +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "From Level" +#: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.label" -msgstr "楼梯" +msgid "node.stair.panel.fromLevel" +msgstr "起始楼层" -# Source-Hash: 4ee35f740730ae87 +# Source-Hash: 523b9912e283b644 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Geometry" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.layout.straight" -msgstr "直跑" +msgid "node.stair.panel.geometry" +msgstr "几何" -# Source-Hash: 1cda16cb49e6fb93 +# Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{layout} turn" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Glass" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.layout.turn" -msgstr "{layout} 转折" +msgid "node.stair.panel.glass" +msgstr "玻璃" -# Source-Hash: aa6d82bdb3cc1d9a +# Source-Hash: 55adba80c39500f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Actions" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Headroom:" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.actions" -msgstr "操作" +msgid "node.stair.panel.headroom" +msgstr "净空:" -# Source-Hash: 15eaf25f306541f9 +# Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add flight" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.addFlight" -msgstr "添加梯段" +msgid "node.stair.panel.height" +msgstr "高度" -# Source-Hash: 1fa37c346bffb8e4 +# Source-Hash: 9bcdccd29e64c4d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Add landing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inner gap" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.addLanding" -msgstr "添加平台" +msgid "node.stair.panel.innerGap" +msgstr "内间隙" -# Source-Hash: 9ccbd6c1785f1e73 +# Source-Hash: 8b54356df7ae40bf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Apply {label} layout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Inner Radius" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.applyLabelLayout" -msgstr "应用{label}布局" +msgid "node.stair.panel.innerRadius" +msgstr "内半径" -# Source-Hash: 7eb42ea0fc442b8d +# Source-Hash: 88d5b9ecb242c650 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Auto Cutout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Integrated" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.autoCutout" -msgstr "自动开洞" +msgid "node.stair.panel.integrated" +msgstr "一体式" -# Source-Hash: 3eda29328f91485d +# Source-Hash: de9566487b17a73b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Balusters" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Landing" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.balusters" -msgstr "栏杆柱" +msgid "node.stair.panel.landing" +msgstr "平台" -# Source-Hash: 19ae2360207ecf5a +# Source-Hash: 54800340a0eeab23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Boards" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Layout" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.boards" -msgstr "木板" +msgid "node.stair.panel.layout" +msgstr "布局" -# Source-Hash: 69578b7dd7723fa1 +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Both" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.both" -msgstr "两侧" +msgid "node.stair.panel.left" +msgstr "左" -# Source-Hash: 5e2429ced8144ab4 +# Source-Hash: 7d4f8532c0d115e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Cable" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left turn" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.cable" -msgstr "钢索" +msgid "node.stair.panel.leftTurn" +msgstr "左转" -# Source-Hash: 11d6eec5d485488d +# Source-Hash: c6aa74075f37313a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Center Column" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Measurements" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.centerColumn" -msgstr "中柱" +msgid "node.stair.panel.measurements" +msgstr "测量" -# Source-Hash: 5fbbf4ad24befa7f +# Source-Hash: 8e464a8f52254f27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Clockwise" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Metal" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.clockwise" -msgstr "顺时针" +msgid "node.stair.panel.metal" +msgstr "金属" -# Source-Hash: 31028ca51b49018b +# Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connected to {surface}. Move the stair to connect to another edge." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Move" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.connectedTo" -msgstr "已连接到{surface}。移动楼梯可连接到其他边。" +msgid "node.stair.panel.move" +msgstr "移动" -# Source-Hash: 33133921e270509f +# Source-Hash: a4f1cc34aae4db27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Connected to a surface. Move the stair to connect to another edge." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Moving this stair keeps its current rise, steps, and run." #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.connectedToSurface" -msgstr "已连接到表面。移动楼梯可连接到其他边。" +msgid "node.stair.panel.movingThisStairKeepsItsCurrent" +msgstr "移动此楼梯会保持其当前的总高、级数和水平长度。" -# Source-Hash: ce1429556f57d7ee +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Construction" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.construction" -msgstr "构造" +msgid "node.stair.panel.none" +msgstr "无" -# Source-Hash: 5e3e3ab7d91c2c4f +# Source-Hash: 47c858b3022b3ae5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Counterclockwise" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No overhead surface" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.counterclockwise" -msgstr "逆时针" +msgid "node.stair.panel.noOverheadSurface" +msgstr "上方无表面" -# Source-Hash: a028e08962c388e0 +# Source-Hash: 17f1933d93cf655c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Curved" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Not evaluated" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.curved" -msgstr "弧形" +msgid "node.stair.panel.notEvaluated" +msgstr "未评估" -# Source-Hash: 0bd4232a56d25366 +# Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Custom rise" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.customRise" -msgstr "自定义踏步高" +msgid "node.stair.panel.opening" +msgstr "开口" -# Source-Hash: f3aa561772702108 +# Source-Hash: 599220556fc4bbfb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Deck" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Opening Offset" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.deck" -msgstr "平台" +msgid "node.stair.panel.openingOffset" +msgstr "开洞偏移" -# Source-Hash: b26de372b4b0eaac +# Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Delete" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Position" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.delete" -msgstr "删除" +msgid "node.stair.panel.position" +msgstr "位置" -# Source-Hash: 1c34e5cc37add163 +# Source-Hash: f522323372a7a59e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Design targets" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post & rail" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.designTargets" -msgstr "设计目标" +msgid "node.stair.panel.postRail" +msgstr "立柱与横杆" -# Source-Hash: 748877ae309c313c +# Source-Hash: 240ed9c77627b9a1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Destination" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.destination" -msgstr "目标" +msgid "node.stair.panel.railing" +msgstr "栏杆" -# Source-Hash: 1fa48e82752d1505 +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Drag near a deck, patio, concrete slab, or landing edge to fit the stair." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.dragNearADeckPatioConcrete" -msgstr "拖到平台、露台、混凝土板或楼梯平台边缘附近以贴合楼梯。" +msgid "node.stair.panel.right" +msgstr "右" -# Source-Hash: 34dc96fe77a31e51 +# Source-Hash: ae876c3e9a5913eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Duplicate" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right turn" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.duplicate" -msgstr "复制" +msgid "node.stair.panel.rightTurn" +msgstr "右转" -# Source-Hash: 776903eb3756eea9 +# Source-Hash: fe8c5b735495eb00 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equal angle" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rise" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.equalAngle" -msgstr "等角" +msgid "node.stair.panel.rise" +msgstr "总高" -# Source-Hash: 8956a359d7cec0a6 +# Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Equal going" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Rotation" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.equalGoing" -msgstr "等踏步宽" +msgid "node.stair.panel.rotation" +msgstr "旋转" -# Source-Hash: 6ff728d5058c7e31 +# Source-Hash: 505d8419cf4cc5e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fit risers and going" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Segments" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.fitRisersAndGoing" -msgstr "适配踢面和踏面" +msgid "node.stair.panel.segments" +msgstr "分段" -# Source-Hash: d60a4c7995bd2184 +# Source-Hash: 0b9a0bef102b75bc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fit To Floor" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{type, select, landing {Landing} other {Stair}}" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.fitToFloor" -msgstr "贴合楼面" +msgid "node.stair.panel.segmentType" +msgstr "{type, select, landing {平台} other {梯段}}" -# Source-Hash: 0638614580661eb0 +# Source-Hash: 87b926bbf34a78ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Fit uniform risers" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sizing" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.fitUniformRisers" -msgstr "适配均匀踢面" +msgid "node.stair.panel.sizing" +msgstr "尺寸设定" -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# Source-Hash: 4d365dbc1fb92b90 +# Source-Hash: 8a0f4562198c266f # Review: required -# English: "Flight {number}: {count, plural, one {{riserCount} riser} other {{riserCount} risers}} · R {riser} · T {going} · {slope}" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Snap to nearby surfaces" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.flightMeasurements" -msgstr "梯段 {number}:{count, plural, other {{riserCount} 级踢面}} · 踢面高 {riser} · 踏面宽 {going} · {slope}" +msgid "node.stair.panel.snapToNearbySurfaces" +msgstr "吸附到附近表面" -# Source-Hash: 6e946bd1acd94637 +# Source-Hash: f9a4a870cb3d3c41 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floors, ceilings and stairs only." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Spiral" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.floorsCeilingsAndStairsOnly" -msgstr "仅限楼板、天花板和楼梯。" +msgid "node.stair.panel.spiral" +msgstr "螺旋" -# Source-Hash: fa10ea42944107a8 +# Source-Hash: f8d4f66145e1eba0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows deck" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Staircase" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.followsDeck" -msgstr "跟随平台" +msgid "node.stair.panel.staircase" +msgstr "楼梯" -# Source-Hash: a5c2353769b603d5 +# Source-Hash: be8122fbf16dec33 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Follows level" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Steps" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.followsLevel" -msgstr "跟随楼层" +msgid "node.stair.panel.steps" +msgstr "踏步" -# Source-Hash: b7fc627a965bc016 +# Source-Hash: 8846dc96332c5181 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "From Level" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Step Supports" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.fromLevel" -msgstr "起始楼层" +msgid "node.stair.panel.stepSupports" +msgstr "踏步支撑" -# Source-Hash: 523b9912e283b644 +# Source-Hash: 4ee35f740730ae87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Geometry" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Straight" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.geometry" -msgstr "几何" +msgid "node.stair.panel.straight" +msgstr "直跑" -# Source-Hash: 8ab91094cf650204 +# Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Glass" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.glass" -msgstr "玻璃" +msgid "node.stair.panel.style" +msgstr "样式" -# Source-Hash: 55adba80c39500f9 +# Source-Hash: cde3878287069df2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Headroom:" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Surface connection" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.headroom" -msgstr "净空:" +msgid "node.stair.panel.surfaceConnection" +msgstr "表面连接" -# Source-Hash: 646ef0fbcbc58edf +# Source-Hash: 4e0f8b363503efff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Height" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Sweep" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.height" -msgstr "高度" +msgid "node.stair.panel.sweep" +msgstr "扫掠" -# Source-Hash: 9bcdccd29e64c4d8 +# Source-Hash: 4c294d88d712855a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inner gap" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target going" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.innerGap" -msgstr "内间隙" +msgid "node.stair.panel.targetGoing" +msgstr "目标踏面宽" -# Source-Hash: 8b54356df7ae40bf +# Source-Hash: 74cfba22cf2e6eb8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Inner Radius" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target headroom" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.innerRadius" -msgstr "内半径" +msgid "node.stair.panel.targetHeadroom" +msgstr "目标净空" -# Source-Hash: 88d5b9ecb242c650 +# Source-Hash: 9d05958a265a6726 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Integrated" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target max riser" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.integrated" -msgstr "一体式" +msgid "node.stair.panel.targetMaxRiser" +msgstr "目标最大踢面高" -# Source-Hash: de9566487b17a73b +# Source-Hash: d10322b16178ce37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Landing" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Target minimum going" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.landing" -msgstr "平台" +msgid "node.stair.panel.targetMinimumGoing" +msgstr "目标最小踏面宽" -# Source-Hash: 54800340a0eeab23 +# Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Layout" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Thickness" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.layout" -msgstr "布局" +msgid "node.stair.panel.thickness" +msgstr "厚度" -# Source-Hash: f365c6b6dd9ebab9 +# Source-Hash: b3214a20e45a7aed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "To" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.left" -msgstr "左" +msgid "node.stair.panel.to" +msgstr "至" -# Source-Hash: 7d4f8532c0d115e9 +# Source-Hash: 846fc58043454194 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left turn" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top Landing" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.leftTurn" -msgstr "左转" +msgid "node.stair.panel.topLanding" +msgstr "顶部平台" -# Source-Hash: c6aa74075f37313a +# Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Measurements" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Type" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.measurements" -msgstr "测量" +msgid "node.stair.panel.type" +msgstr "类型" -# Source-Hash: 8e464a8f52254f27 +# Source-Hash: b4c2f503b19443c6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Metal" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Unavailable" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.metal" -msgstr "金属" +msgid "node.stair.panel.unavailable" +msgstr "不可用" -# Source-Hash: bd02c614454fbd2b +# Source-Hash: 546fa6dd4e62e82d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Move" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Walking line offset" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.move" -msgstr "移动" +msgid "node.stair.panel.walkingLineOffset" +msgstr "行走线偏移" -# Source-Hash: a4f1cc34aae4db27 +# Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Moving this stair keeps its current rise, steps, and run." +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Width" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.movingThisStairKeepsItsCurrent" -msgstr "移动此楼梯会保持其当前的总高、级数和水平长度。" +msgid "node.stair.panel.width" +msgstr "宽度" -# Source-Hash: f2953d2931e36d0c +# Source-Hash: 7b65cc10483fb191 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Winder" #: packages/nodes/src/stair/panel.tsx #, fuzzy -msgid "node.stair.panel.none" -msgstr "无" +msgid "node.stair.panel.winder" +msgstr "扇形踏步" -# Source-Hash: 47c858b3022b3ae5 +# Source-Hash: 69578b7dd7723fa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No overhead surface" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Both" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.noOverheadSurface" -msgstr "上方无表面" +msgid "node.stair.railingControls.both" +msgstr "两侧" -# Source-Hash: 17f1933d93cf655c +# Source-Hash: fe633d20f198d7e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Not evaluated" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Bottom sloped extension" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.notEvaluated" -msgstr "未评估" +msgid "node.stair.railingControls.bottomExtension" +msgstr "底部斜向延伸" -# Source-Hash: e04298381837252f +# Source-Hash: 384842ae1e1c6825 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Continuous" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.opening" -msgstr "开口" +msgid "node.stair.railingControls.continuous" +msgstr "连续" -# Source-Hash: 599220556fc4bbfb +# Source-Hash: d7148fa065bc709b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Opening Offset" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Floor" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.openingOffset" -msgstr "开洞偏移" +msgid "node.stair.railingControls.floor" +msgstr "楼层" -# Source-Hash: 9da0cbfad144d737 +# Source-Hash: 644d2d9e9c3dd31f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Position" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handrail diameter" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.position" -msgstr "位置" +msgid "node.stair.railingControls.handrailDiameter" +msgstr "扶手直径" -# Source-Hash: f522323372a7a59e +# Source-Hash: 5f3f2be1e572a066 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post & rail" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handrail height" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.postRail" -msgstr "立柱与横杆" +msgid "node.stair.railingControls.handrailHeight" +msgstr "扶手高度" -# Source-Hash: 240ed9c77627b9a1 +# Source-Hash: cb3239847f068a1b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Railing" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Handrail inset" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.railing" -msgstr "栏杆" +msgid "node.stair.railingControls.handrailInset" +msgstr "扶手内缩" -# Source-Hash: b34d5ee0f218221d +# Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Left" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.right" -msgstr "右" +msgid "node.stair.railingControls.left" +msgstr "左" -# Source-Hash: ae876c3e9a5913eb +# Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right turn" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "None" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.rightTurn" -msgstr "右转" +msgid "node.stair.railingControls.none" +msgstr "无" -# Source-Hash: fe8c5b735495eb00 +# Source-Hash: e6ac8d7c9639c351 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rise" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "No return" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.rise" -msgstr "总高" +msgid "node.stair.railingControls.noReturn" +msgstr "无回弯" -# Source-Hash: 01989595ee7c1dc0 +# Source-Hash: 5688b2003002d03a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Rotation" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Original layout" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.rotation" -msgstr "旋转" +msgid "node.stair.railingControls.originalLayout" +msgstr "原始布局" -# Source-Hash: 505d8419cf4cc5e1 +# Source-Hash: d0d904fbd052d7b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Segments" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Post-facing" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.segments" -msgstr "分段" +msgid "node.stair.railingControls.postFacing" +msgstr "朝向立柱" -# Source-Hash: 0b9a0bef102b75bc +# Source-Hash: fc4d8c6f156b0430 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "{type, select, landing {Landing} other {Stair}}" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Return length" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.segmentType" -msgstr "{type, select, landing {平台} other {梯段}}" +msgid "node.stair.railingControls.returnLength" +msgstr "回弯长度" -# Source-Hash: 87b926bbf34a78ed +# Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sizing" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Right" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.sizing" -msgstr "尺寸设定" +msgid "node.stair.railingControls.right" +msgstr "右" -# Source-Hash: 8a0f4562198c266f +# Source-Hash: e1f8354a95b5060a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Snap to nearby surfaces" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Separate handrail" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.snapToNearbySurfaces" -msgstr "吸附到附近表面" +msgid "node.stair.railingControls.separateHandrail" +msgstr "独立扶手" -# Source-Hash: f9a4a870cb3d3c41 +# Source-Hash: 005f0197ec3bc95a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Spiral" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Set the length to reach the wall or post." +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.spiral" -msgstr "螺旋" +msgid "node.stair.railingControls.setTheLengthToReachThe" +msgstr "设置长度以到达墙体或立柱。" -# Source-Hash: f8d4f66145e1eba0 +# Source-Hash: bef713f3ec96f758 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Staircase" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Top horizontal extension" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.staircase" -msgstr "楼梯" +msgid "node.stair.railingControls.topExtension" +msgstr "顶部水平延伸" -# Source-Hash: be8122fbf16dec33 +# Source-Hash: bdad79929de6b142 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Steps" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wall-facing" +#: packages/nodes/src/stair/railing-controls.tsx #, fuzzy -msgid "node.stair.panel.steps" -msgstr "踏步" +msgid "node.stair.railingControls.wallFacing" +msgstr "朝向墙体" -# Source-Hash: 8846dc96332c5181 +# Source-Hash: 1709ce71eba750ff # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Step Supports" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A solid poured flight on a footing; risers closed, no stringers." +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.stepSupports" -msgstr "踏步支撑" +msgid "node.stair.structureControls.aSolidPouredFlightOnA" +msgstr "现浇实心梯段,位于基脚上;踢面封闭,无梯梁。" -# Source-Hash: 4ee35f740730ae87 +# Source-Hash: 56be143b76f65392 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Straight" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto ({autoCount})" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.straight" -msgstr "直跑" +msgid "node.stair.structureControls.autoAutocount" +msgstr "自动({autoCount})" -# Source-Hash: 1a79a485d91f3f28 +# Source-Hash: d7820aaac08e4fcb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Style" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto (closed)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.style" -msgstr "样式" +msgid "node.stair.structureControls.autoClosed" +msgstr "自动(封闭)" -# Source-Hash: cde3878287069df2 +# Source-Hash: c7cbd493df719e71 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Surface connection" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto (open)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.surfaceConnection" -msgstr "表面连接" +msgid "node.stair.structureControls.autoOpen" +msgstr "自动(开放)" -# Source-Hash: 4e0f8b363503efff +# Source-Hash: be21258d52930d5c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Sweep" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto (pressure-treated)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.sweep" -msgstr "扫掠" +msgid "node.stair.structureControls.autoPressureTreated" +msgstr "自动(加压防腐)" -# Source-Hash: 4c294d88d712855a +# Source-Hash: 1828540d95a5b5c7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target going" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto ({treads})" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.targetGoing" -msgstr "目标踏面宽" +msgid "node.stair.structureControls.autoTreads" +msgstr "自动({treads})" -# Source-Hash: 74cfba22cf2e6eb8 +# Source-Hash: 43c1949fa53685b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target headroom" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Auto (untreated)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.targetHeadroom" -msgstr "目标净空" +msgid "node.stair.structureControls.autoUntreated" +msgstr "自动(非防腐)" -# Source-Hash: 9d05958a265a6726 +# Source-Hash: d0a3ca3ce29ae833 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target max riser" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Closed (1x8 boards)" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.targetMaxRiser" -msgstr "目标最大踢面高" +msgid "node.stair.structureControls.closed1x8Boards" +msgstr "封闭(1x8 板)" -# Source-Hash: d10322b16178ce37 +# Source-Hash: 824471a3691b51db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Target minimum going" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Concrete" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.targetMinimumGoing" -msgstr "目标最小踏面宽" +msgid "node.stair.structureControls.concrete" +msgstr "混凝土" -# Source-Hash: fdbb503f0941bd56 +# Source-Hash: dcb2dd54c3301068 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Thickness" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# steel channel} other {# steel channels}}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.thickness" -msgstr "厚度" +msgid "node.stair.structureControls.countSteelChannels" +msgstr "{count, plural, other {# 根槽钢}}" -# Source-Hash: b3214a20e45a7aed +# Source-Hash: fbf12088b828a103 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "To" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# steel channel at {spacing} o.c.} other {# steel channels at {spacing} o.c.}}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.to" -msgstr "至" +msgid "node.stair.structureControls.countSteelChannelsAtSpacing" +msgstr "{count, plural, other {# 根槽钢,中距 {spacing}}}" -# Source-Hash: 846fc58043454194 +# Source-Hash: 6f0f06f0531c7e96 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top Landing" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# stringer} other {# stringers}}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.topLanding" -msgstr "顶部平台" +msgid "node.stair.structureControls.countStringers" +msgstr "{count, plural, other {# 根梯梁}}" -# Source-Hash: c44f7ab8bbd24858 +# Source-Hash: cfdb3f3fc95ea940 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Type" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{count, plural, one {# stringer at {spacing} o.c.} other {# stringers at {spacing} o.c.}}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.type" -msgstr "类型" +msgid "node.stair.structureControls.countStringersAtSpacing" +msgstr "{count, plural, other {# 根梯梁,中距 {spacing}}}" -# Source-Hash: b4c2f503b19443c6 +# Source-Hash: fa4b97d3aa600bcd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Unavailable" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Cut" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.unavailable" -msgstr "不可用" +msgid "node.stair.structureControls.cut" +msgstr "锯齿形" -# Source-Hash: 546fa6dd4e62e82d +# Source-Hash: ba4f3c1346b3e7af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Walking line offset" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Flight {number}: {layout}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.walkingLineOffset" -msgstr "行走线偏移" +msgid "node.stair.structureControls.flightLayout" +msgstr "梯段 {number}:{layout}" -# Source-Hash: 3a0ccd6c46877a87 +# Source-Hash: 4cbb34fdf4c1e107 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Width" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Housed sides" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.width" -msgstr "宽度" +msgid "node.stair.structureControls.housedSides" +msgstr "开槽侧梁" -# Source-Hash: 7b65cc10483fb191 +# Source-Hash: e3ddff241f642295 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Winder" -#: packages/nodes/src/stair/panel.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{inches} in o.c." +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.panel.winder" -msgstr "扇形踏步" +msgid "node.stair.structureControls.inchesInOC" +msgstr "中距 {inches} in" -# Source-Hash: 69578b7dd7723fa1 +# Source-Hash: 542ca0bee99a1533 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Both" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "{layout} (auto)" +#. The stringer count was chosen automatically, not set by hand. +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.both" -msgstr "两侧" +msgid "node.stair.structureControls.layoutAuto" +msgstr "{layout}(自动)" -# Source-Hash: fe633d20f198d7e4 +# Source-Hash: 73dcfae611575500 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Bottom sloped extension" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Lumber" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.bottomExtension" -msgstr "底部斜向延伸" +msgid "node.stair.structureControls.lumber" +msgstr "木材" -# Source-Hash: 384842ae1e1c6825 +# Source-Hash: d10743fce478d9f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Continuous" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Max spacing" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.continuous" -msgstr "连续" +msgid "node.stair.structureControls.maxSpacing" +msgstr "最大间距" -# Source-Hash: d7148fa065bc709b +# Source-Hash: ce25dc4a23f3ae10 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Floor" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Nosing" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.floor" -msgstr "楼层" +msgid "node.stair.structureControls.nosing" +msgstr "踏步前缘" -# Source-Hash: 644d2d9e9c3dd31f +# Source-Hash: ba534b07476bc06d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handrail diameter" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "One {stock}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.handrailDiameter" -msgstr "扶手直径" +msgid "node.stair.structureControls.oneStock" +msgstr "一块 {stock}" -# Source-Hash: 5f3f2be1e572a066 +# Source-Hash: 3e52f04f92e08070 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handrail height" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Open" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.handrailHeight" -msgstr "扶手高度" +msgid "node.stair.structureControls.open" +msgstr "开放" -# Source-Hash: cb3239847f068a1b +# Source-Hash: 20f023962f848e14 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Handrail inset" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Original body" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.handrailInset" -msgstr "扶手内缩" +msgid "node.stair.structureControls.originalBody" +msgstr "原始主体" -# Source-Hash: f365c6b6dd9ebab9 +# Source-Hash: ac658d76a942652f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Left" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Plywood + finish" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.left" -msgstr "左" +msgid "node.stair.structureControls.plywoodFinish" +msgstr "胶合板 + 饰面" -# Source-Hash: f2953d2931e36d0c +# Source-Hash: 86fda85cdc89fd27 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "None" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Pressure-treated" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.none" -msgstr "无" +msgid "node.stair.structureControls.pressureTreated" +msgstr "加压防腐" -# Source-Hash: e6ac8d7c9639c351 +# Source-Hash: d903bba423ddb755 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "No return" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Risers" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.noReturn" -msgstr "无回弯" +msgid "node.stair.structureControls.risers" +msgstr "踢面" -# Source-Hash: 5688b2003002d03a +# Source-Hash: ff0400a550f24adf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Original layout" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Steel stringers" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.originalLayout" -msgstr "原始布局" +msgid "node.stair.structureControls.steelStringers" +msgstr "钢梯梁" -# Source-Hash: d0d904fbd052d7b2 +# Source-Hash: 50d4cac7f3002cd2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Post-facing" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringer count" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.postFacing" -msgstr "朝向立柱" +msgid "node.stair.structureControls.stringerCount" +msgstr "梯梁数量" -# Source-Hash: fc4d8c6f156b0430 +# Source-Hash: 71733e5b479af2a0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Return length" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringers" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.returnLength" -msgstr "回弯长度" +msgid "node.stair.structureControls.stringers" +msgstr "梯梁" -# Source-Hash: b34d5ee0f218221d +# Source-Hash: 191196b94d1c86f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Right" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Stringer type" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.right" -msgstr "右" +msgid "node.stair.structureControls.stringerType" +msgstr "梯梁类型" -# Source-Hash: e1f8354a95b5060a +# Source-Hash: a20c89205a4448d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Separate handrail" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Structure" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.separateHandrail" -msgstr "独立扶手" +msgid "node.stair.structureControls.structure" +msgstr "结构" -# Source-Hash: 005f0197ec3bc95a +# Source-Hash: 869e3785611a0858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Set the length to reach the wall or post." -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Treads" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.setTheLengthToReachThe" -msgstr "设置长度以到达墙体或立柱。" +msgid "node.stair.structureControls.treads" +msgstr "踏板" -# Source-Hash: bef713f3ec96f758 +# Source-Hash: e1e6555b827b4620 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Top horizontal extension" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Two {stock}" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.topExtension" -msgstr "顶部水平延伸" +msgid "node.stair.structureControls.twoStock" +msgstr "两块 {stock}" -# Source-Hash: bdad79929de6b142 +# Source-Hash: 5c362de43a2cbac1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus -# English: "Wall-facing" -#: packages/nodes/src/stair/railing-controls.tsx +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Untreated" +#: packages/nodes/src/stair/structure-controls.tsx #, fuzzy -msgid "node.stair.railingControls.wallFacing" -msgstr "朝向墙体" +msgid "node.stair.structureControls.untreated" +msgstr "非防腐" + +# Source-Hash: 401bae5ffee978fa +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Wood stringers" +#: packages/nodes/src/stair/structure-controls.tsx +#, fuzzy +msgid "node.stair.structureControls.woodStringers" +msgstr "木梯梁" # Source-Hash: ce0b6361eb77e93c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A single flight of a parent stair." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -29750,8 +32483,8 @@ msgstr "所属楼梯的单个梯段。" # Source-Hash: 2159ec5769e1c59a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stair Segment" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -29760,8 +32493,8 @@ msgstr "梯段" # Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29770,8 +32503,8 @@ msgstr "操作" # Source-Hash: 551b04c03b07595e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Attachment" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29780,8 +32513,8 @@ msgstr "连接" # Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29790,8 +32523,8 @@ msgstr "删除" # Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dimensions" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29800,8 +32533,8 @@ msgstr "尺寸" # Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duplicate" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29810,8 +32543,8 @@ msgstr "复制" # Source-Hash: ad063fb27f370c28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Editing switches the stair to Custom rise" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29820,8 +32553,8 @@ msgstr "编辑后楼梯将切换为自定义踏步高" # Source-Hash: 776903eb3756eea9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Equal angle" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29830,8 +32563,8 @@ msgstr "等角" # Source-Hash: 8956a359d7cec0a6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Equal going" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29840,8 +32573,8 @@ msgstr "等踏步宽" # Source-Hash: 66f1018b50c2e426 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fill to floor" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29850,8 +32583,8 @@ msgstr "填充至地面" # Source-Hash: deff4254bb163b2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flight" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29860,8 +32593,8 @@ msgstr "梯段" # Source-Hash: d6da828cd0c5e8cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flight shape" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29870,8 +32603,8 @@ msgstr "梯段形状" # Source-Hash: e360f89d3c0ec456 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Front" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29880,8 +32613,8 @@ msgstr "前" # Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Height" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29890,8 +32623,8 @@ msgstr "高度" # Source-Hash: 9bcdccd29e64c4d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Inner gap" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29900,8 +32633,8 @@ msgstr "内间隙" # Source-Hash: de9566487b17a73b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Landing" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29910,8 +32643,8 @@ msgstr "平台" # Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Left" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29920,8 +32653,8 @@ msgstr "左" # Source-Hash: 7d4f8532c0d115e9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Left turn" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29930,8 +32663,8 @@ msgstr "左转" # Source-Hash: 643687bc3adaac76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Length" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29940,8 +32673,8 @@ msgstr "长度" # Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Move" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29950,8 +32683,8 @@ msgstr "移动" # Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Position" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29960,8 +32693,8 @@ msgstr "位置" # Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Right" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29970,8 +32703,8 @@ msgstr "右" # Source-Hash: ae876c3e9a5913eb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Right turn" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29980,8 +32713,8 @@ msgstr "右转" # Source-Hash: 01989595ee7c1dc0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rotation" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -29990,8 +32723,8 @@ msgstr "旋转" # Source-Hash: 2159ec5769e1c59a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stair Segment" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30000,8 +32733,8 @@ msgstr "梯段" # Source-Hash: be8122fbf16dec33 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Steps" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30010,8 +32743,8 @@ msgstr "踏步" # Source-Hash: 4ee35f740730ae87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Straight" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30020,8 +32753,8 @@ msgstr "直跑" # Source-Hash: a20c89205a4448d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Structure" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30030,8 +32763,8 @@ msgstr "结构" # Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Thickness" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30040,8 +32773,8 @@ msgstr "厚度" # Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Type" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30050,8 +32783,8 @@ msgstr "类型" # Source-Hash: 546fa6dd4e62e82d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Walking line offset" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30060,8 +32793,8 @@ msgstr "行走线偏移" # Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Width" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30070,8 +32803,8 @@ msgstr "宽度" # Source-Hash: 7b65cc10483fb191 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Winder" #: packages/nodes/src/stair-segment/panel.tsx #, fuzzy @@ -30080,8 +32813,8 @@ msgstr "扇形踏步" # Source-Hash: 5434a3189441c913 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Persistent construction grid axis with identification bubbles." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30090,8 +32823,8 @@ msgstr "带编号圆圈的持久结构轴线。" # Source-Hash: 0cfe636f7fdd9fd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Structural Grid" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30100,8 +32833,8 @@ msgstr "结构轴网" # Source-Hash: 36b714210f25c284 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wind-driven spinning whirlybird exhaust vent for a roof slope." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30110,198 +32843,198 @@ msgstr "用于屋面坡的风力旋转排气扇。" # Source-Hash: 4a855abb962f5e7a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Turbine Vent" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy msgid "node.turbineVent.label" msgstr "涡轮通风器" -# Review: required # Source-Hash: aa6d82bdb3cc1d9a -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.actions" msgstr "操作" -# Review: required # Source-Hash: c65f02bcdc3231d6 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Cylinder" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.cylinder" msgstr "圆柱" -# Review: required # Source-Hash: b26de372b4b0eaac -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.delete" msgstr "删除" -# Review: required # Source-Hash: 016d8e70618916d4 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Diameter" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.diameter" msgstr "直径" -# Review: required # Source-Hash: 12df69f42beb0643 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dimensions" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.dimensions" msgstr "尺寸" -# Review: required # Source-Hash: 34dc96fe77a31e51 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duplicate" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.duplicate" msgstr "复制" -# Review: required # Source-Hash: 2d4223f80dc3945c -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Globe" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.globe" msgstr "球形" -# Review: required # Source-Hash: 646ef0fbcbc58edf -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Height" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.height" msgstr "高度" -# Review: required # Source-Hash: c0ff16d77ebc9593 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Motion" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.motion" msgstr "运动" -# Review: required # Source-Hash: bd02c614454fbd2b -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Move" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.move" msgstr "移动" -# Review: required # Source-Hash: 6faf9532dcbfe4bc -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Neck Height" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.neckHeight" msgstr "颈部高度" -# Review: required # Source-Hash: 1550d72740e66f77 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Pause" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.pause" msgstr "暂停" -# Review: required # Source-Hash: c7b10382e01914ad -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Play" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.play" msgstr "播放" -# Review: required # Source-Hash: 9da0cbfad144d737 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Position" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.position" msgstr "位置" -# Review: required # Source-Hash: 01989595ee7c1dc0 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rotation" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.rotation" msgstr "旋转" -# Review: required # Source-Hash: bf553d40ce68834d -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Spin Speed" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.spinSpeed" msgstr "转速" -# Review: required # Source-Hash: 1a79a485d91f3f28 -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Style" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.style" msgstr "样式" -# Review: required # Source-Hash: 4a855abb962f5e7a -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Turbine Vent" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy msgid "node.turbineVent.panel.turbineVent" msgstr "涡轮通风器" -# Review: required # Source-Hash: 80cef0dce71e121f -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Vanes" #: packages/nodes/src/turbine-vent/panel.tsx #, fuzzy @@ -30310,8 +33043,8 @@ msgstr "叶片" # Source-Hash: e3d2aaaf5c72bc3b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A named group of zones forming one apartment, hotel room or commercial lot." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30320,8 +33053,8 @@ msgstr "组成一套公寓、酒店客房或商业单元的命名区域组。" # Source-Hash: 40e5a51d0d205fcf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Apartment" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30330,8 +33063,8 @@ msgstr "公寓" # Source-Hash: ad041d9634dd55ea # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Commercial" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30340,8 +33073,8 @@ msgstr "商业" # Source-Hash: 862f30cb2d49f812 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Common" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30350,8 +33083,8 @@ msgstr "公共" # Source-Hash: cd7e1bc42d47a105 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hotel room" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30360,8 +33093,8 @@ msgstr "酒店客房" # Source-Hash: 062cc0f1afef0c52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unit" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -30370,8 +33103,8 @@ msgstr "单元" # Source-Hash: 612dcd5bf06a79c4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Room" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30380,8 +33113,8 @@ msgstr "房间" # Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30390,8 +33123,8 @@ msgstr "区域" # Source-Hash: e25d5b5630b9d8df # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Members sit on levels that are not adjacent." #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30400,8 +33133,8 @@ msgstr "成员位于不相邻的楼层上。" # Source-Hash: 5ebeb440e0e64d01 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No zones assigned yet." #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30410,8 +33143,8 @@ msgstr "尚未分配区域。" # Source-Hash: 07731fa851c75d8c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Remove {name} from unit" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30420,8 +33153,8 @@ msgstr "从单元中移除{name}" # Source-Hash: 389839734c8350b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Remove zone from unit" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30430,8 +33163,8 @@ msgstr "从单元中移除区域" # Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30440,8 +33173,8 @@ msgstr "操作" # Source-Hash: fe18958cedd627d2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Color" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30450,8 +33183,8 @@ msgstr "颜色" # Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30460,8 +33193,8 @@ msgstr "删除" # Source-Hash: b80dc93401f953a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Focus" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30470,8 +33203,8 @@ msgstr "聚焦" # Source-Hash: 1218205b3bb34f1d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gross area" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30480,8 +33213,8 @@ msgstr "总面积" # Source-Hash: aa9d6710f4cac041 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Kind" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30490,8 +33223,8 @@ msgstr "类型" # Source-Hash: cc3d601d59e2e26c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Levels" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30500,8 +33233,8 @@ msgstr "楼层" # Source-Hash: 6bbc51529519435c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Members" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30510,8 +33243,8 @@ msgstr "成员" # Source-Hash: 6cc5df35f0338e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Name" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30520,8 +33253,8 @@ msgstr "名称" # Source-Hash: 54b25f70c7b63446 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No rooms yet. Pick this unit from a room's panel, or draw zones while it is focused." #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30530,8 +33263,8 @@ msgstr "暂无房间。可在房间面板中选择此单元,或在其聚焦时 # Source-Hash: 85d640066187108d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Report" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30540,8 +33273,8 @@ msgstr "报告" # Source-Hash: 062cc0f1afef0c52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unit" #: packages/nodes/src/unit/unit-panel.tsx #, fuzzy @@ -30550,8 +33283,8 @@ msgstr "单元" # Source-Hash: d53242481ff46157 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Merge walls" #: packages/nodes/src/wall/actions.tsx #, fuzzy @@ -30560,28 +33293,38 @@ msgstr "合并墙体" # Source-Hash: d7ead4708d50965f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Split wall" #: packages/nodes/src/wall/actions.tsx #, fuzzy msgid "node.wall.actions.splitWall" msgstr "拆分墙体" +# Source-Hash: 2f8c3189a0b3972b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "These walls cannot be merged." +#: packages/nodes/src/wall/actions.tsx +#, fuzzy +msgid "node.wall.actions.theseWallsCannotBeMerged" +msgstr "这些墙体无法合并。" + # Source-Hash: 96a6f084d095ea36 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column {column}, row {row}: {type, select, glass {glass} solid {solid} other {empty}}" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy msgid "node.wall.curtain.cell" msgstr "第 {column} 列,第 {row} 行:{type, select, glass {玻璃} solid {实板} other {空}}" -# AI-Provider: cursor-agent -# AI-Model: claude-opus # Source-Hash: 904e9b269b68c670 # Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {{number} column} other {{number} columns}} · {spacing} grid spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30590,18 +33333,18 @@ msgstr "{count, plural, other {{number} 列}} · 网格间距 {spacing}" # Source-Hash: 8b2b2f11fca9f077 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "No panels" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy msgid "node.wall.curtain.noPanels" msgstr "无面板" -# AI-Provider: cursor-agent -# AI-Model: claude-opus # Source-Hash: 9f5d9775377b666e # Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{count, plural, one {{number} row} other {{number} rows}} · {spacing} grid spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30610,8 +33353,8 @@ msgstr "{count, plural, other {{number} 行}} · 网格间距 {spacing}" # Source-Hash: 90638d5a19a4f0a9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Apply tint" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30620,8 +33363,8 @@ msgstr "应用色调" # Source-Hash: a7d624ec0f879829 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Border / opening frame" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30630,8 +33373,8 @@ msgstr "边框 / 洞口框" # Source-Hash: b3a163b453896bef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bottom" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30640,8 +33383,8 @@ msgstr "底部" # Source-Hash: 5503fb89c40cefeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bottom row" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30650,8 +33393,8 @@ msgstr "底行" # Source-Hash: 1928d9e7a16360d6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Cancel tint" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30660,8 +33403,8 @@ msgstr "取消色调" # Source-Hash: 5211341ed18f33f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Center" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30670,8 +33413,8 @@ msgstr "居中" # Source-Hash: 9f4c033fa80119db # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Choose a cell or enter its column and row. Use arrow keys to move between cells. Columns run from the wall start; rows count upward." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30680,8 +33423,8 @@ msgstr "选择一个单元格,或输入其列和行。使用方向键在单元 # Source-Hash: bbeadcebc59c923f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Clear hidden overrides" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30690,8 +33433,8 @@ msgstr "清除隐藏的覆盖" # Source-Hash: 3530ac1f4046cd22 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30700,8 +33443,8 @@ msgstr "柱" # Source-Hash: 711a6426e336877a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column layout" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30710,8 +33453,8 @@ msgstr "列布局" # Source-Hash: 59b2ab5fdf54c2e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Column {column}, row {row}" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30720,8 +33463,8 @@ msgstr "第 {column} 列,第 {row} 行" # Source-Hash: ce1429556f57d7ee # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Construction" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30729,9 +33472,9 @@ msgid "node.wall.curtainWallPanel.construction" msgstr "构造" # Source-Hash: 59d2bec8b9ae1025 -# Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Continuous mullions and transoms assembled along the wall." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30740,8 +33483,8 @@ msgstr "沿墙体组装的连续竖梃和横档。" # Source-Hash: bbc5e5f3f3b99232 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Curtain wall panel selection" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30750,8 +33493,8 @@ msgstr "幕墙面板选择" # Source-Hash: 9fd79cf417eab9ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Custom infill" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30760,8 +33503,8 @@ msgstr "自定义填充" # Source-Hash: 097ed751fa47e5fd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Default panel" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30770,8 +33513,8 @@ msgstr "默认面板" # Source-Hash: 0a0c98ae42f519ef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Edit individual panels" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30780,8 +33523,8 @@ msgstr "编辑单个面板" # Source-Hash: 8690f82f64806e4d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Effective thickness: {thickness}, limited by frame depth." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30790,8 +33533,8 @@ msgstr "有效厚度:{thickness},受框架深度限制。" # Source-Hash: 65b1cbba3b92c5b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Empty" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30800,8 +33543,8 @@ msgstr "空" # Source-Hash: c6e7792839d09c69 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Enable panel editing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30810,8 +33553,8 @@ msgstr "启用面板编辑" # Source-Hash: 135874d189176d13 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "End" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30820,8 +33563,8 @@ msgstr "终点" # Source-Hash: 4fb65101d0b1a222 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fixed spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30830,8 +33573,8 @@ msgstr "固定间距" # Source-Hash: 1c851bde836b3b57 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Following wall defaults" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30840,8 +33583,8 @@ msgstr "沿用墙体默认值" # Source-Hash: 49be990b89741501 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Frame dimensions" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30850,8 +33593,8 @@ msgstr "框架尺寸" # Source-Hash: c7e72beff9fe4b37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Framing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30860,8 +33603,8 @@ msgstr "龙骨" # Source-Hash: 221f418784836f11 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fully capped" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30870,8 +33613,8 @@ msgstr "完全封顶" # Source-Hash: 8ab91094cf650204 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glass" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30880,8 +33623,8 @@ msgstr "玻璃" # Source-Hash: a17c63662aa4404d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glass appearance" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30890,8 +33633,8 @@ msgstr "玻璃外观" # Source-Hash: f59c4938a2116a2e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glass appearance is controlled by the paint tool." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30900,8 +33643,8 @@ msgstr "玻璃外观由涂刷工具控制。" # Source-Hash: 9c38875c310547ae # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glass tint" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30910,8 +33653,8 @@ msgstr "玻璃色调" # Source-Hash: 7660a6aa7e7cd365 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Glazing gap" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30920,8 +33663,8 @@ msgstr "玻璃间隙" # Source-Hash: 6e739c8a698efaab # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Grid limited to 32 panels per axis. Spacing expands to fit this wall." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30930,8 +33673,8 @@ msgstr "网格每个方向最多 32 个面板。间距会扩大以适应此墙 # Source-Hash: 1c63255b675bbcd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{length, plural, one {{number} custom panel is outside this grid. It returns if the grid expands.} other {{number} custom panels are outside this grid. They return if the grid expands.}}" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30940,8 +33683,8 @@ msgstr "{length, plural, other {有 {number} 个自定义面板位于此网格 # Source-Hash: 84af317e818c10cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Horizontal caps" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30950,8 +33693,8 @@ msgstr "水平盖板" # Source-Hash: 7a71f6b25c5dc718 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Horizontal frame width" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30960,8 +33703,8 @@ msgstr "水平框架宽度" # Source-Hash: 54800340a0eeab23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Layout" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30970,8 +33713,8 @@ msgstr "布局" # Source-Hash: fc37833ef19c8feb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Low roughness is smooth; high roughness gives a matte surface in rendered shading." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30980,8 +33723,8 @@ msgstr "粗糙度低则光滑;粗糙度高则在渲染中呈哑光表面。" # Source-Hash: 321ca5101ab61db7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Maximum spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -30990,8 +33733,8 @@ msgstr "最大间距" # Source-Hash: 1452f51ec5dfc6ba # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Module joint width" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31000,8 +33743,8 @@ msgstr "模块接缝宽度" # Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "None" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31010,8 +33753,8 @@ msgstr "无" # Source-Hash: 1c0b8a5503c5daeb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opacity" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31020,8 +33763,8 @@ msgstr "不透明度" # Source-Hash: 0f9ba67daa6b4625 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opaque band" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31030,8 +33773,8 @@ msgstr "不透明带" # Source-Hash: fdf533d6592eff60 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opaque bands replace a full row with solid panels. Apply their finish with the paint tool." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31040,8 +33783,8 @@ msgstr "不透明带用实板替换整行。使用涂刷工具应用其饰面。 # Source-Hash: b91302bf741c9fd6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Panel count" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31050,8 +33793,8 @@ msgstr "面板数量" # Source-Hash: 3a019ce58d021431 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Panel infill" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31060,8 +33803,8 @@ msgstr "面板填充" # Source-Hash: 6ce059aee1386f72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Panels" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31070,8 +33813,8 @@ msgstr "面板" # Source-Hash: d24fe036670f54a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Panel thickness" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31080,8 +33823,8 @@ msgstr "面板厚度" # Source-Hash: a780f13a732bab88 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reset this panel" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31090,8 +33833,8 @@ msgstr "重置此面板" # Source-Hash: 03a22f6df69c47d3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Row" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31100,8 +33843,8 @@ msgstr "行" # Source-Hash: 0e18ec19d0e4ea93 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Row layout" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31110,8 +33853,8 @@ msgstr "行布局" # Source-Hash: dfb58bbd8932811d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Separate framed modules with joints between units." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31120,8 +33863,8 @@ msgstr "分离的带框模块,单元之间有接缝。" # Source-Hash: ef3e765e692faf4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Solid" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31130,8 +33873,8 @@ msgstr "实体" # Source-Hash: e4698e83d02beb6c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Spacing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31140,8 +33883,8 @@ msgstr "间距" # Source-Hash: 0a26a1e61c825660 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Start" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31150,8 +33893,8 @@ msgstr "起点" # Source-Hash: d3d738ccbc7103ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stick-built" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31160,8 +33903,8 @@ msgstr "现场搭建" # Source-Hash: fbdb9260ee302d3d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Structural glazing" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31170,8 +33913,8 @@ msgstr "结构玻璃" # Source-Hash: 393d5c5ec4e7014c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Surface roughness" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31180,8 +33923,8 @@ msgstr "表面粗糙度" # Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31190,8 +33933,8 @@ msgstr "顶部" # Source-Hash: 51aa1c35a1761178 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top row" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31200,8 +33943,8 @@ msgstr "顶行" # Source-Hash: 1181faa315f26c83 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Uncapped members sit behind the glazing." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31210,8 +33953,8 @@ msgstr "无盖板的构件位于玻璃后方。" # Source-Hash: e68eeb4033268842 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unitized" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31220,8 +33963,8 @@ msgstr "单元式" # Source-Hash: 355b469b8a9c42f9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Use glass settings instead" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31230,8 +33973,8 @@ msgstr "改用玻璃设置" # Source-Hash: 9d75fad413e547e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Use the Door or Window tool to add an opening through the wall." #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31240,8 +33983,8 @@ msgstr "使用门或窗工具在墙上添加开口。" # Source-Hash: c1fa8c24203a5dde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Vertical caps" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31250,8 +33993,8 @@ msgstr "竖向盖板" # Source-Hash: 0560516882b93f0d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Vertical frame width" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31260,8 +34003,8 @@ msgstr "竖向框架宽度" # Source-Hash: 4b903041c38cdd72 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall system" #: packages/nodes/src/wall/curtain-wall-panel.tsx #, fuzzy @@ -31270,8 +34013,8 @@ msgstr "墙体系统" # Source-Hash: 6c753f6234766116 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A straight or curved wall segment. Hosts doors, windows, lean-to extensions, and wall-mounted items." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -31280,8 +34023,8 @@ msgstr "直线或曲线墙体段,可承载门、窗、单坡扩建和壁挂物 # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -31290,8 +34033,8 @@ msgstr "墙体" # Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31300,8 +34043,8 @@ msgstr "操作" # Source-Hash: 67d2ec01cdce2bdc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Assembly" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31310,8 +34053,8 @@ msgstr "构造" # Source-Hash: 05b65242d8c48791 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Auto" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31320,8 +34063,8 @@ msgstr "自动" # Source-Hash: 69578b7dd7723fa1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Both" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31330,8 +34073,8 @@ msgstr "两侧" # Source-Hash: b3a163b453896bef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bottom" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31340,8 +34083,8 @@ msgstr "底部" # Source-Hash: 75d323d0159b0df8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Brick veneer" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31350,8 +34093,8 @@ msgstr "砖饰面" # Source-Hash: 32d0bfee628c42a5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Chair rail" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31360,8 +34103,8 @@ msgstr "护墙板条" # Source-Hash: a85f39db8f92f8e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "CMU" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31370,8 +34113,8 @@ msgstr "混凝土砌块" # Source-Hash: f76e125a47ed0612 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Colonial" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31380,8 +34123,8 @@ msgstr "殖民式" # Source-Hash: a4962c0f39d629ac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Cove" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31390,8 +34133,8 @@ msgstr "凹弧" # Source-Hash: e5d425095ade6f06 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Craft" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31400,8 +34143,8 @@ msgstr "工艺风格" # Source-Hash: fa8a6b7f2f4eee63 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Crown molding" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31410,8 +34153,8 @@ msgstr "顶角线" # Source-Hash: 9736e0a78294e68d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Curtain wall" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31420,8 +34163,8 @@ msgstr "幕墙" # Source-Hash: f08fbb462e9afc0e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Curve" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31430,8 +34173,8 @@ msgstr "曲线" # Source-Hash: 9e9715d52410c86f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Custom" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31440,8 +34183,8 @@ msgstr "自定义" # Source-Hash: b2a1b3bc9676fe05 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Custom height" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31450,8 +34193,8 @@ msgstr "自定义高度" # Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Depth" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31460,8 +34203,8 @@ msgstr "深度" # Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dimensions" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31470,8 +34213,8 @@ msgstr "尺寸" # Source-Hash: 4da800c75b9a6b23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Drywall" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31480,8 +34223,8 @@ msgstr "石膏板" # Source-Hash: d6ba089e1ca40cdf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Extends downward to meet the terrain. Height and top stay unchanged." #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31490,8 +34233,8 @@ msgstr "向下延伸至地形。高度和顶面保持不变。" # Source-Hash: 0ead5e5711b98bf6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Exterior" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31500,8 +34243,8 @@ msgstr "外部" # Source-Hash: fd89c31f16639f50 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fiber cement" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31510,8 +34253,8 @@ msgstr "纤维水泥" # Source-Hash: a6be391d580de5cf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fill to terrain" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31520,8 +34263,8 @@ msgstr "填充至地形" # Source-Hash: 9cab4d4c95f63cdd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flat" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31530,8 +34273,8 @@ msgstr "平屋顶" # Source-Hash: a5c2353769b603d5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Follows level" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31540,18 +34283,28 @@ msgstr "跟随楼层" # Source-Hash: fd413477f1a9e5ed # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Frame depth" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.frameDepth" msgstr "框架深度" +# Source-Hash: cb22c8e4b0d92234 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Framer's default" +#: packages/nodes/src/wall/panel.tsx +#, fuzzy +msgid "node.wall.panel.framersDefault" +msgstr "框架工默认" + # Source-Hash: c7e72beff9fe4b37 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Framing" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31560,8 +34313,8 @@ msgstr "龙骨" # Source-Hash: eda78e8a76f068d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Gypsum" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31570,8 +34323,8 @@ msgstr "石膏" # Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Height" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31580,8 +34333,8 @@ msgstr "高度" # Source-Hash: 2d89c1638aa8dd7e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hide code" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31590,8 +34343,8 @@ msgstr "隐藏代码" # Source-Hash: 0c6dcbbbda6b4dbb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "ICF" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31600,8 +34353,8 @@ msgstr "保温模板" # Source-Hash: ff005196861cef68 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Interior" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31610,8 +34363,8 @@ msgstr "内部" # Source-Hash: 9a4325140858cfec # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Lap siding" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31620,8 +34373,8 @@ msgstr "搭接壁板" # Source-Hash: 297b21e90e8c25f0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Layered" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31630,8 +34383,8 @@ msgstr "分层" # Source-Hash: bf279d0f8f1e3b78 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Layer thicknesses follow the 2021 IRC assembly data. Drafting aid, not engineering — verify with the authority having jurisdiction." #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31640,8 +34393,8 @@ msgstr "各层厚度依据 2021 IRC 构造数据。仅作制图辅助,并非 # Source-Hash: 643687bc3adaac76 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Length" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31650,8 +34403,8 @@ msgstr "长度" # Source-Hash: 9e84d6d7b9885c4f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Loading…" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31660,8 +34413,8 @@ msgstr "加载中…" # Source-Hash: f6cbdaa17e989b91 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Modern" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31670,8 +34423,8 @@ msgstr "现代" # Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "None" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31680,8 +34433,8 @@ msgstr "无" # Source-Hash: c7300ca33851fba7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "None (single layer)" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31690,8 +34443,8 @@ msgstr "无(单层)" # Source-Hash: 0f0e13abf9b2bb67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Offset" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31700,8 +34453,8 @@ msgstr "偏移" # Source-Hash: 04b3006bd4e6e207 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Ogee" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31710,8 +34463,8 @@ msgstr "S 形" # Source-Hash: 4f7f8af75bf8e914 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "OSB" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31720,8 +34473,8 @@ msgstr "定向刨花板" # Source-Hash: 1243161deca7d470 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Partition: the interior finish is applied to both faces." #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31730,8 +34483,8 @@ msgstr "隔墙:内饰面应用于两面。" # Source-Hash: 3ee270463954f502 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Picture" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31740,8 +34493,8 @@ msgstr "画框" # Source-Hash: a6fd2cbf5c2154e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Plaster" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31750,8 +34503,8 @@ msgstr "灰泥" # Source-Hash: e669c2c08bd80e23 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Plywood" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31760,18 +34513,28 @@ msgstr "胶合板" # Source-Hash: 441f7f652ea6a0d8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Preset" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.preset" msgstr "预设" +# Source-Hash: 240ed9c77627b9a1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" +#: packages/nodes/src/wall/panel.tsx +#, fuzzy +msgid "node.wall.panel.railing" +msgstr "栏杆" + # Source-Hash: 62bf2677b9ec30fc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reference" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31780,8 +34543,8 @@ msgstr "参照" # Source-Hash: 9469a102f04ea196 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Remove" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31790,8 +34553,8 @@ msgstr "移除" # Source-Hash: ad0457800a1f0eb4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Round" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31800,8 +34563,8 @@ msgstr "圆形" # Source-Hash: e9a0a3688faba18b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Scripted finish" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31810,8 +34573,8 @@ msgstr "脚本饰面" # Source-Hash: 36a588e44085108c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Sheathing" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31820,8 +34583,8 @@ msgstr "覆面板" # Source-Hash: 6ae9aa7061d8c617 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Shoe" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31830,8 +34593,8 @@ msgstr "踢脚" # Source-Hash: 136762ac1bc96e6f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Side A" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31840,8 +34603,8 @@ msgstr "A 面" # Source-Hash: 8b9cb16850549c35 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Side B" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31850,8 +34613,8 @@ msgstr "B 面" # Source-Hash: e6a27f6f8cd489b9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Side {face}" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31860,8 +34623,8 @@ msgstr "{face} 面" # Source-Hash: d9d55c5883a53789 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Skirting" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31870,8 +34633,8 @@ msgstr "踢脚线" # Source-Hash: d998c212030bc7c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Standard" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31880,8 +34643,8 @@ msgstr "标准" # Source-Hash: da3e3dd077163ba0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Steel studs" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31890,8 +34653,8 @@ msgstr "钢龙骨" # Source-Hash: ed3989f23a2d185e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Step" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31900,8 +34663,8 @@ msgstr "台阶" # Source-Hash: 9450fcb4a14674af # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stone veneer" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31910,18 +34673,28 @@ msgstr "石材饰面" # Source-Hash: 687cf7bc64b0224e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Stucco" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.stucco" msgstr "灰泥饰面" +# Source-Hash: 4fce02ee3f69bf99 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Studs" +#: packages/nodes/src/wall/panel.tsx +#, fuzzy +msgid "node.wall.panel.studs" +msgstr "龙骨" + # Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Thickness" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31930,18 +34703,28 @@ msgstr "厚度" # Source-Hash: 00cb7b58f3a10140 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{thickness} · from assembly" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.thicknessFromAssembly" msgstr "{thickness} · 来自构造" +# Source-Hash: 9eef4c34dfbc970b +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "This project" +#: packages/nodes/src/wall/panel.tsx +#, fuzzy +msgid "node.wall.panel.thisProject" +msgstr "本项目" + # Source-Hash: 27644f0497fd9849 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31950,8 +34733,8 @@ msgstr "顶部" # Source-Hash: 3ee03b0e9ae1be4c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Total thickness" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31960,8 +34743,8 @@ msgstr "总厚度" # Source-Hash: ea7e8bbd87ce4152 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unverified: {presetNote}" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31970,8 +34753,8 @@ msgstr "未核实:{presetNote}" # Source-Hash: 21242af83a2a6d17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "View code" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31980,8 +34763,8 @@ msgstr "查看代码" # Source-Hash: 2210e5ee50b74dc9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -31990,8 +34773,8 @@ msgstr "墙体" # Source-Hash: eab795728c4a3f5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall type" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32000,8 +34783,8 @@ msgstr "墙体类型" # Source-Hash: e97a456d667465f7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Which face is outside is undetermined (no room detected on either side) — the exterior layers are drawn on side B." #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32010,18 +34793,108 @@ msgstr "无法确定哪一面朝外(两侧都未检测到房间)— 外层 # Source-Hash: 31e404a4a4870faf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wood studs" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.panel.woodStuds" msgstr "木龙骨" +# Source-Hash: ece946252401f4ab +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "A guard's openings must not pass a 4 in sphere (IRC R312.1.3)." +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.aGuardSOpeningsMustNot" +msgstr "护栏开口不得让 4 in 球体通过(IRC R312.1.3)。" + +# Source-Hash: 646ef0fbcbc58edf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Height" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.height" +msgstr "高度" + +# Source-Hash: 7c339a5fae55681d +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Infill" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.infill" +msgstr "填充" + +# Source-Hash: d814a47c4eccee3f +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "2x6 cap" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.n2x6Cap" +msgstr "2x6 顶盖" + +# Source-Hash: 137b45940b723a6e +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "36 in" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.n36In" +msgstr "36 in" + +# Source-Hash: ebf854ac4dd4daaf +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "42 in" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.n42In" +msgstr "42 in" + +# Source-Hash: ede386e1d510ebfb +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Posts" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.posts" +msgstr "立柱" + +# Source-Hash: 240ed9c77627b9a1 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Railing" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.railing" +msgstr "栏杆" + +# Source-Hash: 1a79a485d91f3f28 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Style" +#: packages/nodes/src/wall/railing-wall-panel.tsx +#, fuzzy +msgid "node.wall.railingWallPanel.style" +msgstr "样式" + # Source-Hash: 5211341ed18f33f6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Center" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32030,8 +34903,8 @@ msgstr "居中" # Source-Hash: 09576259041494f3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Inside face" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32040,8 +34913,8 @@ msgstr "内侧面" # Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Left" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32050,8 +34923,8 @@ msgstr "左" # Source-Hash: 697001376b872e74 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Outside face" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32060,8 +34933,8 @@ msgstr "外侧面" # Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Right" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32070,8 +34943,8 @@ msgstr "右" # Source-Hash: eac63d14f275db3d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{trim, select, skirting {Hide skirting} crown {Hide crown molding} other {Hide chair rail}}" #: packages/nodes/src/wall/panel.tsx #, fuzzy @@ -32080,18 +34953,28 @@ msgstr "{trim, select, skirting {隐藏踢脚线} crown {隐藏顶角线} other # Source-Hash: 8db070a4247db221 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "{trim, select, skirting {Show skirting} crown {Show crown molding} other {Show chair rail}}" #: packages/nodes/src/wall/panel.tsx #, fuzzy msgid "node.wall.trim.show" msgstr "{trim, select, skirting {显示踢脚线} crown {显示顶角线} other {显示护墙板条}}" +# Source-Hash: b1757d76048706b7 +# Review: required +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 +# English: "Swap hinge side" +#: packages/nodes/src/window/actions.tsx +#, fuzzy +msgid "node.window.actions.swapHingeSide" +msgstr "切换铰链侧" + # Source-Hash: ea6a51e66eb0c0dc # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A window cut into a wall. Animated open/close for opening windows." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -32100,8 +34983,8 @@ msgstr "开在墙体上的窗,可开启的窗带开关动画。" # Source-Hash: aa3c35ed33e181e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -32110,8 +34993,8 @@ msgstr "窗" # Source-Hash: 011e4de244050a78 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Raise" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32120,8 +35003,8 @@ msgstr "上提" # Source-Hash: 19ca2434d4f7eb87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slats" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32130,8 +35013,8 @@ msgstr "叶片" # Source-Hash: c00de0e2c9b0ddcb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Slide" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32140,8 +35023,8 @@ msgstr "推拉" # Source-Hash: e48604b5f7b2a5f4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Swing" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32150,8 +35033,8 @@ msgstr "平开" # Source-Hash: 1615637fe68e188a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Tilt" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32160,8 +35043,8 @@ msgstr "倾斜" # Source-Hash: aa6d82bdb3cc1d9a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Actions" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32170,8 +35053,8 @@ msgstr "操作" # Source-Hash: 663175a9c461a96d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "All" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32180,8 +35063,8 @@ msgstr "全部" # Source-Hash: 710261f5ffb32617 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Arch" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32190,8 +35073,8 @@ msgstr "拱形" # Source-Hash: 3715cd54e4775087 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Arch Height" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32201,7 +35084,7 @@ msgstr "拱高" # Source-Hash: 05b65242d8c48791 # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 +# AI-Model: claude-opus-5-5 # English: "Auto" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32211,7 +35094,7 @@ msgstr "自动" # Source-Hash: 8a04486ba122ea7d # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 +# AI-Model: claude-opus-5-5 # English: "Auto follows the wall" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32220,8 +35103,8 @@ msgstr "自动跟随墙体" # Source-Hash: 30edd1c180aac9b4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Columns" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32230,8 +35113,8 @@ msgstr "列" # Source-Hash: 2f417371c399ad67 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Col Widths" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32240,8 +35123,8 @@ msgstr "列宽" # Source-Hash: 2ee121dca87bb64a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Corner" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32250,8 +35133,8 @@ msgstr "转角" # Source-Hash: 04e3425c5ea29359 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Corner post" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32260,8 +35143,8 @@ msgstr "角柱" # Source-Hash: 7a90a42b578f2435 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Corner Radius" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32270,8 +35153,8 @@ msgstr "圆角半径" # Source-Hash: 67d10b97eff316c1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Custom: the panes match no style." #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32280,8 +35163,8 @@ msgstr "自定义:窗格不匹配任何样式。" # Source-Hash: b26de372b4b0eaac # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Delete" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32290,8 +35173,8 @@ msgstr "删除" # Source-Hash: 99ac4d03c3061f3a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Depth" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32300,8 +35183,8 @@ msgstr "深度" # Source-Hash: 12df69f42beb0643 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Dimensions" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32310,8 +35193,8 @@ msgstr "尺寸" # Source-Hash: c53c3307e2a2a32a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Divider" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32320,8 +35203,8 @@ msgstr "分隔条" # Source-Hash: 72c65752a1d1bbb1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Down" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32330,8 +35213,8 @@ msgstr "向下" # Source-Hash: 34dc96fe77a31e51 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Duplicate" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32340,8 +35223,8 @@ msgstr "复制" # Source-Hash: 8497c4373d5d18ad # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Enable Sill" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32350,8 +35233,8 @@ msgstr "启用窗台" # Source-Hash: 61f9413d3bbabde7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Flip Side" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32360,8 +35243,8 @@ msgstr "翻转方向" # Source-Hash: ce3a6c03765dbbd8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Frame" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32371,7 +35254,7 @@ msgstr "框架" # Source-Hash: 0cce8ae784f78478 # Review: required # AI-Provider: claude-code -# AI-Model: claude-fable-5-1 +# AI-Model: claude-opus-5-5 # English: "Depth (auto)" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32380,8 +35263,8 @@ msgstr "深度(自动)" # Source-Hash: 092033938ca2debb # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "French" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32390,8 +35273,8 @@ msgstr "法式门" # Source-Hash: a6362b937fffe999 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fused glass" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32400,8 +35283,8 @@ msgstr "熔融玻璃" # Source-Hash: 7e4a0a38f694be6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Grid" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32410,8 +35293,8 @@ msgstr "网格" # Source-Hash: 646ef0fbcbc58edf # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Height" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32420,8 +35303,8 @@ msgstr "高度" # Source-Hash: 42824e50de26bc14 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Individual" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32430,8 +35313,8 @@ msgstr "单独" # Source-Hash: f365c6b6dd9ebab9 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Left" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32440,8 +35323,8 @@ msgstr "左" # Source-Hash: bd02c614454fbd2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Move" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32450,8 +35333,8 @@ msgstr "移动" # Source-Hash: e04298381837252f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opening" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32460,8 +35343,8 @@ msgstr "开口" # Source-Hash: ecb81bd3eefa6a47 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Opening Shape" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32470,8 +35353,8 @@ msgstr "开洞形状" # Source-Hash: cf40395b71bedcca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Other side" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32480,8 +35363,8 @@ msgstr "另一侧" # Source-Hash: 28fe6e9deddde6e8 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "pos" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32490,8 +35373,8 @@ msgstr "位置" # Source-Hash: 9da0cbfad144d737 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Position" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32500,8 +35383,8 @@ msgstr "位置" # Source-Hash: 3b6f225112035fde # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rect" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32510,8 +35393,8 @@ msgstr "矩形" # Source-Hash: 59236bd016c6b904 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Reveal Radius" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32520,8 +35403,8 @@ msgstr "洞口圆角半径" # Source-Hash: b34d5ee0f218221d # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Right" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32530,8 +35413,8 @@ msgstr "右" # Source-Hash: fc826da6c99303e6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rounded" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32540,8 +35423,8 @@ msgstr "圆角" # Source-Hash: fb811056b862b6d0 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Row Heights" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32550,8 +35433,8 @@ msgstr "行高" # Source-Hash: c913b494c3901a17 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Rows" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32560,8 +35443,8 @@ msgstr "行" # Source-Hash: 62ded63b01564969 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Sill" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32570,8 +35453,8 @@ msgstr "窗台" # Source-Hash: 62ab2eb3c775da95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Single" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32580,8 +35463,8 @@ msgstr "单扇" # Source-Hash: a8096eb4beaadeef # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Size is limited to the wall, including clearance for the opening frame." #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32590,8 +35473,8 @@ msgstr "尺寸受墙体限制,包括洞口框的间隙。" # Source-Hash: 1a79a485d91f3f28 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Style" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32600,8 +35483,8 @@ msgstr "样式" # Source-Hash: fdbb503f0941bd56 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Thickness" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32610,8 +35493,8 @@ msgstr "厚度" # Source-Hash: 79ff1ae7250c1711 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "This side" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32620,8 +35503,8 @@ msgstr "此侧" # Source-Hash: 7e2505dd1d5e3513 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top Shape" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32630,8 +35513,8 @@ msgstr "顶部形状" # Source-Hash: c44f7ab8bbd24858 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Type" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32640,8 +35523,8 @@ msgstr "类型" # Source-Hash: c29767f86bd9df1e # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unwrap" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32650,8 +35533,8 @@ msgstr "解除" # Source-Hash: 1d732503a54a532f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Up" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32660,8 +35543,8 @@ msgstr "向上" # Source-Hash: 3a0ccd6c46877a87 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Width" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32670,8 +35553,8 @@ msgstr "宽度" # Source-Hash: aa3c35ed33e181e5 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32680,8 +35563,8 @@ msgstr "窗" # Source-Hash: f59cd625e6082651 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Window Type" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32690,8 +35573,8 @@ msgstr "窗户类型" # Source-Hash: 7bf8c4e2b90b3021 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wraps the corner with {partner}" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32700,8 +35583,8 @@ msgstr "与{partner}包住转角" # Source-Hash: 8f1f8eff5fbe90e1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wraps the corner with its partner" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32710,8 +35593,8 @@ msgstr "与其配对窗户包住转角" # Source-Hash: cccf75b8c8dc5ad6 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wrap the corner" #: packages/nodes/src/window/panel.tsx #, fuzzy @@ -32720,8 +35603,8 @@ msgstr "包住转角" # Source-Hash: 9d63109edd8b22c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Casement" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32730,8 +35613,8 @@ msgstr "平开" # Source-Hash: e06fc5a432b74a5b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Double-hung" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32740,8 +35623,8 @@ msgstr "双悬" # Source-Hash: 7e4a0a38f694be6b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Grid" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32750,8 +35633,8 @@ msgstr "网格" # Source-Hash: fbb293fe8aee84b2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Horizontal bands" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32760,8 +35643,8 @@ msgstr "水平条带" # Source-Hash: 3ee270463954f502 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Picture" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32770,8 +35653,8 @@ msgstr "画框" # Source-Hash: 62ab2eb3c775da95 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Single" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32780,8 +35663,8 @@ msgstr "单扇" # Source-Hash: 18cbc73c5e1590aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Sliding" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32790,8 +35673,8 @@ msgstr "推拉门" # Source-Hash: 0c88aea2bd130193 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Tall grid" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32800,8 +35683,8 @@ msgstr "竖长网格" # Source-Hash: 9628d0cc155e29a3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Transom" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32810,8 +35693,8 @@ msgstr "气窗" # Source-Hash: 305f3aba543b1962 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Triple-hung" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32820,8 +35703,8 @@ msgstr "三悬" # Source-Hash: 8af77effb76bc6e2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wide grid" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32830,8 +35713,8 @@ msgstr "横宽网格" # Source-Hash: 50393830365aaf2b # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Awning" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32840,8 +35723,8 @@ msgstr "上悬窗" # Source-Hash: 8447ee52258e16e4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bay" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32850,8 +35733,8 @@ msgstr "凸窗" # Source-Hash: e828c89bd0ba1ea4 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Bow" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32860,8 +35743,8 @@ msgstr "弓形窗" # Source-Hash: 9d63109edd8b22c2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Casement" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32870,8 +35753,8 @@ msgstr "平开窗" # Source-Hash: b0b737fc5cb1d32a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Double Hung" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32880,8 +35763,8 @@ msgstr "双悬窗" # Source-Hash: 387ce45ca2eb045f # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Fixed" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32890,8 +35773,8 @@ msgstr "固定" # Source-Hash: 04a40f27911c3192 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Hopper" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32900,8 +35783,8 @@ msgstr "下悬窗" # Source-Hash: 5746be19ba2a53be # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Louvered" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32910,8 +35793,8 @@ msgstr "百叶窗" # Source-Hash: de6ffb1cf676f270 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Single Hung" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32920,8 +35803,8 @@ msgstr "单悬窗" # Source-Hash: 18cbc73c5e1590aa # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Sliding" #: packages/nodes/src/shared/opening-labels.ts #, fuzzy @@ -32930,8 +35813,8 @@ msgstr "推拉门" # Source-Hash: 4a4d97a4101793b7 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "A polygonal site zone (lawn, water, paving) with a TSL gradient material." #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -32940,8 +35823,8 @@ msgstr "使用 TSL 渐变材质的多边形场地区域(草坪、水面、铺 # Source-Hash: a107b4d76d6972e3 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone" #: packages/nodes/src/i18n/definition-messages.ts #, fuzzy @@ -32950,8 +35833,8 @@ msgstr "区域" # Source-Hash: e9a6d2e71b97e757 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Enclosed room" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -32960,8 +35843,8 @@ msgstr "封闭房间" # Source-Hash: 3660922f0a8f1d3c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Floor surface" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -32970,8 +35853,8 @@ msgstr "楼面面积" # Source-Hash: 88c8703c4ff21ee1 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Footprint only" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -32980,8 +35863,8 @@ msgstr "仅基底" # Source-Hash: f2953d2931e36d0c # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "None" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -32990,8 +35873,8 @@ msgstr "无" # Source-Hash: a9756a3da570c3dd # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Not proven" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33000,8 +35883,8 @@ msgstr "未验证" # Source-Hash: ff97d005a536cf58 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Room quantities" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33010,8 +35893,8 @@ msgstr "房间工程量" # Source-Hash: f520e6a06fbeb803 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Top view with zone edge dimensions" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33020,8 +35903,8 @@ msgstr "带区域边长尺寸的俯视图" # Source-Hash: 062cc0f1afef0c52 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Unit" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33030,8 +35913,8 @@ msgstr "单元" # Source-Hash: 429bd43d726de417 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Volume" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33040,8 +35923,8 @@ msgstr "体积" # Source-Hash: a7941c60a3b6998a # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Wall surface" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33050,8 +35933,8 @@ msgstr "墙面面积" # Source-Hash: b8b0dbdff53a83ca # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone boundary unavailable" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy @@ -33060,8 +35943,8 @@ msgstr "区域边界不可用" # Source-Hash: 6bfb4c6f4d7b0ff2 # Review: required -# AI-Provider: cursor-agent -# AI-Model: claude-opus +# AI-Provider: claude-code +# AI-Model: claude-opus-5-5 # English: "Zone quantities" #: packages/nodes/src/zone/quantities-panel.tsx #, fuzzy diff --git a/packages/editor/src/i18n/locales/zh-CN/messages.ts b/packages/editor/src/i18n/locales/zh-CN/messages.ts index 311c4550a6..1918fb8198 100644 --- a/packages/editor/src/i18n/locales/zh-CN/messages.ts +++ b/packages/editor/src/i18n/locales/zh-CN/messages.ts @@ -1 +1 @@ -/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"core.level.basement\":[\"地下层\"],\"core.level.basementNumber\":[\"地下 \",[\"number\"],\" 层\"],\"core.level.floorNumber\":[[\"number\"],\" 层\"],\"core.level.groundFloor\":[\"首层\"],\"editor.buildPanel.advanced\":[\"高级\"],\"editor.buildPanel.rooms.hint\":[\"墙体 · 楼板 · 天花板\"],\"editor.buildPanel.rooms.idle\":[\"选择一种形状开始绘制。每个房间都会同时创建墙体、楼板和天花板。\"],\"editor.buildPanel.rooms.polygon.caption\":[[\"lead\"],\"然后再次点击起点闭合。适用于 L 形和斜角房间。\"],\"editor.buildPanel.rooms.polygon.label\":[\"多边形\"],\"editor.buildPanel.rooms.polygon.lead\":[\"依次点击各个角点,\"],\"editor.buildPanel.rooms.polygon.title\":[\"多边形房间\"],\"editor.buildPanel.rooms.rectangle.caption\":[\"在网格上\",[\"lead\"],\"。墙体、楼板和天花板将一并创建。\"],\"editor.buildPanel.rooms.rectangle.label\":[\"矩形\"],\"editor.buildPanel.rooms.rectangle.lead\":[\"点击两个对角点\"],\"editor.buildPanel.rooms.rectangle.title\":[\"矩形房间\"],\"editor.buildPanel.rooms.title\":[\"房间\"],\"editor.buildPanel.rooms.walls.caption\":[[\"lead\"],\"闭合轮廓后会形成房间;保持开口可绘制隔墙。\"],\"editor.buildPanel.rooms.walls.label\":[\"墙体\"],\"editor.buildPanel.rooms.walls.lead\":[\"逐面绘制墙体。\"],\"editor.buildPanel.rooms.walls.title\":[\"墙体\"],\"viewer.camera.orbitLeft\":[\"向左旋转\"],\"viewer.camera.orbitRight\":[\"向右旋转\"],\"viewer.camera.topView\":[\"俯视图\"],\"viewer.common.off\":[\"关闭\"],\"viewer.common.on\":[\"开启\"],\"viewer.display.camera\":[\"相机\"],\"viewer.display.colored\":[\"彩色\"],\"viewer.display.colors\":[\"颜色\"],\"viewer.display.edges.off\":[\"关闭\"],\"viewer.display.edges.offDetail\":[\"不显示边线\"],\"viewer.display.edges.soft\":[\"柔和\"],\"viewer.display.edges.softDetail\":[\"淡化显示主要折线\"],\"viewer.display.edges.strong\":[\"清晰\"],\"viewer.display.edges.strongDetail\":[\"清晰、不透明的边线\"],\"viewer.display.edges.title\":[\"边线\"],\"viewer.display.monochrome\":[\"单色\"],\"viewer.display.orthographic\":[\"正交\"],\"viewer.display.perspective\":[\"透视\"],\"viewer.display.render.rendered\":[\"渲染效果\"],\"viewer.display.render.renderedDetail\":[\"完整环境光遮蔽\"],\"viewer.display.render.solid\":[\"实体\"],\"viewer.display.render.solidDetail\":[\"平整快速,不启用环境光遮蔽\"],\"viewer.display.render.title\":[\"渲染\"],\"viewer.display.shadows\":[\"阴影\"],\"viewer.display.title\":[\"显示设置\"],\"viewer.floorplan.alignNorth\":[\"视图对齐北向\"],\"viewer.floorplan.empty\":[\"此场景没有可用的平面图。\"],\"viewer.floorplan.fit\":[\"适合窗口\"],\"viewer.floorplan.floor\":[\"楼层\"],\"viewer.floorplan.floorPlan\":[\"平面图\"],\"viewer.floorplan.viewLabel\":[[\"floor\"],\"二维视图\"],\"viewer.floorplan.zoomIn\":[\"放大\"],\"viewer.floorplan.zoomOut\":[\"缩小\"],\"viewer.header.back\":[\"返回\"],\"viewer.header.levels\":[\"楼层\"],\"viewer.header.rooms\":[\"房间\"],\"viewer.header.selection\":[\"当前选择\"],\"viewer.header.units\":[\"单元\"],\"viewer.header.untitled\":[\"未命名\"],\"viewer.header.zones\":[\"分区\"],\"viewer.levels.exploded\":[\"分解\"],\"viewer.levels.label\":[\"楼层:\",[\"mode\"]],\"viewer.levels.manual\":[\"手动\"],\"viewer.levels.solo\":[\"单层\"],\"viewer.levels.stacked\":[\"叠层\"],\"viewer.stage.layout\":[\"视图布局\"],\"viewer.stage.split\":[\"分屏\"],\"viewer.theme.blueprint\":[\"蓝图\"],\"viewer.theme.mediterranean\":[\"地中海\"],\"viewer.theme.night\":[\"夜景\"],\"viewer.theme.overcast\":[\"阴天\"],\"viewer.theme.paper\":[\"纸面\"],\"viewer.theme.studio\":[\"影棚\"],\"viewer.theme.sunset\":[\"日落\"],\"viewer.theme.title\":[\"场景主题\"],\"viewer.theme.twilight\":[\"暮色\"],\"viewer.theme.verdant\":[\"绿意\"],\"viewer.visibility.guides\":[\"参考图\"],\"viewer.visibility.scans\":[\"扫描模型\"],\"viewer.visibility.title\":[\"可见性\"],\"viewer.walkthrough.label\":[\"漫游:\",[\"state\"]],\"viewer.walls.cutaway\":[\"剖切墙\"],\"viewer.walls.fullHeight\":[\"全高墙\"],\"viewer.walls.label\":[\"墙体:\",[\"mode\"]],\"viewer.walls.low\":[\"矮墙\"]}")as Messages; \ No newline at end of file +/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"core.level.basement\":[\"地下层\"],\"core.level.basementNumber\":[\"地下 \",[\"number\"],\" 层\"],\"core.level.floorNumber\":[[\"number\"],\" 层\"],\"core.level.groundFloor\":[\"首层\"],\"editor.buildPanel.advanced\":[\"高级\"],\"editor.buildPanel.rooms.hint\":[\"墙体 · 楼板 · 天花板\"],\"editor.buildPanel.rooms.idle\":[\"选择一种形状开始绘制。每个房间都会同时创建墙体、楼板和天花板。\"],\"editor.buildPanel.rooms.polygon.caption\":[[\"lead\"],\"然后再次点击起点闭合。适用于 L 形和斜角房间。\"],\"editor.buildPanel.rooms.polygon.label\":[\"多边形\"],\"editor.buildPanel.rooms.polygon.lead\":[\"依次点击各个角点,\"],\"editor.buildPanel.rooms.polygon.title\":[\"多边形房间\"],\"editor.buildPanel.rooms.rectangle.caption\":[\"在网格上\",[\"lead\"],\"。墙体、楼板和天花板将一并创建。\"],\"editor.buildPanel.rooms.rectangle.label\":[\"矩形\"],\"editor.buildPanel.rooms.rectangle.lead\":[\"点击两个对角点\"],\"editor.buildPanel.rooms.rectangle.title\":[\"矩形房间\"],\"editor.buildPanel.rooms.title\":[\"房间\"],\"editor.buildPanel.rooms.walls.label\":[\"墙体\"],\"editor.buildPanel.rooms.walls.title\":[\"墙体\"],\"viewer.camera.orbitLeft\":[\"向左旋转\"],\"viewer.camera.orbitRight\":[\"向右旋转\"],\"viewer.camera.topView\":[\"俯视图\"],\"viewer.common.off\":[\"关闭\"],\"viewer.common.on\":[\"开启\"],\"viewer.display.camera\":[\"相机\"],\"viewer.display.colored\":[\"彩色\"],\"viewer.display.colors\":[\"颜色\"],\"viewer.display.edges.off\":[\"关闭\"],\"viewer.display.edges.offDetail\":[\"不显示边线\"],\"viewer.display.edges.soft\":[\"柔和\"],\"viewer.display.edges.softDetail\":[\"淡化显示主要折线\"],\"viewer.display.edges.strong\":[\"清晰\"],\"viewer.display.edges.strongDetail\":[\"清晰、不透明的边线\"],\"viewer.display.edges.title\":[\"边线\"],\"viewer.display.monochrome\":[\"单色\"],\"viewer.display.orthographic\":[\"正交\"],\"viewer.display.perspective\":[\"透视\"],\"viewer.display.render.rendered\":[\"渲染效果\"],\"viewer.display.render.renderedDetail\":[\"完整环境光遮蔽\"],\"viewer.display.render.solid\":[\"实体\"],\"viewer.display.render.solidDetail\":[\"平整快速,不启用环境光遮蔽\"],\"viewer.display.render.title\":[\"渲染\"],\"viewer.display.shadows\":[\"阴影\"],\"viewer.display.title\":[\"显示设置\"],\"viewer.floorplan.alignNorth\":[\"视图对齐北向\"],\"viewer.floorplan.empty\":[\"此场景没有可用的平面图。\"],\"viewer.floorplan.fit\":[\"适合窗口\"],\"viewer.floorplan.floor\":[\"楼层\"],\"viewer.floorplan.floorPlan\":[\"平面图\"],\"viewer.floorplan.viewLabel\":[[\"floor\"],\"二维视图\"],\"viewer.floorplan.zoomIn\":[\"放大\"],\"viewer.floorplan.zoomOut\":[\"缩小\"],\"viewer.header.back\":[\"返回\"],\"viewer.header.levels\":[\"楼层\"],\"viewer.header.rooms\":[\"房间\"],\"viewer.header.selection\":[\"当前选择\"],\"viewer.header.units\":[\"单元\"],\"viewer.header.untitled\":[\"未命名\"],\"viewer.header.zones\":[\"分区\"],\"viewer.levels.exploded\":[\"分解\"],\"viewer.levels.label\":[\"楼层:\",[\"mode\"]],\"viewer.levels.manual\":[\"手动\"],\"viewer.levels.solo\":[\"单层\"],\"viewer.levels.stacked\":[\"叠层\"],\"viewer.stage.layout\":[\"视图布局\"],\"viewer.stage.split\":[\"分屏\"],\"viewer.theme.blueprint\":[\"蓝图\"],\"viewer.theme.mediterranean\":[\"地中海\"],\"viewer.theme.night\":[\"夜景\"],\"viewer.theme.overcast\":[\"阴天\"],\"viewer.theme.paper\":[\"纸面\"],\"viewer.theme.studio\":[\"影棚\"],\"viewer.theme.sunset\":[\"日落\"],\"viewer.theme.title\":[\"场景主题\"],\"viewer.theme.twilight\":[\"暮色\"],\"viewer.theme.verdant\":[\"绿意\"],\"viewer.visibility.guides\":[\"参考图\"],\"viewer.visibility.scans\":[\"扫描模型\"],\"viewer.visibility.title\":[\"可见性\"],\"viewer.walkthrough.label\":[\"漫游:\",[\"state\"]],\"viewer.walls.cutaway\":[\"剖切墙\"],\"viewer.walls.fullHeight\":[\"全高墙\"],\"viewer.walls.label\":[\"墙体:\",[\"mode\"]],\"viewer.walls.low\":[\"矮墙\"]}")as Messages; \ No newline at end of file diff --git a/packages/editor/src/index.tsx b/packages/editor/src/index.tsx index 4f0d004463..c0a0c079db 100644 --- a/packages/editor/src/index.tsx +++ b/packages/editor/src/index.tsx @@ -127,12 +127,15 @@ export { } from './components/editor/node-arrow-handles' export { QuickMeasurementCard } from './components/editor/quick-measurement-card' export { SelectionManager } from './components/editor/selection-manager' +export { SeparatorEndGrip } from './components/editor/separator-end-grip' export { type SnapshotCameraData, ThumbnailGenerator, } from './components/editor/thumbnail-generator' export { PLUGINS_VIEW_ID } from './components/editor/views/use-editor-views' export { WallMoveSideHandles } from './components/editor/wall-move-side-handles' +export { WallPushArrow } from './components/editor/wall-push-arrow' +export { useWallsBelowSetting } from './components/editor-2d/floorplan-adjacent-walls-layer' export { useFloorplanRender } from './components/editor-2d/floorplan-render-context' export { FloorplanDimensionRenderer } from './components/editor-2d/renderers/floorplan-dimension-renderer' export { @@ -153,6 +156,7 @@ export { buildSvgArrowHeadPoints, getArcPlanPoint, } from './components/editor-2d/svg-paths' +export { useCeilingsSetting } from './components/systems/ceiling/ceiling-system' export type { SelectionAffordanceHistoryApi, SelectionAffordanceInteractionApi, @@ -183,7 +187,10 @@ export { usePlacementCoordinator, } from './components/tools/item/use-placement-coordinator' export { MoveRegistryNodeTool } from './components/tools/registry/move-registry-node-tool' -export { useRegistryToolContext } from './components/tools/registry-tool-context' +export { + RegistryToolProvider, + useRegistryToolContext, +} from './components/tools/registry-tool-context' export { CursorSphere } from './components/tools/shared/cursor-sphere' export { DRAFT_LABEL_Y_OFFSET, @@ -224,6 +231,7 @@ export { export { preloadRegistryToolModules, ToolManager } from './components/tools/tool-manager' export { chainEndJoinsExistingWall, + createInvisibleWallOnCurrentLevel, createWallOnCurrentLevel, findWallSnapTarget, getSegmentGridStep, @@ -241,6 +249,21 @@ export { type WallPlanPoint, type WallSnapRadii, } from './components/tools/wall/wall-drafting' +export { + lockWallPullDirection, + snapWallPullPoint, + WALL_PULL_ANGLE_STEP, + WALL_PULL_LOCK_TOLERANCE, + WALL_PULL_SNAP_LABELS, + WALL_PULL_SNAP_RADII, + type WallPullDirectionLock, + type WallPullGuide, + type WallPullGuideKind, + type WallPullSnapInput, + type WallPullSnapKind, + type WallPullSnapRadii, + type WallPullSnapResult, +} from './components/tools/wall/wall-pull-snap' // `ToolbarLeft` / `ToolbarRight` alias `ViewerToolbarLeft` / `ViewerToolbarRight` // (same components) under the names headless hosts compose their toolbars with. export { @@ -312,7 +335,9 @@ export { PALETTE_COLORS } from './components/ui/primitives/color-dot' export { DropdownMenu, DropdownMenuContent, + DropdownMenuGroup, DropdownMenuItem, + DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, @@ -347,6 +372,8 @@ export { SnapTargetBadge, SnapTargetIcon, } from './components/ui/snap-target-badge' +// A wall's project wall types: new, edit, duplicate (the wall panel's Assembly). +export { WallTypeMenu } from './components/ui/wall-type/wall-type-menu' export { FloorplanCompassButton, type FloorplanCompassButtonProps, @@ -534,6 +561,7 @@ export { type FloorplanSchedule, type FloorplanToolContext, type FloorplanToolMode, + type FloorplanWallDimensionFaces, floorplanGeometryMetadata, getFloorplanNodeExtension, readFloorplanContext, @@ -663,6 +691,11 @@ export { scopeNodeId, } from './lib/interaction/scope' export { isEditableKeyboardTarget } from './lib/keyboard-pan' +export { + formatLayerDepth, + formatLayerThickness, + parseLayerThickness, +} from './lib/layer-thickness' export { selectPlacedNode } from './lib/level-selection' // Lot drop-in — address → parcel → streets → front edge → setbacks, on the // site node, through the parcel provider the host sets. @@ -757,6 +790,7 @@ export { } from './lib/paint-scope' export { getNodePanelModel, + type MultiPanelControl, type NodePanelModel, PANEL_MODEL_EXTENSION, type PanelAction, @@ -817,7 +851,13 @@ export { clearRoofDuplicateMetadata, duplicateRoofSubtree } from './lib/roof-dup // kind-owned door / window tools in `@pascal-app/nodes` and the item // placement coordinator's roof-wall strategy. export { hasRoofFaceChildOverlap, type RoofWallHit, resolveRoofWallHit } from './lib/roof-wall-hit' -export { WALL_PUSH_AFFORDANCE, type WallPushArrowPayload } from './lib/room-handle-drag' +export { + selectedWallDimensions, + separatorFloorElevation, + separatorPushHandles, + WALL_PUSH_AFFORDANCE, + type WallPushArrowPayload, +} from './lib/room-handle-drag' export { displayRoomName } from './lib/room-name-messages' export type { RoomKey, RoomSelectionRecord } from './lib/room-selection' export { popRoomSelection, selectRoom } from './lib/room-selection-commands' @@ -835,6 +875,11 @@ export { remapSceneMaterialRefs, sceneMaterialUsageCounts, } from './lib/scene-material-refs' +export { + beginSeparatorEndDrag, + runSeparatorEndDrag, + type SeparatorEndDrag, +} from './lib/separator-edit' export { movementSfxStepKey } from './lib/sfx/movement-tick' export { emitDeleteSFX, triggerSFX } from './lib/sfx-bus' export { playSFX, type SFXName, type SFXPlaybackOptions } from './lib/sfx-player' @@ -893,6 +938,7 @@ export { sculptFieldForSite, terrainPointInsideSite, } from './lib/terrain-sculpt' +export { withToolShortcut } from './lib/tool-shortcuts' export { isTypingTarget } from './lib/typing-target' export { enterUnitFocus } from './lib/units' export { exportSceneToUsdz, type UsdzExportOptions } from './lib/usdz-export' @@ -913,10 +959,27 @@ export { } from './lib/viewer-selection' export { getWallDrawVariant, + getWallLineKind, + INVISIBLE_WALL_DRAFT_THICKNESS, + invisibleWallDraftSnapLines, selectWallDrawVariant, + selectWallKind, + useWallDraftThickness, useWallDrawVariant, + useWallKind, + WALL_KINDS, type WallDrawVariant, + type WallKind, + type WallLineKind, } from './lib/wall-draw-variant' +export { + nearestWallParallelTarget, + nudgeWallPosition, + publishWallParallelGuide, + WALL_PARALLEL_SNAP_RADIUS, + type WallParallelTarget, + wallParallelTargets, +} from './lib/wall-parallel-snap' export { createWallPointerTracker, wallPointerInParent, @@ -929,6 +992,32 @@ export { startWallPolygonDraft, wallPolygonDraftWalls, } from './lib/wall-polygon-draft' +export { + endWallPullRun, + releaseWallPullDrag, + startWallPull, + useWallPullRun, + WALL_PULL_AFFORDANCE, + WALL_PULL_GRIP_TITLE, + type WallPullGripPayload, + type WallPullRun, + wallDraftIsRun, + wallPullSeed, + wallPullTypePatch, +} from './lib/wall-pull' +export { + isWallRunFree, + publishWallRunFeedback, + snapWallRunDraftPoint, + wallRunDirection, +} from './lib/wall-run-snap' +export { + deleteProjectWallType, + saveProjectWallType, + useProjectWallTypes, + type WallTypePlacement, + wallTypePlacementOf, +} from './lib/wall-type' export { writeWindowChanges } from './lib/window-changes' export { closeWindowOpenState, @@ -945,7 +1034,11 @@ export { snapWorldXZForActiveBuilding, } from './lib/world-grid-snap' export { subscribeCameraPose } from './store/camera-pose-store' -export { default as useAlignmentGuides } from './store/use-alignment-guides' +export { + type DraftGuideLine, + type DraftGuides, + default as useAlignmentGuides, +} from './store/use-alignment-guides' export { default as useAudio } from './store/use-audio' export { type CameraHintAction, useCameraHintFocus } from './store/use-camera-hint-focus' export { type CommandAction, useCommandRegistry } from './store/use-command-registry' diff --git a/packages/editor/src/lib/continuation.ts b/packages/editor/src/lib/continuation.ts index fdb5c8c2f0..6d605477dc 100644 --- a/packages/editor/src/lib/continuation.ts +++ b/packages/editor/src/lib/continuation.ts @@ -18,10 +18,11 @@ export const CONTINUATION_PROFILES: Record< > = { // The wall tool's drawing mode: a chain that closes into a room ('room', the // Build panel's Polygon), one wall per two clicks ('single', Walls), or a - // two-corner box of four walls ('rectangle', Rectangle). + // two-corner box of four walls ('rectangle', Rectangle). The last one picked + // is what B arms; Rectangle until one is. wall: { options: ['room', 'single', 'rectangle'], - default: 'room', + default: 'rectangle', labels: { room: /* i18n */ { id: 'editor.lib.continuation.polygonRoom', message: 'Polygon room' }, single: /* i18n */ { id: 'editor.lib.continuation.walls', message: 'Walls' }, diff --git a/packages/editor/src/lib/floorplan/dimension-drive.test.ts b/packages/editor/src/lib/floorplan/dimension-drive.test.ts index ea2818d808..c1b8a74699 100644 --- a/packages/editor/src/lib/floorplan/dimension-drive.test.ts +++ b/packages/editor/src/lib/floorplan/dimension-drive.test.ts @@ -157,7 +157,7 @@ describe('driving a wall length', () => { expect(plan?.updates[0]?.data).toEqual({ start: [0, 0], end: [3.5, 0] }) }) - test('a dimension across the wall is not drivable', () => { + test('a dimension across the wall that ends on neither face is not drivable', () => { const nodes = scene() const resolution = resolveDimensionDrive({ nodes, @@ -165,7 +165,10 @@ describe('driving a wall length', () => { start: [1.5, -1], end: [1.5, 1], }) - expect(resolution).toEqual({ drivable: false, reason: 'dimension is not along the wall' }) + expect(resolution).toEqual({ + drivable: false, + reason: 'dimension does not start or end on this wall', + }) }) test('a locked wall refuses to drive', () => { @@ -363,3 +366,29 @@ describe('an opening width tag resizes the opening', () => { expect(plan?.updates).toEqual([{ id: 'win_1' as AnyNodeId, data: { width: 1.2192 } }]) }) }) + +describe('a dimension across a wall slides the wall', () => { + test('a room width from the wall face drives the wall along its normal, away from the far end', () => { + // wall_a runs east along z = 0; the dimension leaves its south face for a wall 3 m south. + const resolution = resolveDimensionDrive({ + nodes: scene(), + ownerNodeId: 'wall_a' as AnyNodeId, + start: [1.5, 0.075], + end: [1.5, 3], + }) + expect(resolution).toEqual({ + drivable: true, + target: { kind: 'wall-offset', wallId: 'wall_a' as AnyNodeId, direction: [0, -1] }, + }) + }) + + test('the wall end of the dimension may be either witness point', () => { + const resolution = resolveDimensionDrive({ + nodes: scene(), + ownerNodeId: 'wall_a' as AnyNodeId, + start: [1.5, -4], + end: [1.5, -0.075], + }) + expect(resolution).toMatchObject({ drivable: true, target: { direction: [0, 1] } }) + }) +}) diff --git a/packages/editor/src/lib/floorplan/dimension-drive.ts b/packages/editor/src/lib/floorplan/dimension-drive.ts index bff942c6e6..29e6b6682d 100644 --- a/packages/editor/src/lib/floorplan/dimension-drive.ts +++ b/packages/editor/src/lib/floorplan/dimension-drive.ts @@ -120,6 +120,17 @@ export type DimensionDriveTarget = openingId: AnyNodeId wallId: AnyNodeId } + | { + /** + * The dimension runs across the wall, from one of its faces to another + * wall (a room width, the outside size): the whole wall slides along + * its normal, its neighbours following, as a push of the wall does. + */ + kind: 'wall-offset' + wallId: AnyNodeId + /** Unit vector the wall travels along when the value grows. */ + direction: DimensionPlanPoint + } export type DimensionDriveResolution = | { drivable: true; target: DimensionDriveTarget } @@ -174,7 +185,7 @@ function resolveWallDrive( const wallDirection = unit(subtract(wall.end, wall.start)) if (!wallDirection) return { drivable: false, reason: 'degenerate wall' } if (Math.abs(cross(wallDirection, dimDirection)) > PARALLEL_TOLERANCE) { - return { drivable: false, reason: 'dimension is not along the wall' } + return resolveWallOffsetDrive(query, wall, wallDirection, dimDirection) } if ((wall as { curvature?: number }).curvature) { return { drivable: false, reason: 'curved walls are not drivable yet' } @@ -210,6 +221,56 @@ function resolveWallDrive( } } +/** How far off a wall's face a witness point may sit and still be on that wall. */ +const FACE_MATCH_TOLERANCE_M = 0.05 + +/** + * A dimension square to the wall, with one end on it: typing a value slides + * the wall along its normal, away from the other end when the value grows. + */ +function resolveWallOffsetDrive( + query: DimensionDriveQuery, + wall: WallNode, + wallDirection: DimensionPlanPoint, + dimDirection: DimensionPlanPoint, +): DimensionDriveResolution { + if (Math.abs(dot(wallDirection, dimDirection)) > PARALLEL_TOLERANCE) { + return { drivable: false, reason: 'dimension is neither along nor across the wall' } + } + if (wall.curveOffset) return { drivable: false, reason: 'curved walls are not drivable yet' } + const reach = (wall.thickness ?? 0.1) + FACE_MATCH_TOLERANCE_M + const onWall = (point: DimensionPlanPoint) => + distanceToSegment(point, wall.start as DimensionPlanPoint, wall.end as DimensionPlanPoint) <= + reach + const startOn = onWall(query.start) + const endOn = onWall(query.end) + if (startOn === endOn) { + return { drivable: false, reason: 'dimension does not start or end on this wall' } + } + const direction = startOn + ? unit(subtract(query.start, query.end)) + : unit(subtract(query.end, query.start)) + if (!direction) return { drivable: false, reason: 'degenerate dimension' } + return { + drivable: true, + target: { kind: 'wall-offset', wallId: wall.id as AnyNodeId, direction }, + } +} + +function distanceToSegment( + point: DimensionPlanPoint, + start: DimensionPlanPoint, + end: DimensionPlanPoint, +): number { + const segment = subtract(end, start) + const lengthSq = dot(segment, segment) + const t = + lengthSq <= 1e-12 + ? 0 + : Math.max(0, Math.min(1, dot(subtract(point, start), segment) / lengthSq)) + return length(subtract(point, [start[0] + segment[0] * t, start[1] + segment[1] * t])) +} + function resolveOpeningDrive( query: DimensionDriveQuery, opening: DoorNode | WindowNode, @@ -360,6 +421,9 @@ export function planDimensionDrive(args: { }): DimensionDrivePlan | null { const delta = args.nextLength - args.currentLength if (!Number.isFinite(delta) || Math.abs(delta) < 1e-9) return { updates: [], delta: 0 } + // A wall offset moves the wall with its junctions re-planned, bridges and + // all: that is the wall-push planner's job (`commitDimensionValue`). + if (args.target.kind === 'wall-offset') return null if (args.target.kind === 'opening-width') { const opening = args.nodes[args.target.openingId] diff --git a/packages/editor/src/lib/floorplan/floorplan-export.test.ts b/packages/editor/src/lib/floorplan/floorplan-export.test.ts index 597d836c77..2896553548 100644 --- a/packages/editor/src/lib/floorplan/floorplan-export.test.ts +++ b/packages/editor/src/lib/floorplan/floorplan-export.test.ts @@ -311,16 +311,27 @@ describe('floor plan export policy', () => { stairAnnotations: true, } - expect(resolveFloorplanExportAnnotationVisibility('expert', liveVisibility)).toEqual( + expect(resolveFloorplanExportAnnotationVisibility('expert', liveVisibility, true)).toEqual( liveVisibility, ) }) + test('exports no automatic dimensions while Display → Dimensions is off', () => { + expect( + resolveFloorplanExportAnnotationVisibility( + 'expert', + DEFAULT_FLOORPLAN_ANNOTATION_VISIBILITY, + false, + ), + ).toEqual({ ...DEFAULT_FLOORPLAN_ANNOTATION_VISIBILITY, automaticDimensions: false }) + }) + test('exports only model geometry and room labels in Default', () => { expect( resolveFloorplanExportAnnotationVisibility( 'default', DEFAULT_FLOORPLAN_ANNOTATION_VISIBILITY, + true, ), ).toEqual({ automaticDimensions: false, @@ -700,7 +711,7 @@ describe('collectFloorplanGeometry', () => { 'meters', DEFAULT_FLOORPLAN_ANNOTATION_VISIBILITY, 'floor-plan', - 'finished-faces', + 'both', [enabledPluginId], ) @@ -758,7 +769,7 @@ describe('collectFloorplanGeometry', () => { 'meters', DEFAULT_FLOORPLAN_ANNOTATION_VISIBILITY, 'floor-plan', - 'finished-faces', + 'both', [enabledPluginId], ) expect(upper.map(({ id }) => id)).toEqual(['site_overlay', 'level_upper_architecture']) @@ -775,7 +786,7 @@ describe('collectFloorplanGeometry', () => { 'meters', DEFAULT_FLOORPLAN_ANNOTATION_VISIBILITY, 'floor-plan', - 'finished-faces', + 'both', [enabledPluginId], ) // A hidden Site hides only its own ground and boundary; the site-scoped @@ -790,7 +801,7 @@ describe('collectFloorplanGeometry', () => { 'meters', DEFAULT_FLOORPLAN_ANNOTATION_VISIBILITY, 'floor-plan', - 'finished-faces', + 'both', [enabledPluginId], ) expect(structure.map(({ id }) => id)).toEqual(['level_architecture']) diff --git a/packages/editor/src/lib/floorplan/floorplan-export.tsx b/packages/editor/src/lib/floorplan/floorplan-export.tsx index 05c47cc353..743ca31d2e 100644 --- a/packages/editor/src/lib/floorplan/floorplan-export.tsx +++ b/packages/editor/src/lib/floorplan/floorplan-export.tsx @@ -44,15 +44,11 @@ import { resolveNodeForDrawingType } from './drawing-coordination' import { type FloorplanMetricNotation, type FloorplanSchedule, - type FloorplanWallDimensionReference, + type FloorplanWallDimensionFaces, getFloorplanNodeExtension, readFloorplanGeometryMetadata, } from './floorplan-extension' -import { - type FloorplanMode, - resolveFloorplanAnnotationVisibility, - resolveFloorplanWallDimensionReference, -} from './floorplan-mode' +import { type FloorplanMode, resolveFloorplanAnnotationVisibility } from './floorplan-mode' import { createFloorplanPdfDocument, type FloorplanPdfDocument } from './floorplan-pdfkit-document' import { renderFloorplanGeometryToPdfKit } from './floorplan-pdfkit-renderer' import { FLOORPLAN_VIEW_ROTATION_DEG } from './geometry' @@ -131,7 +127,7 @@ const NEUTRAL_VIEW_STATE = { export function resolveFloorplanExportViewState( unit: 'metric' | 'imperial', metricNotation: FloorplanMetricNotation, - wallDimensionReference?: FloorplanWallDimensionReference, + wallDimensionFaces?: FloorplanWallDimensionFaces, automaticDimensions = true, ) { return { @@ -139,7 +135,7 @@ export function resolveFloorplanExportViewState( automaticDimensions, unit, metricNotation, - wallDimensionReference, + wallDimensionFaces, } } @@ -195,10 +191,7 @@ export async function exportFloorplanPdf(scope: FloorplanExportScope): Promise>): GeometryContex } describe('floor-plan context extensions', () => { - test('defaults wall dimensions to finished faces', () => { - expect(readFloorplanContext(context()).wallDimensionReference).toBe('finished-faces') + test('measures walls to both faces by default', () => { + expect(readFloorplanContext(context()).wallDimensionFaces).toBe('both') }) - test('carries the selected centerline or stud-face reference', () => { - for (const wallDimensionReference of ['centerline', 'stud-faces'] as const) { - const extensions = createFloorplanContextExtensions({ wallDimensionReference }) - expect(readFloorplanContext(context(extensions)).wallDimensionReference).toBe( - wallDimensionReference, - ) + test('carries the Measure walls choice', () => { + for (const wallDimensionFaces of ['interior', 'exterior', 'both'] as const) { + const extensions = createFloorplanContextExtensions({ wallDimensionFaces }) + expect(readFloorplanContext(context(extensions)).wallDimensionFaces).toBe(wallDimensionFaces) } }) - test('normalizes stale persisted references to the finished-face default', () => { - expect(normalizeFloorplanWallDimensionReference('unknown')).toBe('finished-faces') - expect(normalizeFloorplanWallDimensionReference(null)).toBe('finished-faces') + test('normalizes stale persisted values, including the retired references, to Both', () => { + for (const stale of ['finished-faces', 'centerline', 'stud-faces', 'unknown', null]) { + expect(normalizeFloorplanWallDimensionFaces(stale)).toBe('both') + } }) test('lets presentation code suppress automatic annotation construction', () => { diff --git a/packages/editor/src/lib/floorplan/floorplan-extension.ts b/packages/editor/src/lib/floorplan/floorplan-extension.ts index 590305a313..d94a7a5482 100644 --- a/packages/editor/src/lib/floorplan/floorplan-extension.ts +++ b/packages/editor/src/lib/floorplan/floorplan-extension.ts @@ -8,6 +8,7 @@ import type { SceneApi, } from '@pascal-app/core' import type { ComponentType } from 'react' +import type { WallSelectionDimension } from '../room-push-dimensions' export const FLOORPLAN_NODE_EXTENSION_KEY = 'pascal:editor/floorplan' export const FLOORPLAN_GEOMETRY_METADATA_KEY = 'pascal:editor/floorplan' @@ -16,8 +17,20 @@ export const FLOORPLAN_CONTEXT_EXTENSION_KEY = 'pascal:editor/floorplan' export type FloorplanRenderPurpose = 'edit' | 'document' export type FloorplanMetricNotation = 'meters' | 'millimeters' export type FloorplanToolMode = 'default' | 'expert' -export type FloorplanWallDimensionReference = 'finished-faces' | 'centerline' | 'stud-faces' -export const DEFAULT_FLOORPLAN_WALL_DIMENSION_REFERENCE = 'finished-faces' +/** + * Display → Measure walls: which finished faces wall dimensions measure to — + * the interior faces (ID, the room sizes), the exterior faces (OD, the + * outside size) or both. Read by a selected wall's temporary dimensions in 2D + * and 3D and by the Expert plan's automatic dimension strings. + */ +export type FloorplanWallDimensionFaces = 'interior' | 'exterior' | 'both' +export const DEFAULT_FLOORPLAN_WALL_DIMENSION_FACES: FloorplanWallDimensionFaces = 'both' + +export function normalizeFloorplanWallDimensionFaces(value: unknown): FloorplanWallDimensionFaces { + return value === 'interior' || value === 'exterior' + ? value + : DEFAULT_FLOORPLAN_WALL_DIMENSION_FACES +} export type FloorplanAnnotationRole = | 'automatic-dimension' | 'contextual-dimension' @@ -67,6 +80,24 @@ export type FloorplanNodeExtension = { preferredView?: '2d' | '3d' referencedSelectionAnnotationRole?: FloorplanAnnotationRole contextualDimensions?: (node: N, ctx: GeometryContext) => FloorplanGeometry | null + /** + * A plan hit on this kind selects the node itself, not the room it bounds + * (3D stays room-first). For thin boundary bands whose rooms are clickable + * on either side of them. + */ + planHitSelectsNode?: boolean + /** + * Temporary dimensions shown while this node is selected in Select mode, + * alone or with others, in 2D and 3D (level-local plan points). Its + * `contextualDimensions` also stay in a multi-selection. Each is typeable: + * `commitDimensionValue` drives the node so it reads the typed value. + * Recomputed when the node or its level's rooms change. + */ + selectionDimensions?: (args: { + node: N + nodes: Readonly> + faces: FloorplanWallDimensionFaces + }) => readonly WallSelectionDimension[] actionMenu?: { canCurve?: (args: { node: N; nodes: Readonly> }) => boolean /** Buttons the kind adds to the selection's action menu (2D and 3D); each decides its own visibility. */ @@ -130,15 +161,7 @@ type FloorplanContextExtension = { */ roomLabelOverlay: boolean metricNotation: FloorplanMetricNotation - wallDimensionReference: FloorplanWallDimensionReference -} - -export function normalizeFloorplanWallDimensionReference( - value: unknown, -): FloorplanWallDimensionReference { - return value === 'centerline' || value === 'stud-faces' - ? value - : DEFAULT_FLOORPLAN_WALL_DIMENSION_REFERENCE + wallDimensionFaces: FloorplanWallDimensionFaces } export function getFloorplanNodeExtension( @@ -185,9 +208,7 @@ export function createFloorplanContextExtensions( drafting: values.drafting === true, roomLabelOverlay: values.roomLabelOverlay === true, metricNotation: values.metricNotation === 'millimeters' ? 'millimeters' : 'meters', - wallDimensionReference: normalizeFloorplanWallDimensionReference( - values.wallDimensionReference, - ), + wallDimensionFaces: normalizeFloorplanWallDimensionFaces(values.wallDimensionFaces), } satisfies FloorplanContextExtension, } } @@ -202,9 +223,7 @@ export function readFloorplanContext(ctx: GeometryContext): FloorplanContextExte drafting: extension.drafting === true, roomLabelOverlay: extension.roomLabelOverlay === true, metricNotation: extension.metricNotation === 'millimeters' ? 'millimeters' : 'meters', - wallDimensionReference: normalizeFloorplanWallDimensionReference( - extension.wallDimensionReference, - ), + wallDimensionFaces: normalizeFloorplanWallDimensionFaces(extension.wallDimensionFaces), } } return { @@ -213,7 +232,7 @@ export function readFloorplanContext(ctx: GeometryContext): FloorplanContextExte drafting: false, roomLabelOverlay: false, metricNotation: 'meters', - wallDimensionReference: DEFAULT_FLOORPLAN_WALL_DIMENSION_REFERENCE, + wallDimensionFaces: DEFAULT_FLOORPLAN_WALL_DIMENSION_FACES, } } diff --git a/packages/editor/src/lib/floorplan/floorplan-mode.test.ts b/packages/editor/src/lib/floorplan/floorplan-mode.test.ts index 3d284d8091..735bcdd0a1 100644 --- a/packages/editor/src/lib/floorplan/floorplan-mode.test.ts +++ b/packages/editor/src/lib/floorplan/floorplan-mode.test.ts @@ -5,7 +5,6 @@ import { normalizeFloorplanMode, normalizeFloorplanModesByProject, resolveFloorplanAnnotationVisibility, - resolveFloorplanWallDimensionReference, } from './floorplan-mode' describe('floor-plan mode', () => { @@ -115,10 +114,18 @@ describe('floor-plan mode', () => { }) }) - test('uses centerline dimensions only in Default', () => { - expect(resolveFloorplanWallDimensionReference('default', 'finished-faces')).toBe('centerline') - expect(resolveFloorplanWallDimensionReference('expert', 'finished-faces')).toBe( - 'finished-faces', - ) + test('Dimensions off hides automatic and contextual dimensions in both modes', () => { + for (const mode of ['default', 'expert'] as const) { + const visibility = resolveFloorplanAnnotationVisibility( + mode, + { ...DEFAULT_FLOORPLAN_ANNOTATION_VISIBILITY, contextualDimensions: true }, + { selected: true, target: 'editor', dimensions: false }, + ) + expect(visibility.automaticDimensions).toBe(false) + expect(visibility.contextualDimensions).toBe(false) + // Drawn dimensions and measurements are the user's own: they stay. + expect(visibility.manualDimensions).toBe(true) + expect(visibility.measurements).toBe(true) + } }) }) diff --git a/packages/editor/src/lib/floorplan/floorplan-mode.ts b/packages/editor/src/lib/floorplan/floorplan-mode.ts index 06c51d64c0..f022a19927 100644 --- a/packages/editor/src/lib/floorplan/floorplan-mode.ts +++ b/packages/editor/src/lib/floorplan/floorplan-mode.ts @@ -2,11 +2,7 @@ import { type FloorplanAnnotationVisibility, revealFloorplanAnnotationRole, } from './annotation-visibility' -import type { - FloorplanAnnotationRole, - FloorplanToolMode, - FloorplanWallDimensionReference, -} from './floorplan-extension' +import type { FloorplanAnnotationRole, FloorplanToolMode } from './floorplan-extension' export const FLOORPLAN_MODES = ['default', 'expert'] as const @@ -18,6 +14,8 @@ export type FloorplanPresentationContext = { referencedAnnotationRole?: FloorplanAnnotationRole selected?: boolean target: 'editor' | 'export' + /** Display → Dimensions. Off hides the automatic and contextual dimensions in either mode. */ + dimensions?: boolean } export function normalizeFloorplanMode(value: unknown): FloorplanMode { @@ -45,6 +43,17 @@ export function resolveFloorplanAnnotationVisibility( mode: FloorplanMode, expertVisibility: FloorplanAnnotationVisibility, context: FloorplanPresentationContext, +): FloorplanAnnotationVisibility { + const visibility = resolveModeAnnotationVisibility(mode, expertVisibility, context) + if (context.dimensions !== false) return visibility + if (!visibility.automaticDimensions && !visibility.contextualDimensions) return visibility + return { ...visibility, automaticDimensions: false, contextualDimensions: false } +} + +function resolveModeAnnotationVisibility( + mode: FloorplanMode, + expertVisibility: FloorplanAnnotationVisibility, + context: FloorplanPresentationContext, ): FloorplanAnnotationVisibility { if (mode === 'expert') return expertVisibility @@ -66,10 +75,3 @@ export function resolveFloorplanAnnotationVisibility( ? revealFloorplanAnnotationRole(visibility, context.referencedAnnotationRole) : visibility } - -export function resolveFloorplanWallDimensionReference( - mode: FloorplanMode, - expertReference: FloorplanWallDimensionReference, -): FloorplanWallDimensionReference { - return mode === 'default' ? 'centerline' : expertReference -} diff --git a/packages/editor/src/lib/floorplan/floorplan-plugin-install.test.tsx b/packages/editor/src/lib/floorplan/floorplan-plugin-install.test.tsx index d044a69eee..e9fca50ab7 100644 --- a/packages/editor/src/lib/floorplan/floorplan-plugin-install.test.tsx +++ b/packages/editor/src/lib/floorplan/floorplan-plugin-install.test.tsx @@ -90,7 +90,7 @@ function exportedIds(installedPlugins: readonly string[] | undefined) { 'meters', DEFAULT_FLOORPLAN_ANNOTATION_VISIBILITY, 'floor-plan', - 'finished-faces', + 'both', installedPlugins, ).map(({ id }) => id) } diff --git a/packages/editor/src/lib/floorplan/floorplan-readonly.ts b/packages/editor/src/lib/floorplan/floorplan-readonly.ts index 6ca787cd90..68405484ac 100644 --- a/packages/editor/src/lib/floorplan/floorplan-readonly.ts +++ b/packages/editor/src/lib/floorplan/floorplan-readonly.ts @@ -1,7 +1,7 @@ import type { AnyNode, AnyNodeId, FloorplanPalette, GeometryContext } from '@pascal-app/core' import { createFloorplanContextExtensions, - type FloorplanWallDimensionReference, + type FloorplanWallDimensionFaces, } from './floorplan-extension' export type FloorplanViewState = { @@ -14,7 +14,7 @@ export type FloorplanViewState = { drafting?: boolean /** Room labels drawn as screen pills (see `FloorplanContextExtension.roomLabelOverlay`). */ roomLabelOverlay?: boolean - wallDimensionReference?: FloorplanWallDimensionReference + wallDimensionFaces?: FloorplanWallDimensionFaces highlighted: boolean hovered: boolean moving: boolean @@ -65,7 +65,7 @@ export function buildFloorplanContext( purpose: viewState.purpose ?? 'edit', drafting: viewState.drafting === true, roomLabelOverlay: viewState.roomLabelOverlay === true, - wallDimensionReference: viewState.wallDimensionReference, + wallDimensionFaces: viewState.wallDimensionFaces, }), viewState: viewState.palette ? { diff --git a/packages/editor/src/lib/floorplan/site-plan/site-annotations.test.ts b/packages/editor/src/lib/floorplan/site-plan/site-annotations.test.ts index 4c9312a64e..2abb0d1abb 100644 --- a/packages/editor/src/lib/floorplan/site-plan/site-annotations.test.ts +++ b/packages/editor/src/lib/floorplan/site-plan/site-annotations.test.ts @@ -1,5 +1,12 @@ import { describe, expect, test } from 'bun:test' -import { createTerrainField, type LevelNode, quantize, type SceneSnapshot } from '@pascal-app/core' +import { + createTerrainField, + LevelNode, + quantize, + type SceneSnapshot, + SlabNode, + ZoneNode, +} from '@pascal-app/core' import { buildSitePlanDrawing, setbacksWarning } from './build-site-plan-drawing' import { registerSitePlanContributor } from './contributors' import { computeSiteCoverage } from './coverage' @@ -14,6 +21,7 @@ import { streetEdgeNames, UNNAMED_STREET, } from './site-annotations' +import { outdoorParts } from './site-parts' /** The QA lot (4121 NW 34th St, Gainesville): a through lot, NW 34th Terrace on the west edge (1), NW 34th Street on the east (3). */ const LOT: [number, number][] = [ @@ -436,6 +444,43 @@ describe('the setbacks line a plans examiner reads', () => { }) describe('the finish floor elevation', () => { + test('outdoor plates use their room type for site parts and stay out of the house floor elevation', () => { + const polygon: [number, number][] = [ + [0, 0], + [2, 0], + [2, 2], + [0, 2], + ] + const room = ZoneNode.parse({ name: 'Deck', roomType: 'deck', polygon }) + const plate = SlabNode.parse({ + zoneIds: [room.id], + plateRole: 'sunken', + polygon, + elevation: 0.4, + }) + const floor = SlabNode.parse({ + plateRole: 'base', + zoneIds: [room.id], + polygon: [], + elevation: 0.05, + }) + const level = LevelNode.parse({ children: [plate.id, floor.id, room.id] }) + for (const metadata of [{}, { floor: 'porch-slab' }]) { + const scene = { + nodes: { + [level.id]: level, + [room.id]: room, + [plate.id]: { ...plate, metadata }, + [floor.id]: floor, + }, + } as unknown as SceneSnapshot + expect(outdoorParts(scene, level, null, [], [])).toMatchObject([ + { id: plate.id, kind: 'deck', wood: true }, + ]) + expect(floorTops(scene, level)).toEqual({ floor: 0.05, garage: null }) + } + }) + test('the driveway and walk (flatwork, no floor tag) never become the FF', () => { const nodes = { level_0: { diff --git a/packages/editor/src/lib/floorplan/site-plan/site-annotations.ts b/packages/editor/src/lib/floorplan/site-plan/site-annotations.ts index e073c93ba7..ae19bd9a4d 100644 --- a/packages/editor/src/lib/floorplan/site-plan/site-annotations.ts +++ b/packages/editor/src/lib/floorplan/site-plan/site-annotations.ts @@ -11,7 +11,9 @@ import { type AnyNodeId, type BuildingNode, type FloorplanGeometry, + floorPlateRoom, heightAt, + isOutdoorRoomType, type LevelNode, outwardNormal, type SceneSnapshot, @@ -1072,6 +1074,7 @@ export function floorTops( if (n?.type !== 'slab') continue // the driveway and walks are paving at grade, never the finish floor if (flatworkKindOf(n)) continue + if (isOutdoorRoomType(floorPlateRoom(n, (id) => scene.nodes[id])?.roomType)) continue const tag = n.metadata?.floor const top = typeof n.elevation === 'number' ? n.elevation : 0.05 if (tag === 'garage-slab-at-grade') garage = garage === null ? top : Math.min(garage, top) diff --git a/packages/editor/src/lib/floorplan/site-plan/site-parts.ts b/packages/editor/src/lib/floorplan/site-plan/site-parts.ts index 78af48aa40..52b961fe7a 100644 --- a/packages/editor/src/lib/floorplan/site-plan/site-parts.ts +++ b/packages/editor/src/lib/floorplan/site-plan/site-parts.ts @@ -10,7 +10,9 @@ import { type AnyNode, type AnyNodeId, type BuildingNode, + floorPlateRoom, getRoofSegmentDeckReach, + isOutdoorRoomType, type LevelNode, migrateSiteMetadata, type RoofSegmentNode, @@ -201,7 +203,7 @@ function coveredShare(ring: readonly Pt[], covers: readonly Pt[][]): number { /** * The level's outdoor slabs in site metres: porches, decks, patios and - * landings (a generator `metadata.porch`, or a deck / porch-slab floor, or a + * landings (a generator `metadata.porch`, an outdoor room’s plate, or a * slab lying outside the house's walls) and the flatwork. The house's own * floors (the storey slab, a raised platform, the garage pad) and a porch * cover's beam are not outdoor parts. `roofs` decides which are covered. @@ -247,7 +249,8 @@ export function outdoorParts( // a porch cover's beam box is not a floor if (/beam/i.test(floor) || /beam/i.test(slab.name ?? '')) continue const porch = meta.porch as { policy?: string; entrance?: string } | undefined - const outdoorFloor = floor === 'deck' || floor === 'porch-slab' + const roomType = floorPlateRoom(child, (id) => scene.nodes[id])?.roomType + const outdoorFloor = isOutdoorRoomType(roomType) if (!porch && !outdoorFloor) { // a hand-drawn slab: the house's floor when it lies under the walls if (HOUSE_FLOORS.has(floor)) continue @@ -257,7 +260,7 @@ export function outdoorParts( ) if (walls.length === 0 || walls.some((w) => pointInPolygon(w, c[0], c[1]))) continue } - const wood = floor === 'deck' + const wood = roomType === 'deck' const policy = porch?.policy ?? '' const kind: OutdoorKind = policy === 'deck' || (wood && policy !== 'full' && policy !== 'entry') diff --git a/packages/editor/src/lib/grid-frame.test.ts b/packages/editor/src/lib/grid-frame.test.ts index 3ff9920231..f93eca6742 100644 --- a/packages/editor/src/lib/grid-frame.test.ts +++ b/packages/editor/src/lib/grid-frame.test.ts @@ -1,6 +1,11 @@ -import { expect, test } from 'bun:test' -import { Group, Vector3 } from 'three' -import { gridLocalNormal, gridLocalPoint } from './grid-frame' +import { describe, expect, test } from 'bun:test' +import { Group, Quaternion, Vector3 } from 'three' +import { + gridLocalNormal, + gridLocalPoint, + HORIZONTAL_GRID_QUATERNION, + layHorizontalGrid, +} from './grid-frame' test('grid floor and cursor stay in model coordinates after God-view pan, scale and yaw', () => { const root = new Group() @@ -17,3 +22,51 @@ test('grid floor and cursor stay in model coordinates after God-view pan, scale ).toBeLessThan(1e-8) expect(world.distanceTo(local)).toBeGreaterThan(1) }) + +// The grid plane's lattice lines run at multiples of the cell size in its own +// XY, from its origin: where does plane-local (u, v) land? +function planePoint(position: Vector3, quaternion: Quaternion, u: number, v: number) { + return new Vector3(u, v, 0).applyQuaternion(quaternion).add(position) +} + +describe('layHorizontalGrid', () => { + test("lays the lattice on a turned, offset building's own frame", () => { + const yaw = (17 * Math.PI) / 180 + const position = new Vector3() + const quaternion = new Quaternion() + layHorizontalGrid({ position: [12.37, 0, -8.91], rotationY: yaw }, 0.301, position, quaternion) + + expect(position.toArray()).toEqual([12.37, 0.301, -8.91]) + // Flat… + expect(new Vector3(0, 0, 1).applyQuaternion(quaternion).y).toBeCloseTo(1, 12) + // …and each lattice point is a building-local lattice point: plane (1, -1.5) + // is building-local (1, 1.5), wherever the building's yaw puts it. + const point = planePoint(position, quaternion, 1, -1.5) + const cos = Math.cos(yaw) + const sin = Math.sin(yaw) + expect(point.x).toBeCloseTo(12.37 + cos + 1.5 * sin, 12) + expect(point.y).toBeCloseTo(0.301, 12) + expect(point.z).toBeCloseTo(-8.91 - sin + 1.5 * cos, 12) + }) + + test('with no building the world grid stays anchored at the origin, as before', () => { + const position = new Vector3(5, 5, 5) + const quaternion = new Quaternion() + layHorizontalGrid(null, 0.001, position, quaternion) + + expect(position.toArray()).toEqual([0, 0.001, 0]) + expect(Math.abs(quaternion.dot(HORIZONTAL_GRID_QUATERNION))).toBeCloseTo(1, 12) + const point = planePoint(position, quaternion, 2, -3) + expect(point.x).toBeCloseTo(2, 12) + expect(point.z).toBeCloseTo(3, 12) + }) + + test('an unturned building at the origin draws the same grid as no building', () => { + const position = new Vector3() + const quaternion = new Quaternion() + layHorizontalGrid({ position: [0, 0, 0], rotationY: 0 }, 0.001, position, quaternion) + + expect(position.toArray()).toEqual([0, 0.001, 0]) + expect(Math.abs(quaternion.dot(HORIZONTAL_GRID_QUATERNION))).toBeCloseTo(1, 12) + }) +}) diff --git a/packages/editor/src/lib/grid-frame.ts b/packages/editor/src/lib/grid-frame.ts index 189ef9636b..dd7265f960 100644 --- a/packages/editor/src/lib/grid-frame.ts +++ b/packages/editor/src/lib/grid-frame.ts @@ -1,4 +1,5 @@ -import type { Object3D, Vector3 } from 'three' +import type { BuildingPose } from '@pascal-app/core' +import { type Object3D, Quaternion, Vector3 } from 'three' // Placement surfaces are world-space; the grid lives under the scalable XR // scene root. Keep its lattice and reveal in that root's model coordinates. @@ -16,3 +17,29 @@ export function gridLocalNormal(parent: Object3D | null, normal: Vector3, target if (parent) target.transformDirection(parent.matrixWorld.clone().invert()) return target } + +const UP = new Vector3(0, 1, 0) + +/** Lays the grid's PlaneGeometry (which faces +Z) flat, its normal → +Y. */ +export const HORIZONTAL_GRID_QUATERNION = new Quaternion().setFromUnitVectors( + new Vector3(0, 0, 1), + UP, +) + +/** + * Lay the horizontal grid plane on the lattice the active tools snap on: a + * building's own frame (`pose`, its yaw and offset — the lattice + * `snapWorldXZForActiveBuilding` snaps to), or with `pose` null the world XZ + * grid anchored at (0, 0). The lattice lines run at multiples of the cell size + * from the plane's origin, so a turned house's walls sit square on them. `y` + * is the plane's height in the grid parent's frame. + */ +export function layHorizontalGrid( + pose: BuildingPose | null, + y: number, + position: Vector3, + quaternion: Quaternion, +) { + position.set(pose?.position[0] ?? 0, y, pose?.position[2] ?? 0) + quaternion.setFromAxisAngle(UP, pose?.rotationY ?? 0).multiply(HORIZONTAL_GRID_QUATERNION) +} diff --git a/packages/editor/src/lib/inspector-card-mode.test.ts b/packages/editor/src/lib/inspector-card-mode.test.ts index 3fb3da3f17..745ca6f41f 100644 --- a/packages/editor/src/lib/inspector-card-mode.test.ts +++ b/packages/editor/src/lib/inspector-card-mode.test.ts @@ -1,9 +1,9 @@ import { describe, expect, test } from 'bun:test' import { type InspectorCardMode, + openExtension, resolveActiveExtension, toggleCard, - toggleExtension, } from './inspector-card-mode' const collapsed: InspectorCardMode = { collapsed: true, activeExtensionId: null } @@ -29,27 +29,6 @@ describe('toggleCard (chevron / header press)', () => { }) }) -describe('toggleExtension (header icon press)', () => { - test('folded card opens straight into extension-only mode', () => { - expect(toggleExtension(collapsed, 'bones:eng')).toEqual(engineering) - }) - - test('regular expanded card swaps to extension-only mode', () => { - expect(toggleExtension(regular, 'bones:eng')).toEqual(engineering) - }) - - test('pressing the ACTIVE extension icon again returns to regular mode', () => { - expect(toggleExtension(engineering, 'bones:eng')).toEqual(regular) - }) - - test('pressing another extension icon switches extension modes directly', () => { - expect(toggleExtension(engineering, 'other:ext')).toEqual({ - collapsed: false, - activeExtensionId: 'other:ext', - }) - }) -}) - describe('resolveActiveExtension', () => { const bones = { id: 'bones:eng' } const other = { id: 'other:ext' } @@ -71,20 +50,13 @@ describe('resolveActiveExtension', () => { }) describe('full user flows (QA script)', () => { - test('chevron → regular only; fold; icon → extension only; icon again → regular', () => { + test('chevron → regular only; fold; extension action → extension only; chevron → regular', () => { let mode = collapsed mode = toggleCard(mode) // chevron expect(mode).toEqual(regular) mode = toggleCard(mode) // fold expect(mode).toEqual(collapsed) - mode = toggleExtension(mode, 'bones:eng') // bones icon - expect(mode).toEqual(engineering) - mode = toggleExtension(mode, 'bones:eng') // bones icon again - expect(mode).toEqual(regular) - }) - - test('extension mode exits via the chevron too', () => { - let mode = toggleExtension(collapsed, 'bones:eng') + mode = openExtension('bones:eng') // the action-menu button expect(mode).toEqual(engineering) mode = toggleCard(mode) // chevron expect(mode).toEqual(regular) diff --git a/packages/editor/src/lib/inspector-card-mode.ts b/packages/editor/src/lib/inspector-card-mode.ts index 1e8f6d8268..73a19a86bf 100644 --- a/packages/editor/src/lib/inspector-card-mode.ts +++ b/packages/editor/src/lib/inspector-card-mode.ts @@ -14,9 +14,9 @@ * - chevron / header press ({@link toggleCard}): collapsed → regular, * regular → collapsed, extension → regular (exit extension mode first, * stay expanded); - * - extension icon press ({@link toggleExtension}): enters that - * extension's mode from anywhere (expanding a folded card); pressing - * the ACTIVE extension's icon again returns to regular. + * - an extension's action-menu button ({@link openExtension}): enters that + * extension's mode from anywhere (expanding a folded card); pressed while + * that extension is already showing, it keeps it showing. */ export interface InspectorCardMode { @@ -36,13 +36,8 @@ export function toggleCard(mode: InspectorCardMode): InspectorCardMode { return { collapsed: true, activeExtensionId: null } } -/** Header extension-icon press. */ -export function toggleExtension(mode: InspectorCardMode, extensionId: string): InspectorCardMode { - // The active extension's icon pressed again → back to the regular controls. - if (!mode.collapsed && mode.activeExtensionId === extensionId) { - return { collapsed: false, activeExtensionId: null } - } - // Anywhere else (folded, regular, another extension) → this extension only. +/** An extension's action-menu button: opens the card on that extension, or keeps it there. */ +export function openExtension(extensionId: string): InspectorCardMode { return { collapsed: false, activeExtensionId: extensionId } } diff --git a/packages/editor/src/lib/inspector-expanded.test.ts b/packages/editor/src/lib/inspector-expanded.test.ts index e43dfc1b69..6a6c27b129 100644 --- a/packages/editor/src/lib/inspector-expanded.test.ts +++ b/packages/editor/src/lib/inspector-expanded.test.ts @@ -42,3 +42,16 @@ test('without usable storage the panel opens folded and expanding still works', useInspectorExpanded.getState().setExpanded(true) expect(useInspectorExpanded.getState().expanded).toBe(true) }) + +test('an extension opened from the action menu expands the card; folding it forgets the extension', async () => { + stubStorage({ getItem: () => null, setItem: () => {} }) + const { useInspectorExpanded } = await load() + useInspectorExpanded.getState().applyMode({ collapsed: false, activeExtensionId: 'bones:eng' }) + expect(useInspectorExpanded.getState()).toMatchObject({ + expanded: true, + activeExtensionId: 'bones:eng', + }) + useInspectorExpanded.getState().setExpanded(false) + useInspectorExpanded.getState().setExpanded(true) + expect(useInspectorExpanded.getState().activeExtensionId).toBeNull() +}) diff --git a/packages/editor/src/lib/inspector-expanded.ts b/packages/editor/src/lib/inspector-expanded.ts index d0cabd641e..49e526b493 100644 --- a/packages/editor/src/lib/inspector-expanded.ts +++ b/packages/editor/src/lib/inspector-expanded.ts @@ -1,4 +1,5 @@ import { create } from 'zustand' +import type { InspectorCardMode } from './inspector-card-mode' // One choice for every right-side inspector panel (room, wall, item…): opened // expanded or folded to its header, kept per viewer until they fold it again. @@ -26,11 +27,22 @@ function writeExpanded(expanded: boolean) { export const useInspectorExpanded = create<{ expanded: boolean + /** + * The plugin inspector extension filling the expanded card (see `inspector-card-mode.ts`), + * shared so the action menu can open it. Not remembered: folding the card forgets it. + */ + activeExtensionId: string | null setExpanded: (expanded: boolean) => void + applyMode: (mode: InspectorCardMode) => void }>((set) => ({ expanded: readExpanded(), + activeExtensionId: null, setExpanded: (expanded) => { writeExpanded(expanded) - set({ expanded }) + set(expanded ? { expanded } : { expanded, activeExtensionId: null }) + }, + applyMode: ({ collapsed, activeExtensionId }) => { + writeExpanded(!collapsed) + set({ expanded: !collapsed, activeExtensionId: collapsed ? null : activeExtensionId }) }, })) diff --git a/packages/editor/src/lib/keyboard-pan.test.ts b/packages/editor/src/lib/keyboard-pan.test.ts index f6f96180e6..88ce880288 100644 --- a/packages/editor/src/lib/keyboard-pan.test.ts +++ b/packages/editor/src/lib/keyboard-pan.test.ts @@ -111,6 +111,13 @@ test('modifier chords stay shortcuts, and typing in a field never pans', () => { expect(acceptsKeyboardPan(key({ target: new Input() }))).toBe(false) }) +test('Shift with W, S or D arms a tool instead of panning; Shift with A still pans', () => { + for (const code of ['KeyW', 'KeyS', 'KeyD']) + expect(acceptsKeyboardPan(key({ code, shiftKey: true }))).toBe(false) + expect(acceptsKeyboardPan(key({ code: 'KeyA', shiftKey: true }))).toBe(true) + expect(acceptsKeyboardPan(key({ code: 'KeyD' }))).toBe(true) +}) + test('cruise speed scales with the visible width within fixed bounds', () => { expect(keyboardPanSpeed(0)).toBe(0.5) expect(keyboardPanSpeed(20)).toBeCloseTo(6) diff --git a/packages/editor/src/lib/keyboard-pan.ts b/packages/editor/src/lib/keyboard-pan.ts index c5f55d1f04..3d0e3a695e 100644 --- a/packages/editor/src/lib/keyboard-pan.ts +++ b/packages/editor/src/lib/keyboard-pan.ts @@ -2,6 +2,8 @@ // move the same way. Keys match by physical position (`event.code`): the // cluster stays under the left hand on any layout (Z/Q/S/D on AZERTY). +import { claimsKeyboardPan } from './tool-shortcuts' + export type KeyboardPanState = { forward: boolean backward: boolean @@ -79,10 +81,15 @@ export function clearKeyboardPanKeys(state: KeyboardPanState) { state.right = false } -/** Pan keys are ignored with a modifier held (shortcuts) or while typing. */ +/** + * Pan keys are ignored with a modifier held (shortcuts), for a Shift chord that + * arms a tool (Shift+W window, Shift+S stairs, Shift+D door), and while typing. + */ export function acceptsKeyboardPan(event: KeyboardEvent) { return ( - !(event.metaKey || event.ctrlKey || event.altKey) && !isEditableKeyboardTarget(event.target) + !(event.metaKey || event.ctrlKey || event.altKey) && + !claimsKeyboardPan(event) && + !isEditableKeyboardTarget(event.target) ) } diff --git a/packages/editor/src/lib/layer-thickness.test.ts b/packages/editor/src/lib/layer-thickness.test.ts new file mode 100644 index 0000000000..8c66aa58d4 --- /dev/null +++ b/packages/editor/src/lib/layer-thickness.test.ts @@ -0,0 +1,22 @@ +import { expect, test } from 'bun:test' +import { ROOF_BUILD_UP_PRESETS, roofBuildUpDepths } from '@pascal-app/core' +import { formatLayerDepth, formatLayerThickness } from './layer-thickness' + +const IN = 0.0254 + +// The roof layers read DECK 10-3/16" beside COVERING 0.54": a covering of shingle and underlayment +// is no exact 32nd, so it fell to decimals. Summed depths read as fractions, to the nearest 1/16". +test('summed depths read as fractions to the 1/16", like the deck beside them', () => { + expect(formatLayerDepth(0.54 * IN, 'imperial')).toBe('9/16"') + for (const preset of ROOF_BUILD_UP_PRESETS) { + const { deck, covering } = roofBuildUpDepths(preset.buildUp) + for (const depth of [deck, covering]) + expect(formatLayerDepth(depth, 'imperial')).toMatch(/^(\d+|\d+\/\d+|\d+-\d+\/\d+)"$/) + } + expect(formatLayerDepth(0.0137, 'metric')).toBe('13.7 mm') +}) + +test('a typed thickness still reads back as typed', () => { + expect(formatLayerThickness((7 / 16) * IN, 'imperial')).toBe('7/16"') + expect(formatLayerThickness(0.0111, 'imperial')).toBe('0.437"') +}) diff --git a/packages/editor/src/lib/layer-thickness.ts b/packages/editor/src/lib/layer-thickness.ts new file mode 100644 index 0000000000..c9f62aa1bb --- /dev/null +++ b/packages/editor/src/lib/layer-thickness.ts @@ -0,0 +1,79 @@ +import type { LinearUnit } from './measurements' + +const METRES_PER_INCH = 0.0254 + +/** + * Imperial-friendly thickness input. Accepts `5/8`, `5/8"`, `7/16 in`, + * `1-1/4"`, `1 1/2"`, `12mm`, `0.012m`. A bare number means INCHES in imperial + * display and MILLIMETRES in metric — layers are millimetre-scale and + * typing `0.0127` for half-inch board is nobody's idea of usable. + */ +export function parseLayerThickness(raw: string, unit: LinearUnit): number | null { + const text = raw.trim().toLowerCase().replace(/["”]/g, ' in ') + if (!text) return null + const explicit = /(mm|cm|m|in|ft|')\s*$/.exec(text) + const suffix = explicit?.[1] + const body = (suffix ? text.slice(0, explicit?.index) : text).trim() + + // `1-1/4` / `1 1/2` / `5/8` / `0.4375` + const mixed = /^(\d+(?:\.\d+)?)[\s-]+(\d+)\s*\/\s*(\d+)$/.exec(body) + const fraction = /^(\d+)\s*\/\s*(\d+)$/.exec(body) + let value: number + if (mixed) { + value = Number(mixed[1]) + Number(mixed[2]) / Number(mixed[3]) + } else if (fraction) { + value = Number(fraction[1]) / Number(fraction[2]) + } else { + value = Number(body) + } + if (!Number.isFinite(value) || value < 0) return null + + switch (suffix) { + case 'mm': + return value / 1000 + case 'cm': + return value / 100 + case 'm': + return value + case 'in': + return value * METRES_PER_INCH + case 'ft': + case "'": + return value * 12 * METRES_PER_INCH + default: + return unit === 'imperial' ? value * METRES_PER_INCH : value / 1000 + } +} + +/** + * An exact 32nd of an inch as its fraction, so 7/16 in (0.0111125 m) reads back as `7/16"`; any + * other value as decimal inches (0.0111 m is `0.437"`). + */ +export function formatLayerThickness(metres: number, unit: LinearUnit): string { + if (unit !== 'imperial') return `${Math.round(metres * 1000 * 10) / 10} mm` + const inchValue = metres / METRES_PER_INCH + const parts = Math.round(inchValue * 32) + if (Math.abs(inchValue * 32 - parts) > 1e-6) return `${Math.round(inchValue * 1000) / 1000}"` + const whole = Math.floor(parts / 32) + let numerator = parts % 32 + let denominator = 32 + while (numerator % 2 === 0 && numerator > 0) { + numerator /= 2 + denominator /= 2 + } + if (numerator === 0) return `${whole}"` + return whole > 0 ? `${whole}-${numerator}/${denominator}"` : `${numerator}/${denominator}"` +} + +/** + * A summed depth to read, not type back (a plane's deck or covering, a ceiling's thickness): in + * imperial to the nearest 1/16" as a fraction, as the lumber and panels it adds up read, so a + * covering of 0.54" reads 9/16" beside a 10-3/16" deck. + */ +export function formatLayerDepth(metres: number, unit: LinearUnit): string { + if (unit !== 'imperial') return formatLayerThickness(metres, unit) + return formatLayerThickness( + (Math.round((metres / METRES_PER_INCH) * 16) / 16) * METRES_PER_INCH, + unit, + ) +} diff --git a/packages/editor/src/lib/material-swatch-style.ts b/packages/editor/src/lib/material-swatch-style.ts new file mode 100644 index 0000000000..84275f067f --- /dev/null +++ b/packages/editor/src/lib/material-swatch-style.ts @@ -0,0 +1,24 @@ +import type { MaterialSwatch } from '@pascal-app/core' +import type { CSSProperties } from 'react' + +/** + * The CSS that paints a material swatch: the image over its colour, and a tinted + * albedo multiplied by the colour, as the 3D material tints its map. + */ +export function materialSwatchStyle({ + color, + imageUrl, + tinted, +}: Pick & { tinted?: boolean }): CSSProperties { + return { + backgroundColor: color, + ...(imageUrl + ? { + backgroundImage: `url(${JSON.stringify(imageUrl)})`, + backgroundPosition: 'center', + backgroundSize: 'cover', + ...(tinted ? { backgroundBlendMode: 'multiply' } : {}), + } + : {}), + } +} diff --git a/packages/editor/src/lib/orbit-near-plane.test.ts b/packages/editor/src/lib/orbit-near-plane.test.ts new file mode 100644 index 0000000000..0562722dee --- /dev/null +++ b/packages/editor/src/lib/orbit-near-plane.test.ts @@ -0,0 +1,12 @@ +import { describe, expect, test } from 'bun:test' +import { CLOSE_UP_NEAR, ORBIT_NEAR, orbitNearPlane } from './orbit-near-plane' + +describe('the orbit near plane follows the eye in', () => { + test("standing back it is the viewer's own; close in, a tenth of the distance; never under an inch-off look", () => { + expect(orbitNearPlane(40)).toBe(ORBIT_NEAR) + expect(orbitNearPlane(3)).toBe(ORBIT_NEAR) + expect(orbitNearPlane(1)).toBeCloseTo(0.1, 9) + expect(orbitNearPlane(0.5)).toBeCloseTo(0.05, 9) + expect(orbitNearPlane(0.01)).toBe(CLOSE_UP_NEAR) + }) +}) diff --git a/packages/editor/src/lib/orbit-near-plane.ts b/packages/editor/src/lib/orbit-near-plane.ts new file mode 100644 index 0000000000..b46856b10b --- /dev/null +++ b/packages/editor/src/lib/orbit-near-plane.ts @@ -0,0 +1,13 @@ +/** The viewer's near plane (`viewerCameraClipping`), kept while the eye stands back. */ +export const ORBIT_NEAR = 0.3 +/** How close the near plane comes in when the eye does: a casing seen from an inch off. */ +export const CLOSE_UP_NEAR = 0.01 + +/** + * The near plane for an orbit `distance` from its target: a tenth of it, between `CLOSE_UP_NEAR` + * and the viewer's own, so zooming in on a window's trim never clips it while the eye standing + * back keeps the depth precision it had. + */ +export function orbitNearPlane(distance: number): number { + return Math.min(ORBIT_NEAR, Math.max(CLOSE_UP_NEAR, distance * 0.1)) +} diff --git a/packages/editor/src/lib/paint-scope.test.ts b/packages/editor/src/lib/paint-scope.test.ts index 5ff5a82ef5..27b289a15b 100644 --- a/packages/editor/src/lib/paint-scope.test.ts +++ b/packages/editor/src/lib/paint-scope.test.ts @@ -790,3 +790,56 @@ describe('generated floor plates: scopes per surface', () => { expect(paintScopeRole(manual, 'surface', 'room')).toBe('surface') }) }) + +describe('a surface that declares its own scopes', () => { + it('offers its scopes and labels and paints the role it names for the scope', () => { + const kind = 'paint-surface-scope-test' + if (!nodeRegistry.has(kind)) + registerNode({ + kind, + schemaVersion: 1, + schema: z.object({ type: z.literal(kind) }) as never, + category: 'structure', + defaults: () => ({}), + capabilities: { + slots: () => [{ slotId: 'end:1', label: 'End' }], + paint: { + resolveRole: () => null, + buildPatch: () => ({}), + applyPreview: () => null, + roleLabel: (_node: AnyNode, role: string) => (role === 'end:1' ? 'This end' : null), + scopes: (_node: AnyNode, role: string) => + role === 'end:1' + ? { + scopes: ['single', 'matching'], + labels: { matching: 'Every end' }, + roleFor: (scope: PaintScope) => (scope === 'matching' ? 'ends:all' : role), + } + : null, + }, + }, + floorplanScope: 'level', + renderer: { kind: 'parametric', module: async () => ({ default: () => null }) }, + } as unknown as AnyNodeDefinition) + const node = { id: 'scoped_1', type: kind } as unknown as AnyNode + const hover = paintHoverInfo(node, 'end:1', []) + expect(hover.scopes).toEqual(['single', 'matching']) + expect(paintScopeLabel('single', hover)).toBe('This end') + expect(paintScopeLabel('matching', hover)).toBe('Every end') + const targets = (scope: PaintScope) => + resolvePaintScopeTargets({ + node, + role: 'end:1', + scope, + nodes: { scoped_1: node }, + spaces: {}, + slotRolesOf: () => [], + }).map((target) => `${target.nodeId}:${target.role}`) + expect(targets('single')).toEqual(['scoped_1:end:1']) + expect(targets('matching')).toEqual(['scoped_1:ends:all']) + // a scope the surface does not offer paints the surface alone + expect(targets('room')).toEqual(['scoped_1:end:1']) + // other roles of the kind keep the derived set + expect(availablePaintScopes({ node, slotRoles: [], role: 'side' })).toEqual(['single']) + }) +}) diff --git a/packages/editor/src/lib/paint-scope.ts b/packages/editor/src/lib/paint-scope.ts index 84130be31a..18ad7a9a83 100644 --- a/packages/editor/src/lib/paint-scope.ts +++ b/packages/editor/src/lib/paint-scope.ts @@ -55,6 +55,11 @@ function nodeOffersRoomScope(node: AnyNode): boolean { return nodeRegistry.get(node.type)?.capabilities?.paint?.roomScope === true } +/** The scopes the hovered surface declares for itself (`capabilities.paint.scopes`), if any. */ +function surfaceScopes(node: AnyNode, role: string) { + return nodeRegistry.get(node.type)?.capabilities?.paint?.scopes?.(node, role) ?? null +} + const isFloorPlate = (node: AnyNode): boolean => node.type === 'slab' && node.boundary === 'auto' const FOOTPRINT_FACE_LABELS: Record = { @@ -104,6 +109,8 @@ export function availablePaintScopes(args: { if (args.node.type === 'wall') return ['single', 'room'] const plate = args.role === undefined ? null : platePaintScopes(args.node, args.role) if (plate) return plate.scopes + const own = args.role === undefined ? null : surfaceScopes(args.node, args.role) + if (own) return own.scopes const scopes: PaintScope[] = ['single'] if (args.slotRoles.length > 1) scopes.push('object') if (nodeHasAsset(args.node)) scopes.push('matching') @@ -123,7 +130,7 @@ export function paintHoverInfo(node: AnyNode, role: string, slotRoles: string[]) scopes: availablePaintScopes({ node, slotRoles, role }), slotLabel: paintSurfaceLabel(node, role), nodeNoun: node.type, - labels: platePaintScopes(node, role)?.labels, + labels: platePaintScopes(node, role)?.labels ?? surfaceScopes(node, role)?.labels, } } @@ -168,12 +175,13 @@ export function paintSurfaceLabel(node: AnyNode, role: string): string { return slotDisplayLabel(node, role) } -/** Display label for the hovered slot — declared label wins, else derived from the id. */ +/** Display label for the hovered slot, with a capability override for contextual copy. */ export function slotDisplayLabel(node: AnyNode, role: string): string { const capabilities = nodeRegistry.get(node.type)?.capabilities + const roleLabel = capabilities?.paint?.roleLabel?.(node, role) + if (roleLabel) return roleLabel const declared = capabilities?.slots?.(node)?.find((slot) => slot.slotId === role) - if (declared) return declared.label - return capabilities?.paint?.roleLabel?.(node, role) ?? slotLabelFromId(role) + return declared?.label ?? slotLabelFromId(role) } // ── Fan-out resolution ────────────────────────────────────────────────────── @@ -506,6 +514,12 @@ export function resolvePaintScopeTargets(args: { .map((other) => ({ nodeId: other.id, role: stepRole })) return targets.length ? targets : [{ nodeId: node.id as AnyNodeId, role: stepRole }] } + // A surface with its own scope set paints the role it names for the scope. + const own = surfaceScopes(node, role) + if (own) { + const roleFor = own.roleFor?.(effectivePaintScope(scope, own.scopes)) ?? role + return [{ nodeId: node.id as AnyNodeId, role: roleFor }] + } if (scope === 'single') return single // Whole object: paint every slot of the clicked node. Generic across any diff --git a/packages/editor/src/lib/panel-rows.ts b/packages/editor/src/lib/panel-rows.ts index ef0faaf97e..ebbe0f867c 100644 --- a/packages/editor/src/lib/panel-rows.ts +++ b/packages/editor/src/lib/panel-rows.ts @@ -65,19 +65,28 @@ export const PANEL_MODEL_EXTENSION = 'pascal:editor/panel-model' /** * A control the multi-selection inspector renders for every selected node of * a kind at once (derived settings the raw parametrics can't express). `value` - * null means the selection is mixed: no option shows as active. + * null means the selection is mixed: no option shows as active. `segmented` + * suits a few short options, `select` a longer list; `readout` only shows a + * value the selection cannot edit here. */ export type MultiPanelControl = { id: string - kind: 'segmented' - /** The parametrics group title the control sits in. */ + /** + * The section the control sits in: a parametrics group title, or a section + * of its own, shown after the groups in the order controls name them. + */ section: string label: string - options: ReadonlyArray<{ value: string; label: string }> - value: string | null - /** Applies to every selected node in one undo step. */ - onChange: (value: string) => void -} +} & ( + | { + kind: 'segmented' | 'select' + options: ReadonlyArray<{ value: string; label: string }> + value: string | null + /** Applies to every selected node in one undo step. */ + onChange: (value: string) => void + } + | { kind: 'readout'; value: string; detail?: string } +) export type NodePanelModel = { rows: (context: { diff --git a/packages/editor/src/lib/room-construction.test.ts b/packages/editor/src/lib/room-construction.test.ts index d6817875d7..50f87075de 100644 --- a/packages/editor/src/lib/room-construction.test.ts +++ b/packages/editor/src/lib/room-construction.test.ts @@ -4,6 +4,7 @@ import { area, BuildingNode, CeilingNode, + ColumnNode, clearSceneHistory, createZone, DoorNode, @@ -25,7 +26,12 @@ import { deleteConfirmationContent } from '../components/editor/delete-confirmat import { constructionActions, wallsSwitch } from '../components/ui/panels/room-construction-rows' import useDeleteConfirmation from '../store/use-delete-confirmation' import useEditor from '../store/use-editor' -import { roomClearPolygon, roomConstructionState, roomFloorContents } from './room-construction' +import { + roomClearPolygon, + roomConstructionState, + roomFloorContents, + roomPorchFramingCounts, +} from './room-construction' import { addRoomConstruction, adoptExistingCeiling, @@ -177,6 +183,27 @@ describe('room construction state', () => { expect(constructionActions(room, 'floor')).toEqual({ add: false, remove: true }) }) + test('porch framing counts the room’s generated parts by marker, across node kinds', () => { + const zone = nodes()[zoneId as AnyNodeId] as ZoneNode + const parts = [ + ColumnNode.parse({ metadata: { porchOf: zoneId, porchPart: 'corner:0' } }), + ItemNode.parse({ + ...item('item_side_post', 'Post', LEVEL, [0, 0, 0]), + metadata: { porchOf: zoneId, porchPart: 'side:0:1' }, + }), + ColumnNode.parse({ metadata: { porchOf: zoneId, porchPart: 'beam:0' } }), + ColumnNode.parse({ metadata: { porchOf: 'zone_other', porchPart: 'corner:0' } }), + ColumnNode.parse({}), + ] + const level = nodes()[LEVEL as AnyNodeId] as LevelNode + const scene = { + ...nodes(), + ...Object.fromEntries(parts.map((part) => [part.id, part])), + [level.id]: { ...level, children: [...level.children, ...parts.map((part) => part.id)] }, + } + expect(roomPorchFramingCounts(scene, zone)).toEqual({ posts: 2, beams: 1 }) + }) + test('memoized per nodes identity', () => { expect(roomConstructionState(nodes(), zoneId)).toBe(roomConstructionState(nodes(), zoneId)) expect(roomConstructionState(nodes(), 'zone_missing')).toBeNull() diff --git a/packages/editor/src/lib/room-construction.ts b/packages/editor/src/lib/room-construction.ts index 7f1118addf..f06690461f 100644 --- a/packages/editor/src/lib/room-construction.ts +++ b/packages/editor/src/lib/room-construction.ts @@ -383,3 +383,17 @@ export function roomConstructionState( memo.states.set(zoneId, state) return state } + +export function roomPorchFramingCounts(nodes: StructureNodes, zone: ZoneNode) { + const level = zone.parentId ? nodes[zone.parentId] : undefined + let posts = 0 + let beams = 0 + for (const id of level?.type === 'level' ? level.children : []) { + const metadata = nodes[id]?.metadata + const part = metadata?.porchPart + if (metadata?.porchOf !== zone.id || typeof part !== 'string') continue + if (/^(corner|side):/.test(part)) posts++ + else if (part.startsWith('beam:')) beams++ + } + return { posts, beams } +} diff --git a/packages/editor/src/lib/room-controls-phase6.test.ts b/packages/editor/src/lib/room-controls-phase6.test.ts index e01b2821a0..c3858dd513 100644 --- a/packages/editor/src/lib/room-controls-phase6.test.ts +++ b/packages/editor/src/lib/room-controls-phase6.test.ts @@ -17,6 +17,7 @@ import { import { useViewer } from '@pascal-app/viewer' import { createElement } from 'react' import { roomTransformSource } from '../components/editor/room-controls' +import { commitDimensionValue } from '../components/editor-2d/renderers/floorplan-dimension-edit-overlay' import { getRoomSelectionIndex } from '../hooks/use-selected-room' import useEditor from '../store/use-editor' import useInteractionScope from '../store/use-interaction-scope' @@ -24,6 +25,7 @@ import { installImmediateAnimationFrames } from '../test-utils/immediate-animati import { withSelectionHarness } from '../test-utils/selection-harness' import { useGestureLifecycleOwner } from './gesture-lifecycle' import { + beginWallGroupPush, cancelRoomHandleDrag, commitRoomElevation, commitRoomPush, @@ -34,7 +36,10 @@ import { roomFloorElevation, roomPushHandles, runRoomHandleDrag, + selectedWallDimensions, + useRoomHandleDrag, } from './room-handle-drag' +import { mergeSelectionDimensions } from './room-push-dimensions' import { applyRoomPlan, renameRoom } from './room-structure-commands' import { cancelRoomTransform, @@ -376,6 +381,45 @@ describe('room handles (elevation, push/pull)', () => { expect(useScene.temporal.getState().pastStates).toHaveLength(1) }) + test('a selected wall shows its room width and outside size, and typing either moves the wall', () => { + const east = () => + Object.values(useScene.getState().nodes).find( + (n): n is WallNode => n.type === 'wall' && n.start[0] === n.end[0] && n.start[0] > 3, + )! + const wall = east() + const thickness = wall.thickness ?? 0.1 + const dimensions = selectedWallDimensions(useScene.getState().nodes, wall, 'both') + const interior = dimensions.find((d) => d.faces === 'interior')! + const exterior = dimensions.find((d) => d.faces === 'exterior')! + // The 6 m room between centrelines: face to face inside, outer face to outer face outside. + expect(interior.distance).toBeCloseTo(6 - thickness) + expect(exterior.distance).toBeCloseTo(6 + thickness) + expect(selectedWallDimensions(useScene.getState().nodes, wall, 'interior')).toEqual([interior]) + expect(selectedWallDimensions(useScene.getState().nodes, wall, 'exterior')).toEqual([exterior]) + + // Type 10' ID: the wall moves out until the room is exactly that wide, one undo step. + const target = (d: typeof interior) => ({ + ownerNodeId: wall.id as AnyNodeId, + witnessStart: d.from, + witnessEnd: d.to, + value: d.distance, + }) + expect(commitDimensionValue({ target: target(interior), nextLength: 3.048 })).toEqual({ + ok: true, + }) + // The west face sits half a thickness inside x = 0; the east centreline half outside its face. + expect(east().start[0]).toBeCloseTo(3.048 + thickness) + expect(useScene.temporal.getState().pastStates).toHaveLength(1) + const after = selectedWallDimensions(useScene.getState().nodes, east(), 'both') + expect(after.find((d) => d.faces === 'interior')!.distance).toBeCloseTo(3.048) + + // Type the outside size: the same wall moves so the building reads it. + const outside = after.find((d) => d.faces === 'exterior')! + expect(commitDimensionValue({ target: target(outside), nextLength: 5 })).toEqual({ ok: true }) + expect(east().start[0]).toBeCloseTo(5 - thickness) + expect(useScene.temporal.getState().pastStates).toHaveLength(2) + }) + test('a partial span splits off and moves only the room-facing piece, openings stay put', () => { // A 10 m north wall, of which this 6 m room faces only 0..0.6; a door // on the far stretch must stay where it is. @@ -452,6 +496,102 @@ describe('room handles (elevation, push/pull)', () => { expect(host.start[1]).toBeCloseTo(4) expect(useScene.temporal.getState().pastStates).toHaveLength(1) }) + + const roomWalls = () => { + const walls = Object.values(useScene.getState().nodes).filter( + (n): n is WallNode => n.type === 'wall', + ) + const at = (axis: 0 | 1, value: number) => + walls.find( + (w) => Math.abs(w.start[axis] - value) < 1e-6 && Math.abs(w.end[axis] - value) < 1e-6, + )! + return { east: at(0, 6), west: at(0, 0), north: at(1, 4), south: at(1, 0) } + } + + test('two selected walls move as their push arrows: parallel, still joined, one undo step', () => { + const { east, north, west, south } = roomWalls() + const push = beginWallGroupPush([east.id, north.id], LEVEL) + const nodes = useScene.getState().nodes + // A diagonal drag: each wall takes only the part along its own normal. + push.preview([1, 0.5]) + expect(useLiveNodeOverrides.getState().overrides.get(east.id as AnyNodeId)).toBeDefined() + expect(useScene.getState().nodes).toBe(nodes) + expect(push.commit()).toBe(true) + const after = useScene.getState().nodes + const wall = (id: string) => after[id as AnyNodeId] as WallNode + for (const point of [wall(east.id).start, wall(east.id).end]) expect(point[0]).toBeCloseTo(7) + for (const point of [wall(north.id).start, wall(north.id).end]) + expect(point[1]).toBeCloseTo(4.5) + const corner = (a: WallNode, b: WallNode) => + [a.start, a.end].some((p) => + [b.start, b.end].some((q) => Math.hypot(p[0] - q[0], p[1] - q[1]) < 1e-6), + ) + // Their own corner, and the walls they meet, stay joined; the others keep their line. + expect(corner(wall(east.id), wall(north.id))).toBe(true) + expect(corner(wall(east.id), wall(south.id))).toBe(true) + expect(corner(wall(north.id), wall(west.id))).toBe(true) + for (const point of [wall(west.id).start, wall(west.id).end]) expect(point[0]).toBeCloseTo(0) + for (const point of [wall(south.id).start, wall(south.id).end]) expect(point[1]).toBeCloseTo(0) + expect(useScene.temporal.getState().pastStates).toHaveLength(1) + }) + + test("several selected walls show each one's dimensions, a room between two of them once", () => { + const { east, west, north } = roomWalls() + const thickness = east.thickness ?? 0.1 + const nodes = useScene.getState().nodes + const dimensions = mergeSelectionDimensions( + [east, west, north].map((wall) => ({ + ownerId: wall.id, + dimensions: selectedWallDimensions(nodes, wall, 'both'), + })), + ) + const shown = (faces: 'interior' | 'exterior') => + dimensions + .filter((d) => d.faces === faces) + .map((d) => [d.ownerId, Number(d.distance.toFixed(4))]) + // East and west both measure the 6 m room and the building across it: once each, on east. + expect(shown('interior')).toEqual([ + [east.id, Number((6 - thickness).toFixed(4))], + [north.id, Number((4 - thickness).toFixed(4))], + ]) + expect(shown('exterior')).toEqual([ + [east.id, Number((6 + thickness).toFixed(4))], + [north.id, Number((4 + thickness).toFixed(4))], + ]) + expect(new Set(dimensions.map((d) => d.key)).size).toBe(dimensions.length) + + // Typing one moves the wall it runs from. + const depth = dimensions.find((d) => d.ownerId === north.id && d.faces === 'interior')! + expect( + commitDimensionValue({ + target: { + ownerNodeId: north.id as AnyNodeId, + witnessStart: depth.from, + witnessEnd: depth.to, + value: depth.distance, + }, + nextLength: 5, + }), + ).toEqual({ ok: true }) + const moved = useScene.getState().nodes[north.id as AnyNodeId] as WallNode + expect(moved.start[1]).toBeCloseTo(5 + thickness) + }) + + test('a multi-wall move shows the room widths live, as a single wall push does', () => { + const { east, north, west } = roomWalls() + const thickness = east.thickness ?? 0.1 + const push = beginWallGroupPush([east.id, west.id, north.id], LEVEL) + push.preview([1, 0.5]) + const drag = useRoomHandleDrag.getState().drag + expect(drag?.kind).toBe('wall-group-push') + const widths = (drag?.kind === 'wall-group-push' ? drag.dimensions : []).map((d) => d.distance) + // East and west both moved 1 m: the 6 m room is still 6 m wide, shown once; north went 0.5 m out. + expect(widths.filter((w) => Math.abs(w - (6 - thickness)) < 1e-6)).toHaveLength(1) + expect(widths.some((w) => Math.abs(w - (4.5 - thickness)) < 1e-6)).toBe(true) + push.cancel() + expect(useRoomHandleDrag.getState().drag).toBeNull() + expect(useLiveNodeOverrides.getState().overrides.size).toBe(0) + }) }) describe('room gesture ownership', () => { diff --git a/packages/editor/src/lib/room-handle-drag.ts b/packages/editor/src/lib/room-handle-drag.ts index fc6ad96dd0..b5a3cc03b5 100644 --- a/packages/editor/src/lib/room-handle-drag.ts +++ b/packages/editor/src/lib/room-handle-drag.ts @@ -17,12 +17,16 @@ import { planWallDivision, resolveMovedWallSupportSlabPatch, runAsSingleSceneHistoryStep, + SEPARATOR_JOIN_REACH, + type SeparatorNode, + type SeparatorSpan, type StructureNodes, type StructurePlan, setRoomFloorConstruction, setWallGeometry, setZoneEdges, setZoneIntent, + translateSeparators, upperFloorHeightControl, useLiveNodeOverrides, useScene, @@ -46,19 +50,34 @@ import { roomOwnPlate } from './room-built-on' import { mezzanineEdgeDimensions, type RoomDimension, + sameRoomDimension, + separatorEdgeDimensionRooms, + type WallDimensionFaces, + type WallSelectionDimension, wallPushDimensionRooms, wallPushDimensions, + wallSelectionDimensions, } from './room-push-dimensions' import { applyRoomPlan } from './room-structure-commands' +import { levelSeparatorLines, separatorWallLine } from './separator-lines' import { sfxEmitter } from './sfx-bus' import { type SpatialPointerId, spatialPointerInput } from './spatial-pointer-input' import { isTypingTarget } from './typing-target' +import { + nearestWallParallelTarget, + publishWallParallelGuide, + type WallParallelTarget, + wallParallelTargets, +} from './wall-parallel-snap' +import { isWallRunFree } from './wall-run-snap' export const ROOM_ELEVATION_DRAG_LABEL = 'room-elevation' /** Scope label of every wall push: a selected wall's side arrow and a room's boundary arrow. */ export const WALL_PUSH_DRAG_LABEL = 'wall-push' /** Scope label of a mezzanine edge push (its plate grows or shrinks). */ export const MEZZANINE_EDGE_DRAG_LABEL = 'mezzanine-edge' +/** What a wall push the planner refuses reads. */ +export const PUSH_REFUSED_MESSAGE = "Can't move this wall there" /** A wall a push would create (a moved span piece, a bridge), drawn as a ghost. */ export type RoomPushGhost = { start: Point; end: Point; thickness: number; height: number } @@ -93,6 +112,20 @@ export type RoomHandleDrag = dimensions: RoomDimension[] message?: string } + | { + /** Several selected walls moved together, each along its own normal. */ + kind: 'wall-group-push' + levelId: string + /** Where a refusal reads: over the moved walls' middle, in level plan coordinates. */ + anchor: Point + height: number + /** The lowest moved wall's base, where the ghost pieces stand. */ + base: number + ghosts: RoomPushGhost[] + /** Every moved wall's live room widths, as its own push shows them. */ + dimensions: RoomDimension[] + message?: string + } | { kind: 'mezzanine-edge' zoneId: string @@ -129,9 +162,16 @@ export function roomFloorElevation(nodes: Nodes, zoneId: string): number { /** * The stretch of a wall a push moves: `[0, 1]` is the whole wall (its * neighbours follow through the junction planner), anything shorter is split - * off first and only that piece moves. + * off first and only that piece moves. An edge of invisible walls carries its + * stretches in `separators` (`wallId` is the first one's): they move as one + * line, the invisible walls joined to them following (`translateSeparators`). */ -export type WallPushSpan = { wallId: string; t0: number; t1: number } +export type WallPushSpan = { + wallId: string + t0: number + t1: number + separators?: readonly SeparatorSpan[] +} /** One push/pull arrow: a selected wall's side arrow or a room's boundary arrow. */ export type WallPushHandle = WallPushSpan & { @@ -191,22 +231,27 @@ export function wallPushHandles(wall: WallNode, nodes: Nodes): WallPushHandle[] }) } +type BoundarySpanRef = { + boundaryId: string + kind: string + face: 'a' | 'b' + t0: number + t1: number +} + /** * One push/pull arrow per boundary wall span of the room, outside the wall's * far face, pointing away from the room — where the wall's own side arrow for - * that face sits. `face` is the wall face the room lies on (`a` = front). + * that face sits. `face` is the wall face the room lies on (`a` = front). Its + * invisible walls get one arrow per straight edge (`separatorEdges`), lying + * at `floor` (the room's floor height), where their dashed line is drawn. */ export function roomPushHandles( nodes: Nodes, - spans: ReadonlyArray<{ - boundaryId: string - kind: string - face: 'a' | 'b' - t0: number - t1: number - }>, + spans: ReadonlyArray, + floor = 0, ): WallPushHandle[] { - return spans.flatMap((span) => { + const walls = spans.flatMap((span) => { const wall = nodes[span.boundaryId] if (span.kind !== 'wall' || wall?.type !== 'wall') return [] const handle = wallPushHandle( @@ -218,6 +263,145 @@ export function roomPushHandles( ) return handle ? [handle] : [] }) + const edges = separatorEdges(nodes, spans).map((edge) => { + const first = edge.members[0]! + return separatorPushHandle( + edge, + edge.outward, + floor, + `${first.separatorId}:${edge.face}:${first.t0.toFixed(4)}`, + ) + }) + return [...walls, ...edges] +} + +/** How far outside an invisible wall (m) its push arrow sits, as a mezzanine edge's does. */ +const SEPARATOR_ARROW_OFFSET = 0.3 +/** Its 3D arrow's lift over the floor: where the invisible wall's dashed line is drawn. */ +const SEPARATOR_ARROW_LIFT = 0.02 +/** An invisible-wall edge shorter than this (m) gets no arrow, as a mezzanine edge. */ +const SEPARATOR_EDGE_MIN_LENGTH = 0.2 +/** Stretches this far off each other's line (m) still run along one edge. */ +const EDGE_IN_LINE = 0.01 + +type SeparatorEdge = { + /** The stretches along the edge, in order. */ + members: SeparatorSpan[] + start: Point + end: Point + /** Away from the room. */ + outward: Point + face: 'a' | 'b' +} + +/** + * A room's invisible-wall stretches gathered into its straight edges: stretches + * end to end on one line, the room on the same side, are one edge and push as + * one (an edge drawn in two pieces, or broken where another one meets it). Ends + * meet as far as the room graph joins them (`SEPARATOR_JOIN_REACH`). + */ +function separatorEdges(nodes: Nodes, spans: ReadonlyArray): SeparatorEdge[] { + const pieces = spans.flatMap((span): SeparatorEdge[] => { + const separator = nodes[span.boundaryId] + if (span.kind !== 'separator' || separator?.type !== 'separator') return [] + const dx = separator.end[0] - separator.start[0] + const dz = separator.end[1] - separator.start[1] + const length = Math.hypot(dx, dz) + if (length < 1e-6 || span.t1 - span.t0 < WHOLE) return [] + // Face `a` is the +normal side: the arrow points the other way, off the room. + const sign = span.face === 'a' ? -1 : 1 + const at = (t: number): Point => [separator.start[0] + dx * t, separator.start[1] + dz * t] + return [ + { + members: [{ separatorId: separator.id, t0: span.t0, t1: span.t1 }], + start: at(span.t0), + end: at(span.t1), + outward: [(-dz / length) * sign, (dx / length) * sign], + face: span.face, + }, + ] + }) + const across = (edge: SeparatorEdge, [x, z]: Point) => + Math.abs((x - edge.start[0]) * edge.outward[0] + (z - edge.start[1]) * edge.outward[1]) + const joins = (a: SeparatorEdge, b: SeparatorEdge) => + a.outward[0] * b.outward[0] + a.outward[1] * b.outward[1] > 1 - 1e-4 && + across(a, b.start) < EDGE_IN_LINE && + across(a, b.end) < EDGE_IN_LINE && + [a.start, a.end].some((p) => + [b.start, b.end].some((q) => Math.hypot(p[0] - q[0], p[1] - q[1]) <= SEPARATOR_JOIN_REACH), + ) + let groups: SeparatorEdge[][] = [] + for (const piece of pieces) { + const touching = groups.filter((group) => group.some((other) => joins(piece, other))) + groups = [...groups.filter((group) => !touching.includes(group)), [piece, ...touching.flat()]] + } + return groups.flatMap((group): SeparatorEdge[] => { + const { outward, face } = group[0]! + const dir: Point = [outward[1], -outward[0]] + const along = ([x, z]: Point) => x * dir[0] + z * dir[1] + const ends = group + .flatMap((piece) => [piece.start, piece.end]) + .sort((p, q) => along(p) - along(q)) + const start = ends[0]! + const end = ends.at(-1)! + if (Math.hypot(end[0] - start[0], end[1] - start[1]) < SEPARATOR_EDGE_MIN_LENGTH) return [] + const middle = (piece: SeparatorEdge) => along(piece.start) + along(piece.end) + const members = [...group].sort((p, q) => middle(p) - middle(q)).flatMap((p) => p.members) + return [{ members, start, end, outward, face }] + }) +} + +function separatorPushHandle( + edge: Pick, + outward: Point, + floor: number, + key: string, +): WallPushHandle { + const first = edge.members[0]! + const middle: Point = [(edge.start[0] + edge.end[0]) / 2, (edge.start[1] + edge.end[1]) / 2] + return { + key, + wallId: first.separatorId, + t0: first.t0, + t1: first.t1, + separators: edge.members, + position: [ + middle[0] + outward[0] * SEPARATOR_ARROW_OFFSET, + middle[1] + outward[1] * SEPARATOR_ARROW_OFFSET, + ], + height: floor + SEPARATOR_ARROW_LIFT, + outward, + line: middle[0] * outward[0] + middle[1] * outward[1], + } +} + +/** + * A selected invisible wall's two side arrows, one off each side, at `floor`: + * each pushes the whole separator, the ones joined to it following. + */ +export function separatorPushHandles(separator: SeparatorNode, floor = 0): WallPushHandle[] { + const dx = separator.end[0] - separator.start[0] + const dz = separator.end[1] - separator.start[1] + const length = Math.hypot(dx, dz) + if (length < 1e-6) return [] + const edge = { + members: [{ separatorId: separator.id, t0: 0, t1: 1 }], + start: separator.start, + end: separator.end, + } + return (['a', 'b'] as const).map((side) => { + const sign = side === 'a' ? 1 : -1 + const outward: Point = [(-dz / length) * sign, (dx / length) * sign] + return separatorPushHandle(edge, outward, floor, `${separator.id}:${side}`) + }) +} + +/** The floor an invisible wall lies on: the walking surface of a room it closes, else 0. */ +export function separatorFloorElevation(nodes: Nodes, separatorId: string): number { + const zone = Object.values(nodes).find( + (node) => node.type === 'zone' && node.boundarySeparatorIds.includes(separatorId), + ) + return zone ? roomFloorElevation(nodes, zone.id) : 0 } /** @@ -294,7 +478,8 @@ function diffNodes(before: Scratch, after: Scratch): NodeChange[] { * Pushes the room's stretch of a wall `distance` along `outward`. A span that * covers the whole wall moves the wall; a partial span is split off at its * ends first (hosted openings stay on their pieces) and only that piece moves, - * bridged back to the rest by the junction planner. One plan, one undo step. + * bridged back to the rest by the junction planner. An edge of invisible walls + * moves as one line (`translateSeparators`). One plan, one undo step. */ export function planRoomPush( nodes: StructureNodes, @@ -303,6 +488,12 @@ export function planRoomPush( distance: number, mintId: (kind: 'zone' | 'wall' | 'separator') => string = generateId, ): StructurePlan { + if (span.separators?.length) + return translateSeparators(nodes, { + spans: span.separators, + offset: [outward[0] * distance, outward[1] * distance], + mintId, + }) const wall = nodes[span.wallId] if (wall?.type !== 'wall') throw Error('Select a wall.') const shift = ([x, z]: Point): Point => [x + outward[0] * distance, z + outward[1] * distance] @@ -388,14 +579,18 @@ function clearPushPreview() { function previewSurfaces(nodes: Nodes, levelId: string, after: Scratch) { if (surfacePreview?.levelId !== levelId || surfacePreview.nodes !== nodes) surfacePreview = { levelId, nodes, run: createLevelStructurePreview(levelId, nodes) } - const walls = Object.values(after).filter( - (node): node is WallNode => node.type === 'wall' && node.parentId === levelId, - ) + const level = Object.values(after).filter((node) => node.parentId === levelId) return surfacePreview - .run(walls) + .run( + level.filter((node): node is WallNode => node.type === 'wall'), + level.filter((node): node is SeparatorNode => node.type === 'separator'), + ) .map((patch) => [patch.id as AnyNodeId, patch.data as Partial] as const) } +/** The ghost of an invisible wall a push would create (a jog): a thin strip on the floor. */ +const SEPARATOR_GHOST = { thickness: 0.03, height: 0.04 } + /** * Shows the push live: the plan's updates to existing walls — and the room * surfaces reshaped around them — ride `useLiveNodeOverrides` (renderers merge @@ -410,9 +605,20 @@ export function previewRoomPush( clearPushPreview() if (Math.abs(distance) < 1e-6) return { ghosts: [] } const nodes = useScene.getState().nodes + return previewPushPlan(nodes, nodes[span.wallId as AnyNodeId]?.parentId, () => + planRoomPush(nodes, span, outward, distance, previewMint()), + ) +} + +/** Shows a push plan live (`previewRoomPush`); the caller has cleared the last one. */ +function previewPushPlan( + nodes: Nodes, + levelId: string | null | undefined, + planPush: () => StructurePlan, +): { code?: string; ghosts: RoomPushGhost[] } { let plan: StructurePlan try { - plan = planRoomPush(nodes, span, outward, distance, previewMint()) + plan = planPush() } catch { return { code: 'invalid-geometry', ghosts: [] } } @@ -420,15 +626,17 @@ export function previewRoomPush( const updates: Array]> = plan.changes.flatMap((change) => change.op === 'update' ? [[change.id as AnyNodeId, change.data] as const] : [], ) - const levelId = nodes[span.wallId as AnyNodeId]?.parentId if (levelId) updates.push(...previewSurfaces(nodes, levelId, applyChanges(nodes, plan.changes))) useLiveNodeOverrides .getState() .setMany(updates.map(([id, data]) => [id, data] as [AnyNodeId, Partial])) previewIds = updates.map(([id]) => id) for (const id of previewIds) useScene.getState().markDirty(id as AnyNodeId) - const ghosts = plan.changes.flatMap((change): RoomPushGhost[] => - change.op === 'create' && change.node.type === 'wall' + const ghosts = plan.changes.flatMap((change): RoomPushGhost[] => { + if (change.op !== 'create') return [] + if (change.node.type === 'separator') + return [{ start: change.node.start, end: change.node.end, ...SEPARATOR_GHOST }] + return change.node.type === 'wall' ? [ { start: change.node.start, @@ -437,8 +645,8 @@ export function previewRoomPush( height: getWallEffectiveHeightForNodes(change.node, nodes), }, ] - : [], - ) + : [] + }) // The floor plan draws the same pieces through its bridge-ghost layer. if (ghosts.length) { useWallMoveGhosts.getState().setBridges( @@ -468,9 +676,13 @@ export function endRoomPushPreview() { export function commitRoomPush(span: WallPushSpan, outward: Point, distance: number) { endRoomPushPreview() if (Math.abs(distance) < 1e-6) return true + return commitPushPlan((nodes) => planRoomPush(nodes, span, outward, distance)) +} + +function commitPushPlan(planPush: (nodes: StructureNodes) => StructurePlan) { try { return runAsSingleSceneHistoryStep(useScene, () => { - const plan = planRoomPush(useScene.getState().nodes, span, outward, distance) + const plan = planPush(useScene.getState().nodes) if (!applyRoomPlan(plan)) return false const nodes = useScene.getState().nodes const patches = plan.changes.flatMap((change) => { @@ -716,12 +928,13 @@ export function cancelRoomHandleDrag() { /** * Runs one handle drag on window listeners, independent of the handle's own * mount (handles hide while any scope is active). `sample` maps a pointer to - * the drag's value (`spatial.sample` a controller ray, for a spatial pointer); - * release commits, Escape / ⌘Z / the gesture owner cancel. Cleanup runs + * the drag's value (`spatial.sample` a controller ray, for a spatial pointer): + * a distance or a height, or a plan point for an end dragged across the floor. + * Release commits, Escape / ⌘Z / the gesture owner cancel. Cleanup runs * exactly once whatever happens, and releases only this drag's own scope; * nothing republishes a preview after it. */ -export function runRoomHandleDrag({ +export function runRoomHandleDrag({ label, nodeId, zoneId, @@ -738,9 +951,9 @@ export function runRoomHandleDrag({ zoneId?: string levelId: string requires: string[] - sample: (clientX: number, clientY: number) => number | null - spatial?: { pointerId: SpatialPointerId; sample: (ray: Ray) => number | null } - onValue: (value: number) => void + sample: (clientX: number, clientY: number) => T | null + spatial?: { pointerId: SpatialPointerId; sample: (ray: Ray) => T | null } + onValue: (value: T) => void onCommit: () => void onCancel: () => void }) { @@ -891,10 +1104,20 @@ export function runWallPushDrag({ spatial?: { pointerId: SpatialPointerId; along: (ray: Ray) => number | null } }) { const nodes = useScene.getState().nodes - const wall = nodes[handle.wallId as AnyNodeId] - if (wall?.type !== 'wall') return null - const base = getWallBaseElevationForNodes(wall, nodes) + const boundary = nodes[handle.wallId as AnyNodeId] + // An edge of invisible walls is measured, and lines up, as the one line it moves as. + const edge = handle.separators?.length ? separatorEdgeLine(nodes, handle.separators) : null + const wall = edge ?? (boundary?.type === 'wall' ? boundary : null) + if (!wall) return null + const base = + wall.type === 'wall' + ? getWallBaseElevationForNodes(wall, nodes) + : handle.height - SEPARATOR_ARROW_LIFT const rooms = pushDimensionRooms(nodes, levelId, handle, base) + const levelWalls = Object.values(nodes).filter( + (node): node is WallNode => node.type === 'wall' && node.parentId === levelId, + ) + const moving = new Set([handle.wallId, ...(handle.separators ?? []).map((s) => s.separatorId)]) let distance = 0 let blocked = false let ghosts: RoomPushGhost[] = [] @@ -921,15 +1144,49 @@ export function runWallPushDrag({ message, }, }) - const toDistance = (at: number | null) => - at === null ? null : snapPushDistance(handle.line, at - from) + // The pushed wall lines up with the parallel walls on its level + // (`wall-parallel-snap`) before the grid; Alt pushes it free. Invisible walls + // line up with the walls and with the level's other invisible walls. + const lineUpTargets = + wall.type === 'wall' + ? wallParallelTargets(wall, handle.outward, levelWalls) + : wallParallelTargets(separatorWallLine(wall), handle.outward, [ + ...levelWalls, + ...levelSeparatorLines(nodes, levelId, moving), + ]) + let lineUp: WallParallelTarget | null = null + let altHeld = false + const trackAlt = (event: KeyboardEvent | PointerEvent) => { + altHeld = event.altKey + } + window.addEventListener('pointermove', trackAlt, true) + window.addEventListener('keydown', trackAlt, true) + window.addEventListener('keyup', trackAlt, true) + const stopLineUp = () => { + window.removeEventListener('pointermove', trackAlt, true) + window.removeEventListener('keydown', trackAlt, true) + window.removeEventListener('keyup', trackAlt, true) + if (lineUp) publishWallParallelGuide(null) + lineUp = null + } + const toDistance = (at: number | null) => { + if (at === null) return null + const raw = at - from + const next = isWallRunFree({ altKey: altHeld }) + ? null + : nearestWallParallelTarget(lineUpTargets, handle.line + raw) + if (next !== lineUp) publishWallParallelGuide(next) + lineUp = next + if (next) return next.position - handle.line + return isWallRunFree({ altKey: altHeld }) ? raw : snapPushDistance(handle.line, raw) + } publish() return runRoomHandleDrag({ label: WALL_PUSH_DRAG_LABEL, nodeId: handle.wallId, zoneId, levelId, - requires: zoneId ? [zoneId, handle.wallId] : [handle.wallId], + requires: zoneId ? [zoneId, ...moving] : [...moving], sample: (x, y) => toDistance(along(x, y)), spatial: spatial && { pointerId: spatial.pointerId, @@ -942,13 +1199,17 @@ export function runWallPushDrag({ const preview = previewRoomPush(handle, handle.outward, distance) ghosts = preview.ghosts blocked = !!preview.code - publish(preview.code ? "Can't move this wall there" : undefined) + publish(preview.code ? PUSH_REFUSED_MESSAGE : undefined) }, onCommit: () => { + stopLineUp() if (blocked) endRoomPushPreview() else commitRoomPush(handle, handle.outward, distance) }, - onCancel: () => endRoomPushPreview(), + onCancel: () => { + stopLineUp() + endRoomPushPreview() + }, }) } @@ -960,12 +1221,260 @@ function pushDimensionRooms(nodes: Nodes, levelId: string, span: WallPushSpan, b const index = getRoomSelectionIndex(levelId) const records = index.update(nodes) const topology = index.topology.getLevelTopology(levelId) - return wallPushDimensionRooms(topology?.rooms ?? [], span, (roomId) => { + const elevationOf = (roomId: string) => { const zoneId = records.find((record) => record.id === roomId)?.zoneId return zoneId ? roomFloorElevation(nodes, zoneId) : base + } + const edge = span.separators?.length ? separatorEdgeLine(nodes, span.separators) : null + return edge && span.separators + ? separatorEdgeDimensionRooms( + topology?.rooms ?? [], + { line: edge, separators: span.separators }, + (id) => nodes[id], + elevationOf, + ) + : wallPushDimensionRooms(topology?.rooms ?? [], span, elevationOf) +} + +/** + * The one line an edge of invisible walls pushes as: its first separator, + * running from the edge's first end to its last. + */ +function separatorEdgeLine(nodes: Nodes, spans: readonly SeparatorSpan[]): SeparatorNode | null { + const first = nodes[spans[0]?.separatorId as AnyNodeId] + if (first?.type !== 'separator') return null + const dx = first.end[0] - first.start[0] + const dz = first.end[1] - first.start[1] + const length = Math.hypot(dx, dz) + if (length < 1e-6) return null + const along = ([x, z]: Point) => + ((x - first.start[0]) * dx + (z - first.start[1]) * dz) / (length * length) + let lo = Number.POSITIVE_INFINITY + let hi = Number.NEGATIVE_INFINITY + for (const span of spans) { + const separator = nodes[span.separatorId as AnyNodeId] + if (separator?.type !== 'separator') return null + for (const t of [span.t0, span.t1]) { + const u = along([ + separator.start[0] + (separator.end[0] - separator.start[0]) * t, + separator.start[1] + (separator.end[1] - separator.start[1]) * t, + ]) + lo = Math.min(lo, u) + hi = Math.max(hi, u) + } + } + const at = (u: number): Point => [first.start[0] + dx * u, first.start[1] + dz * u] + return { ...first, start: at(lo), end: at(hi) } +} + +/** + * A selected wall's temporary dimensions as the scene stands: the room widths + * its push shows, before any push, plus the outside size for an exterior wall. + */ +export function selectedWallDimensions( + nodes: Nodes, + wall: WallNode, + faces: WallDimensionFaces, +): WallSelectionDimension[] { + const levelId = wall.parentId + if (!levelId) return [] + const base = getWallBaseElevationForNodes(wall, nodes) + const walls = Object.values(nodes).filter( + (node): node is WallNode => node.type === 'wall' && node.parentId === levelId, + ) + return wallSelectionDimensions({ + rooms: pushDimensionRooms(nodes, levelId, { wallId: wall.id, t0: 0, t1: 1 }, base), + wall, + walls, + faces, + resolve: (id) => nodes[id], + baseElevation: base, }) } +/** An end this close to another moved wall is joined to it. */ +const GROUP_JOIN_REACH = 1e-3 +/** Walls whose directions cross by less than this (sine) run in line, never meet at a corner. */ +const GROUP_PARALLEL_SIN = 1e-4 + +/** The way a wall's push arrows point: its `a`-side normal at its middle. */ +function wallPushNormal(wall: WallNode): Point { + const frame = getWallCurveFrameAt(wall, 0.5) + return [frame.normal.x, frame.normal.y] +} + +function wallDirection(wall: WallNode): Point { + const dx = wall.end[0] - wall.start[0] + const dz = wall.end[1] - wall.start[1] + const length = Math.hypot(dx, dz) || 1 + return [dx / length, dz / length] +} + +/** Whether `point` is on `wall`: one of its ends, or along a straight one. */ +function wallHoldsPoint(wall: WallNode, [x, z]: Point): boolean { + const near = ([px, pz]: Point) => Math.hypot(px - x, pz - z) <= GROUP_JOIN_REACH + if (near(wall.start) || near(wall.end)) return true + if ((wall.curveOffset ?? 0) !== 0) return false + const [ux, uz] = wallDirection(wall) + const along = (x - wall.start[0]) * ux + (z - wall.start[1]) * uz + const length = Math.hypot(wall.end[0] - wall.start[0], wall.end[1] - wall.start[1]) + return ( + along > 0 && + along < length && + Math.abs((z - wall.start[1]) * ux - (x - wall.start[0]) * uz) <= GROUP_JOIN_REACH + ) +} + +/** + * Moves several walls at once, each as its own push arrow would: along its + * normal by `drag` projected on it, so it stays parallel to where it was, the + * walls joined to it following through the junction planner. An end on + * another moved wall that is not in line with it (a corner or a T between + * them) sits on both moved lines, which is where it lands moved by the whole + * drag, so they stay joined. Each wall is planned in turn while the others + * already stand at their targets, so no moved wall is pulled along as + * another's neighbour. One plan, one undo step. + */ +export function planWallGroupPush( + nodes: StructureNodes, + wallIds: readonly string[], + drag: Point, + mintId: (kind: 'zone' | 'wall' | 'separator') => string = generateId, +): StructurePlan { + const walls = wallIds.flatMap((id) => { + const node = nodes[id] + return node?.type === 'wall' ? [node] : [] + }) + const crosses = (a: WallNode, b: WallNode) => { + const [ux, uz] = wallDirection(a) + const [vx, vz] = wallDirection(b) + return Math.abs(ux * vz - uz * vx) > GROUP_PARALLEL_SIN + } + let scratch: Scratch = { ...nodes } + for (const wall of walls) { + const [nx, nz] = wallPushNormal(wall) + const distance = drag[0] * nx + drag[1] * nz + const move = (point: Point): Point => + walls.some((other) => other !== wall && crosses(wall, other) && wallHoldsPoint(other, point)) + ? [point[0] + drag[0], point[1] + drag[1]] + : [point[0] + nx * distance, point[1] + nz * distance] + scratch[wall.id] = { ...wall, start: move(wall.start), end: move(wall.end) } + } + for (const wall of walls) { + const target = scratch[wall.id] + if (target?.type !== 'wall') continue + scratch[wall.id] = { ...target, start: wall.start, end: wall.end } + const moved = setWallGeometry(scratch, { + wallId: wall.id, + start: target.start, + end: target.end, + mintId, + }) + if (moved.conflicts?.length) return moved + scratch = applyChanges(scratch, moved.changes) + } + return { changes: diffNodes(nodes, scratch) } +} + +/** A multi-wall push in flight (`beginWallGroupPush`). */ +export type WallGroupPush = { + /** Previews the walls moved by the level-plan drag. */ + preview: (drag: Point) => void + /** Writes the last preview as one undo step; false when nothing was written. */ + commit: () => boolean + /** Drops the preview; the scene is untouched. */ + cancel: () => void +} + +/** + * The live side of `planWallGroupPush`, for a group move whose selection is + * walls only: the walls, their neighbours and the room surfaces preview + * through overrides, created pieces as ghosts, and each wall's room widths + * show as its own push shows them (`useRoomHandleDrag`, kind + * `wall-group-push`). The caller owns the gesture: its pointer, keys and scope. + */ +export function beginWallGroupPush(wallIds: readonly string[], levelId: string): WallGroupPush { + const nodes = useScene.getState().nodes + const measured = wallIds.flatMap((id) => { + const wall = nodes[id as AnyNodeId] + if (wall?.type !== 'wall') return [] + const base = getWallBaseElevationForNodes(wall, nodes) + return [ + { + wall, + base, + top: base + getWallEffectiveHeightForNodes(wall, nodes), + normal: wallPushNormal(wall), + rooms: pushDimensionRooms(nodes, levelId, { wallId: wall.id, t0: 0, t1: 1 }, base), + }, + ] + }) + const middle: Point = [0, 0] + for (const { wall } of measured) { + middle[0] += (wall.start[0] + wall.end[0]) / 2 / measured.length + middle[1] += (wall.start[1] + wall.end[1]) / 2 / measured.length + } + let drag: Point = [0, 0] + let blocked = false + let shown = false + const dimensions = () => { + const kept: RoomDimension[] = [] + for (const { wall, normal, rooms } of measured) { + const distance = drag[0] * normal[0] + drag[1] * normal[1] + // Two moved walls across one room both measure it: the width shows once. + for (const dimension of wallPushDimensions({ + rooms, + wall, + outward: normal, + distance, + resolve: livePreviewNode, + })) + if (!kept.some((other) => sameRoomDimension(other, dimension))) + kept.push({ ...dimension, key: `${wall.id}:${dimension.key}` }) + } + return kept + } + const publish = (ghosts: RoomPushGhost[], message?: string) => + useRoomHandleDrag.setState({ + drag: { + kind: 'wall-group-push', + levelId, + anchor: [middle[0] + drag[0], middle[1] + drag[1]], + height: Math.max(...measured.map(({ top }) => top)), + base: Math.min(...measured.map(({ base }) => base)), + ghosts, + dimensions: dimensions(), + message, + }, + }) + const end = () => { + endRoomPushPreview() + useRoomHandleDrag.setState({ drag: null }) + } + return { + preview: (next) => { + if (shown && next[0] === drag[0] && next[1] === drag[1]) return + shown = true + drag = [next[0], next[1]] + clearPushPreview() + const preview = + Math.hypot(drag[0], drag[1]) < 1e-6 + ? { ghosts: [] } + : previewPushPlan(useScene.getState().nodes, levelId, () => + planWallGroupPush(useScene.getState().nodes, wallIds, drag, previewMint()), + ) + blocked = !!preview.code + publish(preview.ghosts, preview.code ? PUSH_REFUSED_MESSAGE : undefined) + }, + commit: () => { + end() + if (blocked || Math.hypot(drag[0], drag[1]) < 1e-6) return false + return commitPushPlan((current) => planWallGroupPush(current, wallIds, drag)) + }, + cancel: end, + } +} + /** A node as the push preview draws it: the scene's, with its live override merged. */ function livePreviewNode(id: string): AnyNode | undefined { const node = useScene.getState().nodes[id as AnyNodeId] @@ -986,6 +1495,7 @@ export function wallPointAt(wall: WallNode, t: number): Point { */ export const WALL_PUSH_AFFORDANCE = 'wall-push' +/** A wall's or an invisible wall's side arrow: `wallId` is either. */ export type WallPushArrowPayload = { wallId: string; side: 'a' | 'b' } type PlanPointer = (clientX: number, clientY: number) => readonly [number, number] | null @@ -1001,8 +1511,9 @@ function planAlong(position: Point, outward: Point, toPlan: PlanPointer) { } /** - * A floor-plan wall arrow: the 3D arrow's handle (`wallPushHandles`), drag - * (`runWallPushDrag`) and commit, with the pointer read in plan coordinates. + * A floor-plan wall arrow: the 3D arrow's handle (`wallPushHandles`, or a + * selected invisible wall's `separatorPushHandles`), drag (`runWallPushDrag`) + * and commit, with the pointer read in plan coordinates. */ export function runFloorplanWallPush( payload: unknown, @@ -1013,8 +1524,12 @@ export function runFloorplanWallPush( const { wallId, side } = (payload ?? {}) as Partial const nodes = useScene.getState().nodes const wall = wallId ? nodes[wallId as AnyNodeId] : undefined - if (wall?.type !== 'wall' || !wall.parentId) return null - const handle = wallPushHandles(wall, nodes).find((h) => h.key === `${wall.id}:${side}`) + if ((wall?.type !== 'wall' && wall?.type !== 'separator') || !wall.parentId) return null + const handles = + wall.type === 'wall' + ? wallPushHandles(wall, nodes) + : separatorPushHandles(wall, separatorFloorElevation(nodes, wall.id)) + const handle = handles.find((h) => h.key === `${wall.id}:${side}`) if (!handle) return null return runFloorplanRoomPush({ handle, levelId: wall.parentId, clientX, clientY, toPlan }) } diff --git a/packages/editor/src/lib/room-push-dimensions.test.ts b/packages/editor/src/lib/room-push-dimensions.test.ts index e93223f7a7..9869e04539 100644 --- a/packages/editor/src/lib/room-push-dimensions.test.ts +++ b/packages/editor/src/lib/room-push-dimensions.test.ts @@ -11,8 +11,10 @@ import { DIMENSION_FLOOR_LIFT, mezzanineEdgeDimensions, type RoomDimension, + type WallDimensionFaces, wallPushDimensionRooms, wallPushDimensions, + wallSelectionDimensions, } from './room-push-dimensions' // Rooms are real: the walls go through core's room topology, so the faces the @@ -66,6 +68,20 @@ function measure( }) } +function selection({ nodes, walls }: Scene, wall: WallNode, faces: WallDimensionFaces) { + const index = createRoomTopologyIndex() + index.rebuildLevel(LEVEL, nodes) + const rooms = index.getLevelTopology(LEVEL)?.rooms ?? [] + return wallSelectionDimensions({ + rooms: wallPushDimensionRooms(rooms, { wallId: wall.id, t0: 0, t1: 1 }, () => 0), + wall, + walls, + faces, + resolve: (id) => nodes[id], + baseElevation: 0, + }) +} + const distances = (dimensions: RoomDimension[]) => dimensions.map((dimension) => Number(dimension.distance.toFixed(4))) @@ -206,6 +222,27 @@ describe('two rooms sharing the moving wall', () => { expect(west.key).not.toBe(east.key) }) + test('selected, a shared wall shows both room widths and no outside size, whatever the faces', () => { + for (const faces of ['both', 'interior', 'exterior'] as const) { + const dimensions = selection(rooms, middle, faces) + expect(dimensions.map((dimension) => dimension.faces)).toEqual(['interior', 'interior']) + expect(distances(dimensions).sort()).toEqual([3.8, 3.8]) + } + }) + + test('selected, an exterior wall adds the outside size across the building', () => { + const east = wallAt(rooms, [8, 0], [8, 4]) + const dimensions = selection(rooms, east, 'both') + const outside = dimensions.find((dimension) => dimension.faces === 'exterior')! + // Outer face to outer face, past the middle wall, clear of the room width's line. + expect(outside.distance).toBeCloseTo(8 + THICKNESS) + expect(outside.from[0]).toBeCloseTo(8 + THICKNESS / 2) + expect(outside.to[0]).toBeCloseTo(-THICKNESS / 2) + expect(distances(dimensions.filter((dimension) => dimension.faces === 'interior'))).toEqual([ + 3.8, + ]) + }) + test('a push over part of the wall measures only the rooms along that part', () => { const dimensions = measure(rooms, middle, [1, 0], 0, { t0: 0, t1: 0.5 }) expect(dimensions).toHaveLength(2) diff --git a/packages/editor/src/lib/room-push-dimensions.ts b/packages/editor/src/lib/room-push-dimensions.ts index 38b86bcc8e..ca02bff01e 100644 --- a/packages/editor/src/lib/room-push-dimensions.ts +++ b/packages/editor/src/lib/room-push-dimensions.ts @@ -4,6 +4,7 @@ import { getWallFaceOffsets, isCurvedWall, type Point, + type SeparatorNode, type WallNode, } from '@pascal-app/core' @@ -153,12 +154,62 @@ export function wallPushDimensionRooms( ) } +/** + * The rooms along a pushed edge of invisible walls, as `wallPushDimensionRooms` + * reads them along a wall: each room's stretch of the edge's separators, put + * on the edge's one `line` (`[0, 1]` its length), faced as that line runs. + */ +export function separatorEdgeDimensionRooms( + rooms: ReadonlyArray<{ id: string; spans: readonly BoundarySpan[] }>, + edge: { + line: Pick + separators: ReadonlyArray<{ separatorId: string; t0: number; t1: number }> + }, + resolve: (id: string) => AnyNode | undefined, + elevationOf: (roomId: string) => number, +): PushDimensionRoom[] { + const { start, end } = edge.line + const dx = end[0] - start[0] + const dz = end[1] - start[1] + const lengthSq = dx * dx + dz * dz + if (lengthSq < 1e-12) return [] + const members = new Set(edge.separators.map((member) => member.separatorId)) + const along = ([x, z]: Point) => ((x - start[0]) * dx + (z - start[1]) * dz) / lengthSq + return rooms.flatMap((room) => + room.spans.flatMap((own): PushDimensionRoom[] => { + const member = edge.separators.find((entry) => entry.separatorId === own.boundaryId) + const separator = resolve(own.boundaryId) + if (!member || separator?.type !== 'separator') return [] + const t0 = Math.max(member.t0, own.t0) + const t1 = Math.min(member.t1, own.t1) + if (t1 - t0 < 1e-4) return [] + const sx = separator.end[0] - separator.start[0] + const sz = separator.end[1] - separator.start[1] + const point = (t: number): Point => [separator.start[0] + sx * t, separator.start[1] + sz * t] + const [u0, u1] = [along(point(t0)), along(point(t1))] + // A separator drawn against the edge's line has its faces the other way round. + const same = sx * dx + sz * dz > 0 + return [ + { + id: room.id, + face: same ? own.face : own.face === 'a' ? 'b' : 'a', + t0: Math.min(u0, u1), + t1: Math.max(u0, u1), + others: room.spans.filter((other) => !members.has(other.boundaryId)), + elevation: elevationOf(room.id), + }, + ] + }), + ) +} + /** * The live dimensions of a wall push: for every room along the pushed stretch, * the moving face (the resting face moved `distance` along `outward` — a push * is a pure translation) to each facing parallel boundary of that room, read * through `resolve` so the preview's geometry counts. Per side of the wall: - * nearest first, one per distinct distance, at most three. + * nearest first, one per distinct distance, at most three. An edge of + * invisible walls is measured as its one line. */ export function wallPushDimensions({ rooms, @@ -168,7 +219,7 @@ export function wallPushDimensions({ resolve, }: { rooms: readonly PushDimensionRoom[] - wall: WallNode + wall: WallNode | SeparatorNode outward: Point distance: number resolve: (id: string) => AnyNode | undefined @@ -195,6 +246,179 @@ export function wallPushDimensions({ ) } +/** Whether two dimensions measure the same span, either way round. */ +export function sameRoomDimension(a: RoomDimension, b: RoomDimension): boolean { + const near = (p: Point, q: Point) => Math.hypot(p[0] - q[0], p[1] - q[1]) < 1e-3 + return (near(a.from, b.from) && near(a.to, b.to)) || (near(a.from, b.to) && near(a.to, b.from)) +} + +/** A selected wall's temporary dimension: a room width (ID) or the outside size (OD). */ +export type WallSelectionDimension = RoomDimension & { faces: 'interior' | 'exterior' } + +/** A selection's temporary dimension with the node it runs from: typing it moves that node. */ +export type OwnedSelectionDimension = WallSelectionDimension & { ownerId: string } + +/** + * Several selected nodes' temporary dimensions as one list, keys unique across + * owners. Two selected walls across one room both measure it: the width shows + * once, owned by the first. + */ +export function mergeSelectionDimensions( + owners: ReadonlyArray<{ ownerId: string; dimensions: readonly WallSelectionDimension[] }>, +): OwnedSelectionDimension[] { + const kept: OwnedSelectionDimension[] = [] + for (const { ownerId, dimensions } of owners) + for (const dimension of dimensions) + if (!kept.some((other) => sameRoomDimension(other, dimension))) + kept.push({ ...dimension, key: `${ownerId}:${dimension.key}`, ownerId }) + return kept +} + +/** Which faces a selected wall's temporary dimensions measure to. */ +export type WallDimensionFaces = 'interior' | 'exterior' | 'both' + +const CONNECTION_TOLERANCE = 0.03 +/** Where along the shared stretch the outside size is drawn, clear of the room widths at its middle. */ +const EXTERIOR_DIMENSION_AT = 0.25 + +function pointSegmentDistance(p: Point, a: Point, b: Point): number { + const dx = b[0] - a[0] + const dz = b[1] - a[1] + const lengthSq = dx * dx + dz * dz + const t = + lengthSq < 1e-12 + ? 0 + : Math.max(0, Math.min(1, ((p[0] - a[0]) * dx + (p[1] - a[1]) * dz) / lengthSq)) + return Math.hypot(p[0] - (a[0] + dx * t), p[1] - (a[1] + dz * t)) +} + +function wallsTouch(left: WallNode, right: WallNode): boolean { + return ( + [left.start, left.end].some( + (p) => pointSegmentDistance(p, right.start, right.end) <= CONNECTION_TOLERANCE, + ) || + [right.start, right.end].some( + (p) => pointSegmentDistance(p, left.start, left.end) <= CONNECTION_TOLERANCE, + ) + ) +} + +/** The walls joined to `wall` through shared corners and T junctions, itself included. */ +function connectedWalls(wall: WallNode, walls: readonly WallNode[]): WallNode[] { + const found = new Map([[wall.id, wall]]) + const queue = [wall] + for (let current = queue.pop(); current; current = queue.pop()) { + for (const candidate of walls) { + if (found.has(candidate.id) || !wallsTouch(current, candidate)) continue + found.set(candidate.id, candidate) + queue.push(candidate) + } + } + return [...found.values()] +} + +/** + * The outside size across the building from a wall's exterior face: to the + * far face of the farthest parallel wall of the same connected building that + * shares some of its length — the opposite exterior wall. Null when nothing + * is across (a lone wall, a curved one). + */ +function overallExteriorDimension( + wall: WallNode, + exteriorFace: 'a' | 'b', + walls: readonly WallNode[], +): Measured | null { + const own = boundaryFace(wall, 0, 1, exteriorFace) + if (!own) return null + const dx = own.end[0] - own.start[0] + const dz = own.end[1] - own.start[1] + const length = Math.hypot(dx, dz) + const dir: Point = [dx / length, dz / length] + // The face's room-ward normal points out of the building here: across is its opposite. + const across: Point = [-own.inward[0], -own.inward[1]] + const along = (p: Point) => (p[0] - own.start[0]) * dir[0] + (p[1] - own.start[1]) * dir[1] + let best: { distance: number; lo: number; hi: number } | null = null + for (const other of connectedWalls(wall, walls)) { + if (other.id === wall.id) continue + for (const face of ['a', 'b'] as const) { + const candidate = boundaryFace(other, 0, 1, face) + if (!candidate) continue + const fx = candidate.end[0] - candidate.start[0] + const fz = candidate.end[1] - candidate.start[1] + const faceLength = Math.hypot(fx, fz) + if (Math.abs(dir[0] * fz - dir[1] * fx) / faceLength > PARALLEL_SIN) continue + const distance = + (candidate.start[0] - own.start[0]) * across[0] + + (candidate.start[1] - own.start[1]) * across[1] + if (distance <= MIN_GAP) continue + const a = along(candidate.start) + const b = along(candidate.end) + const lo = Math.max(0, Math.min(a, b)) + const hi = Math.min(length, Math.max(a, b)) + if (hi - lo < MIN_OVERLAP) continue + if (!best || distance > best.distance + SAME_DISTANCE) best = { distance, lo, hi } + } + } + if (!best) return null + const at = (u: number): Point => [own.start[0] + dir[0] * u, own.start[1] + dir[1] * u] + const [lo, hi] = [at(best.lo), at(best.hi)] + // Measured from the same end of the stretch whichever way the wall was drawn, + // so the walls on either side of the building put their outside size in one place. + const fromLo = Math.abs(lo[0] - hi[0]) > 1e-6 ? lo[0] < hi[0] : lo[1] <= hi[1] + const offset = (best.hi - best.lo) * EXTERIOR_DIMENSION_AT + const from = at(fromLo ? best.lo + offset : best.hi - offset) + return { + from, + to: [from[0] + across[0] * best.distance, from[1] + across[1] * best.distance], + distance: best.distance, + } +} + +/** + * The temporary dimensions of a selected wall at rest, in 2D and 3D: the room + * widths a push of it shows (its face to each facing wall, both sides — ID), + * and for an exterior wall the outside size across the building (OD). `faces` + * picks which; a wall with no outside (rooms on both faces) shows its room + * widths whatever the choice. Each dimension runs `from` the selected wall, + * so typing a value moves that wall (`commitDimensionValue`). + */ +export function wallSelectionDimensions({ + rooms, + wall, + walls, + faces, + resolve, + baseElevation, +}: { + rooms: readonly PushDimensionRoom[] + wall: WallNode + /** The level's walls, for the opposite exterior wall. */ + walls: readonly WallNode[] + faces: WallDimensionFaces + resolve: (id: string) => AnyNode | undefined + /** The wall's base, for a dimension with no room floor to stand on. */ + baseElevation: number +}): WallSelectionDimension[] { + const interior = wallPushDimensions({ rooms, wall, outward: [0, 0], distance: 0, resolve }).map( + (dimension): WallSelectionDimension => ({ ...dimension, faces: 'interior' }), + ) + const roomFaces = new Set(rooms.map((room) => room.face)) + const exteriorFace = roomFaces.size === 1 ? (roomFaces.has('a') ? 'b' : 'a') : null + if (!exteriorFace || faces === 'interior') return interior + const overall = overallExteriorDimension(wall, exteriorFace, walls) + const exterior: WallSelectionDimension[] = overall + ? [ + { + ...overall, + key: 'exterior', + faces: 'exterior', + elevation: (rooms[0]?.elevation ?? baseElevation) + DIMENSION_FLOOR_LIFT, + }, + ] + : [] + return faces === 'exterior' ? exterior : [...interior, ...exterior] +} + /** * The live dimensions of a mezzanine edge push: the resting edge moved * `distance` along `outward`, to each facing parallel edge of the outline the diff --git a/packages/editor/src/lib/room-selection.test.ts b/packages/editor/src/lib/room-selection.test.ts index 0d3e23c4f4..c5a4c6a83a 100644 --- a/packages/editor/src/lib/room-selection.test.ts +++ b/packages/editor/src/lib/room-selection.test.ts @@ -868,17 +868,34 @@ describe('room drill-down state through the mounted selection manager', () => { expect(useViewer.getState().selection.selectedIds).toEqual(['wall_free']) }) }) - test('the 2D plan resolves walls room-first and drills on the second click', async () => { + test('the 2D plan gives a wall hit to the wall and a room interior to the room', async () => { await withRooms(async ({ left, right }) => { - expect(resolvePlanRoomHit('wall_west', [-0.05, 2])).toEqual(left) + // Without the kind's `planHitSelectsNode`, a band hit stays room-first. expect(resolvePlanRoomHit('wall_shared', [3.95, 2])).toEqual(left) - expect(resolvePlanRoomHit('wall_shared', [4.05, 2])).toEqual(right) - expect(resolvePlanRoomHit('wall_free', [9.95, 1])).toBeNull() - const hit = resolvePlanRoomHit('wall_west', [-0.05, 2]) + // The wall definition declares it (its floor-plan extension). + const get = nodeRegistry.get.bind(nodeRegistry) + const spy = spyOn(nodeRegistry, 'get').mockImplementation(((kind: string) => + kind === 'wall' + ? ({ + ...get(kind), + extensions: { 'pascal:editor/floorplan': { planHitSelectsNode: true } }, + } as AnyNodeDefinition) + : get(kind)) as typeof nodeRegistry.get) + try { + // Either half of a shared wall's band is the wall, never the room beside it. + expect(resolvePlanRoomHit('wall_west', [-0.05, 2])).toBeNull() + expect(resolvePlanRoomHit('wall_shared', [3.95, 2])).toBeNull() + expect(resolvePlanRoomHit('wall_shared', [4.05, 2])).toBeNull() + expect(resolvePlanRoomHit('wall_free', [9.95, 1])).toBeNull() + } finally { + spy.mockRestore() + } + expect(resolvePlanRoomHit(null, [2, 2])).toEqual(left) + expect(resolvePlanRoomHit(null, [6, 2])).toEqual(right) const select = async (modifiers = plain) => { let selected = false await act(async () => { - selected = selectRoomFromHit(hit, modifiers, 'wall_west') + selected = selectRoomFromHit(resolvePlanRoomHit(null, [2, 2]), modifiers, null) }) return selected } diff --git a/packages/editor/src/lib/selection-cycle.ts b/packages/editor/src/lib/selection-cycle.ts new file mode 100644 index 0000000000..40affb1e1c --- /dev/null +++ b/packages/editor/src/lib/selection-cycle.ts @@ -0,0 +1,63 @@ +/** + * Tab steps the selection through everything stacked under the pointer in the + * floor plan, top first: where walls + * overlap, or a short wall lies inside a longer one or under a marker, a click + * takes the top one and Tab the ones below it in turn. Shift+Tab steps back. + */ + +import type { AnyNodeId } from '@pascal-app/core' +import { useViewer } from '@pascal-app/viewer' + +let pointer: { x: number; y: number } | null = null +let tracking = false + +/** Start following the pointer, so a Tab knows where it is. Idempotent. */ +export function trackSelectionCyclePointer(): void { + if (tracking || typeof window === 'undefined') return + tracking = true + const follow = (event: PointerEvent) => { + pointer = { x: event.clientX, y: event.clientY } + } + window.addEventListener('pointermove', follow, { capture: true, passive: true }) + window.addEventListener('pointerdown', follow, { capture: true, passive: true }) +} + +/** The plan nodes under a screen point, topmost first, each once. */ +export function floorplanNodesAt(x: number, y: number): string[] { + if (typeof document === 'undefined') return [] + const ids: string[] = [] + for (const element of document.elementsFromPoint(x, y)) { + if (!element.closest('[data-floorplan-scene]')) continue + const entry = element.closest('.floorplan-registry-entry[data-node-id]') + const id = entry?.dataset.nodeId + if (id && !ids.includes(id)) ids.push(id) + } + return ids +} + +/** + * The id a Tab selects among `stack` (topmost first): the one after the + * current selection, or before it for Shift+Tab, wrapping round; the top one + * when the selection is not in the stack. + */ +export function nextInStack( + stack: readonly string[], + selected: readonly string[], + back: boolean, +): string | null { + if (stack.length === 0) return null + const index = selected.length === 1 ? stack.indexOf(selected[0]!) : -1 + if (index < 0) return stack[0]! + return stack[(index + (back ? stack.length - 1 : 1)) % stack.length]! +} + +/** Select the next object under the pointer in the floor plan. True when Tab was used. */ +export function cycleSelectionAtPointer(back: boolean): boolean { + if (!pointer) return false + const stack = floorplanNodesAt(pointer.x, pointer.y) + const viewer = useViewer.getState() + const next = nextInStack(stack, viewer.selection.selectedIds, back) + if (!next) return false + viewer.setSelection({ selectedIds: [next as AnyNodeId] }) + return true +} diff --git a/packages/editor/src/lib/separator-edit.test.ts b/packages/editor/src/lib/separator-edit.test.ts new file mode 100644 index 0000000000..9c5d6773cc --- /dev/null +++ b/packages/editor/src/lib/separator-edit.test.ts @@ -0,0 +1,431 @@ +import { afterAll, afterEach, beforeEach, describe, expect, spyOn, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + area, + BuildingNode, + clearSceneHistory, + createZone, + generateId, + initSpaceDetectionSync, + LevelNode, + nodeRegistry, + planSeparatorInsertion, + railingWallDefaults, + type SeparatorNode, + structureChangeBatch, + useLiveNodeOverrides, + useScene, + WallNode, + type ZoneNode, +} from '@pascal-app/core' +import { useViewer } from '@pascal-app/viewer' +import { getRoomSelectionIndex } from '../hooks/use-selected-room' +import useEditor from '../store/use-editor' +import useInteractionScope from '../store/use-interaction-scope' +import { installImmediateAnimationFrames } from '../test-utils/immediate-animation-frames' +import { cancelGestures } from './gesture-lifecycle' +import { endpointReshapeScope } from './interaction/scope' +import { + roomPushHandles, + runFloorplanRoomPush, + runFloorplanWallPush, + separatorPushHandles, + useRoomHandleDrag, + type WallPushHandle, +} from './room-handle-drag' +import { applyRoomPlan } from './room-structure-commands' +import { + beginSeparatorEndDrag, + runSeparatorEndDrag, + SEPARATOR_END_DRAG_LABEL, +} from './separator-edit' + +// A porch off an 8 × 4 house, closed by invisible walls, pushed and dragged +// the way the plan and the 3D view do it. The pointer is faked: plan points +// come straight from the client point (x → plan x, y → plan z). + +type Point = [number, number] +const LEVEL = 'level_separator_edit' +const stubbed: string[] = [] +let stop = () => {} +let restoreFrames = () => {} +let registry: { mockRestore: () => void } | null = null +const toPlan = (clientX: number, clientY: number): [number, number] => [clientX, clientY] + +function pointer(type: 'pointermove' | 'pointerup', x: number, y: number, altKey = false) { + window.dispatchEvent(Object.assign(new Event(type), { clientX: x, clientY: y, altKey })) +} + +const near = (a: Point, b: Point) => Math.hypot(a[0] - b[0], a[1] - b[1]) < 1e-6 +const separators = () => + Object.values(useScene.getState().nodes).filter( + (node): node is SeparatorNode => node.type === 'separator', + ) +/** The invisible wall from `a` to `b`, either way round. */ +const between = (a: Point, b: Point) => + separators().find( + (node) => + (near(node.start, a) && near(node.end, b)) || (near(node.start, b) && near(node.end, a)), + ) +const porchZone = () => + Object.values(useScene.getState().nodes).find( + (node): node is ZoneNode => + node.type === 'zone' && (node.roomType === 'porch' || node.roomType === 'deck'), + ) +const porchArea = () => { + const zone = porchZone() + return zone ? area([{ outer: zone.polygon, holes: zone.holes }]) : 0 +} + +/** Draws the porch's sides — invisible walls, or railings where `railed` — through the store. */ +function drawPorch( + sides: Array<[Point, Point]> = [ + [ + [2, 4], + [2, 6], + ], + [ + [2, 6], + [6, 6], + ], + [ + [6, 6], + [6, 4], + ], + ], + railed = false, +) { + for (const [start, end] of sides) { + const nodes = useScene.getState().nodes + if (railed) { + const railing = WallNode.parse({ + ...railingWallDefaults(), + id: generateId('wall'), + parentId: LEVEL, + start, + end, + }) + useScene.getState().applyNodeChanges(structureChangeBatch([{ op: 'create', node: railing }])) + continue + } + const plan = planSeparatorInsertion(nodes as Record, { + levelId: LEVEL as AnyNodeId, + start, + end, + joinRadius: 0.05, + mintId: () => generateId('separator'), + }) + useScene.getState().applyNodeChanges(plan!.changes) + } + clearSceneHistory() +} + +function porchHandles(): WallPushHandle[] { + const zone = porchZone()! + const record = getRoomSelectionIndex(LEVEL) + .update(useScene.getState().nodes) + .find((room) => room.zoneId === zone.id)! + return roomPushHandles(useScene.getState().nodes, record.spans) +} + +/** The porch arrow pointing along `direction`. */ +const arrow = (handles: WallPushHandle[], direction: Point) => + handles.find( + (handle) => + handle.outward[0] * direction[0] + handle.outward[1] * direction[1] > 0.99 && + !!handle.separators, + ) + +beforeEach(() => { + restoreFrames = installImmediateAnimationFrames() + if (!globalThis.document) { + globalThis.document = { body: { style: { cursor: '' } } } as unknown as Document + stubbed.push('document') + } + if (!globalThis.window) { + globalThis.window = new EventTarget() as Window & typeof globalThis + stubbed.push('window') + } + // The nodes package that registers walls and invisible walls is not loaded + // here: answer their snap context lookup as their definitions do. + const get = nodeRegistry.get.bind(nodeRegistry) + registry = spyOn(nodeRegistry, 'get').mockImplementation(((kind: string) => + kind === 'wall' || kind === 'separator' + ? { snapProfile: 'structural' } + : get(kind)) as typeof nodeRegistry.get) + cancelGestures('cancel') + useInteractionScope.getState().end() + const building = BuildingNode.parse({ id: 'building_separator_edit', children: [LEVEL] }) + const level = LevelNode.parse({ id: LEVEL, parentId: building.id }) + useScene.setState({ + nodes: { [building.id]: building, [level.id]: level }, + rootNodeIds: [building.id], + dirtyNodes: new Set(), + materials: {}, + collections: {}, + readOnly: false, + }) + useScene.temporal.getState().resume() + stop = initSpaceDetectionSync(useScene, { getState: () => ({ spaces: {}, setSpaces: () => {} }) }) + applyRoomPlan( + createZone(useScene.getState().nodes, { + levelId: LEVEL, + polygon: [ + [0, 0], + [8, 0], + [8, 4], + [0, 4], + ], + enclose: true, + mintId: generateId, + }), + ) + useViewer.getState().setSelection({ buildingId: building.id, levelId: LEVEL, selectedIds: [] }) + useEditor.setState({ phase: 'building', mode: 'select', gridSnapStep: 0.5 }) + useEditor.getState().setSnappingMode('polygon', 'grid') + useEditor.getState().setSnappingMode('wall', 'grid') + clearSceneHistory() +}) + +afterEach(() => { + cancelGestures('cancel') + stop() + registry?.mockRestore() + registry = null + restoreFrames() +}) + +afterAll(async () => { + // Let the click-swallow timers fire before the stubs go. + await new Promise((resolve) => setTimeout(resolve, 350)) + for (const key of stubbed.splice(0)) delete (globalThis as Record)[key] +}) + +describe('a porch closed by invisible walls, selected', () => { + test('has a push arrow on each invisible-wall edge, pointing off the porch, beside the house wall’s', () => { + drawPorch() + expect(porchZone()?.roomType).toBe('porch') + const handles = porchHandles() + for (const direction of [ + [-1, 0], + [0, 1], + [1, 0], + ] as Point[]) + expect(arrow(handles, direction)?.separators).toHaveLength(1) + // The house wall's arrow is the wall push it always was. + expect(handles.filter((handle) => !handle.separators)).toHaveLength(1) + const bottom = arrow(handles, [0, 1])! + expect(bottom.position[0]).toBeCloseTo(4, 6) + expect(bottom.position[1]).toBeGreaterThan(6) + }) + + test('an edge drawn in two pieces has one arrow, and it pushes both', () => { + drawPorch([ + [ + [2, 4], + [2, 6], + ], + [ + [2, 6], + [4, 6], + ], + [ + [4, 6], + [6, 6], + ], + [ + [6, 6], + [6, 4], + ], + ]) + const bottom = arrow(porchHandles(), [0, 1])! + expect(bottom.separators).toHaveLength(2) + expect(bottom.position[0]).toBeCloseTo(4, 6) + runFloorplanRoomPush({ handle: bottom, levelId: LEVEL, clientX: 4, clientY: 6.3, toPlan }) + pointer('pointermove', 4, 7.3) + pointer('pointerup', 4, 7.3) + expect(between([2, 7], [4, 7])).toBeDefined() + expect(between([4, 7], [6, 7])).toBeDefined() + expect(porchArea()).toBeCloseTo(12, 6) + }) + + test('its edge pushed out moves the invisible wall, the sides follow, the porch grows; one undo step', () => { + drawPorch() + const before = useScene.getState().nodes + const bottom = arrow(porchHandles(), [0, 1])! + const zoneId = porchZone()!.id + expect( + runFloorplanRoomPush({ + handle: bottom, + levelId: LEVEL, + zoneId, + clientX: 4, + clientY: 6.3, + toPlan, + }), + ).not.toBeNull() + const depth = () => { + const drag = useRoomHandleDrag.getState().drag + return drag?.kind === 'push' ? drag.dimensions.map((dimension) => dimension.distance) : [] + } + // The porch's depth, edge to the house wall's outside face. + const [rest] = depth() + expect(rest).toBeGreaterThan(1.8) + expect(rest).toBeLessThan(2) + // 0.8 m of travel lands the edge on the 0.5 m lattice, a metre out. + pointer('pointermove', 4, 7.1) + expect(useRoomHandleDrag.getState().drag).toMatchObject({ kind: 'push', distance: 1 }) + expect(depth()[0]).toBeCloseTo(rest! + 1, 6) + const live = useLiveNodeOverrides.getState().overrides + const preview = live.get(bottom.wallId) as Partial | undefined + expect(preview?.start?.[1]).toBeCloseTo(7, 6) + // The porch floor follows live; nothing is written until release. + expect(live.get(zoneId as AnyNodeId)).toHaveProperty('polygon') + expect(useScene.getState().nodes).toBe(before) + + pointer('pointerup', 4, 7.1) + expect(useLiveNodeOverrides.getState().overrides.has(bottom.wallId)).toBe(false) + expect(between([2, 7], [6, 7])?.id).toBe(bottom.wallId as SeparatorNode['id']) + expect(between([2, 4], [2, 7])).toBeDefined() + expect(between([6, 7], [6, 4])).toBeDefined() + expect(porchArea()).toBeCloseTo(12, 6) + expect(useScene.temporal.getState().pastStates).toHaveLength(1) + + useScene.temporal.getState().undo() + expect(between([2, 6], [6, 6])).toBeDefined() + expect(between([2, 4], [2, 6])).toBeDefined() + expect(porchArea()).toBeCloseTo(8, 6) + }) + + test('pulled in, it shrinks the porch and stays closed', () => { + drawPorch() + const bottom = arrow(porchHandles(), [0, 1])! + runFloorplanRoomPush({ handle: bottom, levelId: LEVEL, clientX: 4, clientY: 6.3, toPlan }) + pointer('pointermove', 4, 5.3) + pointer('pointerup', 4, 5.3) + expect(between([2, 5], [6, 5])).toBeDefined() + expect(porchArea()).toBeCloseTo(4, 6) + }) + + test('its house-wall arrow still pushes the house wall, the porch following it', () => { + drawPorch() + const house = porchHandles().find((handle) => !handle.separators)! + expect(house.outward[1]).toBeCloseTo(-1, 6) + runFloorplanRoomPush({ + handle: house, + levelId: LEVEL, + clientX: house.position[0], + clientY: house.position[1], + toPlan, + }) + pointer('pointermove', house.position[0], house.position[1] - 1) + pointer('pointerup', house.position[0], house.position[1] - 1) + const moved = Object.values(useScene.getState().nodes).find( + (node): node is WallNode => + node.type === 'wall' && + Math.abs(node.start[1] - 3) < 1e-6 && + Math.abs(node.end[1] - 3) < 1e-6, + ) + expect(moved).toBeDefined() + expect(porchArea()).toBeCloseTo(12, 6) + }) +}) + +test('a deck fenced by railings has the wall arrows on its railings', () => { + drawPorch(undefined, true) + const deck = porchZone() + expect(deck?.roomType).toBe('deck') + const record = getRoomSelectionIndex(LEVEL) + .update(useScene.getState().nodes) + .find((room) => room.zoneId === deck!.id)! + const handles = roomPushHandles(useScene.getState().nodes, record.spans) + const railings = handles.filter( + (handle) => + (useScene.getState().nodes[handle.wallId as AnyNodeId] as WallNode).wallType === 'railing', + ) + expect(railings).toHaveLength(3) + expect(railings.every((handle) => !handle.separators)).toBe(true) +}) + +describe('a selected invisible wall', () => { + test('its side arrow pushes it, the invisible wall joined to it stretching and its end sliding on the house', () => { + drawPorch() + const left = between([2, 4], [2, 6])! + useViewer.getState().setSelection({ selectedIds: [left.id] }) + const side = separatorPushHandles(left).find((handle) => handle.outward[0] < -0.99)! + expect( + runFloorplanWallPush( + { wallId: left.id, side: side.key.endsWith(':a') ? 'a' : 'b' }, + 1.9, + 5, + toPlan, + ), + ).not.toBeNull() + pointer('pointermove', 0.9, 5) + pointer('pointerup', 0.9, 5) + expect(between([1, 4], [1, 6])?.id).toBe(left.id) + expect(between([1, 6], [6, 6])).toBeDefined() + expect(porchArea()).toBeCloseTo(10, 6) + expect(useScene.temporal.getState().pastStates).toHaveLength(1) + }) + + /** Drags the end of `separator` at `corner` (its 3D grip) along `path`, Alt held when `alt`. */ + function dragEnd(separator: SeparatorNode, corner: Point, path: Point[], alt = false) { + const endpoint = near(separator.start, corner) ? 'start' : 'end' + runSeparatorEndDrag({ separatorId: separator.id, endpoint, levelId: LEVEL, toPlan }) + for (const [x, z] of path) pointer('pointermove', x, z, alt) + const [x, z] = path.at(-1)! + pointer('pointerup', x, z, alt) + } + + test('an end dragged takes the invisible wall joined there along, square and on the grid', () => { + drawPorch() + const bottom = between([2, 6], [6, 6])! + const endpoint = near(bottom.start, [2, 6]) ? 'start' : 'end' + runSeparatorEndDrag({ separatorId: bottom.id, endpoint, levelId: LEVEL, toPlan }) + expect(useInteractionScope.getState().scope).toMatchObject({ + kind: 'handle-drag', + nodeId: bottom.id, + handle: SEPARATOR_END_DRAG_LABEL, + }) + pointer('pointermove', 1.07, 5.96) + const live = useLiveNodeOverrides.getState().overrides.get(bottom.id) as Partial + expect(live[endpoint]).toEqual([1, 6]) + expect(between([2, 6], [6, 6])).toBeDefined() + pointer('pointerup', 1.07, 5.96) + expect(between([1, 6], [6, 6])?.id).toBe(bottom.id) + expect(between([2, 4], [1, 6])).toBeDefined() + expect(useLiveNodeOverrides.getState().overrides.has(bottom.id)).toBe(false) + expect(useScene.temporal.getState().pastStates).toHaveLength(1) + expect(useInteractionScope.getState().scope.kind).toBe('idle') + }) + + test('let go with Alt, its end comes back together on its old corner', () => { + drawPorch() + const bottom = between([2, 6], [6, 6])! + dragEnd(bottom, [2, 6], [[1, 7]], true) + expect(between([2, 4], [2, 6])).toBeDefined() + expect(between([2, 6], [6, 6])).toBeUndefined() + + const moved = useScene.getState().nodes[bottom.id as AnyNodeId] as SeparatorNode + dragEnd(moved, near(moved.start, [6, 6]) ? moved.end : moved.start, [[2.12, 6.09]], true) + expect(between([2, 6], [6, 6])?.id).toBe(bottom.id) + expect(porchArea()).toBeCloseTo(8, 6) + }) + + test('the plan’s end handle runs the same drag', () => { + drawPorch() + const bottom = between([2, 6], [6, 6])! + const endpoint = near(bottom.start, [2, 6]) ? 'start' : 'end' + // The plan begins its end-drag scope (the wall snapping set) around the session. + useInteractionScope.getState().begin(endpointReshapeScope(bottom.id, endpoint, 'floorplan')) + const session = beginSeparatorEndDrag(bottom.id, endpoint)! + session.move([1.07, 6.04], false) + expect(session.canCommit()).toBe(true) + useInteractionScope.getState().end() + expect(session.commit()).toBe(true) + expect(between([1, 6], [6, 6])?.id).toBe(bottom.id) + expect(between([2, 4], [1, 6])).toBeDefined() + }) +}) diff --git a/packages/editor/src/lib/separator-edit.ts b/packages/editor/src/lib/separator-edit.ts new file mode 100644 index 0000000000..b3d5022d7c --- /dev/null +++ b/packages/editor/src/lib/separator-edit.ts @@ -0,0 +1,179 @@ +import { + type AnyNode, + type AnyNodeId, + joinedSeparatorIds, + runAsSingleSceneHistoryStep, + type SeparatorNode, + setSeparatorEnd, + useLiveNodeOverrides, + useScene, + type WallNode, + type WallPlanPoint, +} from '@pascal-app/core' +import { runRoomHandleDrag } from './room-handle-drag' +import { applyRoomPlan } from './room-structure-commands' +import { levelSeparatorLines } from './separator-lines' +import { isWallRunFree, publishWallRunFeedback, snapWallRunDraftPoint } from './wall-run-snap' + +/** Scope label of an invisible wall's end drag (its 3D grip). */ +export const SEPARATOR_END_DRAG_LABEL = 'separator-end' + +const SAME_POINT = 1e-6 + +export type SeparatorEndDrag = { + /** The invisible walls the drag may move: the dragged one and those it can carry. */ + affectedIds: AnyNodeId[] + /** Snaps the end to `point` (level plan) and previews it; `detach` (Alt) leaves the joined ones. */ + move: (point: WallPlanPoint, detach: boolean) => void + /** Whether the end has moved somewhere it may stay. */ + canCommit: () => boolean + /** Writes the end as one undo step; false when it did not move or core refused it. */ + commit: () => boolean + /** Drops the preview; writes nothing. */ + cancel: () => void +} + +/** + * An invisible wall's end dragged: its handle on the plan, its grip in 3D. The + * end snaps as a wall run does — square to the house or to its own line, its + * length on the grid, onto wall and invisible-wall ends and bodies, so it + * comes back together on its old corner — the invisible walls joined at that + * end follow it live, and the release writes it once (`setSeparatorEnd`). + * The scene is untouched until then. + */ +export function beginSeparatorEndDrag( + separatorId: string, + endpoint: 'start' | 'end', +): SeparatorEndDrag | null { + const nodes = useScene.getState().nodes + const separator = nodes[separatorId as AnyNodeId] + if (separator?.type !== 'separator') return null + const from = separator[endpoint] + const fixed = endpoint === 'start' ? separator.end : separator.start + const levelId = separator.parentId + const atFrom = (point: WallPlanPoint) => + Math.abs(point[0] - from[0]) <= SAME_POINT && Math.abs(point[1] - from[1]) <= SAME_POINT + const others = Object.values(nodes).filter( + (node): node is SeparatorNode => + node.type === 'separator' && node.parentId === levelId && node.id !== separator.id, + ) + // The ends following this one are no snap targets while they do: they sit where it left. + const joined = joinedSeparatorIds(nodes, separator, endpoint) + const walls = Object.values(nodes).filter( + (node): node is WallNode => node.type === 'wall' && node.parentId === levelId, + ) + const targets = { + attached: [ + ...walls, + ...levelSeparatorLines(nodes, levelId, new Set([separator.id, ...joined])), + ], + detached: [...walls, ...levelSeparatorLines(nodes, levelId, new Set([separator.id]))], + } + const length = Math.hypot(from[0] - fixed[0], from[1] - fixed[1]) + const reference: WallPlanPoint | null = + length > 1e-9 ? [(from[0] - fixed[0]) / length, (from[1] - fixed[1]) / length] : null + let target: { point: WallPlanPoint; detach: boolean } | null = null + const previewIds = new Set() + const preview = (updates: Array<[AnyNodeId, Partial]>) => { + const overrides = useLiveNodeOverrides.getState() + const next = new Set(updates.map(([id]) => id)) + for (const id of previewIds) { + if (next.has(id)) continue + overrides.clear(id) + useScene.getState().markDirty(id) + previewIds.delete(id) + } + if (updates.length) overrides.setMany(updates) + for (const id of next) { + previewIds.add(id) + useScene.getState().markDirty(id) + } + } + return { + affectedIds: [separator.id, ...others.map((node) => node.id)] as AnyNodeId[], + move(point, detach) { + const snap = snapWallRunDraftPoint({ + point, + start: fixed, + runStart: fixed, + reference, + walls: detach ? targets.detached : targets.attached, + free: isWallRunFree(null), + }) + publishWallRunFeedback(snap) + const plan = setSeparatorEnd(nodes, { separatorId, endpoint, point: snap.point, detach }) + if (plan.conflicts?.length) { + target = null + preview([]) + return + } + target = { point: snap.point, detach } + preview( + plan.changes.flatMap( + (change): Array<[AnyNodeId, Partial]> => + change.op === 'update' ? [[change.id as AnyNodeId, change.data]] : [], + ), + ) + }, + canCommit: () => !!target && !atFrom(target.point), + commit() { + preview([]) + publishWallRunFeedback(null) + if (!target || atFrom(target.point)) return false + const current = useScene.getState().nodes + if (current[separatorId as AnyNodeId]?.type !== 'separator') return false + const plan = setSeparatorEnd(current, { separatorId, endpoint, ...target }) + return runAsSingleSceneHistoryStep(useScene, () => applyRoomPlan(plan)) + }, + cancel() { + preview([]) + publishWallRunFeedback(null) + }, + } +} + +/** + * An invisible wall's 3D end grip: `toPlan` reads the pointer on the floor the + * separator lies on, in level plan metres. One gesture under the lifecycle + * owner (Escape or ⌘Z cancels), one undo step; Alt leaves the joined + * invisible walls where they are. + */ +export function runSeparatorEndDrag({ + separatorId, + endpoint, + levelId, + toPlan, +}: { + separatorId: string + endpoint: 'start' | 'end' + levelId: string + toPlan: (clientX: number, clientY: number) => WallPlanPoint | null +}) { + const drag = beginSeparatorEndDrag(separatorId, endpoint) + if (!drag) return null + let altHeld = false + const trackAlt = (event: KeyboardEvent | PointerEvent) => { + altHeld = event.altKey + } + const events = ['pointermove', 'keydown', 'keyup'] as const + for (const type of events) window.addEventListener(type, trackAlt, true) + const stop = () => { + for (const type of events) window.removeEventListener(type, trackAlt, true) + } + return runRoomHandleDrag({ + label: SEPARATOR_END_DRAG_LABEL, + nodeId: separatorId, + levelId, + requires: [separatorId], + sample: toPlan, + onValue: (point) => drag.move(point, altHeld), + onCommit: () => { + stop() + drag.commit() + }, + onCancel: () => { + stop() + drag.cancel() + }, + }) +} diff --git a/packages/editor/src/lib/separator-lines.ts b/packages/editor/src/lib/separator-lines.ts new file mode 100644 index 0000000000..c05db6f6aa --- /dev/null +++ b/packages/editor/src/lib/separator-lines.ts @@ -0,0 +1,38 @@ +import type { AnyNode, SeparatorNode, WallNode } from '@pascal-app/core' + +/** + * Invisible walls (room separators) as the wall snapping reads walls: a line + * with no thickness. A drafted or dragged invisible-wall end catches another's + * ends and body this way, and a pushed one lines up with them, as walls do + * with walls. Never written to the scene. + */ +export function separatorWallLine(separator: SeparatorNode): WallNode { + return { + object: 'node', + id: separator.id as string as WallNode['id'], + type: 'wall', + name: separator.name, + parentId: separator.parentId, + visible: true, + metadata: {}, + children: [], + start: separator.start, + end: separator.end, + thickness: 0, + frontSide: 'unknown', + backSide: 'unknown', + } +} + +/** The invisible walls on `levelId` as wall lines, leaving out `exclude`. */ +export function levelSeparatorLines( + nodes: Readonly>, + levelId: string | null, + exclude: ReadonlySet = new Set(), +): WallNode[] { + return Object.values(nodes).flatMap((node) => + node.type === 'separator' && node.parentId === levelId && !exclude.has(node.id) + ? [separatorWallLine(node)] + : [], + ) +} diff --git a/packages/editor/src/lib/tool-shortcuts.ts b/packages/editor/src/lib/tool-shortcuts.ts new file mode 100644 index 0000000000..4b12b40666 --- /dev/null +++ b/packages/editor/src/lib/tool-shortcuts.ts @@ -0,0 +1,130 @@ +import useEditor from '../store/use-editor' +import useInteractionScope from '../store/use-interaction-scope' +import { openSidebarPanel } from './sidebar-panel' + +/** + * The single-key tools of the editor, and the keys tooltips print for them. + * + * The drafting tools (Door, Window, Stairs, Roof) sit on Shift with their + * letter, as the bare key was taken: W/A/S/D pan the view in 2D and 3D, + * R flips or rotates the selection and the armed placement, and E operates the + * selected door, window or cabinet. Pan stands down for those Shift chords + * (`claimsKeyboardPan`), and R/E still work bare as before. + */ +export type ToolShortcutId = + | 'select' + | 'delete' + | 'wall' + | 'item' + | 'zone' + | 'measurement' + | 'paint' + | 'terrain' + | 'door' + | 'window' + | 'stair' + | 'roof' + +type ArmedByChord = { + /** `KeyboardEvent.code`: the physical key, as pan reads it. */ + code: string + shift: boolean +} + +/** Keys as `ShortcutToken` names them. */ +export const TOOL_SHORTCUT_KEYS: Record = { + select: ['V'], + delete: ['X'], + wall: ['B'], + item: ['F'], + zone: ['Z'], + measurement: ['M'], + paint: ['P'], + terrain: ['G'], + door: ['Shift', 'D'], + window: ['Shift', 'W'], + stair: ['Shift', 'S'], + roof: ['Shift', 'R'], +} + +/** The tools this module arms itself; the older keys stay in `use-keyboard`. */ +const CHORDS: Partial> = { + door: { code: 'KeyD', shift: true }, + window: { code: 'KeyW', shift: true }, + stair: { code: 'KeyS', shift: true }, + roof: { code: 'KeyR', shift: true }, +} + +/** A tool's shortcut as a tooltip prints it: `Shift+D`, `B`. Null for a tool without one. */ +export function toolShortcutLabel(tool: string): string | null { + const keys = TOOL_SHORTCUT_KEYS[tool as ToolShortcutId] + return keys ? keys.join('+') : null +} + +/** A tool's tooltip with its shortcut: `Door (Shift+D)`; the bare label when it has none. */ +export function withToolShortcut(label: string, tool: string | undefined): string { + const shortcut = tool ? toolShortcutLabel(tool) : null + return shortcut ? `${label} (${shortcut})` : label +} + +// Gestures a held Shift modifies (free move, free rotate, force place): a Shift +// chord there is part of the gesture, never a tool switch. +const SHIFT_GESTURE_SCOPES = new Set([ + 'room-divide', + 'placing', + 'moving', + 'handle-drag', + 'mesh-editing', + 'reshaping', + 'box-select', + 'painting', + 'sculpting', + 'pointing', +]) + +/** + * The tool a key press arms, or null: the physical key and Shift, with no other + * modifier and no repeat. A Shift chord is off while a gesture holds Shift, so + * Shift+WASD keeps panning there. + */ +export function toolShortcutForKey( + event: Pick, +): ToolShortcutId | null { + if (event.metaKey || event.ctrlKey || event.altKey || event.repeat) return null + const entry = Object.entries(CHORDS).find( + ([, chord]) => chord.code === event.code && chord.shift === event.shiftKey, + ) + if (!entry) return null + if (event.shiftKey && SHIFT_GESTURE_SCOPES.has(useInteractionScope.getState().scope.kind)) + return null + return entry[0] as ToolShortcutId +} + +/** Whether WASD pan must leave this key to a tool shortcut (Shift+W/S/D). */ +export function claimsKeyboardPan( + event: Pick, +): boolean { + // A held key repeats: once claimed, the repeats stay claimed too. (Fields one by + // one: a DOM event's are getters a spread would drop.) + return ( + event.shiftKey && + toolShortcutForKey({ + code: event.code, + shiftKey: event.shiftKey, + metaKey: event.metaKey, + ctrlKey: event.ctrlKey, + altKey: event.altKey, + repeat: false, + }) !== null + ) +} + +/** Arm the tool `id` names from the keyboard, as its Build panel tile does, with the panel showing. */ +export function armToolShortcut(id: ToolShortcutId): void { + const editor = useEditor.getState() + editor.setPhase('building') + openSidebarPanel(['build']) + // A raw tool, as a tile click arms it: no preset carried over from earlier. + editor.setToolDefaults(id, null) + editor.armToolMode({ mode: 'build', tool: id }) +} diff --git a/packages/editor/src/lib/wall-draw-variant.test.ts b/packages/editor/src/lib/wall-draw-variant.test.ts index 73caf8129a..23ae513815 100644 --- a/packages/editor/src/lib/wall-draw-variant.test.ts +++ b/packages/editor/src/lib/wall-draw-variant.test.ts @@ -1,6 +1,7 @@ import { afterEach, describe, expect, test } from 'bun:test' import { emitter } from '@pascal-app/core' import useEditor from '../store/use-editor' +import { CONTINUATION_PROFILES } from './continuation' import { toolHudTitle } from './hud-title' import { getWallDrawVariant, @@ -23,9 +24,9 @@ describe('Rooms variants', () => { ]) }) - test('default to the chain that closes into a room', () => { - expect(getWallDrawVariant()).toBe('polygon') - expect(wallDrawVariantOf('unknown')).toBe('polygon') + test('default to Rectangle', () => { + expect(wallDrawVariantOf(CONTINUATION_PROFILES.wall.default)).toBe('rectangle') + expect(wallDrawVariantOf('unknown')).toBe('rectangle') }) test('picking one sets the wall tool drawing mode, and it sticks', () => { diff --git a/packages/editor/src/lib/wall-draw-variant.ts b/packages/editor/src/lib/wall-draw-variant.ts index 8f04a9e41d..e2bf7d6009 100644 --- a/packages/editor/src/lib/wall-draw-variant.ts +++ b/packages/editor/src/lib/wall-draw-variant.ts @@ -1,7 +1,15 @@ -import type { MessageDescriptor } from '@pascal-app/core' -import { emitter } from '@pascal-app/core' +import { + emitter, + type MessageDescriptor, + railingWallDefaults, + useScene, + type WallNode, +} from '@pascal-app/core' +import { useViewer } from '@pascal-app/viewer' +import { create } from 'zustand' import useEditor from '../store/use-editor' import type { ContinuationMode } from './continuation' +import { levelSeparatorLines } from './separator-lines' /** * How the wall tool draws, picked from the Build panel's Rooms group before @@ -67,7 +75,7 @@ export function getWallDrawVariantInfo(variant: WallDrawVariant): WallDrawVarian } export function wallDrawVariantOf(mode: ContinuationMode): WallDrawVariant { - return WALL_DRAW_VARIANTS.find((info) => info.mode === mode)?.id ?? 'polygon' + return WALL_DRAW_VARIANTS.find((info) => info.mode === mode)?.id ?? 'rectangle' } export function getWallDrawVariant(): WallDrawVariant { @@ -90,3 +98,95 @@ export function selectWallDrawVariant(variant: WallDrawVariant): void { if (editor.mode === 'build' && editor.tool === 'wall') emitter.emit('tool:cancel') editor.setContinuation('wall', mode) } + +/** + * What the wall tool draws in place of plain walls: invisible walls (room separators no wall + * stands on) or railings. + */ +export type WallLineKind = 'invisible' | 'railing' + +/** + * The Walls variant's kinds, its sub-row in the Build panel: a plain wall (room detection + * sides it exterior or interior), an invisible wall, or a railing. + */ +export type WallKind = 'standard' | WallLineKind + +export const WALL_KINDS: ReadonlyArray<{ id: WallKind; label: MessageDescriptor }> = [ + { + id: 'standard', + label: /* i18n */ { id: 'editor.lib.wallDrawVariant.kind.standard', message: 'Standard' }, + }, + { + id: 'invisible', + label: /* i18n */ { id: 'editor.lib.wallDrawVariant.kind.invisible', message: 'Invisible' }, + }, + { + id: 'railing', + label: /* i18n */ { id: 'editor.lib.wallDrawVariant.kind.railing', message: 'Railing' }, + }, +] + +/** The line an invisible wall's draft is drawn at, metres. */ +export const INVISIBLE_WALL_DRAFT_THICKNESS = 0.01 + +// Session-only, so it lives beside the persisted editor store, not in it. +const useWallLineKindStore = create<{ lineKind: WallLineKind | null }>(() => ({ + lineKind: null, +})) + +export function getWallLineKind(): WallLineKind | null { + return useWallLineKindStore.getState().lineKind +} + +/** The kind the Walls variant draws, for the Build panel's sub-row. */ +export function useWallKind(): WallKind { + return useWallLineKindStore((state) => state.lineKind ?? 'standard') +} + +/** + * Pick what the Walls variant draws, for this session: it lasts while the wall tool draws + * Walls (`subscribeWallKindReset`). Switching while the tool is armed drops the in-flight + * draft, so a half-drawn wall never lands as another kind. + */ +export function selectWallKind(kind: WallKind): void { + const lineKind = kind === 'standard' ? null : kind + if (getWallLineKind() === lineKind) return + const editor = useEditor.getState() + if (editor.mode === 'build' && editor.tool === 'wall') emitter.emit('tool:cancel') + useWallLineKindStore.setState({ lineKind }) +} + +/** Back to plain walls once the wall tool is left or draws another variant. */ +export function subscribeWallKindReset(): () => void { + return useEditor.subscribe((state) => { + if ( + state.mode === 'build' && + state.tool === 'wall' && + state.getContinuation('wall') === 'single' + ) + return + if (getWallLineKind() !== null) useWallLineKindStore.setState({ lineKind: null }) + }) +} + +/** + * What an invisible-wall draft snaps to besides walls: the current level's + * invisible walls, as lines (`separatorWallLine`), so a new one closes onto + * their ends and bodies — its old corner. Nothing while walls or railings draw. + */ +export function invisibleWallDraftSnapLines(): WallNode[] { + if (getWallLineKind() !== 'invisible') return [] + return levelSeparatorLines(useScene.getState().nodes, useViewer.getState().selection.levelId) +} + +/** + * The thickness the wall tool's drafts draw at: an invisible wall's line, a railing's, a + * placed preset's (`toolDefaults.wall`), else `fallback` (a plain wall). + */ +export function useWallDraftThickness(fallback: number): number { + const lineKind = useWallLineKindStore((state) => state.lineKind) + const seeded = useEditor((state) => state.toolDefaults.wall?.thickness) + if (lineKind === 'invisible') return INVISIBLE_WALL_DRAFT_THICKNESS + if (lineKind === 'railing') return railingWallDefaults().thickness + return typeof seeded === 'number' ? seeded : fallback +} diff --git a/packages/editor/src/lib/wall-nudge.test.ts b/packages/editor/src/lib/wall-nudge.test.ts new file mode 100644 index 0000000000..bf2882cf6b --- /dev/null +++ b/packages/editor/src/lib/wall-nudge.test.ts @@ -0,0 +1,44 @@ +import { describe, expect, test } from 'bun:test' +import { WallNode } from '@pascal-app/core' +import { isWallNudgeKey, WALL_NUDGE_IMPERIAL, wallNudgeDistance } from './wall-nudge' + +const outside = { frontSide: 'exterior', backSide: 'interior' } as const +const wall = (id: string, start: [number, number], end: [number, number]) => + WallNode.parse({ id: `wall_${id}`, start, end, thickness: 0.15, ...outside }) + +describe('wallNudgeDistance', () => { + const moving = wall('moving', [5, 0.3], [8, 0.3]) + + test('an arrow across the wall moves it one inch that way', () => { + const down = wallNudgeDistance(moving, [0, 1], [moving], WALL_NUDGE_IMPERIAL) + const up = wallNudgeDistance(moving, [0, -1], [moving], WALL_NUDGE_IMPERIAL) + expect(down).not.toBeNull() + expect(up).not.toBeNull() + // Signed along the move axis: both land 1 in from where the wall was, opposite ways. + const move = (nudge: NonNullable) => nudge.axis[1] * nudge.distance + expect(move(down!)).toBeCloseTo(0.0254, 10) + expect(move(up!)).toBeCloseTo(-0.0254, 10) + }) + + test('an arrow along the wall does nothing', () => { + expect(wallNudgeDistance(moving, [1, 0], [moving], WALL_NUDGE_IMPERIAL)).toBeNull() + expect(wallNudgeDistance(moving, [-1, 0], [moving], WALL_NUDGE_IMPERIAL)).toBeNull() + }) + + test('stops flush with a parallel outside wall it would pass', () => { + const top = wall('top', [0, 0.29], [4, 0.29]) + const nudge = wallNudgeDistance(moving, [0, -1], [moving, top], WALL_NUDGE_IMPERIAL)! + expect(nudge.axis[1] * nudge.distance).toBeCloseTo(-0.01, 10) + }) + + test('a turned plan still picks the arrow nearest across the wall', () => { + const turned = [Math.SQRT1_2, Math.SQRT1_2] as [number, number] + const nudge = wallNudgeDistance(moving, turned, [moving], WALL_NUDGE_IMPERIAL)! + expect(nudge.axis[1] * nudge.distance).toBeCloseTo(0.0254, 10) + }) +}) + +test('only the four bare arrows nudge', () => { + expect(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].every(isWallNudgeKey)).toBe(true) + expect(isWallNudgeKey('w')).toBe(false) +}) diff --git a/packages/editor/src/lib/wall-nudge.ts b/packages/editor/src/lib/wall-nudge.ts new file mode 100644 index 0000000000..f73afdc27c --- /dev/null +++ b/packages/editor/src/lib/wall-nudge.ts @@ -0,0 +1,131 @@ +/** + * Arrow keys nudge the selected wall square to itself in the floor plan: one + * inch a press (a centimetre in metric), or less when a parallel wall it lines + * up with comes first (`wall-parallel-snap`), so it stops flush. The arrow's + * direction on screen picks the way; an arrow along the wall does nothing. + * The nudge is the side arrows' push (`commitRoomPush`), so joined walls + * follow, jogs and overlaps come out as when the wall is pushed, and each + * press is one undo step. + */ + +import { + type AnyNodeId, + getPerpendicularWallMoveAxis, + useScene, + type WallNode, + type WallPlanPoint, +} from '@pascal-app/core' +import { useViewer } from '@pascal-app/viewer' +import { commitRoomPush } from './room-handle-drag' +import { levelSeparatorLines, separatorWallLine } from './separator-lines' +import { nudgeWallPosition, wallParallelTargets } from './wall-parallel-snap' + +/** One nudge in feet and inches, in metres. */ +export const WALL_NUDGE_IMPERIAL = 0.0254 +/** One nudge in metric, in metres. */ +export const WALL_NUDGE_METRIC = 0.01 + +const ARROW_SCREEN_DIRECTIONS: Record = { + ArrowUp: [0, -1], + ArrowDown: [0, 1], + ArrowLeft: [-1, 0], + ArrowRight: [1, 0], +} + +// An arrow within about 67° of the wall's own direction runs along it. +const MIN_ACROSS = 0.4 + +/** True for the four bare arrow keys. */ +export function isWallNudgeKey(key: string): boolean { + return key in ARROW_SCREEN_DIRECTIONS +} + +/** + * The plan direction an arrow points on screen: the shown floor plan's scene + * transform, turned or not, maps it back. Null when no floor plan is shown. + */ +export function floorplanArrowDirection(key: string): WallPlanPoint | null { + const screen = ARROW_SCREEN_DIRECTIONS[key] + if (!screen || typeof document === 'undefined') return null + const scenes = document.querySelectorAll('[data-floorplan-scene]') + for (const scene of scenes) { + const rect = scene.ownerSVGElement?.getBoundingClientRect() + const ctm = scene.getScreenCTM() + if (!ctm || !rect || rect.width === 0 || rect.height === 0) continue + const inverse = ctm.inverse() + const origin = new DOMPoint(0, 0).matrixTransform(inverse) + const tip = new DOMPoint(screen[0], screen[1]).matrixTransform(inverse) + const dx = tip.x - origin.x + const dz = tip.y - origin.y + const length = Math.hypot(dx, dz) + if (length > 1e-12) return [dx / length, dz / length] + } + return null +} + +/** + * How far (signed, along the wall's move axis) one nudge of `wall` in plan + * direction `direction` goes; null when the direction runs along the wall. + */ +export function wallNudgeDistance( + wall: WallNode, + direction: WallPlanPoint, + walls: readonly WallNode[], + step: number, +): { axis: WallPlanPoint; distance: number } | null { + const axis = getPerpendicularWallMoveAxis(wall.start, wall.end) + if (!axis) return null + const across = direction[0] * axis[0] + direction[1] * axis[1] + if (Math.abs(across) < MIN_ACROSS) return null + const position = wall.start[0] * axis[0] + wall.start[1] * axis[1] + const end = nudgeWallPosition( + wallParallelTargets(wall, axis, walls), + position, + Math.sign(across) * step, + ) + return { axis, distance: end - position } +} + +/** + * Nudge the one selected wall for an arrow key while the floor plan is shown. + * An invisible wall nudges the same way, as a line: it stops flush with the + * walls and the other invisible walls, and those joined to it follow. + * Returns true when the key was used. + */ +export function nudgeSelectedWall(key: string): boolean { + const { selectedIds } = useViewer.getState().selection + if (selectedIds.length !== 1) return false + const nodes = useScene.getState().nodes + const selected = nodes[selectedIds[0] as AnyNodeId] + if (selected?.type !== 'wall' && selected?.type !== 'separator') return false + const direction = floorplanArrowDirection(key) + if (!direction) return false + + const walls = Object.values(nodes).filter( + (entry): entry is WallNode => entry?.type === 'wall' && entry.parentId === selected.parentId, + ) + const step = useViewer.getState().unit === 'imperial' ? WALL_NUDGE_IMPERIAL : WALL_NUDGE_METRIC + const nudge = + selected.type === 'wall' + ? wallNudgeDistance(selected, direction, walls, step) + : wallNudgeDistance( + separatorWallLine(selected), + direction, + [...walls, ...levelSeparatorLines(nodes, selected.parentId, new Set([selected.id]))], + step, + ) + if (!nudge) return false + commitRoomPush( + selected.type === 'wall' + ? { wallId: selected.id, t0: 0, t1: 1 } + : { + wallId: selected.id, + t0: 0, + t1: 1, + separators: [{ separatorId: selected.id, t0: 0, t1: 1 }], + }, + nudge.axis, + nudge.distance, + ) + return true +} diff --git a/packages/editor/src/lib/wall-parallel-snap.test.ts b/packages/editor/src/lib/wall-parallel-snap.test.ts new file mode 100644 index 0000000000..464c6e7c37 --- /dev/null +++ b/packages/editor/src/lib/wall-parallel-snap.test.ts @@ -0,0 +1,83 @@ +import { describe, expect, test } from 'bun:test' +import { WallNode } from '@pascal-app/core' +import { + nearestWallParallelTarget, + nudgeWallPosition, + WALL_PARALLEL_SNAP_RADIUS, + wallParallelTargets, +} from './wall-parallel-snap' + +const wall = (id: string, start: [number, number], end: [number, number], extra = {}) => + WallNode.parse({ id: `wall_${id}`, start, end, thickness: 0.15, ...extra }) +const outside = { frontSide: 'exterior', backSide: 'interior' } as const +const DOWN: [number, number] = [0, 1] + +describe('wallParallelTargets', () => { + test('an outside wall lines up with a parallel outside wall, not a partition', () => { + const moving = wall('moving', [5, 0.3], [8, 0.3], outside) + const top = wall('top', [0, 0.07], [4, 0.07], outside) + const partition = wall('partition', [1, 0.2], [3, 0.2]) + const side = wall('side', [4, 0.07], [4, 4], outside) + + const targets = wallParallelTargets(moving, DOWN, [moving, top, partition, side]) + + expect(targets.map((target) => target.wallId)).toEqual(['wall_top']) + expect(targets).toHaveLength(1) + expect(targets[0]!.position).toBeCloseTo(0.07) + // The guide runs along both walls, on the top wall's outdoor face: frontSide + // is the left-normal side, +z for a wall running +x. + const [from, to] = [targets[0]!.from, targets[0]!.to] + expect([from[0], to[0]]).toEqual([0, 8]) + expect(from[1]).toBeCloseTo(0.07 + 0.075) + expect(to[1]).toBeCloseTo(0.07 + 0.075) + }) + + test('a partition lines up with every parallel wall', () => { + const moving = wall('moving', [1, 2], [3, 2]) + const top = wall('top', [0, 0], [4, 0], outside) + const other = wall('other', [1, 3], [3, 3]) + const ids = wallParallelTargets(moving, DOWN, [moving, top, other]).map((t) => t.wallId) + expect(new Set(ids)).toEqual(new Set(['wall_top', 'wall_other'])) + }) + + test('walls of different thickness line up face to face and centre to centre', () => { + const moving = wall('moving', [5, 1], [8, 1], { ...outside, thickness: 0.2 }) + const top = wall('top', [0, 0], [4, 0], { ...outside, thickness: 0.1 }) + const positions = wallParallelTargets(moving, DOWN, [top]).map((t) => t.position) + // Faces at ±0.05 against ±0.1, and the centres. + expect(positions.map((p) => Number(p.toFixed(3))).sort()).toEqual([-0.05, 0, 0.05]) + }) + + test('a reversed or justified wall lines up by its faces', () => { + const moving = wall('moving', [8, 1], [5, 1], { ...outside, justification: 'a' }) + const top = wall('top', [0, 0], [4, 0], outside) + const positions = wallParallelTargets(moving, DOWN, [top]).map((t) => t.position) + // Justified 'a' on a wall running -x puts its body on the -z side of its + // line, so its faces and centre all line up with the top wall's when that + // line sits half a thickness below it. + expect(positions.map((p) => Number(p.toFixed(3)))).toEqual([0.075]) + }) +}) + +describe('nearestWallParallelTarget', () => { + test('snaps within the radius and lets go past it', () => { + const moving = wall('moving', [5, 0.3], [8, 0.3], outside) + const targets = wallParallelTargets(moving, DOWN, [wall('top', [0, 0], [4, 0], outside)]) + expect(nearestWallParallelTarget(targets, 0.1)?.position).toBeCloseTo(0) + expect(nearestWallParallelTarget(targets, WALL_PARALLEL_SNAP_RADIUS + 0.01)).toBeNull() + }) +}) + +describe('nudgeWallPosition', () => { + const moving = wall('moving', [5, 0.3], [8, 0.3], outside) + const targets = wallParallelTargets(moving, DOWN, [wall('top', [0, 0.29], [4, 0.29], outside)]) + + test('stops on a line-up it would pass', () => { + expect(nudgeWallPosition(targets, 0.3, -0.0254)).toBeCloseTo(0.29) + }) + + test('otherwise moves the whole step', () => { + expect(nudgeWallPosition(targets, 0.3, 0.0254)).toBeCloseTo(0.3254) + expect(nudgeWallPosition(targets, 0.29, -0.0254)).toBeCloseTo(0.2646) + }) +}) diff --git a/packages/editor/src/lib/wall-parallel-snap.ts b/packages/editor/src/lib/wall-parallel-snap.ts new file mode 100644 index 0000000000..3ee9434d13 --- /dev/null +++ b/packages/editor/src/lib/wall-parallel-snap.ts @@ -0,0 +1,176 @@ +/** + * Lines a wall that is moving sideways up with the parallel walls around it: + * a face onto the face on the same side of another wall, or its body centre + * onto theirs. An outside wall broken up by partitions moves one piece at a + * time, so each piece can be pulled back flush with the rest of the outside. + * + * A wall with an outdoor face lines up only with other outside walls; any + * other wall lines up with every wall on its level. The 2D and 3D wall moves + * snap through here, and the arrow-key nudge stops on these positions. + */ + +import { + getWallFaceOffsets, + isCurvedWall, + type WallNode, + type WallPlanPoint, +} from '@pascal-app/core' +import useAlignmentGuides from '../store/use-alignment-guides' + +/** How near (metres) a moving wall comes to lining up before it snaps there. */ +export const WALL_PARALLEL_SNAP_RADIUS = 0.15 + +// Walls within about 1° of each other count as parallel. +const PARALLEL_TOLERANCE = Math.sin(Math.PI / 180) +const SAME_POSITION = 1e-6 + +type MovingWall = Pick< + WallNode, + 'id' | 'start' | 'end' | 'thickness' | 'justification' | 'frontSide' | 'backSide' +> & + Partial> + +/** + * A position where the moving wall lines up with another: `position` is where + * its reference line sits along the move axis, `from` → `to` the shared face + * or centre line, drawn along both walls. + */ +export type WallParallelTarget = { + position: number + wallId: string + from: WallPlanPoint + to: WallPlanPoint +} + +function isOutsideWall(wall: Pick): boolean { + return wall.frontSide === 'exterior' || wall.backSide === 'exterior' +} + +function direction(wall: Pick): WallPlanPoint | null { + const dx = wall.end[0] - wall.start[0] + const dz = wall.end[1] - wall.start[1] + const length = Math.hypot(dx, dz) + return length > 1e-9 ? [dx / length, dz / length] : null +} + +const dot = (a: readonly [number, number], b: readonly [number, number]) => + a[0] * b[0] + a[1] * b[1] + +// Which way the wall's left normal (-dy, dx) runs along `axis`. +function normalSign(dir: WallPlanPoint, axis: WallPlanPoint): number { + return Math.sign(dot([-dir[1], dir[0]], axis)) || 1 +} + +/** + * The wall's faces and body centre along `axis`, relative to its reference + * line: the face on the axis's positive side, the other face, the centre. + */ +function sidePlanes(wall: MovingWall, dir: WallPlanPoint, axis: WallPlanPoint) { + const sign = normalSign(dir, axis) + const { a, b } = getWallFaceOffsets(wall) + const high = Math.max(a * sign, b * sign) + const low = Math.min(a * sign, b * sign) + return [high, low, (high + low) / 2] as const +} + +/** + * The order to try a wall's planes in, so the guide of planes that coincide + * is drawn on its outdoor face (frontSide is the left-normal side), else on + * its centre. + */ +function planeOrder(wall: MovingWall, dir: WallPlanPoint, axis: WallPlanPoint): number[] { + const outdoor = wall.frontSide === 'exterior' ? 1 : wall.backSide === 'exterior' ? -1 : 0 + const outward = outdoor * normalSign(dir, axis) + return outward > 0 ? [0, 1, 2] : outward < 0 ? [1, 0, 2] : [2, 0, 1] +} + +/** + * Every position along `axis` (a unit vector square to the wall) where `wall` + * lines up with a parallel wall in `walls`. + */ +export function wallParallelTargets( + wall: MovingWall, + axis: WallPlanPoint, + walls: readonly WallNode[], +): WallParallelTarget[] { + const dir = direction(wall) + if (!dir || isCurvedWall(wall)) return [] + const own = sidePlanes(wall, dir, axis) + const outsideOnly = isOutsideWall(wall) + const ownSpan = [dot(wall.start, dir), dot(wall.end, dir)] + const targets: WallParallelTarget[] = [] + + for (const other of walls) { + if (other.id === wall.id || isCurvedWall(other)) continue + if (outsideOnly && !isOutsideWall(other)) continue + const otherDir = direction(other) + if (!otherDir || Math.abs(otherDir[0] * dir[1] - otherDir[1] * dir[0]) > PARALLEL_TOLERANCE) { + continue + } + const line = dot(other.start, axis) + const planes = sidePlanes(other, otherDir, axis) + const along = [...ownSpan, dot(other.start, dir), dot(other.end, dir)] + const lo = Math.min(...along) + const hi = Math.max(...along) + const seen: number[] = [] + for (const index of planeOrder(other, otherDir, axis)) { + const shared = line + planes[index]! + const position = shared - own[index]! + if (seen.some((value) => Math.abs(value - position) < SAME_POSITION)) continue + seen.push(position) + targets.push({ + position, + wallId: other.id, + from: [dir[0] * lo + axis[0] * shared, dir[1] * lo + axis[1] * shared], + to: [dir[0] * hi + axis[0] * shared, dir[1] * hi + axis[1] * shared], + }) + } + } + return targets +} + +/** The target nearest `position`, if one is within `radius`. */ +export function nearestWallParallelTarget( + targets: readonly WallParallelTarget[], + position: number, + radius = WALL_PARALLEL_SNAP_RADIUS, +): WallParallelTarget | null { + let best: WallParallelTarget | null = null + for (const target of targets) { + const gap = Math.abs(target.position - position) + if (gap > radius) continue + if (!best || gap < Math.abs(best.position - position)) best = target + } + return best +} + +/** + * Where a nudge of `step` (signed, along the axis) from `position` ends: the + * full step, or the first line-up it passes on the way. + */ +export function nudgeWallPosition( + targets: readonly WallParallelTarget[], + position: number, + step: number, +): number { + let end = position + step + for (const target of targets) { + const travel = (target.position - position) * Math.sign(step) + if (travel > SAME_POSITION && travel < Math.abs(step) - SAME_POSITION) { + if (Math.abs(target.position - position) < Math.abs(end - position)) end = target.position + } + } + return end +} + +/** Show the line a moving wall has snapped onto (null clears it). */ +export function publishWallParallelGuide(target: WallParallelTarget | null): void { + if (!target) { + useAlignmentGuides.getState().clear() + return + } + useAlignmentGuides.getState().setDraft({ + lines: [{ kind: 'alignment', from: target.from, to: target.to }], + intersections: [], + }) +} diff --git a/packages/editor/src/lib/wall-placement-pointer.test.ts b/packages/editor/src/lib/wall-placement-pointer.test.ts index e8c1bc1083..a1554f60cc 100644 --- a/packages/editor/src/lib/wall-placement-pointer.test.ts +++ b/packages/editor/src/lib/wall-placement-pointer.test.ts @@ -4,6 +4,7 @@ import { createWallPointerTracker, wallPointerInParent, wallSideAtPointer, + wallSideOfPlanPoint, } from './wall-placement-pointer' test('keeps the grab offset across a pointer gap on the original face', () => { @@ -40,3 +41,25 @@ test('reads the pointer in the rotated wall parent and identifies its face', () expect(local[1]).toBeCloseTo(3) expect(wallSideAtPointer(local)).toBe('back') }) + +test('a plan point reads the wall face it is on, as a 3D hover does', () => { + // Along +X the frame's +Z (front) is the plan's +Z side. + const wall = { + start: [0, 0] as [number, number], + end: [4, 0] as [number, number], + thickness: 0.2, + } + expect(wallSideOfPlanPoint(wall, [2, 0.3])).toBe('front') + expect(wallSideOfPlanPoint(wall, [2, -0.3])).toBe('back') + // Drawn the other way, the same point is on its back. + expect( + wallSideOfPlanPoint( + { ...wall, start: [4, 0] as [number, number], end: [0, 0] as [number, number] }, + [2, 0.3], + ), + ).toBe('back') + // A justified wall splits at its body's middle, not its reference line. + const justified = { ...wall, justification: 'a' as const } + expect(wallSideOfPlanPoint(justified, [2, 0.05])).toBe('back') + expect(wallSideOfPlanPoint(justified, [2, 0.15])).toBe('front') +}) diff --git a/packages/editor/src/lib/wall-placement-pointer.ts b/packages/editor/src/lib/wall-placement-pointer.ts index 06d288bbb8..9fdffe4e66 100644 --- a/packages/editor/src/lib/wall-placement-pointer.ts +++ b/packages/editor/src/lib/wall-placement-pointer.ts @@ -1,3 +1,4 @@ +import { getWallBodyCenterOffset, type WallNode } from '@pascal-app/core' import { type Object3D, Vector3 } from 'three' type WallSide = 'front' | 'back' @@ -55,3 +56,20 @@ export function wallPointerInParent( export function wallSideAtPointer(point: readonly number[]): WallSide { return point[2]! >= 0 ? 'front' : 'back' } + +/** + * The face of a straight wall a plan point is on, as a 3D hover reports it: `front` is the wall + * frame's +Z (the plan side `(-dz, dx)` of start → end), measured from the wall body's centre so a justified + * wall splits at its middle. The plan's stand-in for the hovered face's normal. + */ +export function wallSideOfPlanPoint( + wall: Pick, + point: readonly [number, number], +): WallSide { + const dx = wall.end[0] - wall.start[0] + const dz = wall.end[1] - wall.start[1] + const length = Math.hypot(dx, dz) + if (length < 1e-9) return 'front' + const across = ((point[0] - wall.start[0]) * -dz + (point[1] - wall.start[1]) * dx) / length + return across >= getWallBodyCenterOffset(wall) ? 'front' : 'back' +} diff --git a/packages/editor/src/lib/wall-pull.test.ts b/packages/editor/src/lib/wall-pull.test.ts new file mode 100644 index 0000000000..a657a17eda --- /dev/null +++ b/packages/editor/src/lib/wall-pull.test.ts @@ -0,0 +1,245 @@ +import { afterEach, beforeEach, describe, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + detectSpacesForLevel, + getWallAssemblyPreset, + LevelNode as LevelSchema, + nodeRegistry, + registerNode, + useScene, + type WallNode, + WallNode as WallSchema, + wallAssemblyPatch, + wallClosesRoom, +} from '@pascal-app/core' +import { useViewer } from '@pascal-app/viewer' +import { createWallOnCurrentLevel } from '../components/tools/wall/wall-drafting' +import type { WallPlanPoint } from '../components/tools/wall/wall-snap-geometry' +import useEditor from '../store/use-editor' +import { selectWallDrawVariant } from './wall-draw-variant' +import { + endWallPullRun, + startWallPull, + useWallPullRun, + wallDraftIsRun, + wallPullSeed, + wallPullTypePatch, +} from './wall-pull' +import { isWallRunFree, snapWallRunDraftPoint, wallRunDirection } from './wall-run-snap' + +// `updateNodes` batches its dirty-marking through requestAnimationFrame, +// which bun's test runtime doesn't provide. +if (typeof globalThis.requestAnimationFrame === 'undefined') { + globalThis.requestAnimationFrame = ((callback: FrameRequestCallback) => + setTimeout(() => callback(0), 0)) as unknown as typeof requestAnimationFrame + globalThis.cancelAnimationFrame = ((id: number) => + clearTimeout(id)) as typeof cancelAnimationFrame +} + +const LEVEL_ID = 'level_pull' as AnyNodeId + +function levelWalls(): WallNode[] { + return Object.values(useScene.getState().nodes).filter( + (node): node is WallNode => node?.type === 'wall' && node.parentId === LEVEL_ID, + ) +} + +/** A lone stucco wall running east to the origin, 3.1 m tall on a 2.7 m storey, painted. */ +function seedSourceWall(): WallNode { + const preset = getWallAssemblyPreset('exterior-2x6-stucco') + if (!preset) throw new Error('Expected the stucco preset') + const source = WallSchema.parse({ + id: 'wall_source', + name: 'Source', + parentId: LEVEL_ID, + start: [-4, 0], + end: [0, 0], + height: 3.1, + ...wallAssemblyPatch(structuredClone(preset.assembly)), + slots: { a: 'library:paint-sage', b: 'library:stucco-white' }, + skirting: { enabled: true, sides: 'both', height: 0.12, proud: 0.02, profile: 'flat' }, + }) + const level = LevelSchema.parse({ + id: LEVEL_ID, + level: 0, + height: 2.7, + children: [source.id], + }) + useScene.setState({ + nodes: { [level.id]: level as AnyNode, [source.id]: source as AnyNode }, + rootNodeIds: [level.id], + dirtyNodes: new Set(), + collections: {}, + } as never) + return source +} + +describe('pulling the next wall from a wall end', () => { + let restoreRegistry: (() => void) | undefined + let previousEditor: Partial> + + beforeEach(() => { + previousEditor = { + toolDefaults: useEditor.getState().toolDefaults, + continuationByContext: useEditor.getState().continuationByContext, + } + // The wall's snap profile makes the armed wall tool the 'wall' snapping + // context (grid lengths), as in the app. + restoreRegistry = nodeRegistry._snapshot() + registerNode({ + kind: 'wall', + schemaVersion: 10, + schema: WallSchema, + category: 'structure', + snapProfile: 'structural', + defaults: () => WallSchema.parse({ start: [0, 0], end: [1, 0] }), + capabilities: {}, + } as never) + useEditor.getState().setContinuation('wall', 'room') + useEditor.getState().setSnappingMode('wall', 'grid') + useEditor.getState().armToolMode({ mode: 'select' }) + useViewer.setState({ + selection: { + buildingId: null, + levelId: LEVEL_ID, + zoneId: null, + selectedIds: ['wall_source'], + }, + } as never) + seedSourceWall() + useScene.temporal.getState().clear() + useScene.temporal.getState().resume() + }) + + afterEach(() => { + endWallPullRun() + restoreRegistry?.() + restoreRegistry = undefined + useEditor.setState(previousEditor as never) + useEditor.getState().armToolMode({ mode: 'select' }) + }) + + test('the pull arms the Walls run at the end, with the pulled wall’s type', () => { + const source = useScene.getState().nodes['wall_source' as AnyNodeId] as WallNode + expect(startWallPull({ wallId: source.id, endpoint: 'end', origin: '3d' })).toBe(true) + + const run = useWallPullRun.getState().run + expect(run).toMatchObject({ + sourceWallId: source.id, + levelId: LEVEL_ID, + runStart: [0, 0], + start: [0, 0], + origin: '3d', + dragging: true, + }) + expect(run?.reference[0]).toBeCloseTo(1, 9) + expect(run?.reference[1]).toBeCloseTo(0, 9) + const editor = useEditor.getState() + expect(editor.mode).toBe('build') + expect(editor.tool).toBe('wall') + expect(editor.getContinuation('wall')).toBe('single') + expect(useViewer.getState().selection.selectedIds).toEqual([]) + + // The pulled wall's construction, finishes and own height, not the Build + // panel's types. + const pulled = createWallOnCurrentLevel([0, 0], [3, 0]) + expect(pulled?.assembly).toEqual(source.assembly) + expect(pulled?.thickness).toBe(source.thickness) + expect(pulled?.height).toBe(3.1) + expect(pulled?.slots).toEqual(source.slots) + expect(pulled?.skirting).toEqual(source.skirting) + expect(pulled?.start).toEqual([0, 0]) + + // Ending puts back the Rooms shape and the wall tool defaults, in Select. + endWallPullRun() + expect(useWallPullRun.getState().run).toBeNull() + expect(useEditor.getState().mode).toBe('select') + expect(useEditor.getState().getContinuation('wall')).toBe('room') + expect(useEditor.getState().toolDefaults.wall).toBeUndefined() + }) + + test('the type patch keeps a plain wall plain and a storey-high wall on the storey', () => { + const plain = WallSchema.parse({ start: [0, 0], end: [2, 0], height: 2.7 }) + expect(wallPullTypePatch(plain, 2.7)).toEqual({ thickness: plain.thickness ?? 0.1 }) + const pulledFromStart = wallPullSeed(plain, 'start') + expect(pulledFromStart?.start).toEqual([0, 0]) + expect(pulledFromStart?.reference[0]).toBeCloseTo(-1, 9) + }) + + test('closing the run back to its start forms a room, one undo step per wall', () => { + startWallPull({ wallId: 'wall_source', endpoint: 'end', origin: '3d' }) + expect(isWallRunFree()).toBe(false) + const run = useWallPullRun.getState().run! + // The run as the tool drafts it: each wall from the last one's end, + // square to it — the pulled wall first. + let start = run.start + let reference: WallPlanPoint | null = run.reference + const place = (cursor: WallPlanPoint) => { + const snapped = snapWallRunDraftPoint({ + point: cursor, + start, + runStart: run.runStart, + reference, + walls: levelWalls(), + free: isWallRunFree(), + }) + const before = useScene.temporal.getState().pastStates.length + const wall = createWallOnCurrentLevel(start, snapped.point)! + expect(useScene.temporal.getState().pastStates.length).toBe(before + 1) + start = wall.end + reference = wallRunDirection(wall.start, wall.end) + return { wall, snapped } + } + + // Straight on (6° off) to a grid length; square up; back west until the + // run's start lines up; then onto the start itself. + const first = place([5.1, 0.45]) + expect(first.snapped.lock).toBe('straight') + expect(first.wall.end).toEqual([5, 0]) + const second = place([5.25, 3.9]) + expect(second.snapped.lock).toBe('square') + expect(second.wall.end).toEqual([5, 4]) + expect(wallClosesRoom(levelWalls(), second.wall)).toBe(false) + const third = place([0.1, 4.05]) + expect(third.snapped.snap).toBe('alignment') + expect(third.wall.end).toEqual([0, 4]) + const last = place([0.12, 0.2]) + expect(last.snapped.snap).toBe('endpoint') + expect(last.wall.end).toEqual([0, 0]) + + const walls = levelWalls() + expect(wallClosesRoom(walls, last.wall)).toBe(true) + const rooms = detectSpacesForLevel(LEVEL_ID, walls).spaces.filter((space) => !space.isExterior) + expect(rooms).toHaveLength(1) + const xs = rooms[0]!.polygon.map((point) => point[0]) + const zs = rooms[0]!.polygon.map((point) => point[1]) + expect([Math.min(...xs), Math.max(...xs), Math.min(...zs), Math.max(...zs)]).toEqual([ + 0, 5, 0, 4, + ]) + }) + + // The Walls variant had become a run that chained every wall from the last; it draws one wall + // per two clicks and stops. A Polygon room's sides and a pulled run still chain. + test('a Walls segment is one wall; Polygon sides and a pulled run chain', () => { + selectWallDrawVariant('walls') + expect(wallDraftIsRun()).toBe(false) + selectWallDrawVariant('polygon') + expect(wallDraftIsRun()).toBe(true) + startWallPull({ wallId: 'wall_source', endpoint: 'end', origin: '2d' }) + expect(useEditor.getState().getContinuation('wall')).toBe('single') + expect(wallDraftIsRun()).toBe(true) + endWallPullRun() + selectWallDrawVariant('walls') + expect(wallDraftIsRun()).toBe(false) + }) + + test('leaving the wall tool ends the run without leaving Select behind', () => { + startWallPull({ wallId: 'wall_source', endpoint: 'start', origin: '2d' }) + expect(useWallPullRun.getState().run?.start).toEqual([-4, 0]) + useEditor.getState().armToolMode({ mode: 'build', tool: 'slab' }) + expect(useWallPullRun.getState().run).toBeNull() + expect(useEditor.getState().tool).toBe('slab') + expect(useEditor.getState().getContinuation('wall')).toBe('room') + }) +}) diff --git a/packages/editor/src/lib/wall-pull.ts b/packages/editor/src/lib/wall-pull.ts new file mode 100644 index 0000000000..6db060fc87 --- /dev/null +++ b/packages/editor/src/lib/wall-pull.ts @@ -0,0 +1,209 @@ +/** + * "Pull to continue": a selected wall's end carries a grip that, dragged, + * draws the next wall from that end. + * + * Pressing the grip arms the wall tool on Walls, as a run (each wall starts + * where the last ended, `wallDraftIsRun`) already started at the pulled end, + * with the pulled wall's type: its assembly, thickness, height and finishes. + * The drag shows the next wall; letting go places it, and the run carries on + * from its far end, click by click, until Esc, a double-click, closing the loop + * or teeing into a wall. Then the editor is back in Select, with the Rooms + * shape and wall tool settings the user had. + * + * Its walls snap as every line run does once started (`wall-run-snap.ts`): + * square to the wall before — the pulled one, for the first — or the house's + * axes, 15° steps past that, Alt free. The 3D wall tool and the floor plan each + * seed their run from this store, the way they share the plain run: whichever + * view owns the input places the walls. + */ + +import { + type AnyNodeId, + getWallCurveFrameAt, + getWallThickness, + useScene, + WALL_CONSTRUCTION_FIELDS, + type WallNode, + type WallPlanPoint, + wallFollowsStorey, +} from '@pascal-app/core' +import { useViewer } from '@pascal-app/viewer' +import { create } from 'zustand' +import useEditor from '../store/use-editor' +import type { ContinuationMode } from './continuation' +import { getWallDrawVariant, selectWallDrawVariant } from './wall-draw-variant' +import { publishWallRunFeedback } from './wall-run-snap' + +/** The floor plan's affordance id for a wall end's pull grip (a `move-arrow`, variant `pull`). */ +export const WALL_PULL_AFFORDANCE = 'wall-pull' + +/** What a pull grip carries: the wall, and which of its ends it pulls from. */ +export type WallPullGripPayload = { wallId: string; endpoint: 'start' | 'end' } + +/** The grip's tooltip, in both views. */ +export const WALL_PULL_GRIP_TITLE = 'Drag to draw the next wall' + +export type WallPullRun = { + /** Bumped per pull, so each view seeds its draft from it once. */ + seq: number + sourceWallId: AnyNodeId + levelId: AnyNodeId + /** The pulled end, where the run started: its walls can close square back to it. */ + runStart: WallPlanPoint + /** Where the first wall starts: the pulled end. */ + start: WallPlanPoint + /** Unit direction of the pulled wall, pointing out of the pulled end. */ + reference: WallPlanPoint + /** The view the grip was pulled in; the floor plan drafts a 3D pull only beside it. */ + origin: '2d' | '3d' + /** From the press on the grip until it is let go. */ + dragging: boolean +} + +type WallPullState = { run: WallPullRun | null } + +/** The open pull run, if any. */ +export const useWallPullRun = create(() => ({ run: null })) + +/** + * Whether the wall tool's open segment belongs to a run: a Polygon room's sides, or the walls + * pulled from a wall end. A run's segment holds square to the one before it (`wall-run-snap.ts`) + * and the next chains from its end. Otherwise it is a Walls segment: one wall, locked to 15° rays + * from its start, and the tool stops once it is placed. + */ +export function wallDraftIsRun(): boolean { + return getWallDrawVariant() !== 'walls' || useWallPullRun.getState().run !== null +} + +/** + * The wall tool defaults that draw walls of `wall`'s type (core + * `WALL_CONSTRUCTION_FIELDS`; position, support and paint regions stay with + * each wall): its assembly and the thickness it sums to (a plain wall's own + * thickness, so the Build panel's types don't take over), its finishes and + * trims, and its height when it has its own rather than following the storey + * (`storeyHeight`). + */ +export function wallPullTypePatch(wall: WallNode, storeyHeight: number | null): Partial { + const patch: Record = {} + for (const field of WALL_CONSTRUCTION_FIELDS) { + if (wall[field] !== undefined) patch[field] = structuredClone(wall[field]) + } + patch.thickness = getWallThickness(wall) + if (!wallFollowsStorey(wall, storeyHeight)) patch.height = wall.height + return patch as Partial +} + +/** + * The pulled end of `wall` and the direction out of it: along the wall for a + * straight one, along its tangent for a curved one. + */ +export function wallPullSeed( + wall: Pick, + endpoint: 'start' | 'end', +): { start: WallPlanPoint; reference: WallPlanPoint } | null { + const start: WallPlanPoint = + endpoint === 'start' ? [wall.start[0], wall.start[1]] : [wall.end[0], wall.end[1]] + const tangent = getWallCurveFrameAt(wall as WallNode, endpoint === 'start' ? 0 : 1).tangent + const sign = endpoint === 'start' ? -1 : 1 + const length = Math.hypot(tangent.x, tangent.y) + if (!(length > 1e-9)) return null + return { start, reference: [(tangent.x / length) * sign, (tangent.y / length) * sign] } +} + +// What the pull changed for its run, put back when it ends. +let restore: { shape: ContinuationMode; toolDefaults: Record | null } | null = null +let stopWatching: (() => void) | null = null +let pullSeq = 0 + +/** + * Start a pull from `endpoint` of wall `wallId`: arm the Walls run at that end + * with the wall's type. `origin` is the view the grip was pressed in. False + * when there is no such wall. + */ +export function startWallPull(args: { + wallId: string + endpoint: 'start' | 'end' + origin: '2d' | '3d' +}): boolean { + const nodes = useScene.getState().nodes + const wall = nodes[args.wallId as AnyNodeId] + if (wall?.type !== 'wall' || !wall.parentId) return false + const level = nodes[wall.parentId as AnyNodeId] + if (level?.type !== 'level') return false + const seed = wallPullSeed(wall, args.endpoint) + if (!seed) return false + + endWallPullRun() + const editor = useEditor.getState() + restore = { + shape: editor.getContinuation('wall'), + toolDefaults: (editor.toolDefaults.wall as Record | undefined) ?? null, + } + // The grips belong to a selected wall; drawing goes on without one. + useViewer.getState().setSelection({ selectedIds: [], levelId: level.id }) + selectWallDrawVariant('walls') + editor.setToolDefaults('wall', wallPullTypePatch(wall, level.height ?? null)) + editor.armToolMode({ mode: 'build', tool: 'wall' }) + pullSeq += 1 + useWallPullRun.setState({ + run: { + seq: pullSeq, + sourceWallId: wall.id as AnyNodeId, + levelId: wall.parentId as AnyNodeId, + runStart: seed.start, + start: seed.start, + reference: seed.reference, + origin: args.origin, + dragging: true, + }, + }) + watchWallPullRun() + return true +} + +function watchWallPullRun() { + stopWatching?.() + // Leaving the wall tool (another tool, Select) ends the run. + const stopEditor = useEditor.subscribe((state) => { + if (!(state.mode === 'build' && state.tool === 'wall')) endWallPullRun() + }) + // A release the view did not take as the placing click (off the plan, say) + // still ends the drag; the run waits for a click. + const onPointerUp = () => releaseWallPullDrag() + const target = typeof window === 'undefined' ? null : window + target?.addEventListener('pointerup', onPointerUp) + target?.addEventListener('pointercancel', onPointerUp) + stopWatching = () => { + stopEditor() + target?.removeEventListener('pointerup', onPointerUp) + target?.removeEventListener('pointercancel', onPointerUp) + } +} + +/** The grip was let go: the run goes on by clicks. */ +export function releaseWallPullDrag(): void { + const run = useWallPullRun.getState().run + if (run?.dragging) useWallPullRun.setState({ run: { ...run, dragging: false } }) +} + +/** + * End the pull run, however its walls ended: back to Select from the wall tool, + * with the Rooms shape and wall tool defaults the pull replaced. No-op when no + * run is open. + */ +export function endWallPullRun(): void { + const run = useWallPullRun.getState().run + if (!run) return + useWallPullRun.setState({ run: null }) + stopWatching?.() + stopWatching = null + publishWallRunFeedback(null) + const editor = useEditor.getState() + if (editor.mode === 'build' && editor.tool === 'wall') editor.armToolMode({ mode: 'select' }) + const saved = restore + restore = null + if (!saved) return + const after = useEditor.getState() + if (after.getContinuation('wall') !== saved.shape) after.setContinuation('wall', saved.shape) + after.setToolDefaults('wall', saved.toolDefaults) +} diff --git a/packages/editor/src/lib/wall-push-line-up.test.ts b/packages/editor/src/lib/wall-push-line-up.test.ts new file mode 100644 index 0000000000..b32ec80365 --- /dev/null +++ b/packages/editor/src/lib/wall-push-line-up.test.ts @@ -0,0 +1,132 @@ +import { afterAll, afterEach, beforeEach, describe, expect, spyOn, test } from 'bun:test' +import { clearSceneHistory, nodeRegistry, useScene, WallNode } from '@pascal-app/core' +import { useViewer } from '@pascal-app/viewer' +import useAlignmentGuides from '../store/use-alignment-guides' +import useEditor from '../store/use-editor' +import useInteractionScope from '../store/use-interaction-scope' +import { installImmediateAnimationFrames } from '../test-utils/immediate-animation-frames' +import { seedRoundTripScene } from '../test-utils/live-gesture-round-trip' +import { cancelGestures } from './gesture-lifecycle' +import { runWallPushDrag, wallPushHandles } from './room-handle-drag' +import { nextInStack } from './selection-cycle' + +// A side arrow push lines the wall up with a parallel wall before the grid, as +// the wall moves do; Alt pushes it free. + +const LEVEL = 'level_push_line_up' +const stubbed: string[] = [] +let stop = () => {} +let restoreFrames = () => {} +let registry: { mockRestore: () => void } | null = null + +const nodes = () => useScene.getState().nodes +const eastWall = () => + Object.values(nodes()).find( + (n): n is WallNode => n.type === 'wall' && n.start[0] === 6 && n.end[0] === 6, + )! + +function pointer(type: 'pointermove' | 'pointerup', clientX: number, altKey = false) { + window.dispatchEvent(Object.assign(new Event(type), { clientX, clientY: 0, altKey })) +} + +beforeEach(() => { + restoreFrames = installImmediateAnimationFrames() + if (!globalThis.document) { + globalThis.document = { body: { style: { cursor: '' } } } as unknown as Document + stubbed.push('document') + } + if (!globalThis.window) { + globalThis.window = new EventTarget() as Window & typeof globalThis + stubbed.push('window') + } + // The nodes package that registers walls is not loaded here. + const get = nodeRegistry.get.bind(nodeRegistry) + registry = spyOn(nodeRegistry, 'get').mockImplementation(((kind: string) => + kind === 'wall' ? { snapProfile: 'structural' } : get(kind)) as typeof nodeRegistry.get) + cancelGestures('cancel') + useInteractionScope.getState().end() + useScene.temporal.getState().resume() + ;({ stop } = seedRoundTripScene('building_push_line_up', LEVEL)) + // An outside wall standing apart, 0.3 m east of the room's east wall line. + const apart = WallNode.parse({ + id: 'wall_apart', + start: [6.3, 6], + end: [6.3, 9], + frontSide: 'exterior', + backSide: 'interior', + }) + useScene.getState().applyNodeChanges({ create: [{ node: apart, parentId: LEVEL as never }] }) + useViewer.getState().setSelection({ + buildingId: 'building_push_line_up', + levelId: LEVEL, + selectedIds: [], + }) + useEditor.setState({ phase: 'building', mode: 'select', gridSnapStep: 0.5 }) + useEditor.getState().setSnappingMode('polygon', 'grid') + clearSceneHistory() +}) + +afterEach(() => { + cancelGestures('cancel') + stop() + registry?.mockRestore() + registry = null + restoreFrames() +}) + +afterAll(async () => { + // Let the click-swallow timers fire before the stubs go. + await new Promise((resolve) => setTimeout(resolve, 350)) + for (const key of stubbed.splice(0)) delete (globalThis as Record)[key] +}) + +function startPush() { + const handle = wallPushHandles(eastWall(), nodes()).find((h) => h.outward[0] > 0.5)! + runWallPushDrag({ handle, levelId: LEVEL, from: 0, along: (clientX) => clientX }) + return eastWall().id +} + +describe('wall push line-up', () => { + test('a push near a parallel outside wall lands on its line, guide shown while it holds', () => { + expect(eastWall().frontSide === 'exterior' || eastWall().backSide === 'exterior').toBe(true) + const id = startPush() + pointer('pointermove', 0.24) + expect(useAlignmentGuides.getState().draft?.lines).toHaveLength(1) + pointer('pointerup', 0.24) + expect(useAlignmentGuides.getState().draft).toBeNull() + const wall = nodes()[id as never] as WallNode + expect(wall.start[0]).toBeCloseTo(6.3, 9) + expect(wall.end[0]).toBeCloseTo(6.3, 9) + }) + + test('away from any line the push still steps on the grid', () => { + const id = startPush() + pointer('pointermove', 0.9) + pointer('pointerup', 0.9) + expect((nodes()[id as never] as WallNode).start[0]).toBeCloseTo(7, 9) + }) + + test('Alt pushes it free', () => { + const id = startPush() + pointer('pointermove', 0.24, true) + expect(useAlignmentGuides.getState().draft).toBeNull() + pointer('pointerup', 0.24, true) + expect((nodes()[id as never] as WallNode).start[0]).toBeCloseTo(6.24, 9) + }) +}) + +describe('Tab through stacked objects', () => { + test('steps to the next one under the pointer and wraps round', () => { + const stack = ['wall_top', 'wall_inside', 'zone_room'] + expect(nextInStack(stack, [], false)).toBe('wall_top') + expect(nextInStack(stack, ['wall_top'], false)).toBe('wall_inside') + expect(nextInStack(stack, ['zone_room'], false)).toBe('wall_top') + }) + + test('Shift+Tab steps back; a selection elsewhere starts at the top', () => { + const stack = ['wall_top', 'wall_inside'] + expect(nextInStack(stack, ['wall_top'], true)).toBe('wall_inside') + expect(nextInStack(stack, ['wall_other'], true)).toBe('wall_top') + expect(nextInStack([], ['wall_top'], false)).toBeNull() + }) +}) diff --git a/packages/editor/src/lib/wall-region-list.ts b/packages/editor/src/lib/wall-region-list.ts index 01dc9b6bc8..be625dc9c1 100644 --- a/packages/editor/src/lib/wall-region-list.ts +++ b/packages/editor/src/lib/wall-region-list.ts @@ -1,6 +1,7 @@ import { type AnyNode, getCatalogMaterialById, + getMaterialSwatch, parseMaterialRef, roomSideFaces, type SceneMaterial, @@ -18,7 +19,13 @@ import { getLinearUnitLabel, type LinearUnit, metersToLinearUnit } from './measu const FALLBACK_SWATCH_COLOR = '#d4d4d8' -export type WallRegionFinish = { name: string; color: string; imageUrl?: string } +export type WallRegionFinish = { + name: string + color: string + imageUrl?: string + /** The image is a white albedo `color` tints: multiply it (a siding's profile). */ + tinted?: boolean +} export type WallRegionRow = { id: string @@ -63,11 +70,13 @@ export function describeRegionFinish( } if (parsed?.kind === 'library') { const item = getCatalogMaterialById(parsed.id) - const imageUrl = item?.previewThumbnailUrl ?? item?.preset.maps.albedoMap + if (!item) return { name: 'Library finish', color: FALLBACK_SWATCH_COLOR } + const swatch = getMaterialSwatch(item) return { - name: item?.label ?? 'Library finish', - color: item?.previewColor ?? item?.preset.mapProperties.color ?? FALLBACK_SWATCH_COLOR, - ...(imageUrl ? { imageUrl } : {}), + name: item.label, + color: swatch.color, + ...(swatch.imageUrl ? { imageUrl: swatch.imageUrl } : {}), + ...(swatch.tinted ? { tinted: true } : {}), } } return { name: 'Custom finish', color: FALLBACK_SWATCH_COLOR } diff --git a/packages/editor/src/lib/wall-run-snap.test.ts b/packages/editor/src/lib/wall-run-snap.test.ts new file mode 100644 index 0000000000..0bf2312aa8 --- /dev/null +++ b/packages/editor/src/lib/wall-run-snap.test.ts @@ -0,0 +1,188 @@ +import { afterEach, beforeEach, describe, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + detectSpacesForLevel, + LevelNode as LevelSchema, + nodeRegistry, + registerNode, + useScene, + type WallNode, + WallNode as WallSchema, + wallClosesRoom, +} from '@pascal-app/core' +import { useViewer } from '@pascal-app/viewer' +import { createWallOnCurrentLevel } from '../components/tools/wall/wall-drafting' +import type { WallPlanPoint } from '../components/tools/wall/wall-snap-geometry' +import useEditor from '../store/use-editor' +import { + addWallPolygonDraftCorner, + discardWallPolygonDraft, + startWallPolygonDraft, + wallPolygonDraftWalls, +} from './wall-polygon-draft' +import { isWallRunFree, snapWallRunDraftPoint, wallRunDirection } from './wall-run-snap' + +// `updateNodes` batches its dirty-marking through requestAnimationFrame, +// which bun's test runtime doesn't provide. +if (typeof globalThis.requestAnimationFrame === 'undefined') { + globalThis.requestAnimationFrame = ((callback: FrameRequestCallback) => + setTimeout(() => callback(0), 0)) as unknown as typeof requestAnimationFrame + globalThis.cancelAnimationFrame = ((id: number) => + clearTimeout(id)) as typeof cancelAnimationFrame +} + +const LEVEL_ID = 'level_run' as AnyNodeId +const deg = (degrees: number) => (degrees * Math.PI) / 180 + +function levelWalls(): WallNode[] { + return Object.values(useScene.getState().nodes).filter( + (node): node is WallNode => node?.type === 'wall' && node.parentId === LEVEL_ID, + ) +} + +/** + * A plain run as the wall tool drafts it once its first point is placed: each + * wall from the last one's end, square to it, snapped against the level's walls. + */ +function plainRun(runStart: WallPlanPoint) { + let start = runStart + let reference: WallPlanPoint | null = null + return (cursor: WallPlanPoint, free = false) => { + const snapped = snapWallRunDraftPoint({ + point: cursor, + start, + runStart, + reference, + walls: levelWalls(), + free, + }) + const wall = createWallOnCurrentLevel(start, snapped.point)! + start = wall.end + reference = wallRunDirection(wall.start, wall.end) + return { wall, snapped } + } +} + +describe('a plain wall run snaps like a pulled one once started', () => { + let restoreRegistry: (() => void) | undefined + let previousEditor: Partial> + + beforeEach(() => { + previousEditor = { + toolDefaults: useEditor.getState().toolDefaults, + continuationByContext: useEditor.getState().continuationByContext, + } + // The wall's snap profile makes the armed wall tool the 'wall' snapping + // context (grid lengths), as in the app. + restoreRegistry = nodeRegistry._snapshot() + registerNode({ + kind: 'wall', + schemaVersion: 10, + schema: WallSchema, + category: 'structure', + snapProfile: 'structural', + defaults: () => WallSchema.parse({ start: [0, 0], end: [1, 0] }), + capabilities: {}, + } as never) + useEditor.getState().setSnappingMode('wall', 'grid') + useEditor.getState().armToolMode({ mode: 'build', tool: 'wall' }) + useViewer.setState({ + selection: { buildingId: null, levelId: LEVEL_ID, zoneId: null, selectedIds: [] }, + } as never) + const level = LevelSchema.parse({ id: LEVEL_ID, level: 0, height: 2.7, children: [] }) + useScene.setState({ + nodes: { [level.id]: level as AnyNode }, + rootNodeIds: [level.id], + dirtyNodes: new Set(), + collections: {}, + } as never) + }) + + afterEach(() => { + discardWallPolygonDraft() + restoreRegistry?.() + restoreRegistry = undefined + useEditor.getState().setSnappingMode('wall', 'grid') + useEditor.setState(previousEditor as never) + useEditor.getState().armToolMode({ mode: 'select' }) + }) + + test("the first wall holds to the house's axes, steps 15° past them, and Alt frees it", () => { + const snap = (cursor: WallPlanPoint, free = false) => + snapWallRunDraftPoint({ + point: cursor, + start: [0, 0], + runStart: [0, 0], + reference: null, + walls: [], + free, + }) + const axis = snap([4.1, 0.35]) + expect(axis.lock).toBe('axis') + expect(axis.point).toEqual([4, 0]) + const stepped = snap([Math.cos(deg(40)) * 3, Math.sin(deg(40)) * 3]) + expect(stepped.lock).toBe('angle') + expect(stepped.point[0]).toBeCloseTo(Math.cos(deg(45)) * 3, 6) + expect(stepped.point[1]).toBeCloseTo(Math.sin(deg(45)) * 3, 6) + expect(isWallRunFree({ altKey: true })).toBe(true) + expect(isWallRunFree()).toBe(false) + expect(snap([3.13, 1.07], isWallRunFree({ altKey: true })).point).toEqual([3.13, 1.07]) + // Snapping off frees it too. + useEditor.getState().setSnappingMode('wall', 'off') + expect(isWallRunFree()).toBe(true) + }) + + test('a Walls run squares up, lines up with its start and closes into a room', () => { + // The first point keeps the tool's own snapping; the run starts at (0, 0). + const place = plainRun([0, 0]) + const first = place([5.1, 0.4]) + expect(first.snapped.lock).toBe('axis') + expect(first.wall.end).toEqual([5, 0]) + const second = place([5.3, 3.9]) + expect(second.snapped.lock).toBe('square') + expect(second.wall.end).toEqual([5, 4]) + const third = place([0.1, 4.05]) + expect(third.snapped.snap).toBe('alignment') + expect(third.snapped.label).toBe('In line with start') + expect(third.snapped.guides.some((guide) => guide.kind === 'run-start')).toBe(true) + expect(third.snapped.guides.some((guide) => guide.kind === 'extension')).toBe(true) + expect(third.wall.end).toEqual([0, 4]) + const last = place([0.12, 0.18]) + expect(last.snapped.snap).toBe('endpoint') + expect(last.wall.end).toEqual([0, 0]) + expect(wallClosesRoom(levelWalls(), last.wall)).toBe(true) + const rooms = detectSpacesForLevel(LEVEL_ID, levelWalls()).spaces.filter( + (space) => !space.isExterior, + ) + expect(rooms).toHaveLength(1) + }) + + test('a Polygon room snaps its corners the same way and closes on its first', () => { + startWallPolygonDraft(LEVEL_ID, [0, 0]) + let start: WallPlanPoint = [0, 0] + let reference: WallPlanPoint | null = null + const corner = (cursor: WallPlanPoint) => { + const snapped = snapWallRunDraftPoint({ + point: cursor, + start, + runStart: [0, 0], + reference, + walls: [...levelWalls(), ...wallPolygonDraftWalls()], + free: false, + }) + const outcome = addWallPolygonDraftCorner(snapped.point) + reference = wallRunDirection(start, snapped.point) + start = snapped.point + return { snapped, outcome } + } + expect(corner([3.9, -0.3]).snapped.point).toEqual([4, 0]) + expect(corner([4.2, 2.95]).snapped.point).toEqual([4, 3]) + const across = corner([-0.08, 3.1]) + expect(across.snapped.label).toBe('In line with start') + expect(across.snapped.point).toEqual([0, 3]) + const close = corner([0.1, 0.2]) + expect(close.snapped.snap).toBe('endpoint') + expect(close.outcome).toBe('closed') + }) +}) diff --git a/packages/editor/src/lib/wall-run-snap.ts b/packages/editor/src/lib/wall-run-snap.ts new file mode 100644 index 0000000000..3455c83663 --- /dev/null +++ b/packages/editor/src/lib/wall-run-snap.ts @@ -0,0 +1,83 @@ +/** + * Snapping for the wall tool's line runs once their first point is placed — + * a Polygon room's sides and a run pulled from a wall end (`wall-pull.ts`, + * `wallDraftIsRun`); a Walls segment is one wall and snaps as its first point. + * + * Each wall holds square: straight on from the wall before it, square to it, + * or along the house's axes within about 7°, and on 15° steps past that, with + * its length on the grid; existing walls, the run's start and the projection + * guides win over that (`snapWallPullPoint`). Alt, or snapping off, leaves the + * end at the cursor. The run's first point keeps the tool's own snapping. + * + * The 3D wall tool and the floor plan each draft a run from their own start, + * run start and previous wall, and snap through here, so both views place the + * same point; the view that owns the input publishes the guides and marker. + */ + +import type { WallNode, WallPlanPoint } from '@pascal-app/core' +import { getSegmentGridStep } from '../components/tools/wall/wall-drafting' +import { snapWallPullPoint, type WallPullSnapResult } from '../components/tools/wall/wall-pull-snap' +import useAlignmentGuides from '../store/use-alignment-guides' +import { getActiveSnappingMode } from '../store/use-editor' +import useWallSnapIndicator from '../store/use-wall-snap-indicator' + +/** True while a run's walls follow the cursor freely: Alt, or snapping off. */ +export function isWallRunFree(event?: { altKey?: boolean } | null): boolean { + return Boolean(event?.altKey) || getActiveSnappingMode() === 'off' +} + +/** Unit direction of a placed wall `start` → `end`: the next wall holds square to it. */ +export function wallRunDirection(start: WallPlanPoint, end: WallPlanPoint): WallPlanPoint | null { + const dx = end[0] - start[0] + const dz = end[1] - start[1] + const length = Math.hypot(dx, dz) + return length > 1e-9 ? [dx / length, dz / length] : null +} + +/** + * Snap the drafted end of a run's current wall, which starts at `start`. + * `runStart` is where the run began, `reference` the direction of the wall + * before (null for the run's first wall), and `walls` the level's walls with + * any open Polygon room's sides. + */ +export function snapWallRunDraftPoint(args: { + point: WallPlanPoint + start: WallPlanPoint + runStart: WallPlanPoint + reference: WallPlanPoint | null + walls: readonly WallNode[] + free: boolean +}): WallPullSnapResult { + return snapWallPullPoint({ ...args, gridStep: getSegmentGridStep() }) +} + +/** + * Show a run's snap: its projection guides and crossings (the alignment guide + * layers draw them) and the snap marker with what it caught. Null clears both. + */ +export function publishWallRunFeedback(result: WallPullSnapResult | null): void { + if (!result) { + useAlignmentGuides.getState().clear() + useWallSnapIndicator.getState().clear() + return + } + useAlignmentGuides.getState().setDraft({ + lines: result.guides.map((guide) => ({ + kind: guide.kind, + from: [guide.from[0], guide.from[1]], + to: [guide.to[0], guide.to[1]], + })), + intersections: result.intersections.map((point) => [point[0], point[1]]), + }) + useWallSnapIndicator.getState().set( + result.snap + ? { + x: result.point[0], + z: result.point[1], + kind: result.snap, + wallIds: result.targetWallIds.length > 0 ? result.targetWallIds : undefined, + label: result.label ?? undefined, + } + : null, + ) +} diff --git a/packages/editor/src/lib/wall-type.test.ts b/packages/editor/src/lib/wall-type.test.ts new file mode 100644 index 0000000000..88fa8f547e --- /dev/null +++ b/packages/editor/src/lib/wall-type.test.ts @@ -0,0 +1,125 @@ +import { afterEach, beforeEach, describe, expect, test } from 'bun:test' +import { + GYPSUM_HALF, + getSceneDocument, + projectWallTypes, + SiteNode, + STUD_2X8, + useScene, + WallTypeDefinition, + wallTypeAssembly, +} from '@pascal-app/core' +import { + deleteProjectWallType, + newWallTypeBlockedReason, + PROJECT_WALL_TYPE_LIMIT, + saveProjectWallType, + WALL_TYPE_LAYER_LIMIT, + WALL_TYPE_SAVE_FAILURE, +} from './wall-type' + +// Scene writes schedule their dirty pass on a frame; bun has none. +globalThis.requestAnimationFrame ??= () => 0 +globalThis.cancelAnimationFrame ??= () => {} + +const currentProjectWallTypes = () => { + const { nodes, rootNodeIds } = useScene.getState() + return projectWallTypes(nodes, rootNodeIds) +} + +/** A 2x8 at 24 in partition, drywall both faces. */ +const SOUND_WALL: WallTypeDefinition = { + id: 'custom-soundwall', + label: '2x8 sound wall', + assembly: wallTypeAssembly('custom-soundwall', [ + { role: 'lining', material: 'drywall', thickness: GYPSUM_HALF }, + { role: 'structure', core: true, material: 'wood', thickness: STUD_2X8, spacing: 0.6096 }, + { role: 'lining', material: 'drywall', thickness: GYPSUM_HALF }, + ]), +} + +beforeEach(() => { + useScene.getState().unloadScene() + useScene.getState().loadScene() +}) + +afterEach(() => { + useScene.getState().unloadScene() +}) + +describe('project wall types', () => { + test('save with the project and come back from a saved scene', () => { + expect(saveProjectWallType(SOUND_WALL)).toBe('saved') + expect(currentProjectWallTypes()).toEqual([SOUND_WALL]) + const document = JSON.parse(JSON.stringify(getSceneDocument())) + useScene.getState().unloadScene() + expect(currentProjectWallTypes()).toEqual([]) + useScene.getState().setScene(document.nodes, document.rootNodeIds) + expect(currentProjectWallTypes()).toEqual([SOUND_WALL]) + // Saving again under the same id edits it in place. + saveProjectWallType({ ...SOUND_WALL, label: 'Sound wall' }) + expect(currentProjectWallTypes().map((type) => type.label)).toEqual(['Sound wall']) + deleteProjectWallType(SOUND_WALL.id) + expect(currentProjectWallTypes()).toEqual([]) + }) + + test('a 13th layer and a 65th type are refused, each saying why, and nothing is written', () => { + const stack = (linings: number) => + wallTypeAssembly('custom-thick', [ + { role: 'structure', core: true, material: 'wood', thickness: STUD_2X8 }, + ...Array.from({ length: linings }, () => ({ + role: 'lining' as const, + material: 'drywall', + thickness: GYPSUM_HALF, + })), + ]) + const thick = { id: 'custom-thick', label: 'Thick', assembly: stack(WALL_TYPE_LAYER_LIMIT) } + expect(saveProjectWallType(thick)).toBe('too-many-layers') + expect(currentProjectWallTypes()).toEqual([]) + // The limits are the schema's own. + expect(WallTypeDefinition.safeParse(thick).success).toBe(false) + expect(saveProjectWallType({ ...thick, assembly: stack(WALL_TYPE_LAYER_LIMIT - 1) })).toBe( + 'saved', + ) + deleteProjectWallType(thick.id) + + const numbered = (n: number) => ({ + ...SOUND_WALL, + id: `custom-sound-${n}`, + label: `Sound ${n}`, + }) + for (let n = 1; n <= PROJECT_WALL_TYPE_LIMIT; n += 1) + expect(saveProjectWallType(numbered(n))).toBe('saved') + expect(newWallTypeBlockedReason(currentProjectWallTypes())).toContain( + `${PROJECT_WALL_TYPE_LIMIT} wall types`, + ) + expect(saveProjectWallType(numbered(PROJECT_WALL_TYPE_LIMIT + 1))).toBe('too-many-types') + expect(currentProjectWallTypes()).toHaveLength(PROJECT_WALL_TYPE_LIMIT) + const site = Object.values(useScene.getState().nodes).find((node) => node.type === 'site') + expect(SiteNode.safeParse(site).success).toBe(true) + const over = [...currentProjectWallTypes(), numbered(PROJECT_WALL_TYPE_LIMIT + 1)] + expect(SiteNode.safeParse({ ...site, wallTypes: over }).success).toBe(false) + // A type the project keeps can still be edited in place. + expect(saveProjectWallType({ ...numbered(1), label: 'Quiet wall' })).toBe('saved') + expect(currentProjectWallTypes()[0]?.label).toBe('Quiet wall') + deleteProjectWallType(numbered(1).id) + expect(newWallTypeBlockedReason(currentProjectWallTypes())).toBeNull() + }) + + test('a type that does not parse says so, apart from a scene with no site', () => { + const coreless = { + ...SOUND_WALL, + assembly: { + ...SOUND_WALL.assembly, + layers: SOUND_WALL.assembly.layers.filter((l) => !l.core), + }, + } + expect(saveProjectWallType(coreless)).toBe('invalid') + expect(saveProjectWallType({ ...SOUND_WALL, label: ' ' })).toBe('invalid') + expect(currentProjectWallTypes()).toEqual([]) + useScene.getState().unloadScene() + expect(saveProjectWallType(SOUND_WALL)).toBe('no-site') + expect(WALL_TYPE_SAVE_FAILURE.invalid).not.toBe(WALL_TYPE_SAVE_FAILURE['no-site']) + expect(WALL_TYPE_SAVE_FAILURE.invalid).not.toContain('site') + }) +}) diff --git a/packages/editor/src/lib/wall-type.ts b/packages/editor/src/lib/wall-type.ts new file mode 100644 index 0000000000..781f99633d --- /dev/null +++ b/packages/editor/src/lib/wall-type.ts @@ -0,0 +1,119 @@ +import { + type AnyNodeId, + type Assembly, + isExteriorWallAssembly, + parseWallTypes, + projectWallTypes, + type SiteNode, + useScene, + WallTypeDefinition, +} from '@pascal-app/core' +import { useMemo } from 'react' + +/** + * A project's own wall types (`SiteNode.wallTypes`), made and edited from a wall's + * Assembly controls (`WallTypeMenu`): saved on the site, so they travel with the + * project and undo like any edit. + * + * A placement is the kind of wall a stack builds, read from its layers: `exterior` + * with a cladding side, `interior` lined alike on both faces. A new type starts from + * a typical stack of its placement. + */ +export type WallTypePlacement = 'exterior' | 'interior' + +function siteOf(state: ReturnType): SiteNode | undefined { + for (const id of state.rootNodeIds) { + const node = state.nodes[id] + if (node?.type === 'site') return node + } + return undefined +} + +/** The project's own wall types, kept current as they are saved, edited or undone. */ +export function useProjectWallTypes(): WallTypeDefinition[] { + const saved = useScene((state) => siteOf(state)?.wallTypes) + return useMemo(() => parseWallTypes(saved), [saved]) +} + +/** The placement a stack builds, read from its layers (`isExteriorWallAssembly`). */ +export function wallTypePlacementOf(assembly: Assembly): WallTypePlacement { + return isExteriorWallAssembly(assembly) ? 'exterior' : 'interior' +} + +/** The most layers a wall type's stack holds (`Assembly.layers`). */ +export const WALL_TYPE_LAYER_LIMIT = 12 + +/** The most wall types a project keeps on its site (`SiteNode.wallTypes`). */ +export const PROJECT_WALL_TYPE_LIMIT = 64 + +/** + * Why no new wall type can be made in this project — it keeps `PROJECT_WALL_TYPE_LIMIT` + * already — or null while it has room: what "New wall type…" and "Duplicate as a new + * type…" say when they are off. + */ +export function newWallTypeBlockedReason( + projectTypes: readonly WallTypeDefinition[], +): string | null { + return projectTypes.length >= PROJECT_WALL_TYPE_LIMIT + ? `This project keeps ${PROJECT_WALL_TYPE_LIMIT} wall types, the most it can. Delete one to make another.` + : null +} + +/** + * What saving a project wall type came to: `saved`, or why not — the scene has no + * site to keep it on, its stack has more layers than a wall type holds, the project + * keeps as many types as it can and this one is new, or it does not parse. + */ +export type WallTypeSaveResult = + | 'saved' + | 'no-site' + | 'too-many-layers' + | 'too-many-types' + | 'invalid' + +/** What the wall type editor says when a type was not saved. */ +export const WALL_TYPE_SAVE_FAILURE: Record, string> = { + 'no-site': 'This project has no site to keep wall types on, so the type was not saved.', + 'too-many-layers': `A wall type holds at most ${WALL_TYPE_LAYER_LIMIT} layers. Remove one to save it.`, + 'too-many-types': `This project keeps ${PROJECT_WALL_TYPE_LIMIT} wall types, the most it can. Delete one to save another.`, + invalid: + 'These layers do not make a wall type (one framing core, every layer a thickness), so it was not saved.', +} + +/** + * Saves a project wall type on the site, in place of the one with its id or after + * the others: one undo step, saved and shared with the project. Nothing is written + * unless it comes to `saved` (`WallTypeSaveResult`): a stack of more than + * `WALL_TYPE_LAYER_LIMIT` layers, or a new type past `PROJECT_WALL_TYPE_LIMIT`, would + * leave a site that no longer parses. + */ +export function saveProjectWallType(type: WallTypeDefinition): WallTypeSaveResult { + const state = useScene.getState() + const site = siteOf(state) + if (!site) return 'no-site' + if ((type.assembly?.layers?.length ?? 0) > WALL_TYPE_LAYER_LIMIT) return 'too-many-layers' + const parsed = WallTypeDefinition.safeParse(type) + if (!parsed.success) return 'invalid' + const current = projectWallTypes(state.nodes, state.rootNodeIds) + const editing = current.some((entry) => entry.id === type.id) + if (!editing && current.length >= PROJECT_WALL_TYPE_LIMIT) return 'too-many-types' + const next = editing + ? current.map((entry) => (entry.id === type.id ? parsed.data : entry)) + : [...current, parsed.data] + state.updateNode(site.id as AnyNodeId, { wallTypes: next } as Partial) + return 'saved' +} + +/** Removes a project wall type from the site. Walls drawn with it keep their stack. */ +export function deleteProjectWallType(id: string): void { + const state = useScene.getState() + const site = siteOf(state) + if (!site) return + const next = projectWallTypes(state.nodes, state.rootNodeIds).filter((type) => type.id !== id) + state.updateNode( + site.id as AnyNodeId, + { + wallTypes: next.length > 0 ? next : undefined, + } as Partial, + ) +} diff --git a/packages/editor/src/lib/world-grid-snap.test.ts b/packages/editor/src/lib/world-grid-snap.test.ts index 70436b2692..5a29340d69 100644 --- a/packages/editor/src/lib/world-grid-snap.test.ts +++ b/packages/editor/src/lib/world-grid-snap.test.ts @@ -1,14 +1,26 @@ import { afterEach, describe, expect, test } from 'bun:test' -import { BuildingNode, LevelNode, useScene } from '@pascal-app/core' +import { BuildingNode, LevelNode, snapWorldXZToBuildingLocal, useScene } from '@pascal-app/core' import { useViewer } from '@pascal-app/viewer' -import { getActiveBuildingId } from './world-grid-snap' +import useEditor from '../store/use-editor' +import useInteractionScope from '../store/use-interaction-scope' +import { + getActiveBuildingId, + getActiveGridPose, + resolveAlignmentForActiveBuilding, + resolveAlignmentForFloorplanView, + snapBuildingLocalToWorldGrid, + snapWorldXZForActiveBuilding, +} from './world-grid-snap' const originalNodes = useScene.getState().nodes const originalSelection = useViewer.getState().selection +const originalPhase = useEditor.getState().phase afterEach(() => { useScene.setState({ nodes: originalNodes } as never) useViewer.setState({ selection: originalSelection } as never) + useEditor.setState({ phase: originalPhase }) + useInteractionScope.getState().end() }) describe('getActiveBuildingId', () => { @@ -46,3 +58,128 @@ describe('getActiveBuildingId', () => { expect(getActiveBuildingId()).toBe(building.id) }) }) + +// A building the site planner set on its lot: turned and offset. The plan only +// carries the level, as it often does (`selection.buildingId` null). +const YAW = (17 * Math.PI) / 180 +const POSITION: [number, number, number] = [12.37, 0, -8.91] + +function selectTurnedBuilding() { + const level = LevelNode.parse({}) + const building = BuildingNode.parse({ + position: POSITION, + rotation: [0, YAW, 0], + children: [level.id], + }) + useScene.setState({ + nodes: { [building.id]: building, [level.id]: { ...level, parentId: building.id } }, + } as never) + useViewer.setState({ + selection: { buildingId: null, levelId: level.id, zoneId: null, selectedIds: [] }, + } as never) + return building +} + +describe("grid snap on the building's own lattice", () => { + test('a turned, offset building snaps square to itself, not to the world grid', () => { + selectTurnedBuilding() + expect(snapBuildingLocalToWorldGrid([1.26, 3.74], 0.5)).toEqual([1.5, 3.5]) + expect(snapBuildingLocalToWorldGrid([1.26, 3.74], 0)).toEqual([1.26, 3.74]) + }) + + test('an unturned building at the origin keeps the world grid, which is its lattice', () => { + const building = BuildingNode.parse({}) + useScene.setState({ nodes: { [building.id]: building } } as never) + useViewer.setState({ + selection: { buildingId: building.id, levelId: null, zoneId: null, selectedIds: [] }, + } as never) + expect(snapBuildingLocalToWorldGrid([1.26, 3.74], 0.5)).toEqual([1.5, 3.5]) + expect(snapWorldXZForActiveBuilding(1.26, 3.74, 0.5)).toEqual({ + world: [1.5, 3.5], + local: [1.5, 3.5], + }) + }) + + test('a world cursor lands on the building lattice, in both frames', () => { + selectTurnedBuilding() + const { world, local } = snapWorldXZForActiveBuilding(15.2, -4.4, 0.5) + const raw = snapWorldXZToBuildingLocal(15.2, -4.4, POSITION, YAW, 0).local + expect(local).toEqual(snapBuildingLocalToWorldGrid(raw, 0.5)) + const back = snapWorldXZToBuildingLocal(world[0], world[1], POSITION, YAW, 0).local + expect(back[0]).toBeCloseTo(local[0], 9) + expect(back[1]).toBeCloseTo(local[1], 9) + }) +}) + +describe('resolveAlignmentForFloorplanView', () => { + test("aligns on a turned building's own axes and returns building-local guides", () => { + selectTurnedBuilding() + const result = resolveAlignmentForFloorplanView({ + moving: [{ nodeId: 'moving', kind: 'corner', x: 2.05, z: 1 }], + candidates: [{ nodeId: 'wall', kind: 'corner', x: 2, z: 5 }], + threshold: 0.08, + }) + expect(result.snap?.dx).toBeCloseTo(-0.05, 9) + expect(result.snap?.dz).toBeCloseTo(0, 9) + expect(result.guides).toHaveLength(1) + expect(result.guides[0]?.axis).toBe('x') + expect(result.guides[0]?.anchor).toEqual({ x: 2, z: 5 }) + }) +}) + +describe('resolveAlignmentForActiveBuilding', () => { + test("aligns on a turned building's own axes; guide ends come back in world coords", () => { + selectTurnedBuilding() + const result = resolveAlignmentForActiveBuilding({ + moving: [{ nodeId: 'moving', kind: 'corner', x: 2.05, z: 1 }], + candidates: [{ nodeId: 'wall', kind: 'corner', x: 2, z: 5 }], + threshold: 0.08, + }) + expect(result.snap?.dx).toBeCloseTo(-0.05, 9) + expect(result.snap?.dz).toBeCloseTo(0, 9) + const anchor = result.guides[0]?.anchor + const ends = [result.guides[0]?.from, result.guides[0]?.to] + // The candidate end sits at the anchor's world position. + const world = ends.find( + (end) => + end && + Math.abs(end.x - (POSITION[0] + 2 * Math.cos(YAW) + 5 * Math.sin(YAW))) < 1e-9 && + Math.abs(end.z - (POSITION[2] - 2 * Math.sin(YAW) + 5 * Math.cos(YAW))) < 1e-9, + ) + expect(anchor).toEqual({ x: 2, z: 5 }) + expect(world).toBeDefined() + }) +}) + +describe('getActiveGridPose (the frame the 3D grid is drawn in)', () => { + test("is the active building's pose while working in it", () => { + useEditor.setState({ phase: 'building' }) + selectTurnedBuilding() + expect(getActiveGridPose()).toEqual({ position: POSITION, rotationY: YAW }) + }) + + test('is the world grid for site work and while the building itself moves', () => { + const building = selectTurnedBuilding() + useEditor.setState({ phase: 'site' }) + expect(getActiveGridPose()).toBeNull() + + useEditor.setState({ phase: 'building' }) + useInteractionScope.getState().begin({ + kind: 'moving', + node: building, + nodeId: building.id, + nodeType: 'building', + view: '3d', + }) + expect(getActiveGridPose()).toBeNull() + }) + + test('is the world grid with no building', () => { + useEditor.setState({ phase: 'building' }) + useScene.setState({ nodes: {} } as never) + useViewer.setState({ + selection: { buildingId: null, levelId: null, zoneId: null, selectedIds: [] }, + } as never) + expect(getActiveGridPose()).toBeNull() + }) +}) diff --git a/packages/editor/src/lib/world-grid-snap.ts b/packages/editor/src/lib/world-grid-snap.ts index 2889cad3e0..ef79bee3bb 100644 --- a/packages/editor/src/lib/world-grid-snap.ts +++ b/packages/editor/src/lib/world-grid-snap.ts @@ -1,12 +1,18 @@ /** - * World-grid snap for tools that consume `grid:move` / `grid:click`. + * Grid snap and alignment frames for tools that consume `grid:move` / + * `grid:click` inside a building. * - * Tools historically snapped on `event.localPosition` (the cursor in the - * active building's local frame). After the floor-plan grid was pulled - * out of the rotated scene group, snapping has to follow the WORLD XZ - * grid — otherwise a rotated building drags every placement off the - * visible grid lines. This helper resolves the active building's pose - * and projects the world snap back into local coords for storage. + * A building placed on a lot by the site planner is usually turned (yaw) and + * offset. Everything drawn or placed in it — walls, slabs, rooms, furniture, + * doors and windows — lives in the building's own frame, and so does the grid + * both views draw for it: the floor plan's grid sits inside the rotated scene + * group, and the 3D grid is laid on the building (`getActiveGridPose`). The + * snaps here follow that lattice, so a wall drawn square to the house stays + * square to it and lands on the lattice its neighbours were drawn on. A + * world-XZ lattice sits at the building's yaw to the house and off it by the + * building's offset, leaving drafted ends a fraction short of the walls they + * meet. For an unturned building at the origin the two coincide; outside any + * building the world grid is the lattice. */ import { type AlignmentAnchor, @@ -21,6 +27,8 @@ import { useScene, } from '@pascal-app/core' import { useViewer } from '@pascal-app/viewer' +import useEditor from '../store/use-editor' +import { getMovingNode } from '../store/use-interaction-scope' /** * Look up the active building's pose, or null when we're at the site root. @@ -68,13 +76,26 @@ export function getActiveBuildingPose(): BuildingPose | null { } /** - * Resolve Figma-style alignment for tools whose anchors are in the active - * building's local frame, but where alignment must run on the WORLD axes - * (the frame the user sees the grid in). Wraps `resolveAlignmentInBuildingWorld` - * with the active building lookup so callers don't repeat the boilerplate. + * The frame of the lattice the 3D grid is drawn on: the active building's pose + * for everything drawn or placed in it, or null — the world XZ grid — for + * site work (the site phase, which terrain sculpting also runs in), while a + * building itself is being moved (it moves on the site), and with no building. + */ +export function getActiveGridPose(): BuildingPose | null { + if (useEditor.getState().phase === 'site') return null + if (getMovingNode()?.type === 'building') return null + return getActiveBuildingPose() +} + +/** + * Resolve Figma-style alignment for 3D tools whose anchors are in the active + * building's local frame, on the building's own axes (the axes its grid is + * drawn on). Wraps `resolveAlignmentInBuildingWorld` with the active building + * lookup so callers don't repeat the boilerplate. * * Returns: - * - `guides` in WORLD coords (renderer must live in a world-space group), + * - `guides` with `from` / `to` in WORLD coords (callers bring them back + * with `projectAlignmentGuidesWorldToActiveBuildingLocal`), * - `snap` in BUILDING-LOCAL coords (ready to add to a local position). */ export function resolveAlignmentForActiveBuilding(args: { @@ -82,7 +103,24 @@ export function resolveAlignmentForActiveBuilding(args: { candidates: readonly AlignmentAnchor[] threshold: number }): ResolveAlignmentInBuildingResult { - return resolveAlignmentInBuildingWorld({ ...args, pose: getActiveBuildingPose() }) + // Pose `null` resolves in the anchors' own (building-local) frame. + const result = resolveAlignmentInBuildingWorld({ ...args, pose: null }) + const pose = getActiveBuildingPose() + if (!pose) return result + return { + snap: result.snap, + guides: result.guides.map((guide) => { + const [fromX, fromZ] = poseLocalXZToWorld(guide.from.x, guide.from.z, pose) + const [toX, toZ] = poseLocalXZToWorld(guide.to.x, guide.to.z, pose) + return { ...guide, from: { x: fromX, z: fromZ }, to: { x: toX, z: toZ } } + }), + } +} + +function poseLocalXZToWorld(x: number, z: number, pose: BuildingPose): [number, number] { + const cos = Math.cos(pose.rotationY) + const sin = Math.sin(pose.rotationY) + return [pose.position[0] + x * cos + z * sin, pose.position[2] - x * sin + z * cos] } function worldXZToPoseLocal(x: number, z: number, pose: BuildingPose | null): [number, number] { @@ -97,9 +135,10 @@ function worldXZToPoseLocal(x: number, z: number, pose: BuildingPose | null): [n /** * Project WORLD-frame alignment guides into the active building's LOCAL frame. * - * The 3D alignment layer is still mounted inside the building-local tool group, - * so tools that resolve alignment on the world axes (item placement, slab move) - * need their guides converted before publishing to `useAlignmentGuides`. + * The 3D alignment layer is mounted inside the building-local tool group, so + * tools that resolve through `resolveAlignmentForActiveBuilding` (item + * placement, slab move) convert its guides before publishing to + * `useAlignmentGuides`. */ export function projectAlignmentGuidesWorldToActiveBuildingLocal( guides: readonly AlignmentGuide[], @@ -117,119 +156,77 @@ export function projectAlignmentGuidesWorldToActiveBuildingLocal( } /** - * Baseline rotation the floor-plan view applies on top of the building - * rotation. Mirrors `FLOORPLAN_VIEW_ROTATION_DEG = 0` in lib/floorplan/geometry.ts — - * the scene group reads it via `floorplanSceneRotationDeg = FVR - buildingRot`. - */ -const FLOORPLAN_VIEW_ROTATION_RAD = 0 - -function rotateAnchorsBy( - anchors: readonly AlignmentAnchor[], - cos: number, - sin: number, -): AlignmentAnchor[] { - return anchors.map((a) => ({ - nodeId: a.nodeId, - kind: a.kind, - x: a.x * cos - a.z * sin, - z: a.x * sin + a.z * cos, - })) -} - -/** - * Resolve alignment in the 2D floor-plan view frame — the frame the user - * sees the (always axis-aligned) grid lines in, regardless of how the - * building has been rotated. Use this from EVERY 2D floor-plan path so - * alignment guides stay parallel to the visible grid. + * Resolve alignment for the 2D floor plan, on the active building's own axes. + * Use this from EVERY 2D floor-plan path so alignment guides stay parallel to + * the plan's grid. * - * Why it differs from `resolveAlignmentForActiveBuilding`: the 3D viewport - * shows the world XZ grid, so world-frame alignment matches the visible - * grid there. The 2D floor plan, however, rotates the scene `` by - * `floorplanSceneRotationDeg = FVR − buildingRot` and renders the grid - * OUTSIDE that rotated group — so the visible axes are - * `R(FVR − buildingRot) · local`. World-frame alignment would land on - * world axes, which appear diagonal in this view; view-frame alignment - * lands on the SVG axes the user actually reads. + * The floor plan rotates its scene `` by the building's yaw (and the user's + * view rotation) and draws both its grid and the alignment-guide layer inside + * that group, in building-local metres. So the axes the user reads are the + * building's local axes, and guides must come back in local coords: resolving + * on world axes would align a turned building's corners on a diagonal to its + * walls and draw each guide away from the anchors it matched. * - * Returns guides in view-frame coords (correct input for the floor-plan - * alignment-guide layer, which is mounted outside the rotated scene - * group) and a snap delta projected back into building-local (so callers - * can add it to a local position as-is). + * Returns guides and the snap delta in building-local coords (add the delta + * to a local position as-is). */ export function resolveAlignmentForFloorplanView(args: { moving: readonly AlignmentAnchor[] candidates: readonly AlignmentAnchor[] threshold: number }): ResolveAlignmentInBuildingResult { - const pose = getActiveBuildingPose() - const buildingRotY = pose?.rotationY ?? 0 - const rot = FLOORPLAN_VIEW_ROTATION_RAD - buildingRotY - const cos = Math.cos(rot) - const sin = Math.sin(rot) - const result = resolveAlignmentInBuildingWorld({ - moving: rotateAnchorsBy(args.moving, cos, sin), - candidates: rotateAnchorsBy(args.candidates, cos, sin), - threshold: args.threshold, - // Pose `null` keeps `resolveAlignmentInBuildingWorld` in its no-op - // path: it just runs `resolveAlignment` on the already-rotated - // anchors and returns the snap delta in the same view frame. - pose: null, - }) - if (!result.snap) return result - // View-frame delta → local-frame delta (transpose of R(rot)). - const { dx, dz } = result.snap - return { - guides: result.guides, - snap: { dx: dx * cos + dz * sin, dz: -dx * sin + dz * cos }, - } + // Pose `null` resolves in the anchors' own (building-local) frame. + return resolveAlignmentInBuildingWorld({ ...args, pose: null }) } /** - * Snap a world XZ position to the grid, then express it in the active - * building's local frame. When no building is active, world == local. + * Snap a world XZ position onto the active building's grid lattice (see + * `snapBuildingLocalToWorldGrid`) and return the snapped point in both + * frames. With no active building, world == local and the world grid is the + * lattice. */ export function snapWorldXZForActiveBuilding( worldX: number, worldZ: number, step: number, ): { world: [number, number]; local: [number, number] } { - const buildingId = useViewer.getState().selection.buildingId - const building = buildingId ? useScene.getState().nodes[buildingId] : null - if (building?.type !== 'building') { - if (step <= 0) return { world: [worldX, worldZ], local: [worldX, worldZ] } - const sx = Math.round(worldX / step) * step - const sz = Math.round(worldZ / step) * step - return { world: [sx, sz], local: [sx, sz] } + const pose = getActiveBuildingPose() + if (!pose) { + const [x, z] = snapBuildingLocalToWorldGrid([worldX, worldZ], step) + return { world: [x, z], local: [x, z] } } - return snapWorldXZToBuildingLocal( - worldX, - worldZ, - building.position, - building.rotation[1] ?? 0, - step, - ) + const { local } = snapWorldXZToBuildingLocal(worldX, worldZ, pose.position, pose.rotationY, 0) + const [x, z] = snapBuildingLocalToWorldGrid(local, step) + return { world: poseLocalXZToWorld(x, z, pose), local: [x, z] } } /** - * Snap a building-local plan point so the resulting position sits on the - * world XZ grid. The returned point is still in building-local coords — - * useful as a `gridSnap` callback for snapWallDraftPoint / snapFenceDraftPoint - * etc., which operate entirely in the local frame. + * Snap a plan point in the 3D tools' frame (a grid event's `localPosition`) + * onto the lattice the grid is drawn on, one axis at a time with the caller's + * per-axis snap (an item snaps its edges by its own size). Inside a building + * the point is building-local and the lattice runs along the building's axes; + * outside any building it is the world point and the world grid is the + * lattice — so no pose is needed either way. + */ +export function snapPlanPointToActiveGrid( + point: readonly [number, number], + snap: (value: number, axis: 0 | 1) => number, +): [number, number] { + return [snap(point[0], 0), snap(point[1], 1)] +} + +/** + * Snap a building-local plan point onto the building's own grid lattice: + * multiples of `step` along its local axes from its origin, the lattice both + * views draw and the wall tool drafts on. Coordinates in and out are + * building-local, so it suits a `gridSnap` callback for snapWallDraftPoint / + * snapFenceDraftPoint etc. (The name predates the building frame: it used to + * snap onto the world XZ grid, at a turned building's yaw to the house.) */ export function snapBuildingLocalToWorldGrid( local: readonly [number, number], step: number, ): [number, number] { - const buildingId = useViewer.getState().selection.buildingId - const building = buildingId ? useScene.getState().nodes[buildingId] : null - if (building?.type !== 'building') { - if (step <= 0) return [local[0], local[1]] - return [Math.round(local[0] / step) * step, Math.round(local[1] / step) * step] - } - const rotY = building.rotation[1] ?? 0 - const cos = Math.cos(rotY) - const sin = Math.sin(rotY) - const worldX = building.position[0] + local[0] * cos + local[1] * sin - const worldZ = building.position[2] - local[0] * sin + local[1] * cos - return snapWorldXZToBuildingLocal(worldX, worldZ, building.position, rotY, step).local + if (step <= 0) return [local[0], local[1]] + return snapPlanPointToActiveGrid(local, (value) => Math.round(value / step) * step) } diff --git a/packages/editor/src/store/use-alignment-guides.ts b/packages/editor/src/store/use-alignment-guides.ts index 4f6f3eff67..09dc4c684e 100644 --- a/packages/editor/src/store/use-alignment-guides.ts +++ b/packages/editor/src/store/use-alignment-guides.ts @@ -6,16 +6,42 @@ import type { AlignmentGuide } from '@pascal-app/core' import { create } from 'zustand' +/** + * A wall draft's dashed projection guide, in building-local plan coordinates: + * the extension of the wall the draft comes from, a line through another wall's + * end on one of the house's axes, or the same through the run's start. + */ +export type DraftGuideLine = { + kind: 'extension' | 'alignment' | 'run-start' + from: [number, number] + to: [number, number] +} + +/** + * The projection guides of a wall pulled from a selected wall's end (and of + * the run it continues): dashed lines, and markers where two of them cross. + */ +export type DraftGuides = { + lines: DraftGuideLine[] + intersections: Array<[number, number]> +} + type AlignmentGuidesState = { guides: AlignmentGuide[] + /** A wall draft's projection guides, drawn by the same layers; null when none. */ + draft: DraftGuides | null set(guides: AlignmentGuide[]): void + /** Publish a wall draft's projection guides, which take the place of alignment guides. */ + setDraft(draft: DraftGuides | null): void clear(): void } const useAlignmentGuides = create((set) => ({ guides: [], + draft: null, set: (guides) => set({ guides }), - clear: () => set({ guides: [] }), + setDraft: (draft) => set({ guides: [], draft }), + clear: () => set({ guides: [], draft: null }), })) export default useAlignmentGuides diff --git a/packages/editor/src/store/use-editor.tsx b/packages/editor/src/store/use-editor.tsx index f64c2c5d56..b9c026e3ba 100644 --- a/packages/editor/src/store/use-editor.tsx +++ b/packages/editor/src/store/use-editor.tsx @@ -528,6 +528,24 @@ type EditorState = { setReferenceFloorOffset: (offset: number) => void referenceFloorOpacity: number setReferenceFloorOpacity: (opacity: number) => void + // The 2D plan's dashed outlines of the walls on the level below / above + // the active one. "Below" is set apart for the roof plan, where it traces + // the top storey's walls the roof is checked against and starts on, and the + // floor plans, where it starts off (`useWallsBelowSetting`). Persisted. + showWallsBelow: boolean + setShowWallsBelow: (show: boolean) => void + showRoofWallsBelow: boolean + setShowRoofWallsBelow: (show: boolean) => void + showWallsAbove: boolean + setShowWallsAbove: (show: boolean) => void + // Ceilings drawn solid from above as well as from below. Set apart like + // "Walls below": on for the roof level, where the roof is checked over closed + // rooms, off for the floor plans, where the camera looks into the rooms + // (`useCeilingsSetting`). Persisted. + showCeilings: boolean + setShowCeilings: (show: boolean) => void + showRoofCeilings: boolean + setShowRoofCeilings: (show: boolean) => void // Development-only camera debug flag for inspecting underside geometry allowUndergroundCamera: boolean setAllowUndergroundCamera: (enabled: boolean) => void @@ -605,6 +623,11 @@ type PersistedEditorLayoutState = Pick< | 'showReferenceFloor' | 'referenceFloorOffset' | 'referenceFloorOpacity' + | 'showWallsBelow' + | 'showRoofWallsBelow' + | 'showWallsAbove' + | 'showCeilings' + | 'showRoofCeilings' > type PersistedEditorState = PersistedEditorUiState & PersistedEditorLayoutState @@ -640,6 +663,11 @@ export const DEFAULT_PERSISTED_EDITOR_LAYOUT_STATE: PersistedEditorLayoutState = showReferenceFloor: false, referenceFloorOffset: 1, referenceFloorOpacity: 0.35, + showWallsBelow: false, + showRoofWallsBelow: true, + showWallsAbove: false, + showCeilings: false, + showRoofCeilings: true, } const GRID_SNAP_STEPS: GridSnapStep[] = [0.5, 0.25, 0.1, 0.05] @@ -899,6 +927,11 @@ export function normalizePersistedEditorLayoutState( Number.isFinite(state.referenceFloorOpacity) ? Math.min(0.8, Math.max(0.1, state.referenceFloorOpacity)) : DEFAULT_PERSISTED_EDITOR_LAYOUT_STATE.referenceFloorOpacity, + showWallsBelow: state?.showWallsBelow === true, + showRoofWallsBelow: state?.showRoofWallsBelow !== false, + showWallsAbove: state?.showWallsAbove === true, + showCeilings: state?.showCeilings === true, + showRoofCeilings: state?.showRoofCeilings !== false, } } @@ -1568,6 +1601,16 @@ const useEditor = create()( referenceFloorOpacity: DEFAULT_PERSISTED_EDITOR_LAYOUT_STATE.referenceFloorOpacity, setReferenceFloorOpacity: (opacity) => set({ referenceFloorOpacity: Math.min(0.8, Math.max(0.1, opacity)) }), + showWallsBelow: DEFAULT_PERSISTED_EDITOR_LAYOUT_STATE.showWallsBelow, + setShowWallsBelow: (show) => set({ showWallsBelow: show }), + showRoofWallsBelow: DEFAULT_PERSISTED_EDITOR_LAYOUT_STATE.showRoofWallsBelow, + setShowRoofWallsBelow: (show) => set({ showRoofWallsBelow: show }), + showWallsAbove: DEFAULT_PERSISTED_EDITOR_LAYOUT_STATE.showWallsAbove, + setShowWallsAbove: (show) => set({ showWallsAbove: show }), + showCeilings: DEFAULT_PERSISTED_EDITOR_LAYOUT_STATE.showCeilings, + setShowCeilings: (show) => set({ showCeilings: show }), + showRoofCeilings: DEFAULT_PERSISTED_EDITOR_LAYOUT_STATE.showRoofCeilings, + setShowRoofCeilings: (show) => set({ showRoofCeilings: show }), allowUndergroundCamera: false, setAllowUndergroundCamera: (enabled) => set({ allowUndergroundCamera: enabled }), show2dVoronoi: false, @@ -1672,6 +1715,11 @@ const useEditor = create()( showReferenceFloor: state.showReferenceFloor, referenceFloorOffset: state.referenceFloorOffset, referenceFloorOpacity: state.referenceFloorOpacity, + showWallsBelow: state.showWallsBelow, + showRoofWallsBelow: state.showRoofWallsBelow, + showWallsAbove: state.showWallsAbove, + showCeilings: state.showCeilings, + showRoofCeilings: state.showRoofCeilings, }), skipHydration: true, }, diff --git a/packages/editor/src/store/use-floorplan-annotation-visibility.test.ts b/packages/editor/src/store/use-floorplan-annotation-visibility.test.ts new file mode 100644 index 0000000000..bc6acab98f --- /dev/null +++ b/packages/editor/src/store/use-floorplan-annotation-visibility.test.ts @@ -0,0 +1,64 @@ +import { afterEach, describe, expect, test } from 'bun:test' + +const STORAGE_KEY = 'pascal-floorplan-annotation-visibility' +const savedWindow = Object.getOwnPropertyDescriptor(globalThis, 'window') +afterEach(() => { + if (savedWindow) Object.defineProperty(globalThis, 'window', savedWindow) + else Reflect.deleteProperty(globalThis, 'window') +}) + +/** A browser's localStorage, seeded with what an earlier session saved. */ +function stubStorage(state?: Record) { + const values = new Map( + state ? [[STORAGE_KEY, JSON.stringify({ state, version: 0 })]] : [], + ) + const localStorage: Partial = { + getItem: (key) => values.get(key) ?? null, + setItem: (key, value) => void values.set(key, value), + removeItem: (key) => void values.delete(key), + } + Object.defineProperty(globalThis, 'window', { configurable: true, value: { localStorage } }) + return { read: () => JSON.parse(values.get(STORAGE_KEY) ?? 'null')?.state } +} + +let fresh = 0 +async function loadStore() { + const { default: store } = await import( + `./use-floorplan-annotation-visibility.ts?load=${++fresh}` + ) + return store as typeof import('./use-floorplan-annotation-visibility').default +} + +describe('Display dimension preferences', () => { + test('a first visit shows dimensions and measures walls to both faces', async () => { + stubStorage() + const store = await loadStore() + await store.persist.rehydrate() + + expect(store.getState().showDimensions).toBe(true) + expect(store.getState().wallDimensionFaces).toBe('both') + }) + + test('a stale saved choice, from the retired Wall dimensions option, opens on Both', async () => { + stubStorage({ wallDimensionReference: 'stud-faces', wallDimensionFaces: 'centerline' }) + const store = await loadStore() + await store.persist.rehydrate() + + expect(store.getState().wallDimensionFaces).toBe('both') + expect(store.getState()).not.toHaveProperty('wallDimensionReference') + }) + + test('Dimensions and Measure walls come back after a reload', async () => { + const storage = stubStorage() + const firstSession = await loadStore() + await firstSession.persist.rehydrate() + firstSession.getState().setShowDimensions(false) + firstSession.getState().setWallDimensionFaces('interior') + expect(storage.read()).toMatchObject({ showDimensions: false, wallDimensionFaces: 'interior' }) + + const nextSession = await loadStore() + await nextSession.persist.rehydrate() + expect(nextSession.getState().showDimensions).toBe(false) + expect(nextSession.getState().wallDimensionFaces).toBe('interior') + }) +}) diff --git a/packages/editor/src/store/use-floorplan-annotation-visibility.ts b/packages/editor/src/store/use-floorplan-annotation-visibility.ts index 2c9f21864e..1e892a0f0c 100644 --- a/packages/editor/src/store/use-floorplan-annotation-visibility.ts +++ b/packages/editor/src/store/use-floorplan-annotation-visibility.ts @@ -9,49 +9,74 @@ import { normalizeFloorplanAnnotationVisibility, } from '../lib/floorplan/annotation-visibility' import { - DEFAULT_FLOORPLAN_WALL_DIMENSION_REFERENCE, - type FloorplanWallDimensionReference, - normalizeFloorplanWallDimensionReference, + DEFAULT_FLOORPLAN_WALL_DIMENSION_FACES, + type FloorplanWallDimensionFaces, + normalizeFloorplanWallDimensionFaces, } from '../lib/floorplan/floorplan-extension' -type FloorplanAnnotationVisibilityState = { +type PersistedFloorplanAnnotationState = { visibility: FloorplanAnnotationVisibility - wallDimensionReference: FloorplanWallDimensionReference + showDimensions: boolean + wallDimensionFaces: FloorplanWallDimensionFaces +} + +type FloorplanAnnotationVisibilityState = PersistedFloorplanAnnotationState & { setCategory: (category: FloorplanAnnotationCategory, visible: boolean) => void - setWallDimensionReference: (reference: FloorplanWallDimensionReference) => void + setShowDimensions: (shown: boolean) => void + setWallDimensionFaces: (faces: FloorplanWallDimensionFaces) => void reset: () => void } +const defaultState = (): PersistedFloorplanAnnotationState => ({ + visibility: { ...DEFAULT_FLOORPLAN_ANNOTATION_VISIBILITY }, + showDimensions: true, + wallDimensionFaces: DEFAULT_FLOORPLAN_WALL_DIMENSION_FACES, +}) + +/** + * The persisted part of the store, read back from storage. Anything stale or + * unknown (an older shape, a retired `wallDimensionReference`) falls back to + * the default. + */ +function normalizeFloorplanAnnotationState(persisted: unknown): PersistedFloorplanAnnotationState { + const record = (persisted && typeof persisted === 'object' ? persisted : {}) as Record< + string, + unknown + > + return { + visibility: normalizeFloorplanAnnotationVisibility(record.visibility), + showDimensions: record.showDimensions !== false, + wallDimensionFaces: normalizeFloorplanWallDimensionFaces(record.wallDimensionFaces), + } +} + +/** + * Display preferences for dimensions and annotations, kept per browser: + * Display → Dimensions (`showDimensions`) and Measure walls + * (`wallDimensionFaces`) apply to the plan and the 3D view; `visibility` is + * the Expert plan's annotation categories. + */ const useFloorplanAnnotationVisibility = create()( persist( (set) => ({ - visibility: { ...DEFAULT_FLOORPLAN_ANNOTATION_VISIBILITY }, - wallDimensionReference: DEFAULT_FLOORPLAN_WALL_DIMENSION_REFERENCE, + ...defaultState(), setCategory: (category, visible) => set((state) => ({ visibility: { ...state.visibility, [category]: visible } })), - setWallDimensionReference: (wallDimensionReference) => set({ wallDimensionReference }), - reset: () => - set({ - visibility: { ...DEFAULT_FLOORPLAN_ANNOTATION_VISIBILITY }, - wallDimensionReference: DEFAULT_FLOORPLAN_WALL_DIMENSION_REFERENCE, - }), + setShowDimensions: (showDimensions) => set({ showDimensions }), + setWallDimensionFaces: (wallDimensionFaces) => set({ wallDimensionFaces }), + reset: () => set(defaultState()), }), { name: 'pascal-floorplan-annotation-visibility', merge: (persistedState, currentState) => ({ ...currentState, - visibility: normalizeFloorplanAnnotationVisibility( - (persistedState as { visibility?: unknown } | undefined)?.visibility, - ), - wallDimensionReference: normalizeFloorplanWallDimensionReference( - (persistedState as { wallDimensionReference?: unknown } | undefined) - ?.wallDimensionReference, - ), + ...normalizeFloorplanAnnotationState(persistedState), }), partialize: (state) => ({ visibility: state.visibility, - wallDimensionReference: state.wallDimensionReference, + showDimensions: state.showDimensions, + wallDimensionFaces: state.wallDimensionFaces, }) as FloorplanAnnotationVisibilityState, }, ), diff --git a/packages/editor/src/store/use-wall-snap-indicator.ts b/packages/editor/src/store/use-wall-snap-indicator.ts index 9cdbd4a9c2..4a98e59adf 100644 --- a/packages/editor/src/store/use-wall-snap-indicator.ts +++ b/packages/editor/src/store/use-wall-snap-indicator.ts @@ -7,8 +7,19 @@ import { create } from 'zustand' -/** Which kind of wall geometry the draft point snapped to. */ -export type WallSnapKind = 'endpoint' | 'midpoint' | 'intersection' | 'wall' +/** + * Which kind of geometry the draft point snapped to. A pulled wall also lands + * square on a wall (`perpendicular`), on a projection guide (`alignment`), or + * at a grid length (`grid`). + */ +export type WallSnapKind = + | 'endpoint' + | 'midpoint' + | 'intersection' + | 'wall' + | 'perpendicular' + | 'alignment' + | 'grid' export type WallSnapPoint = { /** Building-local plan coordinates (XZ meters). */ @@ -17,6 +28,8 @@ export type WallSnapPoint = { kind: WallSnapKind /** Optional wall ids whose geometry produced this snap. */ wallIds?: string[] + /** Words the marker shows beside its glyph ("Endpoint", "On wall"); none when absent. */ + label?: string } type WallSnapIndicatorState = { diff --git a/packages/ifc-converter/src/index.ts b/packages/ifc-converter/src/index.ts index f7b2e90c17..ffe20a9a82 100644 --- a/packages/ifc-converter/src/index.ts +++ b/packages/ifc-converter/src/index.ts @@ -24,6 +24,7 @@ import { ZoneNode, zoneColorForSeed, } from '@pascal-app/core' +import { NEW_DOOR_FRAME_THICKNESS } from '@pascal-app/core/building' import * as WebIFC from 'web-ifc' import { extractBeamGeometry } from './beam-geometry' import { type IfcConversionSimplificationOptions, simplifyConvertedSceneGraph } from './cleanup' @@ -1859,6 +1860,7 @@ export async function convertIfcToPascalWithReport( object: 'node', id: nodeId, type: 'door', + frameThickness: NEW_DOOR_FRAME_THICKNESS, name: element.Name?.value || `Door`, parentId: wallNodeId, visible: true, @@ -2049,6 +2051,7 @@ export async function convertIfcToPascalWithReport( object: 'node', id: nodeId, type: 'door', + frameThickness: NEW_DOOR_FRAME_THICKNESS, name: element.Name?.value || `Door`, parentId: parentNodeId, visible: true, diff --git a/packages/ifc-converter/tests/openings.test.ts b/packages/ifc-converter/tests/openings.test.ts index 4623372205..8bc2fefa6a 100644 --- a/packages/ifc-converter/tests/openings.test.ts +++ b/packages/ifc-converter/tests/openings.test.ts @@ -21,6 +21,7 @@ function assertUniqueFills(graph: PascalSceneGraph) { fills.map((node) => node.metadata?.expressID).sort((a, b) => Number(a) - Number(b)), ).toEqual(fillIds) for (const fill of fills) { + if (fill.type === 'door') expect(fill.frameThickness).toBe(0.02) const parent = fill.parentId ? graph.nodes[fill.parentId] : undefined expect(parent).toBeDefined() if (parent && 'children' in parent) { diff --git a/packages/mcp/README.md b/packages/mcp/README.md index ea8f01c7d2..3b336b036f 100644 --- a/packages/mcp/README.md +++ b/packages/mcp/README.md @@ -408,8 +408,8 @@ is a "pitch" fraction like `"1/4 pitch"`, which is rise over span. | `find_by_type` | Find everything of one type: nodes of a kind (any core or plugin kind), items of a category, lights, and typed parts inside authored objects, windows and doors; narrowed by level, parent, zone (on its level, by plan point, holes left out) or import source id (`provenance.refs[].id` or legacy `metadata.sourceIds`, exact or prefix); without a type, every node the filters match. Each result is the node's id, name, kind, level and parent, with its metadata and provenance (one over 1 KB named in `omitted`). | `{ type?, levelId?, parentId?, zoneId?, sourceId?, sourceIdPrefix?, limit? }` | `{ type?, count, nodes, parts, results[], truncated?, hint? }`, at most `limit` (200) results listed; refusals `unknown_type`, `level_not_found`, `node_not_found`, `zone_not_found`, `not_a_zone` | | `list_levels` | List every building's levels in floor order with their role (storey, roof-only, support), their standing against the ground line (`gradeStanding`, `isGroundLevel`) and, per building, the level at grade. | — | `{ activeSceneId, activeLevelId, levelCount, occupiedStoryCount, supportLevelCount, roofLevelIds, groundLevels[], levels[] }` | | `get_level_summary` | Compact summary of one level: role, counts, walls with openings, zones with areas, slabs, ceilings, items, stairs, roofs, and everything else by type. Omit `levelId` for the lowest storey. | `{ levelId?, level? }` | `{ levelId, role, counts, walls, zones, slabs, ceilings, items, stairs, roofs, other }` | -| `get_walls` | Walls on a level with length, stored and resolved height, and child doors/windows. | `{ levelId?, level? }` | `{ levelId, walls[] }` | -| `get_zones` | Room/zone polygons with holes, areas (holes taken out), bounds and floor choices. | `{ levelId?, level? }` | `{ levelId, zones[] }` | +| `get_walls` | Walls on a level with length, stored and resolved height, and child doors/windows. Each wall reports type `{ id, label }` or null; wallTypes lists available preset and project types. wallType reads standard (when absent), railing or curtain. | `{ levelId?, level? }` | `{ levelId, walls[] }` | +| `get_zones` | Room/zone polygons with holes, areas (holes taken out), bounds and floor choices. Reports roomType (room/porch/deck/patio), floor.drop in metres, porchFraming (auto, postSize, postSpacing in metres, beamSize, postCount, beamCount; null with no intent), and decking (boardSize, gap in metres, direction), matching set_zone_intent. | `{ levelId?, level? }` | `{ levelId, zones[] }` | | `get_site` | The site a building stands on, in its level coordinates (a lot with no building yet, in site coordinates): the lot and its area with the footprint a house usually covers (30 to 45%), the buildable area inside the setbacks with its centre, area, each edge's frontage and depth and its front edge, the street side with the lot's frontage and depth, north, the ground (sloped, read flat or not read), address, parcel and zoning, whether the lot is the new-project placeholder, and the footprint's fit and yards. | `{ building?, site? }` | `{ siteId, buildingId, pose, lot, placeholder, buildable, street, ground, northDeg, address, parcel, zone, footprint, others, summary }`; refusals `no_site`, `building_required`, `site_not_found`, `not_a_site`, `building_not_on_site` | | `place_building` | Stand a building on its site by moving the building node only (walls keep their level coordinates): its footprint, the outline about to be drawn or the walls standing, centred in the buildable area or at the yards given; a house standing keeps its rotation unless `rotationDeg` is given, one with no walls yet is squared to the street. | `{ building?, outline?, yards?: { front?, rear?, left?, right? }, rotationDeg? }` | `{ buildingId, position, rotationDeg, moved, footprint, yards, fit, overhang, movedWithIt?, message }`; refusals `no_site`, `needs_footprint`, `other_building_on_site`, `no_street`, `yards_conflict`, `yards_infeasible`, `building_required` | | `measure` | Distance between two nodes' world-space reference points (hosted doors, windows and items resolved through their host; every node kind); area when applicable. | `{ fromId, toId }` | `{ distanceMeters, fromPoint?, toPoint?, areaSqMeters?, units: 'meters' }` | @@ -434,7 +434,9 @@ is a "pitch" fraction like `"1/4 pitch"`, which is rise over span. | `apply_patch` | Batched create/update/delete/move, validated and dry-run before commit. Batch-first is the default: send all create/update/delete ops for a build step in one atomic call (stable order, later ops may reference earlier created ids); do not loop one-op calls. A create with an id already in the scene is refused (`node_exists`); delete it earlier in the same patch to replace it. Updates cannot change `id` or `type` (`identity_change`), `object` or `children` (`immutable_field`), move a node under a missing or childless parent (`invalid_parent`), or add schema issues (`invalid_update`); default gutters and downspouts a delete regenerates are addressable only in a later call (`regenerated_default`). Refusals are tool errors with JSON text `{ code, patchIndex, id, message }`. A level created without a `height`, or an update that clears it, gets the height the editor's load derives from what the level holds (an empty level: 2.5 m), one line per level in `notes`. A roof the patch makes or moves onto the storey whose walls carry it is seated on the level above those walls, one line per roof in `notes`; a new storey at or above the roof level moves it up. Refused: storey content on a roof level (`roof_level`), declaring a level that holds storey content the roof level (`roof_level_holds_storey`), floor indexes that put the roof level under a storey (`roof_level_on_top`). | `{ patches: Patch[] }` | `{ applied: number, notes?: string[] }` | | `add_level` | Add an empty level to a building, as the editor does: on top of its storeys, under its roof level (which moves up one), or below the lowest for a basement (every existing floor, the ground floor included, keeps its place). Omit `buildingId` for the scene's only building. | `{ buildingId?, position?, name?, height? }` | `{ levelId, buildingId, floorIndex, height, shiftedLevelIds? }`; refusals `building_required`, `building_not_found`, `no_building` | | `set_ground_level` | Make a level the building's ground floor, as the level panel's "Set as ground floor": the building names it, is seated so that floor stands over grade as the building's foundation construction seats it, the top of the foundation (8 in, 0.203 m, on block: the default and the US; 0.15 m on cast concrete in Europe; height only, the plan stays), and the floor indexes are renumbered so it is 0 and the levels under it are the basements. | `{ levelId }` | `{ levelId, buildingId, floorElevation, aboveGrade, foundation { region, construction, basis }, movedBuildingBy, renumbered, unchanged? }`; refusals `level_not_found`, `not_a_level`, `no_building`, `not_a_storey` | -| `add_wall` | Add a wall to a level, straight or, with `curveOffset`, an arc. Omit `levelId` for the lowest storey. | `{ start, end, levelId?, thickness?, height?, curveOffset? }` | `{ wallId, levelId, length }`; refusals `roof_level`, `wall_too_short`, `level_not_found` | +| `add_wall` | Add a wall to a level, straight or, with `curveOffset`, an arc. Omit `levelId` for the lowest storey. wallType railing builds a guard (default 0.9144 m high); railing sets style, posts, infill and cap; postSize sets thickness. | `{ start, end, levelId?, thickness?, height?, curveOffset?, type?, wallType?, railing? }` | `{ wallId, levelId, length }`; refusals `roof_level`, `wall_too_short`, `level_not_found`, `unknown_wall_type` | +| `set_wall_type` | Apply a preset or project wall assembly to existing standard walls; copies layers and total thickness. null clears the assembly. | `{ wallIds, type }` | `{ ok, wallIds, type }`; refusals `unknown_wall_type`, `target_not_found`, `curtain_wall`, `railing_wall` | +| `add_column` | Add or rebuild a column. role post uses the Post tile: square pressure-treated wood, postSize 4x4, 6x6 (default), 8x8; postBase none (default), post-base (steel), pier (concrete). | `{ x?, z?, level?, role?, postSize?, postBase?, height?, nodeId?, ... }` | `{ columnId, nodeId, height, width, depth }`; `not_a_post` for post choices on an ordinary column | | `add_fence` | Add a fence along points on a level, one fence per side; `closed` runs it back to the first point (a lot's boundary). Privacy panels unless `style` says otherwise. | `{ points, closed?, height?, style?, baseStyle?, materialPreset?, levelId? }` | `{ count, fenceIds, levelId, length, achieved }`; refusals `fence_too_short`, `roof_level`, `unknown_material`, `level_not_found` | | `place_items` | Place catalog items in one call, each placed or refused on its own, at level `(x, z)`: on the level's floor, or on the host each names (`targetNodeId`): a wall (`y`, the height of its bottom, required), a ceiling, or an item standing on the floor. A floor item in a door's clearance is refused `blocks_door` (naming the door and a spot that clears every door), one its room cannot hold in any turn `too_large_for_room`. | `{ items: [{ assetId, x, z, y?, targetNodeId?, rotation? }], levelId? }` | `{ levelId, items: [{ ok, itemId?, hostId?, restingOn?, code? }] }`; per-item refusals `asset_not_found`, `outside_rooms`, `blocks_door`, `too_large_for_room`, `height_required`, `item_too_tall`, `unsupported_host`, `host_not_found`, `host_not_on_level` | | `place_design` | Create one design (procedural item recipe, object or JSON string) that passes `validate_design`. Its mounting picks the host: level/slab/zone or a design surface (`surfaceId`), a straight wall face, or a ceiling. Create-only, one undo step, inline designs up to 24 KiB, with coded refusals. | `{ design, hostId, position, rotation?, side?, surfaceId?, parameters?, slots?, name?, id? }` | `{ designId, parentId, surfaceId }` | diff --git a/packages/mcp/src/resources/agent-guide.ts b/packages/mcp/src/resources/agent-guide.ts index e5e63277cc..aa9431ed20 100644 --- a/packages/mcp/src/resources/agent-guide.ts +++ b/packages/mcp/src/resources/agent-guide.ts @@ -39,6 +39,10 @@ export const AGENT_GUIDE = [ '## Scene Facts and Tools', '', '- `get_site` gives the lot, the buildable area inside its setbacks with its centre and its frontage and depth on the street, the footprint a house usually covers, the ground and whether the lot is only the new-project placeholder, in the level coordinates you draw in. `place_building` takes the outline of the plan about to be drawn, in the coordinates it will be drawn in (and the yards a site plan gives), so the house rises inside the lot, centred. `create_room` and `add_wall` take your coordinates as given and say when they cross the lot line; `verify_scene` reports a house past it.', + '- `get_walls.wallTypes` lists assembly preset and project type ids and labels. `add_wall.type` copies the assembly and its total thickness; `set_wall_type({ wallIds, type })` changes existing standard walls (null clears the assembly, keeping thickness). Unknown ids refuse `unknown_wall_type`. Each wall reads its known type as `{ id, label }`, or null.', + '- `add_column` with role post makes a framing post: postSize 4x4, 6x6 (default), or 8x8; postBase none (default), post-base (steel), or pier (concrete). Height in metres defaults to the beam above or ceiling plane, as the Post tile does.', + '- `add_wall.wallType` is standard (default) or railing. A railing defaults to the Build panel post-and-rail guard, height 0.9144 m, with style-specific members. railing accepts style, postSpacing, postSize (sets thickness), infillSize, infillGap, bottomClearance (metres) and cap. It takes no assembly or foundation. Windows refuse railing_window; skirting refuses railing_wall; doors are gaps. `get_walls` reports wallType.', + '- `get_zones` reports roomType room (when absent), porch, deck or patio; floor.drop in metres (0 when absent; explicit floor.elevation wins); porchFraming auto, postSize, postSpacing in metres, beamSize, postCount and beamCount of generated parts still present (null with no outdoor/framing intent); and decking boardSize, gap in metres, direction, including deck defaults. Covered porches frame by default; decks/patios only with auto true. auto false leaves framing to hand edits. `set_zone_intent.patch` uses the same names and units.', '- A semantic tool performs the editor’s own operation for what it makes; `apply_patch` writes graph nodes as given, so it carries none of that.', "- A call whose arguments a tool's schema rejects is refused with the code `invalid_input` before anything runs and its message names the arguments. A level you write without a `height` is given the height the editor would derive from what it holds (an empty level 2.5 m), and `apply_patch` says so in `notes`.", '- `apply_patch` takes create/update/delete ops in one call, applied in order so later ops can reference ids created earlier. A single call is atomic (all or nothing).', diff --git a/packages/mcp/src/resources/resources.test.ts b/packages/mcp/src/resources/resources.test.ts index 237c892b8a..522f6ecacd 100644 --- a/packages/mcp/src/resources/resources.test.ts +++ b/packages/mcp/src/resources/resources.test.ts @@ -239,6 +239,7 @@ describe('pascal://agent-guide', () => { 'roof_mixed_in_storey', 'room_named_by_person', 'scene_wipe_blocked', + 'unknown_wall_type', ] // Hosted-only tools: the hosted server registers them beside the package's. const HOSTED_ONLY_TOOLS = [ diff --git a/packages/mcp/src/templates/empty-studio.ts b/packages/mcp/src/templates/empty-studio.ts index 0944ab99e8..ec1ef22688 100644 --- a/packages/mcp/src/templates/empty-studio.ts +++ b/packages/mcp/src/templates/empty-studio.ts @@ -1,4 +1,5 @@ import { DEFAULT_LEVEL_HEIGHT } from '@pascal-app/core' +import { NEW_DOOR_FRAME_THICKNESS } from '@pascal-app/core/building' import type { SceneGraph } from '@pascal-app/core/clone-scene-graph' import type { AnyNode, AnyNodeId } from '@pascal-app/core/schema' @@ -73,7 +74,7 @@ function buildNodes(): StudioNodes { rotation: [0, 0, 0], width: 0.9, height: 2.1, - frameThickness: 0.05, + frameThickness: NEW_DOOR_FRAME_THICKNESS, threshold: true, thresholdHeight: 0.02, hingesSide: 'left', diff --git a/packages/mcp/src/templates/garden-house.ts b/packages/mcp/src/templates/garden-house.ts index 93d3e5cf01..d48b4d86b6 100644 --- a/packages/mcp/src/templates/garden-house.ts +++ b/packages/mcp/src/templates/garden-house.ts @@ -1,3 +1,4 @@ +import { NEW_DOOR_FRAME_THICKNESS } from '@pascal-app/core/building' import type { SceneGraph } from '@pascal-app/core/clone-scene-graph' import type { AnyNode, AnyNodeId } from '@pascal-app/core/schema' @@ -64,7 +65,7 @@ function door(id: string, parentWallId: string, width = 0.9): AnyNode { rotation: [0, 0, 0], width, height: 2.1, - frameThickness: 0.05, + frameThickness: NEW_DOOR_FRAME_THICKNESS, threshold: true, thresholdHeight: 0.02, hingesSide: 'left', diff --git a/packages/mcp/src/templates/templates.test.ts b/packages/mcp/src/templates/templates.test.ts index 8277811186..d94ea8967d 100644 --- a/packages/mcp/src/templates/templates.test.ts +++ b/packages/mcp/src/templates/templates.test.ts @@ -31,6 +31,7 @@ describe('scene templates', () => { ) } expect(res.success).toBe(true) + if (res.data.type === 'door') expect(res.data.frameThickness).toBe(0.02) } }) diff --git a/packages/mcp/src/templates/two-bedroom.ts b/packages/mcp/src/templates/two-bedroom.ts index e385cfd08c..60883efdd5 100644 --- a/packages/mcp/src/templates/two-bedroom.ts +++ b/packages/mcp/src/templates/two-bedroom.ts @@ -1,3 +1,4 @@ +import { NEW_DOOR_FRAME_THICKNESS } from '@pascal-app/core/building' import type { SceneGraph } from '@pascal-app/core/clone-scene-graph' import type { AnyNode, AnyNodeId } from '@pascal-app/core/schema' @@ -65,7 +66,7 @@ function door(id: string, parentWallId: string): AnyNode { rotation: [0, 0, 0], width: 0.8, height: 2.1, - frameThickness: 0.05, + frameThickness: NEW_DOOR_FRAME_THICKNESS, threshold: true, thresholdHeight: 0.02, hingesSide: 'left', diff --git a/packages/mcp/src/tools/measure-world.test.ts b/packages/mcp/src/tools/measure-world.test.ts index 42fab0d910..575e7b3df8 100644 --- a/packages/mcp/src/tools/measure-world.test.ts +++ b/packages/mcp/src/tools/measure-world.test.ts @@ -43,6 +43,7 @@ type MeasurePayload = { /** Fields a kind needs beyond its schema defaults (mirrors core's node fixtures). */ const REQUIRED_FIELDS: Record> = { 'procedural-item': { recipe: shelfRecipe }, + beam: { start: [0, 0], end: [4, 0] }, ceiling: { polygon: [ [0, 0], diff --git a/packages/mcp/src/tools/read-tool-annotations.test.ts b/packages/mcp/src/tools/read-tool-annotations.test.ts index 3bd96c3a1e..b29d82b687 100644 --- a/packages/mcp/src/tools/read-tool-annotations.test.ts +++ b/packages/mcp/src/tools/read-tool-annotations.test.ts @@ -98,6 +98,7 @@ const TOOL_POLICIES = [ 'add_object', 'author_scene', 'add_column', + 'set_wall_type', 'edit_collection', 'create_from_template', 'create_house_from_brief', diff --git a/packages/mcp/src/tools/shared-tools.test.ts b/packages/mcp/src/tools/shared-tools.test.ts index fc4e576ef1..cbbd1bdabf 100644 --- a/packages/mcp/src/tools/shared-tools.test.ts +++ b/packages/mcp/src/tools/shared-tools.test.ts @@ -10,6 +10,7 @@ import { AGENT_TOOL_CASES } from '../../../core/src/agent-operations/__fixtures_ import { CATALOG_BRIEF } from '../../../core/src/agent-operations/__fixtures__/design-brief-cases' import { SceneBridge } from '../bridge/scene-bridge' import { createSceneOperations } from '../operations' +import { registerAddColumn } from './add-column' import { ADDITIVE_TOOL_ANNOTATIONS } from './annotations' import { type AssetCatalog, builtInCatalog } from './asset-catalog' import { type PlanReadingHosts, registerOperationTool, registerSharedTools } from './shared-tools' @@ -84,6 +85,7 @@ describe('shared tools over MCP', () => { beforeEach(async () => { bridge = new SceneBridge() const server = new McpServer({ name: 'test', version: '0.0.0' }) + registerAddColumn(server, createSceneOperations({ bridge, activeLevelId: () => viewed })) registerSharedTools( server, createSceneOperations({ bridge, activeLevelId: () => viewed }), diff --git a/packages/mcp/src/tools/shared-tools.ts b/packages/mcp/src/tools/shared-tools.ts index c98507ab8c..767472e23e 100644 --- a/packages/mcp/src/tools/shared-tools.ts +++ b/packages/mcp/src/tools/shared-tools.ts @@ -61,6 +61,7 @@ import { setCheckpointTool, setGroundLevelTool, setUnitMembersTool, + setWallTypeTool, validateDesignTool, verifySceneTool, viewAssetsTool, @@ -237,7 +238,11 @@ const SHARED_TOOLS: SharedTool[] = [ contract: getWallsTool, operation: AGENT_OPERATIONS.get_walls, annotations: READ_ONLY_TOOL_ANNOTATIONS, - outputSchema: { levelId: z.string(), walls: z.array(jsonObject) }, + outputSchema: { + levelId: z.string(), + walls: z.array(jsonObject), + wallTypes: z.array(jsonObject), + }, }, { contract: getZonesTool, @@ -353,6 +358,11 @@ const SHARED_TOOLS: SharedTool[] = [ operation: AGENT_OPERATIONS.add_wall, annotations: ADDITIVE_TOOL_ANNOTATIONS, }, + { + contract: setWallTypeTool, + operation: AGENT_OPERATIONS.set_wall_type, + annotations: DESTRUCTIVE_TOOL_ANNOTATIONS, + }, { contract: addFenceTool, operation: AGENT_OPERATIONS.add_fence, diff --git a/packages/nodes/src/__tests__/duplicate-hosted-children.test.tsx b/packages/nodes/src/__tests__/duplicate-hosted-children.test.tsx index 60829c4389..8b0717d0cf 100644 --- a/packages/nodes/src/__tests__/duplicate-hosted-children.test.tsx +++ b/packages/nodes/src/__tests__/duplicate-hosted-children.test.tsx @@ -584,7 +584,6 @@ for (const kind of ['table', 'table-design', 'shelf', 'design', 'nested']) { siblingEpoch, unit: 'metric', metricNotation: 'meters', - wallDimensionReference: 'centerline', visibilityRootId: undefined, })!.base! const anchor = (geometry: FloorplanGeometry): readonly number[] => { diff --git a/packages/nodes/src/beam/actions/move-endpoint.test.ts b/packages/nodes/src/beam/actions/move-endpoint.test.ts new file mode 100644 index 0000000000..abef5e11c9 --- /dev/null +++ b/packages/nodes/src/beam/actions/move-endpoint.test.ts @@ -0,0 +1,71 @@ +import { beforeEach, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + BeamNode, + BuildingNode, + clearSceneHistory, + createDragSession, + createSceneApi, + LevelNode, + useScene, +} from '@pascal-app/core' +import { moveBeamEndpointDragAction } from './move-endpoint' + +type RafFn = (cb: (time: number) => void) => number +;(globalThis as unknown as { requestAnimationFrame?: RafFn }).requestAnimationFrame ??= (cb) => { + cb(0) + return 0 +} +;(globalThis as unknown as { cancelAnimationFrame?: (id: number) => void }).cancelAnimationFrame ??= + () => {} + +const BEAM = BeamNode.parse({ id: 'beam_a', parentId: 'level_g', start: [0, 0], end: [3, 0] }) +// Alt: the end goes where the pointer is, whatever the snapping mode. +const free = { shift: false, alt: true, ctrl: false, meta: false } + +beforeEach(() => { + const building = BuildingNode.parse({ id: 'building_a', children: ['level_g'] }) + const level = LevelNode.parse({ + id: 'level_g', + parentId: building.id, + level: 0, + children: [BEAM.id], + }) + const nodes = Object.fromEntries([building, level, BEAM].map((node) => [node.id, node])) + useScene.getState().setScene(nodes as Record, [building.id as AnyNodeId], { + installedPlugins: [], + hasExplicitPluginInstallState: false, + }) + clearSceneHistory() +}) + +const beam = () => useScene.getState().nodes[BEAM.id as AnyNodeId] as BeamNode + +test('a dragged end follows the pointer, the other stays, and the drag is one undo step', () => { + const session = createDragSession(moveBeamEndpointDragAction, createSceneApi(useScene)) + session.start({ node: BEAM, handleId: 'end', point: [3, 0] }) + session.move([4, 1], free) + expect(beam().end).toEqual([4, 1]) + session.move([5, 2], free) + expect(session.commit()).toBe(true) + expect(beam()).toMatchObject({ start: [0, 0], end: [5, 2] }) + useScene.temporal.getState().undo() + expect(beam()).toMatchObject({ start: [0, 0], end: [3, 0] }) +}) + +test('the start drags too, and a beam too short to draw is put back', () => { + const session = createDragSession(moveBeamEndpointDragAction, createSceneApi(useScene)) + session.start({ node: BEAM, handleId: 'start', point: [0, 0] }) + session.move([2.998, 0], free) + expect(session.commit()).toBe(false) + expect(beam()).toMatchObject({ start: [0, 0], end: [3, 0] }) +}) + +test('Esc puts the beam back', () => { + const session = createDragSession(moveBeamEndpointDragAction, createSceneApi(useScene)) + session.start({ node: BEAM, handleId: 'start', point: [0, 0] }) + session.move([-1, 1], free) + session.cancel() + expect(beam()).toMatchObject({ start: [0, 0], end: [3, 0] }) +}) diff --git a/packages/nodes/src/beam/actions/move-endpoint.ts b/packages/nodes/src/beam/actions/move-endpoint.ts new file mode 100644 index 0000000000..1254b4fb93 --- /dev/null +++ b/packages/nodes/src/beam/actions/move-endpoint.ts @@ -0,0 +1,73 @@ +import { + type AnyNode, + type AnyNodeId, + type BeamNode, + type DragAction, + useScene, +} from '@pascal-app/core' +import { isSegmentLongEnough, type WallPlanPoint } from '@pascal-app/editor' +import { snapBeamPoint } from '../drafting' + +export type MoveBeamEndpointCtx = { + beamId: AnyNodeId + endpoint: 'start' | 'end' + levelId: string | null + /** The end that stays put. */ + fixed: WallPlanPoint +} + +export type MoveBeamEndpointDraft = { start: WallPlanPoint; end: WallPlanPoint } + +/** + * A beam's end dragged in 3D, as a pure drag action: + * - **preview**: the pointer snapped as the beam tool snaps (wall faces and ends, other beams, + * post centres, the grid), angle-stepped off the end that stays; Alt places it freely. + * - **apply**: writes the ends into the scene while history is paused. + * - **commit**: refuses a beam too short to draw; otherwise reverts, resumes history and writes + * the final ends once, so the drag is one undo step. + * - **cancel**: `createDragSession` restores the beam it touched. + */ +export const moveBeamEndpointDragAction: DragAction = { + begin: (input) => { + const beam = input.node as BeamNode | undefined + if (beam?.type !== 'beam') throw new Error('[moveBeamEndpointDragAction] begin requires a beam') + const endpoint = input.handleId === 'start' ? 'start' : 'end' + return { + beamId: beam.id as AnyNodeId, + endpoint, + levelId: beam.parentId ?? null, + fixed: endpoint === 'start' ? [beam.end[0], beam.end[1]] : [beam.start[0], beam.start[1]], + } + }, + + preview: (ctx, point, modifiers) => { + const moved: WallPlanPoint = ctx.levelId + ? snapBeamPoint({ + point: [point[0], point[1]], + nodes: useScene.getState().nodes, + levelId: ctx.levelId, + start: ctx.fixed, + ignoreIds: [ctx.beamId], + free: modifiers.alt, + }).point + : [point[0], point[1]] + return ctx.endpoint === 'start' + ? { start: moved, end: ctx.fixed } + : { start: ctx.fixed, end: moved } + }, + + apply: (draft, ctx, scene) => { + scene.update(ctx.beamId, { start: draft.start, end: draft.end } as Partial) + return [ctx.beamId] + }, + + commit: (draft, ctx, scene) => { + if (!(draft && isSegmentLongEnough(draft.start, draft.end))) return false + scene.restoreAll() + scene.resumeHistory() + scene.update(ctx.beamId, { start: draft.start, end: draft.end } as Partial) + return true + }, + + cancel: () => {}, +} diff --git a/packages/nodes/src/beam/definition.test.ts b/packages/nodes/src/beam/definition.test.ts new file mode 100644 index 0000000000..4f3521a627 --- /dev/null +++ b/packages/nodes/src/beam/definition.test.ts @@ -0,0 +1,117 @@ +import { expect, test } from 'bun:test' +import { type BeamNode, createBeam, createSceneApi, useScene } from '@pascal-app/core' +import { beamDefinition } from './definition' +import { beamToolOptions, useBeamDraft } from './draft-settings' +import { beamBox, buildBeamGeometry } from './geometry' + +const IN = 0.0254 + +test('a beam is a selectable, duplicable, deletable structural kind drawn with its own tool', () => { + expect(beamDefinition).toMatchObject({ + kind: 'beam', + category: 'structure', + snapProfile: 'structural', + presentation: { label: 'Beam', paletteSection: 'structure' }, + }) + expect(beamDefinition.capabilities).toMatchObject({ + selectable: { hitVolume: 'bbox' }, + duplicable: true, + deletable: true, + drawTool: true, + }) + expect(typeof beamDefinition.tool).toBe('function') + expect(Object.keys(beamDefinition.affordanceTools ?? {}).sort()).toEqual([ + 'move', + 'move-endpoint', + ]) + expect(Object.keys(beamDefinition.floorplanAffordances ?? {})).toEqual(['move-endpoint']) + const defaults = beamDefinition.defaults() + expect(defaults).toMatchObject({ plies: 1, material: 'sawn', placement: 'dropped' }) +}) + +test('selected, it has a move arrow either side, a picker at each end and a top tracker', () => { + const beam = createBeam({ start: [0, 0], end: [4, 0], preset: '6x8', topElevation: 2.4 }) + const handles = + typeof beamDefinition.handles === 'function' + ? beamDefinition.handles(beam, createSceneApi(useScene)) + : (beamDefinition.handles ?? []) + expect(handles.map((handle) => handle.kind)).toEqual([ + 'tap-action', + 'tap-action', + 'tap-action', + 'tap-action', + 'linear-resize', + ]) + const sceneApi = createSceneApi(useScene) + const [side, , startPicker, , top] = handles + // the side arrow sits beside the beam at its mid-depth + const at = side!.placement.position(beam, sceneApi) + expect(at[1]).toBeCloseTo(2.4 - 3.75 * IN) + expect(Math.abs(at[2])).toBeGreaterThan(beam.width / 2) + // the end picker stands at the beam's underside at its start + expect(startPicker!.placement.position(beam, sceneApi)).toEqual([0, 2.4 - 7.5 * IN, 0]) + // the top tracker writes the top it is dragged to + if (top?.kind !== 'linear-resize') throw new Error('the top handle resizes') + expect(top.currentValue(beam)).toBeCloseTo(2.4) + expect(top.apply(beam, 2.1, sceneApi)).toEqual({ topElevation: 2.1 } as Partial) +}) + +test('the box sits along the centreline with its top where the beam resolves it', () => { + const beam = createBeam({ start: [1, 1], end: [1, 5], preset: '6x8' }) + const box = beamBox(beam, 2.7)! + expect(box.position[0]).toBeCloseTo(1) + expect(box.position[1]).toBeCloseTo(2.7 - 3.75 * IN) + expect(box.position[2]).toBeCloseTo(3) + expect(box.size[0]).toBeCloseTo(4) + // local +X runs along the beam: a run toward +Z turns it -90° + expect(box.rotationY).toBeCloseTo(-Math.PI / 2) + expect(beamBox({ ...beam, end: beam.start }, 2.7)).toBeNull() +}) + +test('a built-up beam shows its plies, a steel one its flanges and web', () => { + const plies = buildBeamGeometry( + { width: 4.5 * IN, depth: 9.25 * IN, plies: 3, material: 'sawn' }, + 2, + ) + const solid = buildBeamGeometry( + { width: 5.5 * IN, depth: 7.5 * IN, plies: 1, material: 'sawn' }, + 2, + ) + const steel = buildBeamGeometry( + { width: 3.94 * IN, depth: 7.89 * IN, plies: 1, material: 'steel' }, + 2, + ) + const triangles = (geometry: ReturnType) => + geometry.getAttribute('position').count / 3 + expect(triangles(solid)).toBe(12) + expect(triangles(plies)).toBe(36) + expect(triangles(steel)).toBe(36) + // the plies keep the beam's full width between their outer faces + plies.computeBoundingBox() + expect(plies.boundingBox!.max.z - plies.boundingBox!.min.z).toBeCloseTo(4.5 * IN, 4) + expect(solid.getAttribute('uv')).toBeTruthy() +}) + +test("the tool's rows pick a material, its sizes and the top", () => { + expect(beamToolOptions.map((option) => option.id)).toEqual([ + 'beam-material', + 'beam-size-sawn', + 'beam-size-lvl', + 'beam-size-glulam', + 'beam-size-steel', + 'beam-top', + ]) + const [material, sawn, lvl] = beamToolOptions + expect(sawn!.visible!.value()).toBe(true) + expect(lvl!.visible!.value()).toBe(false) + // picking LVL brings its usual size along; going treated keeps a sawn size + material!.set('lvl') + expect(useBeamDraft.getState()).toMatchObject({ material: 'lvl', preset: '(2)lvl-1-3/4x11-7/8' }) + expect(lvl!.visible!.value()).toBe(true) + material!.set('pressure-treated') + expect(useBeamDraft.getState().preset).toBe('6x8') + sawn!.set('(3)2x12') + material!.set('sawn') + expect(useBeamDraft.getState().preset).toBe('(3)2x12') + useBeamDraft.setState({ preset: '6x8', material: 'sawn', top: 'ceiling-dropped' }) +}) diff --git a/packages/nodes/src/beam/definition.ts b/packages/nodes/src/beam/definition.ts new file mode 100644 index 0000000000..bdc0a43a6e --- /dev/null +++ b/packages/nodes/src/beam/definition.ts @@ -0,0 +1,204 @@ +import { + type BeamNode as BeamNodeType, + beamPlan, + beamTopElevation, + type HandleDescriptor, + type NodeDefinition, + type SceneApi, +} from '@pascal-app/core' +import { + clearStructuralElevationGuide, + FLOORPLAN_NODE_EXTENSION_KEY, + type FloorplanNodeExtension, + PANEL_MODEL_EXTENSION, + publishStructuralElevationGuide, + resolveStructuralElevationSnap, +} from '@pascal-app/editor' +import { useViewer } from '@pascal-app/viewer' +import { beamToolOptions } from './draft-settings' +import { buildBeamFloorplan } from './floorplan' +import { beamEndpointAffordance } from './floorplan-affordances' +import { beamFloorplanMoveTarget } from './floorplan-move' +import { beamPanelModel } from './panel-model' +import { beamParametrics } from './parametrics' +import { BeamNode } from './schema' + +const SIDE_HANDLE_OFFSET = 0.22 +const INCH = 0.0254 + +/** Where a beam's top is in the live scene (a descriptor may run before the scene has a level). */ +function topOf(beam: BeamNodeType, sceneApi?: SceneApi): number { + return beamTopElevation(sceneApi?.nodes() ?? {}, beam) +} + +function midFrame(beam: BeamNodeType) { + const plan = beamPlan(beam) + return { + mid: [(plan.start[0] + plan.end[0]) / 2, (plan.start[1] + plan.end[1]) / 2] as const, + normal: plan.normal, + } +} + +/** The beam's top, as the elevation guides read a structural datum. */ +function guideSource(beam: BeamNodeType) { + const { mid } = midFrame(beam) + return { nodeId: beam.id, levelId: beam.parentId, anchor: mid } +} + +// Side arrows: a tap hands the beam to its move tool, either side of its middle at mid-depth. +function beamSideMoveHandle(side: 1 | -1): HandleDescriptor { + return { + kind: 'tap-action', + onActivate: (node, _scene, editor) => editor.engageMove(node), + placement: { + position: (n, sceneApi) => { + const { mid, normal } = midFrame(n) + const offset = (n.width / 2 + SIDE_HANDLE_OFFSET) * side + return [ + mid[0] + normal[0] * offset, + topOf(n, sceneApi) - n.depth / 2, + mid[1] + normal[1] * offset, + ] + }, + rotationY: (n) => { + const { normal } = midFrame(n) + return Math.atan2(-normal[1] * side, normal[0] * side) + }, + }, + cursor: 'ew-resize', + } +} + +// End pickers: a dashed leader down the beam's depth and a disc at its end; a tap drags the end. +function beamEndPicker(endpoint: 'start' | 'end'): HandleDescriptor { + return { + kind: 'tap-action', + shape: 'corner-picker', + cursor: 'move', + nodeHeight: (n) => n.depth, + onActivate: (node, _scene, editor) => editor.engageEndpointMove(node, endpoint), + placement: { + position: (n, sceneApi) => { + const point = n[endpoint] + return [point[0], topOf(n, sceneApi) - n.depth, point[1]] + }, + }, + } +} + +/** + * The beam's top, dragged up and down: it stores the top it lands on, caught by the levels' + * structural heights (a ceiling plane, a slab top) and otherwise to the half inch (the centimetre + * on a metric plan). + */ +function beamTopHandle(current: number): HandleDescriptor { + return { + kind: 'linear-resize', + axis: 'y', + anchor: 'min', + shape: 'tracker', + currentValue: () => current, + magneticSnap: (n, value, sceneApi) => { + const snapped = resolveStructuralElevationSnap(guideSource(n), value, sceneApi.nodes()) + if (snapped !== value) return snapped + const step = useViewer.getState().unit === 'imperial' ? INCH / 2 : 0.01 + return Math.round(value / step) * step + }, + onDrag: (n, sceneApi) => + publishStructuralElevationGuide(guideSource(n), topOf(n, sceneApi), sceneApi.nodes()), + onDragEnd: (n) => clearStructuralElevationGuide(n.id), + apply: (_n, top) => ({ topElevation: top }), + placement: { + position: (n, sceneApi) => { + const { mid } = midFrame(n) + return [mid[0], topOf(n, sceneApi), mid[1]] + }, + }, + } +} + +const beamHandles = (node: BeamNodeType, sceneApi?: SceneApi): HandleDescriptor[] => [ + beamSideMoveHandle(1), + beamSideMoveHandle(-1), + beamEndPicker('start'), + beamEndPicker('end'), + beamTopHandle(topOf(node, sceneApi)), +] + +/** + * Beam — a horizontal framing member drawn by hand, end to end like a wall: a porch's header on + * its posts, a deck's beam, a girder, a beam across an open span. A box of its actual section + * along the centreline, its top stored or following the ceiling plane over it (`beamTopElevation` + * in core); the plan draws it dashed with its size, as a framing plan does. `createBeam` in core + * makes one from code. + * + * No `movable`: a beam has no `position`; it moves by both ends, through `affordanceTools.move` in + * 3D and `floorplanMoveTarget` in the plan. + */ +export const beamDefinition: NodeDefinition = { + kind: 'beam', + snapProfile: 'structural', + schemaVersion: 1, + schema: BeamNode, + category: 'structure', + extensions: { + [FLOORPLAN_NODE_EXTENSION_KEY]: { + // In 2D-only view the 3D tool never mounts: the plan drafts beams itself. + tool: () => import('./tool').then((module) => ({ default: module.BeamFloorplanTool })), + // A beam crosses rooms: a plan click on it picks the beam, not the room. + planHitSelectsNode: true, + } satisfies FloorplanNodeExtension, + [PANEL_MODEL_EXTENSION]: beamPanelModel, + }, + + defaults: () => { + const { id: _id, type: _type, ...rest } = BeamNode.parse({ start: [0, 0], end: [3, 0] }) + return rest + }, + + capabilities: { + selectable: { hitVolume: 'bbox' }, + surfaces: { hosting: false }, + duplicable: true, + deletable: true, + drawTool: true, + }, + + // The renderer reads the scene and live overrides itself; nothing consumes a dirty mark. + dirtyTracking: false, + rendersChildren: false, + renderer: { kind: 'parametric', module: () => import('./renderer') }, + parametrics: beamParametrics, + handles: beamHandles, + + tool: () => import('./tool'), + toolOptions: beamToolOptions, + toolHints: [ + { key: 'Left click', label: 'Set beam start / end; the next beam starts there' }, + { key: 'Alt', label: 'Free place' }, + { key: 'Esc', label: 'End the run' }, + ], + + floorplan: buildBeamFloorplan, + floorplanMoveTarget: beamFloorplanMoveTarget, + floorplanAffordances: { + 'move-endpoint': beamEndpointAffordance, + }, + affordanceTools: { + move: () => import('./move-tool'), + 'move-endpoint': () => import('./move-endpoint-tool'), + }, + + presentation: { + label: 'Beam', + description: 'A framing beam drawn end to end: a porch header, a deck beam, a girder.', + icon: { kind: 'url', src: '/icons/beam.svg' }, + paletteSection: 'structure', + paletteOrder: 72, + }, + + mcp: { + description: + 'A horizontal framing beam: start/end centreline (level-local), actual width/depth, nominal size and plies, material, dropped or flush placement, and a top elevation (absent = under the ceiling plane).', + }, +} diff --git a/packages/nodes/src/beam/draft-settings.ts b/packages/nodes/src/beam/draft-settings.ts new file mode 100644 index 0000000000..fd8ec74d22 --- /dev/null +++ b/packages/nodes/src/beam/draft-settings.ts @@ -0,0 +1,119 @@ +import { + BEAM_MATERIAL_LABELS, + BEAM_SIZE_PRESETS, + BEAM_TOP_REFERENCE_LABELS, + BEAM_TOP_REFERENCES, + type BeamMaterial, + type BeamTopReference, + beamSizePreset, + DEFAULT_BEAM_SIZE_PRESET_ID, + type ToolOption, +} from '@pascal-app/core' +import { create } from 'zustand' + +/** What the beam tool draws with: its size, material and where its top goes. */ +export type BeamDraftChoices = { + preset: string + material: BeamMaterial + top: BeamTopReference +} + +/** + * The beam tool's choices, kept apart from the editor's tool defaults: a host clears those when it + * arms a tool from its tile, which would forget the size just picked. + */ +export const useBeamDraft = create< + BeamDraftChoices & { set: (patch: Partial) => void } +>((set) => ({ + preset: DEFAULT_BEAM_SIZE_PRESET_ID, + material: 'sawn', + top: 'ceiling-dropped', + set: (patch) => set(patch), +})) + +/** The stock sizes come in four families; a treated beam is a sawn size. */ +type BeamFamily = 'sawn' | 'lvl' | 'glulam' | 'steel' + +const familyOf = (material: BeamMaterial): BeamFamily => + material === 'pressure-treated' ? 'sawn' : material + +/** The size a family starts at when its material is picked. */ +const FAMILY_SIZE: Record = { + sawn: DEFAULT_BEAM_SIZE_PRESET_ID, + lvl: '(2)lvl-1-3/4x11-7/8', + glulam: 'glulam-5-1/8x12', + steel: 'W8x10', +} + +const MATERIAL_DESCRIPTIONS: Record = { + sawn: 'A solid timber or 2x plies nailed up, inside where it stays dry', + 'pressure-treated': 'Treated sawn lumber, for a porch, a deck or anything in the weather', + lvl: 'Laminated veneer lumber: a stiff beam for a long span inside', + glulam: 'Glued-laminated timber: long spans, often left exposed', + steel: 'A steel W shape, for the longest spans', +} + +const TOP_DESCRIPTIONS: Record = { + 'ceiling-dropped': + 'Hangs under the ceiling plane, the top of the walls: the joists or rafters bear on it', + 'ceiling-flush': + 'In the ceiling framing, its underside on the ceiling plane: the joists hang from its sides', + 'floor-flush': 'Its top flush with the floor over it, in the floor framing', + 'floor-under': + "Under the floor's framing: a girder in a crawl space, or a deck's beam under its joists", +} + +const subscribe = (onChange: () => void) => useBeamDraft.subscribe(() => onChange()) + +/** The material row: picking another family brings its usual size along. */ +const materialOption: ToolOption = { + id: 'beam-material', + label: 'Material', + choices: (Object.keys(BEAM_MATERIAL_LABELS) as BeamMaterial[]).map((material) => ({ + value: material, + label: BEAM_MATERIAL_LABELS[material], + description: MATERIAL_DESCRIPTIONS[material], + })), + subscribe, + value: () => useBeamDraft.getState().material, + set: (value) => { + const material = value as BeamMaterial + const preset = beamSizePreset(useBeamDraft.getState().preset) + const keeps = preset && familyOf(preset.material) === familyOf(material) + useBeamDraft + .getState() + .set({ material, ...(keeps ? {} : { preset: FAMILY_SIZE[familyOf(material)] }) }) + }, +} + +/** One Size row per family, shown while its material is the one picked. */ +const sizeOptions: ToolOption[] = (['sawn', 'lvl', 'glulam', 'steel'] as const).map((family) => ({ + id: `beam-size-${family}`, + label: 'Size', + choices: BEAM_SIZE_PRESETS.filter((preset) => familyOf(preset.material) === family).map( + (preset) => ({ value: preset.id, label: preset.label.replace(/ (LVL|GLB)$/, '') }), + ), + subscribe, + value: () => useBeamDraft.getState().preset, + set: (value) => useBeamDraft.getState().set({ preset: value }), + visible: { + subscribe, + value: () => familyOf(useBeamDraft.getState().material) === family, + }, +})) + +const topOption: ToolOption = { + id: 'beam-top', + label: 'Top', + choices: BEAM_TOP_REFERENCES.map((top) => ({ + value: top, + label: BEAM_TOP_REFERENCE_LABELS[top], + description: TOP_DESCRIPTIONS[top], + })), + subscribe, + value: () => useBeamDraft.getState().top, + set: (value) => useBeamDraft.getState().set({ top: value as BeamTopReference }), +} + +/** The Beam tool's rows in the Build panel: material, size, top. */ +export const beamToolOptions: readonly ToolOption[] = [materialOption, ...sizeOptions, topOption] diff --git a/packages/nodes/src/beam/drafting.test.ts b/packages/nodes/src/beam/drafting.test.ts new file mode 100644 index 0000000000..747e2d99ee --- /dev/null +++ b/packages/nodes/src/beam/drafting.test.ts @@ -0,0 +1,173 @@ +import { afterAll, afterEach, beforeAll, describe, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + BeamNode, + BuildingNode, + ColumnNode, + LevelNode, + nodeRegistry, + registerNode, + SlabNode, + WallNode, +} from '@pascal-app/core' +import { type SnappingMode, useEditor } from '@pascal-app/editor' +import { beamDefinition } from './definition' +import { useBeamDraft } from './draft-settings' +import { beamSnapTargets, draftBeam, snapBeamPoint } from './drafting' + +const IN = 0.0254 +type Nodes = Record +const previous = useEditor.getState() +let restore: () => void = () => {} + +beforeAll(() => { + restore = nodeRegistry._snapshot() + if (!nodeRegistry.has('beam')) registerNode(beamDefinition) +}) +afterAll(() => restore()) +afterEach(() => { + useEditor.setState(previous, true) + useBeamDraft.setState({ preset: '6x8', material: 'sawn', top: 'ceiling-dropped' }) +}) + +/** The beam tool armed, drafting under `mode`. */ +function drafting(mode: SnappingMode) { + useEditor.setState((state) => ({ + mode: 'build', + tool: 'beam', + gridSnapStep: 0.5, + snappingModeByContext: { ...state.snappingModeByContext, wall: mode }, + })) +} + +const WALL = WallNode.parse({ + id: 'wall_a', + parentId: 'level_g', + start: [0, 0], + end: [4, 0], + thickness: 0.2, +}) +const OTHER = BeamNode.parse({ id: 'beam_b', parentId: 'level_g', start: [0, 3], end: [4, 3] }) +const POST = ColumnNode.parse({ id: 'column_p', parentId: 'level_g', position: [6, 0, 6] }) +const ELSEWHERE = BeamNode.parse({ id: 'beam_u', parentId: 'level_u', start: [0, 9], end: [4, 9] }) + +function storey(extra: AnyNode[] = []): Nodes { + return Object.fromEntries( + [ + BuildingNode.parse({ id: 'building_a', children: ['level_g', 'level_u'] }), + LevelNode.parse({ + id: 'level_g', + parentId: 'building_a', + level: 0, + height: 2.7, + children: ['slab_g', WALL.id, OTHER.id, POST.id, ...extra.map((n) => n.id)], + }), + LevelNode.parse({ id: 'level_u', parentId: 'building_a', level: 1, height: 2.7 }), + SlabNode.parse({ + id: 'slab_g', + parentId: 'level_g', + polygon: [ + [-1, -1], + [9, -1], + [9, 9], + [-1, 9], + ], + elevation: 0.05, + thickness: 0.25, + }), + WALL, + OTHER, + POST, + ELSEWHERE, + ...extra, + ].map((node) => [node.id, node]), + ) as Nodes +} + +describe('what a beam snaps to', () => { + test("the level's walls and both faces, other beams' centrelines and post centres", () => { + const targets = beamSnapTargets(storey(), 'level_g') + expect(targets.map((target) => target.id).sort()).toEqual( + ['beam_b', 'column_p', 'wall_a', 'wall_a:a', 'wall_a:b'].sort(), + ) + const faceA = targets.find((target) => target.id === 'wall_a:a')! + expect(faceA.start).toEqual([0, 0.1]) + expect(faceA.end).toEqual([4, 0.1]) + expect(targets.find((target) => target.id === 'column_p')).toMatchObject({ + start: [6, 6], + end: [6, 6], + }) + // the beam being edited is no target of its own + expect(beamSnapTargets(storey(), 'level_g', ['beam_b']).map((t) => t.id)).not.toContain( + 'beam_b', + ) + }) + + test('a point near a beam end, a post or a wall face corner lands on it', () => { + drafting('lines') + const nodes = storey() + const at = (point: [number, number]) => + snapBeamPoint({ point, nodes, levelId: 'level_g' }).point + expect(at([4.05, 3.04])).toEqual([4, 3]) + expect(at([6.03, 5.98])).toEqual([6, 6]) + const corner = at([0.03, 0.14]) + expect(corner[0]).toBeCloseTo(0) + expect(corner[1]).toBeCloseTo(0.1) + // Alt places it where the pointer is + expect(snapBeamPoint({ point: [4.05, 3.04], nodes, levelId: 'level_g', free: true })).toEqual({ + point: [4.05, 3.04], + snap: null, + }) + }) + + test('on the grid, a point lands on the grid away from anything to catch', () => { + drafting('grid') + expect(snapBeamPoint({ point: [2.2, 6.7], nodes: storey(), levelId: 'level_g' }).point).toEqual( + [2, 6.5], + ) + }) +}) + +describe('the beam a draft makes', () => { + test('takes the Build panel size, material and top', () => { + const nodes = storey() + const beam = draftBeam([1, 1], [5, 1], 'level_g', nodes, { + preset: '(3)2x12', + material: 'pressure-treated', + top: 'floor-under', + }) + expect(beam).toMatchObject({ + type: 'beam', + parentId: 'level_g', + start: [1, 1], + end: [5, 1], + size: '2x12', + plies: 3, + material: 'pressure-treated', + placement: 'dropped', + }) + expect(beam.width).toBeCloseTo(4.5 * IN) + // under the floor slab's body: 0.05 top, 0.25 thick + expect(beam.topElevation).toBeCloseTo(-0.2) + const under = draftBeam([1, 1], [5, 1], 'level_g', nodes, { + preset: '6x8', + material: 'sawn', + top: 'ceiling-dropped', + }) + expect(under.topElevation).toBeUndefined() + }) + + test('a preset the host armed the tool with wins over the panel', () => { + const beam = draftBeam( + [0, 0], + [3, 0], + 'level_g', + storey(), + { preset: '6x8', material: 'sawn', top: 'ceiling-dropped' }, + { material: 'glulam', width: 0.13, depth: 0.3, size: '5-1/8x12', topElevation: 2.4 }, + ) + expect(beam).toMatchObject({ material: 'glulam', width: 0.13, topElevation: 2.4 }) + expect(beam.start).toEqual([0, 0]) + }) +}) diff --git a/packages/nodes/src/beam/drafting.ts b/packages/nodes/src/beam/drafting.ts new file mode 100644 index 0000000000..72bffcd904 --- /dev/null +++ b/packages/nodes/src/beam/drafting.ts @@ -0,0 +1,154 @@ +import { + type AnyNode, + type AnyNodeId, + BeamNode, + beamTopReferencePatch, + createBeam, + getWallFaceLine, + type WallNode, +} from '@pascal-app/core' +import { + getSegmentGridStep, + isAngleSnapActive, + isMagneticSnapActive, + snapBuildingLocalToWorldGrid, + snapWallDraftPointDetailed, + type WallDraftSnapKind, + type WallPlanPoint, +} from '@pascal-app/editor' +import { type BeamDraftChoices, useBeamDraft } from './draft-settings' + +type Nodes = Readonly> + +/** A segment as the wall snap reads a wall: its ends, its middle and its body catch a point. */ +function reference( + id: string, + parentId: string | null, + start: WallPlanPoint, + end: WallPlanPoint, +): WallNode { + return { + object: 'node', + id: id as WallNode['id'], + type: 'wall', + parentId, + visible: true, + metadata: {}, + children: [], + start, + end, + frontSide: 'unknown', + backSide: 'unknown', + } +} + +const targetsMemo = new WeakMap>() + +/** + * What a beam drawn on `levelId` snaps to, through the wall snap (`snapWallDraftPoint`): the + * level's wall centrelines and both faces of each straight wall (so a beam end lands on a wall's + * face or its corner), other beams' centrelines (their ends, middles and runs), and every post + * and column centre (a segment of no length). Kept per scene, so a pointer move asks once. + */ +export function beamSnapTargets( + nodes: Nodes, + levelId: string, + ignoreIds: readonly string[] = [], +): WallNode[] { + const key = `${levelId}|${ignoreIds.join(',')}` + let byKey = targetsMemo.get(nodes) + if (!byKey) { + byKey = new Map() + targetsMemo.set(nodes, byKey) + } + const cached = byKey.get(key) + if (cached) return cached + const targets: WallNode[] = [] + for (const node of Object.values(nodes)) { + if (node.parentId !== levelId || node.visible === false || ignoreIds.includes(node.id)) continue + if (node.type === 'wall') { + targets.push(node) + if (Math.abs(node.curveOffset ?? 0) > 1e-6) continue + for (const face of ['a', 'b'] as const) { + const line = getWallFaceLine(node, face) + targets.push( + reference( + `${node.id}:${face}`, + node.parentId, + [line.start.x, line.start.y], + [line.end.x, line.end.y], + ), + ) + } + } else if (node.type === 'beam') { + targets.push(reference(node.id, node.parentId, node.start, node.end)) + } else if (node.type === 'column') { + const centre: WallPlanPoint = [node.position[0], node.position[2]] + targets.push(reference(node.id, node.parentId, centre, centre)) + } + } + byKey.set(key, targets) + return targets +} + +/** A snapped plan point and what caught it (null: the grid, an angle step, or nothing). */ +export type BeamPlanSnap = { point: WallPlanPoint; snap: WallDraftSnapKind | null } + +/** + * A beam point snapped as the beam tool snaps: wall and beam ends, faces, middles and crossings, + * post centres, the grid, and from `start` the angle steps. `free` (Alt) places it as it is. + */ +export function snapBeamPoint(args: { + point: WallPlanPoint + nodes: Nodes + levelId: string + start?: WallPlanPoint | null + ignoreIds?: readonly string[] + free?: boolean +}): BeamPlanSnap { + if (args.free) return { point: args.point, snap: null } + const step = getSegmentGridStep() + const angleSnap = !!args.start && isAngleSnapActive() + const result = snapWallDraftPointDetailed({ + point: args.point, + walls: beamSnapTargets(args.nodes, args.levelId, args.ignoreIds), + start: args.start ?? undefined, + angleSnap, + magnetic: isMagneticSnapActive(), + gridSnap: (point) => snapBuildingLocalToWorldGrid(point, step), + }) + return { point: result.point, snap: result.snap } +} + +/** + * The beam a draft makes from `start` to `end` on `levelId` with the tool's choices, its top set + * from the chosen reference; `seed` (a preset the host armed the tool with) overrides them. + */ +export function draftBeam( + start: WallPlanPoint, + end: WallPlanPoint, + levelId: string, + nodes: Nodes, + choices: BeamDraftChoices = useBeamDraft.getState(), + seed?: Readonly> | null, + fields: Partial = {}, +): BeamNode { + const base = createBeam({ + start, + end, + preset: choices.preset, + material: choices.material, + levelId, + }) + const placed = { ...base, ...beamTopReferencePatch(nodes, base, choices.top) } + return BeamNode.parse({ + ...placed, + ...(seed ?? {}), + ...fields, + id: base.id, + type: 'beam', + start, + end, + parentId: levelId, + }) +} diff --git a/packages/nodes/src/beam/floorplan-affordances.ts b/packages/nodes/src/beam/floorplan-affordances.ts new file mode 100644 index 0000000000..8ad2b26698 --- /dev/null +++ b/packages/nodes/src/beam/floorplan-affordances.ts @@ -0,0 +1,47 @@ +import { + type AnyNodeId, + type BeamNode, + type FloorplanAffordance, + useLiveNodeOverrides, + useScene, +} from '@pascal-app/core' +import { isSegmentLongEnough, type WallPlanPoint } from '@pascal-app/editor' +import { snapBeamPoint } from './drafting' +import type { BeamEndpointPayload } from './floorplan' + +/** + * A beam's end, dragged in the plan: snapped as the beam tool snaps, angle-stepped off the other + * end. Previews through live overrides, writes the last end on release, and refuses an end that + * would leave the beam too short to draw. + */ +export const beamEndpointAffordance: FloorplanAffordance = { + start({ node, payload, nodes }) { + const { endpoint } = payload as BeamEndpointPayload + const id = node.id as AnyNodeId + const fixed: WallPlanPoint = endpoint === 'start' ? node.end : node.start + let last: WallPlanPoint | null = null + return { + affectedIds: [id], + apply({ planPoint, modifiers }) { + last = node.parentId + ? snapBeamPoint({ + point: [planPoint[0], planPoint[1]], + nodes, + levelId: node.parentId, + start: fixed, + ignoreIds: [node.id], + free: modifiers.altKey, + }).point + : [planPoint[0], planPoint[1]] + useLiveNodeOverrides.getState().set(id, { [endpoint]: last }) + }, + canCommit() { + return last !== null && isSegmentLongEnough(fixed, last) + }, + commit() { + if (last) useScene.getState().updateNodes([{ id, data: { [endpoint]: last } }]) + useLiveNodeOverrides.getState().clear(id) + }, + } + }, +} diff --git a/packages/nodes/src/beam/floorplan-move.ts b/packages/nodes/src/beam/floorplan-move.ts new file mode 100644 index 0000000000..59691ea7da --- /dev/null +++ b/packages/nodes/src/beam/floorplan-move.ts @@ -0,0 +1,65 @@ +import { + type AnyNodeId, + type BeamNode, + type FloorplanMoveTarget, + useLiveNodeOverrides, + useScene, +} from '@pascal-app/core' +import { triggerSFX, type WallPlanPoint } from '@pascal-app/editor' +import { useViewer } from '@pascal-app/viewer' +import { snapBeamPoint } from './drafting' + +/** A beam translated by `delta`, both ends together. */ +export function movedBeamEnds( + beam: Pick, + delta: WallPlanPoint, +): Pick { + return { + start: [beam.start[0] + delta[0], beam.start[1] + delta[1]], + end: [beam.end[0] + delta[0], beam.end[1] + delta[1]], + } +} + +/** + * A beam moved in the plan: its start follows the pointer and snaps as the beam tool snaps (wall + * faces and ends, other beams, post centres, the grid); its end travels with it. Previews through + * live overrides, writes once on release. + */ +export const beamFloorplanMoveTarget: FloorplanMoveTarget = ({ node, nodes }) => { + const id = node.id as AnyNodeId + const origin: WallPlanPoint = [node.start[0], node.start[1]] + let anchor: WallPlanPoint | null = null + let delta: WallPlanPoint = [0, 0] + + return { + affectedIds: [id], + apply({ planPoint, modifiers }) { + if (!anchor) { + anchor = [planPoint[0], planPoint[1]] + return + } + const at = node.parentId + ? snapBeamPoint({ + point: [origin[0] + planPoint[0] - anchor[0], origin[1] + planPoint[1] - anchor[1]], + nodes, + levelId: node.parentId, + ignoreIds: [node.id], + free: modifiers.altKey, + }).point + : origin + const next: WallPlanPoint = [at[0] - origin[0], at[1] - origin[1]] + if (next[0] === delta[0] && next[1] === delta[1]) return + delta = next + triggerSFX('sfx:grid-snap') + useLiveNodeOverrides.getState().set(id, movedBeamEnds(node, delta)) + }, + canCommit() { + return delta[0] !== 0 || delta[1] !== 0 + }, + commit() { + useScene.getState().updateNodes([{ id, data: movedBeamEnds(node, delta) }]) + useLiveNodeOverrides.getState().clear(id) + useViewer.getState().setSelection({ selectedIds: [id] }) + }, + } +} diff --git a/packages/nodes/src/beam/floorplan.test.ts b/packages/nodes/src/beam/floorplan.test.ts new file mode 100644 index 0000000000..068d92c8f3 --- /dev/null +++ b/packages/nodes/src/beam/floorplan.test.ts @@ -0,0 +1,135 @@ +import { afterEach, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + BeamNode, + BuildingNode, + clearSceneHistory, + createBeam, + type FloorplanGeometry, + type GeometryContext, + LevelNode, + useLiveNodeOverrides, + useScene, +} from '@pascal-app/core' +import { readFloorplanGeometryMetadata } from '@pascal-app/editor' +import { buildBeamFloorplan } from './floorplan' +import { beamEndpointAffordance } from './floorplan-affordances' +import { beamFloorplanMoveTarget, movedBeamEnds } from './floorplan-move' + +type RafFn = (cb: (time: number) => void) => number +;(globalThis as unknown as { requestAnimationFrame?: RafFn }).requestAnimationFrame ??= (cb) => { + cb(0) + return 0 +} +;(globalThis as unknown as { cancelAnimationFrame?: (id: number) => void }).cancelAnimationFrame ??= + () => {} + +const FT = 0.3048 +// Alt: the drags place freely, so the expected points are the pointer's. +const modifiers = { shiftKey: false, altKey: true, ctrlKey: false, metaKey: false } +const BEAM = createBeam({ start: [0, 0], end: [12 * FT, 0], preset: '(2)2x10', levelId: 'level_g' }) + +afterEach(() => { + useLiveNodeOverrides.getState().clearAll() +}) + +/** A storey holding the beam, as the scene store loads one. */ +function load(beam: BeamNode) { + const building = BuildingNode.parse({ id: 'building_a', children: ['level_g'] }) + const level = LevelNode.parse({ + id: 'level_g', + parentId: building.id, + level: 0, + height: 2.7, + children: [beam.id], + }) + const nodes = Object.fromEntries([building, level, beam].map((node) => [node.id, node])) + useScene.getState().setScene(nodes as Record, [building.id as AnyNodeId], { + installedPlugins: [], + hasExplicitPluginInstallState: false, + }) + clearSceneHistory() +} + +function flat(geometry: FloorplanGeometry | null): FloorplanGeometry[] { + if (!geometry) return [] + return geometry.kind === 'group' ? geometry.children.flatMap(flat) : [geometry] +} + +const view = (selected: boolean, unit: 'metric' | 'imperial' = 'imperial') => + ({ + viewState: { selected, highlighted: false, hovered: false, moving: false, unit }, + }) as unknown as GeometryContext + +test('a beam is drawn as a dashed double outline of its width, its size beside it', () => { + const parts = flat(buildBeamFloorplan(BEAM, view(false))) + const outline = parts.find((part) => part.kind === 'polygon') + expect(outline?.kind === 'polygon' && outline.strokeDasharray).toBeTruthy() + expect(outline?.kind === 'polygon' && outline.points.length).toBe(4) + // the outline spans the beam's 3 in across + const zs = outline?.kind === 'polygon' ? outline.points.map((point) => point[1]) : [] + expect(Math.max(...zs) - Math.min(...zs)).toBeCloseTo(3 * 0.0254) + expect(readFloorplanGeometryMetadata(outline as never)?.annotationObstacle).toBe('outline') + const labels = parts.filter((part) => part.kind === 'dimension-label') + expect(labels.map((label) => label.kind === 'dimension-label' && label.text)).toEqual([ + '(2) 2x10', + ]) + // a click near the line picks it, at any zoom + expect(parts.some((part) => part.kind === 'hit-line')).toBe(true) + // unselected: no handles + expect(parts.some((part) => part.kind === 'endpoint-handle')).toBe(false) +}) + +test('selected, it shows its end handles, a move arrow either side and its length', () => { + const parts = flat(buildBeamFloorplan(BEAM, view(true))) + const ends = parts.filter((part) => part.kind === 'endpoint-handle') + expect(ends.map((end) => end.kind === 'endpoint-handle' && end.payload)).toEqual([ + { endpoint: 'start' }, + { endpoint: 'end' }, + ]) + expect(parts.filter((part) => part.kind === 'move-arrow')).toHaveLength(2) + const labels = parts.flatMap((part) => (part.kind === 'dimension-label' ? [part.text] : [])) + expect(labels).toEqual(['(2) 2x10', `12'0"`]) + expect( + flat(buildBeamFloorplan(BEAM, view(true, 'metric'))).flatMap((part) => + part.kind === 'dimension-label' ? [part.text] : [], + ), + ).toContain('3.66m') +}) + +test('a beam of no length draws nothing', () => { + expect(buildBeamFloorplan(BeamNode.parse({ start: [1, 1], end: [1, 1] }), view(false))).toBeNull() +}) + +test('an end dragged in the plan previews live and writes once; a too-short beam is refused', () => { + load(BEAM) + const session = beamEndpointAffordance.start({ + node: BEAM, + payload: { endpoint: 'end' }, + nodes: useScene.getState().nodes, + initialPlanPoint: [12 * FT, 0], + gridSnapStep: 0.5, + }) + session.apply({ planPoint: [5, 1], modifiers }) + expect(useLiveNodeOverrides.getState().overrides.get(BEAM.id)).toEqual({ end: [5, 1] }) + expect(session.canCommit()).toBe(true) + session.commit?.() + expect((useScene.getState().nodes[BEAM.id] as BeamNode).end).toEqual([5, 1]) + expect(useLiveNodeOverrides.getState().overrides.get(BEAM.id)).toBeUndefined() + session.apply({ planPoint: [0.002, 0], modifiers }) + expect(session.canCommit()).toBe(false) +}) + +test('a plan move carries both ends together', () => { + expect(movedBeamEnds(BEAM, [1, 2])).toEqual({ start: [1, 2], end: [12 * FT + 1, 2] }) + load(BEAM) + const session = beamFloorplanMoveTarget({ node: BEAM, nodes: useScene.getState().nodes }) + session.apply({ planPoint: [2, 2], modifiers }) + session.apply({ planPoint: [3, 2.5], modifiers }) + expect(session.canCommit()).toBe(true) + session.commit?.() + const moved = useScene.getState().nodes[BEAM.id] as BeamNode + expect(moved.start).toEqual([1, 0.5]) + expect(moved.end[0]).toBeCloseTo(12 * FT + 1) +}) diff --git a/packages/nodes/src/beam/floorplan.ts b/packages/nodes/src/beam/floorplan.ts new file mode 100644 index 0000000000..1a6bf9df38 --- /dev/null +++ b/packages/nodes/src/beam/floorplan.ts @@ -0,0 +1,112 @@ +import { + type BeamNode, + beamOutline, + beamPlan, + beamSizeLabel, + type FloorplanGeometry, + type GeometryContext, +} from '@pascal-app/core' +import { + floorplanGeometryMetadata, + formatLinearMeasurement, + readFloorplanMetricNotationOverride, +} from '@pascal-app/editor' + +/** Hidden work: a beam is over the plan's cut, so it is drawn dashed, as a framing plan draws it. */ +const HIDDEN_DASH = '8 4' +const MOVE_ARROW_OFFSET = 0.17 +/** Screen pixels between the beam's line and its size label (and, selected, its length). */ +const LABEL_OFFSET_PX = 11 + +export type BeamEndpointPayload = { endpoint: 'start' | 'end' } + +/** + * A beam in the plan, the way a framing plan draws one: its width as a dashed double outline and + * its size beside it ("6x8", "(2) 2x10"), over a clear hit area. Selected, it gets its end handles, + * a move arrow either side and its length. + */ +export function buildBeamFloorplan(node: BeamNode, ctx: GeometryContext): FloorplanGeometry | null { + const plan = beamPlan(node) + if (plan.length < 1e-6) return null + const view = ctx.viewState + const selected = view?.selected ?? false + const chrome = selected || (view?.highlighted ?? false) + const stroke = + chrome && view?.palette + ? view.palette.selectedStroke + : view?.hovered && view.palette + ? view.palette.wallHoverStroke + : '#374151' + const mid: [number, number] = [ + (plan.start[0] + plan.end[0]) / 2, + (plan.start[1] + plan.end[1]) / 2, + ] + const angle = Math.atan2(plan.direction[1], plan.direction[0]) + + const children: FloorplanGeometry[] = [ + { + kind: 'polygon', + points: beamOutline(node), + fill: chrome ? '#fed7aa' : 'transparent', + fillOpacity: chrome ? 0.35 : undefined, + stroke, + strokeWidth: chrome ? 1.75 : 1.25, + strokeDasharray: HIDDEN_DASH, + vectorEffect: 'non-scaling-stroke', + // A room's name and area move off a beam rather than hide it. + metadata: floorplanGeometryMetadata({ annotationObstacle: 'outline' }), + }, + // A beam is a few inches wide: a click near its line picks it at any zoom. + { + kind: 'hit-line', + x1: plan.start[0], + y1: plan.start[1], + x2: plan.end[0], + y2: plan.end[1], + strokeWidthPx: 12, + }, + { + kind: 'dimension-label', + cx: mid[0], + cy: mid[1], + text: beamSizeLabel(node), + angle, + offsetPx: LABEL_OFFSET_PX, + appearance: 'outlined', + }, + ] + + if (selected) { + for (const endpoint of ['start', 'end'] as const) + children.push({ + kind: 'endpoint-handle', + point: plan[endpoint], + state: 'idle', + affordance: 'move-endpoint', + payload: { endpoint } satisfies BeamEndpointPayload, + }) + for (const side of [1, -1] as const) { + // No affordance: the layer hands the beam to `floorplanMoveTarget`. + const offset = (plan.width / 2 + MOVE_ARROW_OFFSET) * side + children.push({ + kind: 'move-arrow', + point: [mid[0] + plan.normal[0] * offset, mid[1] + plan.normal[1] * offset], + angle: Math.atan2(plan.normal[1] * side, plan.normal[0] * side), + }) + } + if (plan.length >= 0.1) + children.push({ + kind: 'dimension-label', + cx: mid[0], + cy: mid[1], + text: formatLinearMeasurement( + plan.length, + view?.unit ?? 'metric', + readFloorplanMetricNotationOverride(ctx) ?? 'meters', + ), + angle, + offsetPx: -LABEL_OFFSET_PX - 4, + }) + } + return { kind: 'group', children } +} diff --git a/packages/nodes/src/beam/geometry.ts b/packages/nodes/src/beam/geometry.ts new file mode 100644 index 0000000000..e410ec5eb9 --- /dev/null +++ b/packages/nodes/src/beam/geometry.ts @@ -0,0 +1,80 @@ +import { type BeamNode, beamPlan } from '@pascal-app/core' +import { BoxGeometry, type BufferGeometry } from 'three' +import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js' +import { applyPlanarWorldUvs, copyUvToSecondaryChannel } from '../shared/primitive-uv' + +/** The seam left between the plies of a built-up beam, so a (2) 2x10 reads as two boards. */ +const PLY_SEAM = 0.0015 + +/** + * Where a beam's box sits in its level, level-local: its centre, its turn about Y (local X runs + * start → end) and its size along, up and across. Null for a beam of no length. + */ +export type BeamBox = { + position: [number, number, number] + rotationY: number + size: [number, number, number] +} + +export function beamBox( + beam: Pick, + top: number, +): BeamBox | null { + const plan = beamPlan(beam) + if (plan.length < 1e-6) return null + return { + position: [ + (plan.start[0] + plan.end[0]) / 2, + top - beam.depth / 2, + (plan.start[1] + plan.end[1]) / 2, + ], + // Three.js turns local +X to (cos θ, 0, −sin θ): θ = −atan2(dz, dx) runs it along the beam. + rotationY: -Math.atan2(plan.direction[1], plan.direction[0]), + size: [plan.length, beam.depth, beam.width], + } +} + +function box(length: number, height: number, across: number, y: number, z: number): BufferGeometry { + const geometry = new BoxGeometry(length, height, across).toNonIndexed() + geometry.translate(0, y, z) + return geometry +} + +/** + * The beam's solid about its own centre, local X along it: one block for a solid timber, glulam + * or a single LVL; its plies side by side with a hairline between for a built-up beam; a W shape's + * two flanges and web for steel. UVs run a metre to the texture repeat, the grain along the beam. + */ +export function buildBeamGeometry( + beam: Pick, + length: number, +): BufferGeometry { + const { width, depth } = beam + let parts: BufferGeometry[] + if (beam.material === 'steel') { + // A W8x10's flanges are 0.205 in, its web 0.17 in: the same proportions at any size. + const flange = Math.max(0.004, depth * 0.026) + const web = Math.max(0.003, width * 0.043) + parts = [ + box(length, flange, width, depth / 2 - flange / 2, 0), + box(length, flange, width, -depth / 2 + flange / 2, 0), + box(length, depth - flange * 2, web, 0, 0), + ] + } else if (beam.plies > 1) { + // The seams fall between the plies; the outer faces stay the beam's. + const seam = Math.min(PLY_SEAM, width / beam.plies / 2) + const ply = (width - seam * (beam.plies - 1)) / beam.plies + parts = Array.from({ length: beam.plies }, (_, index) => + box(length, depth, ply, 0, -width / 2 + ply / 2 + index * (ply + seam)), + ) + } else { + parts = [box(length, depth, width, 0, 0)] + } + const merged = parts.length === 1 ? parts[0]! : (mergeGeometries(parts) ?? parts[0]!) + if (merged !== parts[0]) for (const part of parts) part.dispose() + applyPlanarWorldUvs(merged) + copyUvToSecondaryChannel(merged) + merged.computeBoundingBox() + merged.computeBoundingSphere() + return merged +} diff --git a/packages/nodes/src/beam/index.ts b/packages/nodes/src/beam/index.ts new file mode 100644 index 0000000000..f9fb6a8403 --- /dev/null +++ b/packages/nodes/src/beam/index.ts @@ -0,0 +1,2 @@ +export { BeamNode } from '@pascal-app/core' +export { beamDefinition } from './definition' diff --git a/packages/nodes/src/beam/move-endpoint-tool.tsx b/packages/nodes/src/beam/move-endpoint-tool.tsx new file mode 100644 index 0000000000..06401ae632 --- /dev/null +++ b/packages/nodes/src/beam/move-endpoint-tool.tsx @@ -0,0 +1,93 @@ +'use client' + +import { + type AnyNode, + type BeamNode, + beamTopElevation, + sceneRegistry, + useScene, +} from '@pascal-app/core' +import { + CursorSphere, + MeasurementPill, + triggerSFX, + useDragAction, + useInteractionScope, +} from '@pascal-app/editor' +import { useViewer } from '@pascal-app/viewer' +import { Html } from '@react-three/drei' +import { createPortal } from '@react-three/fiber' +import { moveBeamEndpointDragAction } from './actions/move-endpoint' + +/** + * The reshaped node and which end: the tool manager builds it from the endpoint scope, naming a + * kind it has no slot for under `wall`. + */ +export type MovingBeamEndpoint = { + wall?: AnyNode + fence?: AnyNode + beam?: AnyNode + endpoint: 'start' | 'end' +} + +/** + * A beam's end dragged in 3D: the thin wrapper around `moveBeamEndpointDragAction`, which owns + * the snapping and the single undo step. Shows the cursor at the moving end and the beam's height, + * length and width while it runs. Mounted by the tool manager from `move-endpoint`. + */ +export const MoveBeamEndpointTool: React.FC<{ target: MovingBeamEndpoint }> = ({ target }) => { + const initial = (target.beam ?? target.wall ?? target.fence) as BeamNode | undefined + const unit = useViewer((state) => state.unit) + const beamId = initial?.id + const live = useScene((state) => (beamId ? state.nodes[beamId] : undefined)) + const beam = live?.type === 'beam' ? live : initial + const top = useScene((state) => (beam ? beamTopElevation(state.nodes, beam) : 0)) + + const exit = (committed: boolean) => { + if (committed) triggerSFX('sfx:item-place') + if (beamId) useViewer.getState().setSelection({ selectedIds: [beamId] }) + useInteractionScope + .getState() + .endIf((scope) => scope.kind === 'reshaping' && scope.reshape === 'endpoint') + } + + useDragAction({ + active: initial?.type === 'beam', + action: moveBeamEndpointDragAction, + initial: { + node: initial, + handleId: target.endpoint, + point: initial ? initial[target.endpoint] : [0, 0], + }, + onCommit: () => exit(true), + onCancel: () => exit(false), + }) + + const level = beam?.parentId ? sceneRegistry.nodes.get(beam.parentId) : undefined + if (!(beam?.type === 'beam' && level)) return null + const moving = beam[target.endpoint] + const length = Math.hypot(beam.end[0] - beam.start[0], beam.end[1] - beam.start[1]) + // In the beam's level, where its top is measured. + return createPortal( + + + + + + , + level, + ) +} + +export default MoveBeamEndpointTool diff --git a/packages/nodes/src/beam/move-tool.tsx b/packages/nodes/src/beam/move-tool.tsx new file mode 100644 index 0000000000..a573e82aa7 --- /dev/null +++ b/packages/nodes/src/beam/move-tool.tsx @@ -0,0 +1,140 @@ +'use client' + +import { + type AnyNodeId, + type BeamNode, + beamTopElevation, + emitter, + type GridEvent, + sceneRegistry, + useLiveNodeOverrides, + useScene, +} from '@pascal-app/core' +import { + CursorSphere, + consumePlacementDragRelease, + isFreshPlacementMetadata, + markToolCancelConsumed, + stripPlacementMetadataFlags, + triggerSFX, + useEditor, + type WallPlanPoint, +} from '@pascal-app/editor' +import { useViewer } from '@pascal-app/viewer' +import { createPortal } from '@react-three/fiber' +import { useEffect, useRef, useState } from 'react' +import { snapBeamPoint } from './drafting' +import { movedBeamEnds } from './floorplan-move' + +/** + * A beam moved in 3D, both ends together: its start follows the pointer, snapped as the beam tool + * snaps (wall faces and ends, other beams, post centres, the grid; Alt free), the run keeping its + * length and angle. Previews through live overrides and writes once on the click, one undo step; + * Esc puts it back. Mounted by the move dispatcher from `affordanceTools.move`. + */ +export const MoveBeamTool: React.FC<{ node: BeamNode }> = ({ node }) => { + const activatedAt = useRef(Date.now()) + const [cursor, setCursor] = useState<[number, number, number] | null>(null) + const top = useScene((state) => beamTopElevation(state.nodes, node)) + + useEffect(() => { + const id = node.id as AnyNodeId + const origin: WallPlanPoint = [node.start[0], node.start[1]] + const fresh = isFreshPlacementMetadata(node.metadata) + let anchor: WallPlanPoint | null = null + let delta: WallPlanPoint = [0, 0] + let committed = false + + const exit = () => useEditor.getState().setMovingNode(null) + const preview = () => { + useLiveNodeOverrides.getState().set(id, movedBeamEnds(node, delta)) + useScene.getState().markDirty(id) + } + + const onGridMove = (event: GridEvent) => { + const raw: WallPlanPoint = [event.localPosition[0], event.localPosition[2]] + anchor ??= raw + const at = node.parentId + ? snapBeamPoint({ + point: [origin[0] + raw[0] - anchor[0], origin[1] + raw[1] - anchor[1]], + nodes: useScene.getState().nodes, + levelId: node.parentId, + ignoreIds: [node.id], + free: event.nativeEvent?.altKey === true, + }).point + : origin + const next: WallPlanPoint = [at[0] - origin[0], at[1] - origin[1]] + if (next[0] === delta[0] && next[1] === delta[1]) return + delta = next + triggerSFX('sfx:grid-snap') + const moved = movedBeamEnds(node, delta) + setCursor([(moved.start[0] + moved.end[0]) / 2, 0, (moved.start[1] + moved.end[1]) / 2]) + preview() + } + + const onGridClick = (event: GridEvent) => { + if (committed) return + if (Date.now() - activatedAt.current < 150) { + event.nativeEvent?.stopPropagation?.() + return + } + committed = true + const moved = movedBeamEnds(node, delta) + useScene.getState().updateNodes([ + { + id, + data: fresh + ? { + ...moved, + metadata: stripPlacementMetadataFlags(node.metadata) as BeamNode['metadata'], + } + : moved, + }, + ]) + useLiveNodeOverrides.getState().clear(id) + triggerSFX('sfx:item-place') + useViewer.getState().setSelection({ selectedIds: [id] }) + exit() + event.nativeEvent?.stopPropagation?.() + } + + const onPlacementDragPointerUp = (event: PointerEvent) => { + if (!consumePlacementDragRelease(event)) return + activatedAt.current = 0 + onGridClick({ nativeEvent: event } as unknown as GridEvent) + } + + const onCancel = () => { + useLiveNodeOverrides.getState().clear(id) + useScene.getState().markDirty(id) + useViewer.getState().setSelection({ selectedIds: [id] }) + markToolCancelConsumed() + // This tool owns the teardown: the 2D overlay leaves the beam to it. + useEditor.getState().setMovingNodeOrigin('3d') + exit() + } + + emitter.on('grid:move', onGridMove) + emitter.on('grid:click', onGridClick) + emitter.on('tool:cancel', onCancel) + window.addEventListener('pointerup', onPlacementDragPointerUp) + return () => { + // Only the live preview is ever undone here: a move the 2D overlay committed is in the + // scene already, and an override is never the scene. + if (!committed) useLiveNodeOverrides.getState().clear(id) + emitter.off('grid:move', onGridMove) + emitter.off('grid:click', onGridClick) + emitter.off('tool:cancel', onCancel) + window.removeEventListener('pointerup', onPlacementDragPointerUp) + } + }, [node]) + + const level = node.parentId ? sceneRegistry.nodes.get(node.parentId) : undefined + if (!(cursor && level)) return null + return createPortal( + , + level, + ) +} + +export default MoveBeamTool diff --git a/packages/nodes/src/beam/panel-model.test.ts b/packages/nodes/src/beam/panel-model.test.ts new file mode 100644 index 0000000000..981781a8c8 --- /dev/null +++ b/packages/nodes/src/beam/panel-model.test.ts @@ -0,0 +1,109 @@ +import { beforeEach, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + type BeamNode, + BuildingNode, + clearSceneHistory, + createBeam, + LevelNode, + SlabNode, + useScene, +} from '@pascal-app/core' +import { beamPliesPatch } from './panel' +import { beamPanelModel, beamSizeOptions, beamSizeValue } from './panel-model' + +type RafFn = (cb: (time: number) => void) => number +;(globalThis as unknown as { requestAnimationFrame?: RafFn }).requestAnimationFrame ??= (cb) => { + cb(0) + return 0 +} +;(globalThis as unknown as { cancelAnimationFrame?: (id: number) => void }).cancelAnimationFrame ??= + () => {} + +const IN = 0.0254 +const A = createBeam({ start: [0, 0], end: [3, 0], preset: '6x8', levelId: 'level_g' }) +const B = createBeam({ start: [0, 2], end: [3, 2], preset: '6x8', levelId: 'level_g' }) + +beforeEach(() => { + const building = BuildingNode.parse({ id: 'building_a', children: ['level_g'] }) + const level = LevelNode.parse({ + id: 'level_g', + parentId: building.id, + level: 0, + height: 2.7, + children: ['slab_g', A.id, B.id], + }) + const slab = SlabNode.parse({ + id: 'slab_g', + parentId: level.id, + polygon: [ + [-1, -1], + [5, -1], + [5, 5], + [-1, 5], + ], + elevation: 0.05, + thickness: 0.2, + }) + const nodes = Object.fromEntries([building, level, slab, A, B].map((node) => [node.id, node])) + useScene.getState().setScene(nodes as Record, [building.id as AnyNodeId], { + installedPlugins: [], + hasExplicitPluginInstallState: false, + }) + clearSceneHistory() +}) + +const read = (id: string) => useScene.getState().nodes[id as AnyNodeId] as BeamNode +const controls = () => + beamPanelModel.multiControls!({ + selection: [read(A.id), read(B.id)], + nodes: useScene.getState().nodes, + }) + +test('selected beams take a size, a material and a top together, in one undo step', () => { + const [size, material, top] = controls() + expect(size).toMatchObject({ id: 'beam-size', value: '6x8' }) + expect(material).toMatchObject({ id: 'beam-material', value: 'sawn' }) + expect(top).toMatchObject({ id: 'beam-top', value: 'ceiling-dropped' }) + if (size?.kind !== 'select') throw new Error('size is a select') + size.onChange('(3)2x10') + for (const id of [A.id, B.id]) { + expect(read(id)).toMatchObject({ size: '2x10', plies: 3 }) + expect(read(id).width).toBeCloseTo(4.5 * IN) + } + const [, , nextTop] = controls() + if (nextTop?.kind !== 'select') throw new Error('top is a select') + nextTop.onChange('floor-flush') + expect(read(A.id)).toMatchObject({ topElevation: 0.05, placement: 'flush' }) + useScene.temporal.getState().undo() + expect(read(B.id).topElevation).toBeUndefined() +}) + +test('a mixed selection shows no value; a custom section reads Custom', () => { + useScene.getState().updateNode(B.id, { material: 'lvl' }) + const [, material] = controls() + expect(material?.kind === 'select' && material.value).toBeNull() + const custom = { ...read(A.id), width: 2 * IN, size: undefined } + expect(beamSizeValue(custom)).toBe('custom') + expect(beamSizeOptions('custom')[0]).toEqual({ label: 'Custom', value: 'custom' }) + expect(beamSizeOptions('6x8').some((option) => option.value === 'custom')).toBe(false) +}) + +test('the XR rows step through sizes and materials', () => { + const rows = beamPanelModel.rows({ + node: read(A.id), + nodes: useScene.getState().nodes, + update: (patch) => useScene.getState().updateNode(A.id, patch), + }) + const size = rows.find((row) => row.id === 'beam-size') + expect(size?.kind === 'cycle' && size.value).toBe('6x8') + if (size?.kind === 'cycle') size.next() + expect(read(A.id).size).toBe('6x10') +}) + +test('plies add boards of the same width', () => { + const doubled = createBeam({ start: [0, 0], end: [1, 0], preset: '(2)2x10' }) + expect(beamPliesPatch(doubled, 3).width).toBeCloseTo(4.5 * IN) + expect(beamPliesPatch(doubled, 1)).toMatchObject({ plies: 1 }) +}) diff --git a/packages/nodes/src/beam/panel-model.ts b/packages/nodes/src/beam/panel-model.ts new file mode 100644 index 0000000000..c773b04a01 --- /dev/null +++ b/packages/nodes/src/beam/panel-model.ts @@ -0,0 +1,157 @@ +import { + type AnyNode, + type AnyNodeId, + BEAM_MATERIAL_LABELS, + BEAM_SIZE_PRESETS, + BEAM_TOP_REFERENCE_LABELS, + BEAM_TOP_REFERENCES, + type BeamMaterial, + type BeamNode, + type BeamTopReference, + beamSizePresetPatch, + beamTopReferenceOf, + beamTopReferencePatch, + matchBeamSizePreset, + runAsSingleSceneHistoryStep, + useScene, +} from '@pascal-app/core' +import type { NodePanelModel } from '@pascal-app/editor' + +type Nodes = Record + +const CUSTOM = 'custom' + +/** The Size choices: every stock size, and Custom while the beam is no stock size. */ +export function beamSizeOptions(current: string | null) { + return [ + ...(current === CUSTOM ? [{ label: 'Custom', value: CUSTOM }] : []), + ...BEAM_SIZE_PRESETS.map((preset) => ({ label: preset.label, value: preset.id })), + ] +} + +/** Which Size choice a beam is: its stock size, or Custom. */ +export function beamSizeValue(beam: BeamNode): string { + return matchBeamSizePreset(beam)?.id ?? CUSTOM +} + +export const BEAM_MATERIAL_OPTIONS = (Object.keys(BEAM_MATERIAL_LABELS) as BeamMaterial[]).map( + (material) => ({ label: BEAM_MATERIAL_LABELS[material], value: material }), +) + +/** The Top choices: the references, and Custom while the top is typed in. */ +export function beamTopOptions(current: string | null) { + return [ + ...BEAM_TOP_REFERENCES.map((top) => ({ label: BEAM_TOP_REFERENCE_LABELS[top], value: top })), + ...(current === CUSTOM ? [{ label: 'Custom', value: CUSTOM }] : []), + ] +} + +export function beamTopValue(nodes: Nodes, beam: BeamNode): string { + return beamTopReferenceOf(nodes, beam) ?? CUSTOM +} + +/** The one value every beam shares, or null for a mixed selection. */ +function shared(values: string[]): string | null { + return values.every((value) => value === values[0]) ? (values[0] ?? null) : null +} + +/** Writes one patch per beam in a single undo step. */ +function updateAll(beams: BeamNode[], patch: (beam: BeamNode) => Partial) { + runAsSingleSceneHistoryStep(useScene, () => + useScene + .getState() + .updateNodes(beams.map((beam) => ({ id: beam.id as AnyNodeId, data: patch(beam) }))), + ) +} + +/** Steps through a list of choices, wrapping round. */ +function cycle(list: readonly T[], current: T | string, step: 1 | -1): T { + const index = list.indexOf(current as T) + return list[(index + step + list.length) % list.length]! +} + +/** + * The beam's settings as panel rows (the XR wand's panel) and as controls the multi-selection + * inspector applies to every selected beam at once: size, material, top. A porch's beams take a + * new size together. + */ +export const beamPanelModel: NodePanelModel = { + rows: ({ node, nodes, update }) => { + const sizes = BEAM_SIZE_PRESETS.map((preset) => preset.id as string) + const materials = BEAM_MATERIAL_OPTIONS.map((option) => option.value) + const size = beamSizeValue(node) + const top = beamTopValue(nodes, node) + return [ + { + id: 'beam-size', + kind: 'cycle', + section: 'Beam', + label: 'Size', + value: BEAM_SIZE_PRESETS.find((preset) => preset.id === size)?.label ?? 'Custom', + next: () => update(beamSizePresetPatch(node, cycle(sizes, size, 1))), + previous: () => update(beamSizePresetPatch(node, cycle(sizes, size, -1))), + }, + { + id: 'beam-material', + kind: 'cycle', + section: 'Beam', + label: 'Material', + value: BEAM_MATERIAL_LABELS[node.material], + next: () => update({ material: cycle(materials, node.material, 1) }), + previous: () => update({ material: cycle(materials, node.material, -1) }), + }, + { + id: 'beam-top', + kind: 'cycle', + section: 'Beam', + label: 'Top', + value: top === CUSTOM ? 'Custom' : BEAM_TOP_REFERENCE_LABELS[top as BeamTopReference], + next: () => update(beamTopReferencePatch(nodes, node, cycle(BEAM_TOP_REFERENCES, top, 1))), + previous: () => + update(beamTopReferencePatch(nodes, node, cycle(BEAM_TOP_REFERENCES, top, -1))), + }, + ] + }, + multiControls: ({ selection, nodes }) => { + if (selection.length === 0) return [] + const size = shared(selection.map(beamSizeValue)) + const top = shared(selection.map((beam) => beamTopValue(nodes, beam))) + return [ + { + id: 'beam-size', + kind: 'select', + section: 'Beam', + label: 'Size', + options: beamSizeOptions(size), + value: size, + onChange: (id) => { + if (id !== CUSTOM) updateAll(selection, (beam) => beamSizePresetPatch(beam, id)) + }, + }, + { + id: 'beam-material', + kind: 'select', + section: 'Beam', + label: 'Material', + options: BEAM_MATERIAL_OPTIONS, + value: shared(selection.map((beam) => beam.material)), + onChange: (material) => + updateAll(selection, () => ({ material: material as BeamMaterial })), + }, + { + id: 'beam-top', + kind: 'select', + section: 'Beam', + label: 'Top', + options: beamTopOptions(top), + value: top, + onChange: (reference) => { + if (reference === CUSTOM) return + updateAll(selection, (beam) => + beamTopReferencePatch(nodes, beam, reference as BeamTopReference), + ) + }, + }, + ] + }, +} diff --git a/packages/nodes/src/beam/panel.tsx b/packages/nodes/src/beam/panel.tsx new file mode 100644 index 0000000000..7b4dfc758e --- /dev/null +++ b/packages/nodes/src/beam/panel.tsx @@ -0,0 +1,260 @@ +'use client' + +import { + type AnyNodeId, + type BeamMaterial, + type BeamNode, + type BeamPlacement, + type BeamTopReference, + beamCeilingPlane, + beamPlan, + beamSizeLabel, + beamSizePresetPatch, + beamTopElevation, + beamTopReferencePatch, + DEFAULT_FRAMING_POST_SIZE, + usePascalI18n, + useScene, +} from '@pascal-app/core' +import { + ActionButton, + ActionGroup, + formatLinearMeasurement, + MetricControl, + PanelSection, + PanelWrapper, + SegmentedControl, + SelectControl, + triggerSFX, + useEditor, +} from '@pascal-app/editor' +import { useViewer } from '@pascal-app/viewer' +import { Columns2, Move, Trash2 } from 'lucide-react' +import { useState } from 'react' +import { electedPostFoot, framingPostsUnderBeam } from '../column/post-placement' +import { + BEAM_MATERIAL_OPTIONS, + beamSizeOptions, + beamSizeValue, + beamTopOptions, + beamTopValue, +} from './panel-model' + +const IN = 0.0254 +const CUSTOM = 'custom' + +/** A section size in metres, shown in inches on an imperial plan (feet would show 7-1/2 in as 0.63). */ +function InchField({ + label, + value, + onCommit, +}: { + label: string + value: number + onCommit: (meters: number) => void +}) { + const [draft, setDraft] = useState(null) + const imperial = useViewer((state) => state.unit) === 'imperial' + const toShown = (meters: number) => (imperial ? meters / IN : meters) + return ( + setDraft(next)} + onCommit={(next) => { + setDraft(null) + onCommit(imperial ? next * IN : next) + }} + precision={imperial ? 3 : 4} + restoreOnCommit={false} + step={imperial ? 0.25 : 0.005} + unit={imperial ? 'in' : 'm'} + value={draft ?? toShown(value)} + /> + ) +} + +/** The fields a ply count writes: as many plies of the same board, the width growing with them. */ +export function beamPliesPatch(beam: Pick, plies: number) { + return { plies, width: (beam.width / beam.plies) * plies } +} + +/** + * A beam's panel: its size (a stock size, or a width, depth and plies of its own), what it is made + * of, how the joists meet it and where its top is, with its length and underside; Move, Delete, + * and posts under it at each end and every 8 ft. + */ +export default function BeamPanel() { + const i18n = usePascalI18n() + const selectedId = useViewer((state) => state.selection.selectedIds[0]) + const setSelection = useViewer((state) => state.setSelection) + const unit = useViewer((state) => state.unit) + const metricNotation = useViewer((state) => state.metricNotation) + const nodes = useScene((state) => state.nodes) + const beam = selectedId ? nodes[selectedId as AnyNodeId] : undefined + if (beam?.type !== 'beam') return null + + const update = (patch: Partial) => useScene.getState().updateNode(beam.id, patch) + const length = (meters: number) => formatLinearMeasurement(meters, unit, metricNotation) + const size = beamSizeValue(beam) + const top = beamTopValue(nodes, beam) + const topY = beamTopElevation(nodes, beam) + const plane = beamCeilingPlane(nodes, beam) + + return ( + setSelection({ selectedIds: [] })} + title={beam.name ?? i18n._({ id: 'node.beam.panel.beam', message: 'Beam' })} + width={300} + > + + { + if (id !== CUSTOM) update(beamSizePresetPatch(beam, id)) + }} + options={beamSizeOptions(size)} + value={size} + /> + update({ material: material as BeamMaterial })} + options={BEAM_MATERIAL_OPTIONS} + value={beam.material} + /> + update({ width, size: undefined })} + value={beam.width} + /> + update({ depth, size: undefined })} + value={beam.depth} + /> + update(beamPliesPatch(beam, Number(plies)))} + options={['1', '2', '3', '4'].map((plies) => ({ + label: + plies === '1' + ? i18n._({ id: 'node.beam.panel.n1Ply', message: '1 ply' }) + : i18n._({ + id: 'node.beam.panel.pliesPlies', + message: '{plies} plies', + values: { plies }, + }), + value: plies, + }))} + value={String(beam.plies)} + /> + + + update({ placement })} + options={[ + { + label: i18n._({ id: 'node.beam.panel.dropped', message: 'Dropped' }), + value: 'dropped', + }, + { label: i18n._({ id: 'node.beam.panel.flush', message: 'Flush' }), value: 'flush' }, + ]} + value={beam.placement} + /> + { + if (reference !== CUSTOM) + update(beamTopReferencePatch(nodes, beam, reference as BeamTopReference)) + }} + options={beamTopOptions(top)} + value={top} + /> + update({ topElevation: value })} + precision={3} + step={0.01} + unit="m" + value={topY} + /> +

+ {i18n._({ + id: 'node.beam.panel.lengthLongItsUnderside', + message: + '{length} long; its underside {underside} over the floor, the ceiling plane {plane}.', + values: { + length: length(beamPlan(beam).length), + underside: length(topY - beam.depth), + plane: length(plane), + }, + })} +

+ {beam.topElevation !== undefined && ( + + )} +
+ + + } + label={i18n._({ id: 'node.beam.panel.addPosts', message: 'Add posts' })} + onClick={() => { + const posts = beam.parentId + ? framingPostsUnderBeam({ + nodes, + beam, + choices: { size: DEFAULT_FRAMING_POST_SIZE, base: 'none' }, + foot: electedPostFoot(nodes, beam.parentId), + }) + : [] + if (posts.length === 0) return + const standing = Object.values(nodes).filter( + (node) => node.type === 'column' && node.role === 'post', + ).length + useScene.getState().createNodes( + posts.map((post, index) => ({ + node: { ...post, name: `Post ${standing + index + 1}` }, + parentId: beam.parentId as AnyNodeId, + })), + ) + triggerSFX('sfx:structure-build') + }} + /> + } + label={i18n._({ id: 'node.beam.panel.move', message: 'Move' })} + onClick={() => { + triggerSFX('sfx:item-pick') + useEditor.getState().setMovingNode(beam) + }} + /> + } + label={i18n._({ id: 'node.beam.panel.delete', message: 'Delete' })} + onClick={() => { + useScene.getState().deleteNode(beam.id) + setSelection({ selectedIds: [] }) + }} + /> + + +
+ ) +} diff --git a/packages/nodes/src/beam/parametrics.ts b/packages/nodes/src/beam/parametrics.ts new file mode 100644 index 0000000000..f0bd58b84f --- /dev/null +++ b/packages/nodes/src/beam/parametrics.ts @@ -0,0 +1,6 @@ +import type { BeamNode, ParametricDescriptor } from '@pascal-app/core' + +export const beamParametrics: ParametricDescriptor = { + groups: [], + customPanel: () => import('./panel'), +} diff --git a/packages/nodes/src/beam/renderer.tsx b/packages/nodes/src/beam/renderer.tsx new file mode 100644 index 0000000000..ff78b4e75c --- /dev/null +++ b/packages/nodes/src/beam/renderer.tsx @@ -0,0 +1,77 @@ +'use client' + +import { + BEAM_MATERIAL_LIBRARY_REFS, + type BeamNode, + beamTopElevation, + useLiveNodeOverrides, + useRegistry, + useScene, +} from '@pascal-app/core' +import { + createSurfaceRoleMaterial, + resolveSlotDefaultMaterial, + useNodeEvents, + useViewer, +} from '@pascal-app/viewer' +import { useEffect, useMemo, useRef } from 'react' +import type { Group, Material } from 'three' +import { beamBox, buildBeamGeometry } from './geometry' + +/** How a beam of `material` looks: its library material, or the plain surface colour when textures are off. */ +export function useBeamMaterial(material: BeamNode['material']): Material { + const shading = useViewer((state) => state.shading) + const textures = useViewer((state) => state.textures) + const colorPreset = useViewer((state) => state.colorPreset) + return useMemo( + () => + textures + ? resolveSlotDefaultMaterial(BEAM_MATERIAL_LIBRARY_REFS[material], shading) + : createSurfaceRoleMaterial('wall', colorPreset), + [material, shading, textures, colorPreset], + ) +} + +/** + * A beam: its solid laid along the centreline in its level, the top where the beam's top resolves + * (`beamTopElevation`: its own, else the ceiling plane over it). Reads live overrides, so a drag + * in either view moves it at once. + */ +export default function BeamRenderer({ node: stored }: { node: BeamNode }) { + const ref = useRef(null!) + useRegistry(stored.id, 'beam', ref) + const live = useLiveNodeOverrides((state) => state.overrides.get(stored.id)) + const node = useMemo(() => (live ? ({ ...stored, ...live } as BeamNode) : stored), [stored, live]) + const handlers = useNodeEvents(node, 'beam') + const top = useScene((state) => beamTopElevation(state.nodes, node)) + const material = useBeamMaterial(node.material) + const placed = beamBox(node, top) + const length = placed?.size[0] ?? 0 + const geometry = useMemo( + () => + length > 0 + ? buildBeamGeometry( + { width: node.width, depth: node.depth, plies: node.plies, material: node.material }, + length, + ) + : null, + [length, node.width, node.depth, node.plies, node.material], + ) + useEffect(() => () => geometry?.dispose(), [geometry]) + + return ( + + {placed && geometry && ( + + )} + + ) +} diff --git a/packages/nodes/src/beam/schema.ts b/packages/nodes/src/beam/schema.ts new file mode 100644 index 0000000000..704388383a --- /dev/null +++ b/packages/nodes/src/beam/schema.ts @@ -0,0 +1 @@ +export { BeamNode } from '@pascal-app/core' diff --git a/packages/nodes/src/beam/tool.test.ts b/packages/nodes/src/beam/tool.test.ts new file mode 100644 index 0000000000..47249072e5 --- /dev/null +++ b/packages/nodes/src/beam/tool.test.ts @@ -0,0 +1,126 @@ +import { afterEach, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + type BeamNode, + BuildingNode, + clearSceneHistory, + emitter, + type GridEvent, + LevelNode, + useScene, +} from '@pascal-app/core' +import { + getFloorplanNodeExtension, + sceneLayout, + useEditor, + usePlacementPreview, +} from '@pascal-app/editor' +import { useViewer } from '@pascal-app/viewer' +import { act, create } from '@react-three/test-renderer' +import { createElement } from 'react' +import { beamDefinition } from './definition' +import { useBeamDraft } from './draft-settings' +import { beamDraftDimensions } from './tool' + +type RafFn = (cb: (time: number) => void) => number +;(globalThis as unknown as { requestAnimationFrame?: RafFn }).requestAnimationFrame ??= (cb) => { + cb(0) + return 0 +} +;(globalThis as unknown as { cancelAnimationFrame?: (id: number) => void }).cancelAnimationFrame ??= + () => {} +;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true + +const previous = { editor: useEditor.getState(), viewer: useViewer.getState() } + +afterEach(() => { + useEditor.setState(previous.editor, true) + useViewer.setState(previous.viewer, true) + usePlacementPreview.getState().clear() + useBeamDraft.setState({ preset: '6x8', material: 'sawn', top: 'ceiling-dropped' }) +}) + +function setScene() { + const building = BuildingNode.parse({}) + const ground = LevelNode.parse({ parentId: building.id, level: 0, height: 2.7 }) + building.children = [ground.id] + const nodes = Object.fromEntries([building, ground].map((node) => [node.id, node])) + useScene.getState().setScene(nodes as Record, [building.id as AnyNodeId], { + installedPlugins: [], + hasExplicitPluginInstallState: false, + }) + clearSceneHistory() + useViewer.getState().setSelection({ buildingId: building.id, levelId: ground.id }) + useEditor.setState({ + mode: 'build', + tool: 'beam', + workspaceMode: 'edit', + viewLayouts: { edit: sceneLayout('2d') }, + }) + return { ground } +} + +const beams = () => + Object.values(useScene.getState().nodes).filter((node): node is BeamNode => node.type === 'beam') + +// Alt: the points are the pointer's, whatever the snapping mode. +const gridEvent = (x: number, z: number) => + ({ + position: [x, 0, z], + localPosition: [x, 0, z], + nativeEvent: { altKey: true } as GridEvent['nativeEvent'], + }) satisfies GridEvent + +const move = (x: number, z: number) => act(async () => emitter.emit('grid:move', gridEvent(x, z))) +const click = (x: number, z: number) => + act(async () => { + emitter.emit('grid:move', gridEvent(x, z)) + emitter.emit('grid:click', gridEvent(x, z)) + }) + +test('in 2D-only view the plan draws a run of beams, each from where the last ended', async () => { + const { ground } = setScene() + useBeamDraft.setState({ preset: '(2)2x10', material: 'pressure-treated' }) + const extension = getFloorplanNodeExtension(beamDefinition) + // A plan click on a beam over a room picks the beam. + expect(extension?.planHitSelectsNode).toBe(true) + const { default: PlanTool } = await extension!.tool!() + const renderer = await create(createElement(PlanTool as () => null)) + try { + await click(0, 0) + await move(3, 0) + expect(usePlacementPreview.getState().node).toMatchObject({ + type: 'beam', + start: [0, 0], + end: [3, 0], + }) + // the plan shows the draft's length + expect(usePlacementPreview.getState().dimensions[0]).toMatchObject({ value: 3 }) + await click(3, 0) + await click(3, 2) + expect(beams().map(({ start, end, parentId }) => ({ start, end, parentId }))).toEqual([ + { start: [0, 0], end: [3, 0], parentId: ground.id }, + { start: [3, 0], end: [3, 2], parentId: ground.id }, + ]) + expect(beams()[0]).toMatchObject({ size: '2x10', plies: 2, material: 'pressure-treated' }) + + // Esc ends the run: the next click starts a new beam. + await act(async () => emitter.emit('tool:cancel')) + await click(5, 5) + expect(beams()).toHaveLength(2) + await click(6, 5) + expect(beams()[2]).toMatchObject({ start: [5, 5], end: [6, 5] }) + } finally { + await act(async () => renderer.unmount()) + } + expect(usePlacementPreview.getState().node).toBeNull() +}) + +test('the draft length reads along the beam, off its side', () => { + const [dimension] = beamDraftDimensions( + beamDefinition.schema.parse({ start: [0, 0], end: [0, 4], width: 0.14 }), + ) + expect(dimension).toMatchObject({ value: 4, renderIn3d: false }) + expect(dimension?.offsetNormal[0]).toBeCloseTo(-1) +}) diff --git a/packages/nodes/src/beam/tool.tsx b/packages/nodes/src/beam/tool.tsx new file mode 100644 index 0000000000..c527524336 --- /dev/null +++ b/packages/nodes/src/beam/tool.tsx @@ -0,0 +1,220 @@ +'use client' + +import { + type AnyNodeId, + type BeamNode, + beamPlan, + beamTopElevation, + emitter, + type GridEvent, + sceneRegistry, + useScene, +} from '@pascal-app/core' +import { + CursorSphere, + DRAFT_LABEL_Y_OFFSET, + DraftMeasurementLabel, + formatLinearMeasurement, + isSegmentLongEnough, + markToolCancelConsumed, + type PlacementPreviewDimension, + triggerSFX, + useEditor, + usePlacementPreview, + useWallSnapIndicator, + visibleScene, + type WallPlanPoint, +} from '@pascal-app/editor' +import { getSceneTheme, useViewer } from '@pascal-app/viewer' +import { createPortal } from '@react-three/fiber' +import { useEffect, useMemo, useState } from 'react' +import { DoubleSide } from 'three' +import { MeshBasicNodeMaterial } from 'three/webgpu' +import { + type FloorPlacementClickTriggerEvent, + stopPlacementCommitPropagation, + subscribeFloorPlacementClicks, +} from '../shared/floor-placement' +import { draftBeam, snapBeamPoint } from './drafting' +import { beamBox, buildBeamGeometry } from './geometry' + +const ghostMaterial = new MeshBasicNodeMaterial({ + color: '#f59e0b', + depthWrite: false, + opacity: 0.5, + side: DoubleSide, + transparent: true, +}) + +/** The draft's length, as a dimension along it in the plan (the 3D view prints its own label). */ +export function beamDraftDimensions(beam: BeamNode): PlacementPreviewDimension[] { + const plan = beamPlan(beam) + if (plan.length < 0.05) return [] + return [ + { + id: 'beam-length', + start: [plan.start[0], 0, plan.start[1]], + end: [plan.end[0], 0, plan.end[1]], + offsetNormal: plan.normal, + offsetDistance: plan.width / 2 + 0.25, + value: plan.length, + renderIn3d: false, + }, + ] +} + +/** + * Drafting beams from the grid events both views send: a click sets the start, the next ends the + * beam and starts the next one there, so a porch's run is drawn corner to corner; Esc ends the run. + * Points snap as walls do (wall ends, faces and crossings, other beams' ends and runs, post + * centres, the grid, the angle steps off the start); Alt places freely. The beam takes the Build + * panel's size, material and top (`useBeamDraft`), or the preset a host armed the tool with. + * `enabled` off, it stands aside. + */ +function useBeamDrafting(enabled: boolean) { + const levelId = useViewer((state) => state.selection.levelId) + const [draft, setDraft] = useState(null) + const [cursor, setCursor] = useState<[number, number, number] | null>(null) + + useEffect(() => { + if (!(enabled && levelId)) return + let start: WallPlanPoint | null = null + let last: WallPlanPoint | null = null + setDraft(null) + + const snap = (event: GridEvent | FloorPlacementClickTriggerEvent): WallPlanPoint => { + const { point, snap: caught } = snapBeamPoint({ + point: [event.localPosition[0], event.localPosition[2]], + nodes: useScene.getState().nodes, + levelId, + start, + free: event.nativeEvent?.altKey === true, + }) + if (caught) useWallSnapIndicator.getState().set({ x: point[0], z: point[1], kind: caught }) + else useWallSnapIndicator.getState().clear() + return point + } + const make = (from: WallPlanPoint, to: WallPlanPoint, fields?: Partial) => + draftBeam( + from, + to, + levelId, + useScene.getState().nodes, + undefined, + useEditor.getState().toolDefaults.beam, + fields, + ) + const show = (next: BeamNode | null) => { + setDraft(next) + if (next) usePlacementPreview.getState().set(next, null, beamDraftDimensions(next)) + else usePlacementPreview.getState().clear() + } + + const onMove = (event: GridEvent) => { + const point = snap(event) + if (last && point[0] === last[0] && point[1] === last[1]) return + last = point + setCursor([point[0], event.localPosition[1], point[1]]) + show(start && isSegmentLongEnough(start, point) ? make(start, point) : null) + } + const onClick = (event: FloorPlacementClickTriggerEvent) => { + const point = last ?? snap(event) + stopPlacementCommitPropagation(event) + if (!start) { + start = point + triggerSFX('sfx:grid-snap') + return + } + if (!isSegmentLongEnough(start, point)) return + const count = Object.values(useScene.getState().nodes).filter( + (node) => node.type === 'beam', + ).length + const beam = make(start, point, { name: `Beam ${count + 1}` }) + useScene.getState().createNode(beam, levelId as AnyNodeId) + triggerSFX('sfx:structure-build') + // The run goes on from the end just placed. + start = point + show(null) + } + const onCancel = () => { + if (!start) return + markToolCancelConsumed() + start = null + show(null) + } + + emitter.on('grid:move', onMove) + emitter.on('tool:cancel', onCancel) + const unsubscribeClicks = subscribeFloorPlacementClicks(onClick) + return () => { + emitter.off('grid:move', onMove) + emitter.off('tool:cancel', onCancel) + unsubscribeClicks() + usePlacementPreview.getState().clear() + useWallSnapIndicator.getState().clear() + setDraft(null) + setCursor(null) + } + }, [enabled, levelId]) + + return { levelId, draft, cursor } +} + +/** + * The beam tool in 2D-only view: the 3D tool lives in the canvas, which never renders while its + * pane is hidden. The plan draws the draft from the placement preview. Split and 3D views keep the + * 3D tool as the one owner. + */ +export function BeamFloorplanTool() { + useBeamDrafting(useEditor((state) => visibleScene(state) === '2d')) + return null +} + +const BeamTool = () => { + const { levelId, draft, cursor } = useBeamDrafting( + useEditor((state) => visibleScene(state) !== '2d'), + ) + const top = useScene((state) => (draft ? beamTopElevation(state.nodes, draft) : 0)) + const unit = useViewer((state) => state.unit) + const metricNotation = useViewer((state) => state.metricNotation) + const dark = useViewer((state) => getSceneTheme(state.sceneTheme).appearance === 'dark') + const placed = draft ? beamBox(draft, top) : null + const length = placed?.size[0] ?? 0 + const geometry = useMemo( + () => (draft && length > 0 ? buildBeamGeometry(draft, length) : null), + [draft, length], + ) + useEffect(() => () => geometry?.dispose(), [geometry]) + const level = levelId ? sceneRegistry.nodes.get(levelId) : undefined + + if (!levelId) return null + return ( + <> + {cursor && } + {placed && + geometry && + level && + createPortal( + + {}} + renderOrder={2} + rotation-y={placed.rotationY} + /> + + , + level, + )} + + ) +} + +export default BeamTool diff --git a/packages/nodes/src/ceiling/build-up-section.tsx b/packages/nodes/src/ceiling/build-up-section.tsx new file mode 100644 index 0000000000..67bb89d810 --- /dev/null +++ b/packages/nodes/src/ceiling/build-up-section.tsx @@ -0,0 +1,150 @@ +'use client' + +import { + type CeilingBuildUp, + type CeilingFraming, + type CeilingNode, + ceilingBuildUpThickness, + LUMBER_DEPTH, + type MessageDescriptor, + usePascalI18n, +} from '@pascal-app/core' +import { PanelSection, SelectControl } from '@pascal-app/editor' +import { + BuildUpReadout, + editedBuildUp, + FinishFields, + FramingSizeFields, + InsulationFields, + NONE, + PanelFields, +} from '../shared/build-up-controls' +import { formatLayerDepth } from '../shared/layer-thickness' +import { + ceilingBuildUpPresetOptions, + ceilingBuildUpPresetPatch, + ceilingBuildUpPresetValue, +} from './panel-model' + +const INCH = 0.0254 + +const FRAMING_OPTIONS: { + label: MessageDescriptor + value: CeilingFraming['system'] | typeof NONE +}[] = [ + { label: /* i18n */ { id: 'node.ceiling.buildUpSection.none', message: 'None' }, value: NONE }, + { + label: /* i18n */ { + id: 'node.ceiling.buildUpSection.ceilingJoists', + message: 'Ceiling joists', + }, + value: 'joists', + }, + { + label: /* i18n */ { + id: 'node.ceiling.buildUpSection.trussBottomChords', + message: 'Truss bottom chords', + }, + value: 'truss-chords', + }, +] + +const NEW_FRAMING: Record = { + joists: { system: 'joists', size: '2x6', spacing: 16 * INCH }, + 'truss-chords': { system: 'truss-chords', size: '2x4', spacing: 24 * INCH }, +} + +export function CeilingBuildUpSection({ + node, + onUpdate, + unit, +}: { + node: CeilingNode + onUpdate: (patch: Partial) => void + unit: 'metric' | 'imperial' +}) { + const i18n = usePascalI18n() + const buildUp = node.buildUp + const edit = (change: Partial) => { + if (buildUp) onUpdate({ buildUp: editedBuildUp(buildUp, change) }) + } + const framing = buildUp?.framing + + return ( + + { + const patch = ceilingBuildUpPresetPatch(id) + if (patch) onUpdate(patch) + }} + options={ceilingBuildUpPresetOptions(ceilingBuildUpPresetValue(buildUp))} + value={ceilingBuildUpPresetValue(buildUp)} + /> + {buildUp && ( + <> + edit({ finish })} + unit={unit} + /> + + edit({ + framing: + system === NONE + ? undefined + : framing + ? { ...framing, system } + : NEW_FRAMING[system], + }) + } + options={FRAMING_OPTIONS.map((option) => ({ ...option, label: i18n._(option.label) }))} + value={framing?.system ?? NONE} + /> + {framing && ( + edit({ framing: { ...framing, ...change } })} + sizeLabel={ + framing.system === 'joists' + ? i18n._({ id: 'node.ceiling.buildUpSection.joists', message: 'Joists' }) + : i18n._({ + id: 'node.ceiling.buildUpSection.bottomChord', + message: 'Bottom chord', + }) + } + unit={unit} + /> + )} + edit({ decking })} + optional + unit={unit} + /> + edit({ insulation })} + unit={unit} + /> + +
+ {i18n._({ + id: 'node.ceiling.buildUpSection.theHeightIsTheFinishedUnderside', + message: 'The height is the finished underside; the layers rise from it.', + })} +
+ + )} +
+ ) +} diff --git a/packages/nodes/src/ceiling/definition.ts b/packages/nodes/src/ceiling/definition.ts index 0129eb6a22..295912578b 100644 --- a/packages/nodes/src/ceiling/definition.ts +++ b/packages/nodes/src/ceiling/definition.ts @@ -12,6 +12,7 @@ import { DRAFTING_SURFACE_EXTENSION_KEY, type DraftingSurfaceExtension, type FloorplanNodeExtension, + PANEL_MODEL_EXTENSION, publishStructuralElevationGuide, resolveStructuralElevationSnap, } from '@pascal-app/editor' @@ -28,6 +29,7 @@ import { import { ceilingFloorplanMoveTarget } from './floorplan-move' import { CEILING_HANDLE_MIN_HEIGHT, ceilingHeightRange } from './height-bounds' import { ceilingPaint } from './paint' +import { ceilingPanelModel } from './panel-model' import { ceilingParametrics } from './parametrics' import { CeilingNode } from './schema' @@ -139,6 +141,7 @@ export const ceilingDefinition: NodeDefinition = { 'pascal:editor/floorplan': { selectionCounterparts: sameOutlineSurfaceCounterparts, } satisfies FloorplanNodeExtension, + [PANEL_MODEL_EXTENSION]: ceilingPanelModel, }, // Height-less on purpose: a new ceiling follows the level top until the diff --git a/packages/nodes/src/ceiling/materials.ts b/packages/nodes/src/ceiling/materials.ts index 3a2195e295..058058535e 100644 --- a/packages/nodes/src/ceiling/materials.ts +++ b/packages/nodes/src/ceiling/materials.ts @@ -77,6 +77,27 @@ export function getCeilingMaterials( } } +/** + * The upper face, drawn while the viewer shows ceiling tops: the ceiling's colour, facing up, so + * the ceiling reads as solid from above. + */ +export function getCeilingCapMaterial(color: string, shading: RenderShading): Material { + return createMaterial( + { + preset: 'custom', + properties: { + color, + roughness: 0.9, + metalness: 0, + opacity: 1, + transparent: false, + side: 'front', + }, + }, + shading, + ) +} + /** Resolve through the shared caches, without mutating another surface's material. */ export function resolveCeilingFinish( finish: MaterialSchema | string | undefined, diff --git a/packages/nodes/src/ceiling/multi-layers.test.ts b/packages/nodes/src/ceiling/multi-layers.test.ts new file mode 100644 index 0000000000..46527eba91 --- /dev/null +++ b/packages/nodes/src/ceiling/multi-layers.test.ts @@ -0,0 +1,50 @@ +import { afterEach, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + CEILING_BUILD_UP_PRESETS, + CeilingNode, + useScene, +} from '@pascal-app/core' +import { getNodePanelModel, type MultiPanelControl } from '@pascal-app/editor' +import { ceilingDefinition } from './definition' + +globalThis.requestAnimationFrame ??= () => 0 +globalThis.cancelAnimationFrame ??= () => {} + +const originalState = useScene.getState() +afterEach(() => useScene.setState(originalState)) + +type Choice = Extract + +const load = (nodes: AnyNode[]) => { + useScene.setState({ + nodes: Object.fromEntries(nodes.map((n) => [n.id, n])) as Record, + rootNodeIds: [], + }) + useScene.temporal.getState().clear() + useScene.temporal.getState().resume() +} +const current = (nodes: T[]) => + nodes.map((n) => useScene.getState().nodes[n.id as AnyNodeId] as T) + +test('multi-selected ceilings take one layers preset; mixed reads as mixed', () => { + const chosen = CEILING_BUILD_UP_PRESETS[0]! + const ceilings = [ + CeilingNode.parse({ polygon: [] }), + CeilingNode.parse({ polygon: [], buildUp: chosen.buildUp }), + ] + load(ceilings) + const controls = () => + getNodePanelModel(ceilingDefinition)!.multiControls!({ + selection: current(ceilings), + nodes: useScene.getState().nodes, + }) as Choice[] + expect(controls()[0]?.value).toBeNull() + controls()[0]!.onChange(chosen.id) + expect(current(ceilings).map((ceiling) => ceiling.buildUp)).toEqual([ + chosen.buildUp, + chosen.buildUp, + ]) + expect(controls()[0]?.value).toBe(chosen.id) +}) diff --git a/packages/nodes/src/ceiling/panel-model.ts b/packages/nodes/src/ceiling/panel-model.ts new file mode 100644 index 0000000000..f86881ca71 --- /dev/null +++ b/packages/nodes/src/ceiling/panel-model.ts @@ -0,0 +1,63 @@ +import { + type AnyNodeId, + CEILING_BUILD_UP_PRESETS, + type CeilingBuildUp, + type CeilingNode, + runAsSingleSceneHistoryStep, + useScene, +} from '@pascal-app/core' +import type { NodePanelModel } from '@pascal-app/editor' + +const NONE = 'none' +const CUSTOM = 'custom' + +/** The Preset choices for the `current` value: none, the presets, and Custom while it is. */ +export function ceilingBuildUpPresetOptions(current: string | null) { + return [ + { label: 'None (a bare surface)', value: NONE }, + ...(current === CUSTOM ? [{ label: 'Custom', value: CUSTOM }] : []), + ...CEILING_BUILD_UP_PRESETS.map((preset) => ({ label: preset.label, value: preset.id })), + ] +} + +export function ceilingBuildUpPresetValue(buildUp: CeilingBuildUp | undefined): string { + return buildUp ? (buildUp.presetId ?? CUSTOM) : NONE +} + +/** The patch a Preset choice writes; `null` for Custom, which is no choice. */ +export function ceilingBuildUpPresetPatch(id: string): Partial | null { + if (id === NONE) return { buildUp: undefined } + const preset = CEILING_BUILD_UP_PRESETS.find((entry) => entry.id === id) + return preset ? { buildUp: preset.buildUp } : null +} + +/** Multi-selected ceilings take one layers preset together, in one undo step. */ +export const ceilingPanelModel: NodePanelModel = { + rows: () => [], + multiControls: ({ selection }) => { + if (selection.length === 0) return [] + const values = selection.map((ceiling) => ceilingBuildUpPresetValue(ceiling.buildUp)) + const value = values.every((entry) => entry === values[0]) ? values[0]! : null + return [ + { + id: 'ceiling-layers-preset', + kind: 'select', + section: 'Layers', + label: 'Preset', + options: ceilingBuildUpPresetOptions(value), + value, + onChange: (id) => { + const patch = ceilingBuildUpPresetPatch(id) + if (!patch) return + runAsSingleSceneHistoryStep(useScene, () => + useScene + .getState() + .updateNodes( + selection.map((ceiling) => ({ id: ceiling.id as AnyNodeId, data: patch })), + ), + ) + }, + }, + ] + }, +} diff --git a/packages/nodes/src/ceiling/panel.tsx b/packages/nodes/src/ceiling/panel.tsx index 1ee5b20ebd..43fc42d3ae 100644 --- a/packages/nodes/src/ceiling/panel.tsx +++ b/packages/nodes/src/ceiling/panel.tsx @@ -12,7 +12,9 @@ import { ActionButton, ActionGroup, exitCeilingEditToRoom, + formatAreaLabel, formatLinearMeasurement, + getAreaUnitLabel, holeEditScope, PanelSection, PanelWrapper, @@ -20,6 +22,7 @@ import { ShapeChoice, SliderControl, setCeilingHoles, + squareMetersToAreaUnit, startOpeningDraft, triggerSFX, useCeilingEditCeilingId, @@ -31,6 +34,7 @@ import { import { useViewer } from '@pascal-app/viewer' import { Edit, Move, Plus, Trash2 } from 'lucide-react' import { useCallback, useEffect, useRef } from 'react' +import { CeilingBuildUpSection } from './build-up-section' import { CEILING_PANEL_MIN_HEIGHT, ceilingHeightRange, clampCeilingHeight } from './height-bounds' /** @@ -367,10 +371,14 @@ export function CeilingPanel() { )} + +
{i18n._({ id: 'node.ceiling.panel.area', message: 'Area' })} - {area.toFixed(2)} m² + + {formatAreaLabel(area, unit, 2)} +
@@ -416,9 +424,14 @@ export function CeilingPanel() { {i18n._({ id: 'node.holeSummary', message: - '{area} m² · {count, plural, one {{points} pt} other {{points} pts}} · {source}', + '{area} {unit} · {count, plural, one {{points} pt} other {{points} pts}} · {source}', values: { - area: formatFixed(holeArea, 2, i18n.getLocale()), + area: formatFixed( + squareMetersToAreaUnit(holeArea, unit), + 2, + i18n.getLocale(), + ), + unit: getAreaUnitLabel(unit), count: hole.length, points: String(hole.length), source: isAutoHole diff --git a/packages/nodes/src/ceiling/renderer.tsx b/packages/nodes/src/ceiling/renderer.tsx index 44db9bed66..a7476a200d 100644 --- a/packages/nodes/src/ceiling/renderer.tsx +++ b/packages/nodes/src/ceiling/renderer.tsx @@ -13,6 +13,7 @@ import { useScene, } from '@pascal-app/core' import { + CEILING_CAP_MESH, CEILING_REGION_MESH, type CeilingRegionMaterial, createSurfaceRoleMaterial, @@ -23,14 +24,22 @@ import { useViewer, } from '@pascal-app/viewer' import { useCallback, useEffect, useLayoutEffect, useMemo, useRef } from 'react' -import { BackSide, type Mesh } from 'three/webgpu' +import { BackSide, FrontSide, type Mesh } from 'three/webgpu' import { createPlaceholderGeometry } from '../shared/placeholder-geometry' -import { ceilingColorFromRef, getCeilingMaterials, resolveCeilingFinish } from './materials' +import { + ceilingColorFromRef, + getCeilingCapMaterial, + getCeilingMaterials, + resolveCeilingFinish, +} from './materials' function createEmptyGeometry() { return createPlaceholderGeometry() } +// The cap is only seen: a click from above still reaches what it reached without it. +const noopRaycast = () => {} + export const CeilingRenderer = ({ node }: { node: CeilingNode }) => { const ref = useRef(null!) const handlers = useNodeEvents(node, 'ceiling') @@ -52,6 +61,7 @@ export const CeilingRenderer = ({ node }: { node: CeilingNode }) => { const libraryMaterialsVersion = useLibraryMaterialsVersion() const colorPreset = useViewer((s) => s.colorPreset) const sceneTheme = useViewer((s) => s.sceneTheme) + const showTop = useViewer((s) => s.showCeilingTops) // Subscribe to the scene-material library so editing a `scene:` material the // ceiling slot references re-tints it live. const sceneMaterials = useScene((s) => s.materials) @@ -85,11 +95,13 @@ export const CeilingRenderer = ({ node }: { node: CeilingNode }) => { // revealed (placing a ceiling-hosted item, or selecting one of its // children). Without that the top mesh would ship an opaque surface-role // material and a top-down camera would lose everything under the ceiling. + // The opaque top is the cap's, drawn only while the viewer shows ceiling tops. if (!textures) { const ceilingColor = resolveSurfaceColor('ceiling', colorPreset, sceneTheme) return { topMaterial: getCeilingMaterials(ceilingColor).topMaterial, bottomMaterial: createSurfaceRoleMaterial('ceiling', colorPreset, BackSide, sceneTheme), + capMaterial: createSurfaceRoleMaterial('ceiling', colorPreset, FrontSide, sceneTheme), } } @@ -102,6 +114,7 @@ export const CeilingRenderer = ({ node }: { node: CeilingNode }) => { const fallback = getCeilingMaterials(gridColor, shading) return { topMaterial: fallback.topMaterial, + capMaterial: getCeilingCapMaterial(gridColor, shading), bottomMaterial: resolveCeilingFinish(node.slots?.surface, sceneMaterials, shading) ?? resolveCeilingFinish(node.materialPreset, sceneMaterials, shading) ?? @@ -171,6 +184,14 @@ export const CeilingRenderer = ({ node }: { node: CeilingNode }) => { scale={0} visible={false} /> + {(node.children ?? []).map((childId) => ( ))} diff --git a/packages/nodes/src/ceiling/tool.test.ts b/packages/nodes/src/ceiling/tool.test.ts new file mode 100644 index 0000000000..4dbe7261e7 --- /dev/null +++ b/packages/nodes/src/ceiling/tool.test.ts @@ -0,0 +1,162 @@ +import { afterEach, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + BuildingNode, + clearSceneHistory, + emitter, + type GridEvent, + LevelNode, + useScene, +} from '@pascal-app/core' +import { sceneLayout, useEditor } from '@pascal-app/editor' +import { useViewer } from '@pascal-app/viewer' +import { act, create } from '@react-three/test-renderer' +import { createElement } from 'react' +import { CeilingTool } from './tool' + +type RafFn = (cb: (time: number) => void) => number +;(globalThis as unknown as { requestAnimationFrame?: RafFn }).requestAnimationFrame ??= (cb) => { + cb(0) + return 0 +} +;(globalThis as unknown as { cancelAnimationFrame?: (id: number) => void }).cancelAnimationFrame ??= + () => {} +;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true + +const previous = { editor: useEditor.getState(), viewer: useViewer.getState() } + +afterEach(() => { + useEditor.setState(previous.editor, true) + useViewer.setState(previous.viewer, true) +}) + +const ceilings = () => Object.values(useScene.getState().nodes).filter((n) => n.type === 'ceiling') + +const click = (x: number, z: number) => + act(async () => { + const event = { + position: [x, 0, z], + localPosition: [x, 0, z], + nativeEvent: {} as GridEvent['nativeEvent'], + } satisfies GridEvent + emitter.emit('grid:move', event) + emitter.emit('grid:click', event) + }) + +async function drawSquare() { + for (const [x, z] of [ + [0, 0], + [4, 0], + [4, 4], + [0, 4], + [0, 0], + ] as const) + await click(x, z) +} + +function seedLevel() { + const building = BuildingNode.parse({}) + const level = LevelNode.parse({ parentId: building.id, level: 0, height: 3 }) + building.children = [level.id] + useScene + .getState() + .setScene( + { [building.id]: building, [level.id]: level } as Record, + [building.id as AnyNodeId], + { installedPlugins: [], hasExplicitPluginInstallState: false }, + ) + clearSceneHistory() + useViewer.getState().setSelection({ buildingId: building.id, levelId: level.id }) +} + +const showScene = (scene: '2d' | '3d' | 'split') => + act(async () => useEditor.setState({ viewLayouts: { edit: sceneLayout(scene) } })) + +// The 3D tool stays mounted behind the hidden canvas once 3D has been shown, and hears the plan's +// clicks; in 2D-only view the plan commits the ceiling too, so each one was made twice. +test('the 3D ceiling tool leaves a 2D-only plan its clicks, and commits beside a plan', async () => { + seedLevel() + useEditor.setState({ + mode: 'build', + tool: null, + workspaceMode: 'edit', + viewLayouts: { edit: sceneLayout('2d') }, + }) + const renderer = await create(createElement(CeilingTool)) + try { + await drawSquare() + expect(ceilings()).toHaveLength(0) + + await showScene('split') + await drawSquare() + expect(ceilings()).toHaveLength(1) + } finally { + await act(async () => renderer.unmount()) + } +}) + +// The plan finishes a ceiling begun beside it once the view goes 2D-only; corners the 3D tool kept +// would start the next ceiling drawn back in split view, which then never closed. +test('a ceiling begun in split view and finished on the 2D-only plan leaves no corners behind', async () => { + seedLevel() + useEditor.setState({ + mode: 'build', + tool: null, + workspaceMode: 'edit', + viewLayouts: { edit: sceneLayout('split') }, + }) + const renderer = await create(createElement(CeilingTool)) + try { + await click(10, 10) + await click(14, 10) + await showScene('2d') + for (const [x, z] of [ + [14, 14], + [10, 14], + [10, 10], + ] as const) + await click(x, z) + await showScene('split') + await drawSquare() + expect(ceilings().map((ceiling) => ceiling.polygon)).toEqual([ + [ + [0, 0], + [4, 0], + [4, 4], + [0, 4], + ], + ]) + } finally { + await act(async () => renderer.unmount()) + } +}) + +// The plan starts its own copy of the draft empty whenever it appears, so corners this tool kept +// from 3D-only view closed a different polygon than the one the plan beside it showed. +test('a ceiling drawn beside the plan starts from the corners the plan shows', async () => { + seedLevel() + useEditor.setState({ + mode: 'build', + tool: null, + workspaceMode: 'edit', + viewLayouts: { edit: sceneLayout('3d') }, + }) + const renderer = await create(createElement(CeilingTool)) + try { + await click(10, 10) + await click(14, 10) + await showScene('split') + await drawSquare() + expect(ceilings().map((ceiling) => ceiling.polygon)).toEqual([ + [ + [0, 0], + [4, 0], + [4, 4], + [0, 4], + ], + ]) + } finally { + await act(async () => renderer.unmount()) + } +}) diff --git a/packages/nodes/src/ceiling/tool.tsx b/packages/nodes/src/ceiling/tool.tsx index df6f85e562..999907b230 100644 --- a/packages/nodes/src/ceiling/tool.tsx +++ b/packages/nodes/src/ceiling/tool.tsx @@ -20,6 +20,7 @@ import { triggerSFX, useEditor, useFloorplanDraftPreview, + visibleScene, } from '@pascal-app/editor' import { useViewer } from '@pascal-app/viewer' import { useEffect, useMemo, useRef, useState } from 'react' @@ -94,6 +95,21 @@ export const CeilingTool: React.FC = () => { [], ) + // The plan keeps its own copy of the corners, started empty on every view change, and finishes a + // polygon in 2D-only view without this tool. Corners kept here once the plan shows (from split + // or 3D-only view) would close a different polygon than the one the plan draws. + useEffect(() => { + let shownScene = visibleScene(useEditor.getState()) + return useEditor.subscribe((state) => { + const nextScene = visibleScene(state) + if (nextScene === shownScene) return + shownScene = nextScene + if (nextScene === '3d') return + setPoints([]) + clearCeilingSnapFeedback() + }) + }, []) + const verticalGeo = useMemo( () => new BufferGeometry().setFromPoints([ @@ -111,8 +127,13 @@ export const CeilingTool: React.FC = () => { useEffect(() => { if (!currentLevelId) return + // In 2D-only view the plan drafts and commits the ceiling; this tool, mounted behind the + // hidden canvas from an earlier visit, still hears the plan's grid events, so it stands aside + // (it made every ceiling twice). + const planOwnsInput = () => visibleScene(useEditor.getState()) === '2d' + const onGridMove = (event: GridEvent) => { - if (!(cursorRef.current && gridCursorRef.current)) return + if (!(cursorRef.current && gridCursorRef.current) || planOwnsInput()) return const rawPoint: [number, number] = [event.localPosition[0], event.localPosition[2]] // Honour the active snapping mode: grid lattice + 15° angle lock are each // gated on the mode (off / lines → free), like the slab tool. @@ -151,7 +172,7 @@ export const CeilingTool: React.FC = () => { } const onGridClick = (_event: GridEvent) => { - if (!currentLevelId) return + if (!currentLevelId || planOwnsInput()) return const clickPoint = previousSnappedPointRef.current ?? cursorPosition const firstPoint = points[0] if ( @@ -173,7 +194,7 @@ export const CeilingTool: React.FC = () => { } const onGridDoubleClick = (_event: GridEvent) => { - if (!currentLevelId) return + if (!currentLevelId || planOwnsInput()) return if (points.length >= 3) { const ceilingId = commitCeilingDrawing(currentLevelId, points) setSelection({ selectedIds: [ceilingId] }) diff --git a/packages/nodes/src/column/definition.ts b/packages/nodes/src/column/definition.ts index a24e8d0148..dd2cd6cf22 100644 --- a/packages/nodes/src/column/definition.ts +++ b/packages/nodes/src/column/definition.ts @@ -20,6 +20,7 @@ import { columnFloorplanMoveTarget } from './floorplan-move' import { columnHostedPolicy } from './hosted-resize' import { columnPaint } from './paint' import { columnParametrics } from './parametrics' +import { columnPlaceOption, postBaseOption } from './post-options' import { ColumnNode } from './schema' import { columnSurfaceProvider } from './surface' @@ -439,6 +440,8 @@ export const columnDefinition: NodeDefinition = { // bare sphere the legacy editor-side `ColumnTool` showed. `ToolManager`'s // registry-first path mounts this and skips the legacy ``. tool: () => import('./tool'), + // One family with the Post tool: a column, or a framing post that stands up to the beam over it. + toolOptions: [columnPlaceOption, postBaseOption], toolHints: [ { key: 'Left click', label: 'Place column' }, { key: 'Esc', label: 'Cancel' }, diff --git a/packages/nodes/src/column/floorplan.ts b/packages/nodes/src/column/floorplan.ts index 548ebc97b2..8332975d88 100644 --- a/packages/nodes/src/column/floorplan.ts +++ b/packages/nodes/src/column/floorplan.ts @@ -146,6 +146,28 @@ export function buildColumnFloorplan( metadata: floorplanGeometryMetadata({ annotationRole: 'column-center' }), }, ) + // A framing post reads as a framing plan draws one: its own square (not its base's) crossed + // corner to corner. + if (node.role === 'post') { + const square = getRotatedRectanglePolygon( + { x: centerX, y: centerZ }, + node.width, + node.depth, + -node.rotation, + ) + for (const [a, b] of [[square[0]!, square[2]!] as const, [square[1]!, square[3]!] as const]) + children.push({ + kind: 'line', + x1: a.x, + y1: a.y, + x2: b.x, + y2: b.y, + stroke, + strokeWidth: 0.9, + vectorEffect: 'non-scaling-stroke', + pointerEvents: 'none', + }) + } const levelData = ctx.levelData as ColumnFloorplanLevelData | undefined const gridReference = resolveStructuralGridReference( diff --git a/packages/nodes/src/column/panel.tsx b/packages/nodes/src/column/panel.tsx index 39007a0bf3..62248ce401 100644 --- a/packages/nodes/src/column/panel.tsx +++ b/packages/nodes/src/column/panel.tsx @@ -27,6 +27,7 @@ import { useCallback } from 'react' import { AuthoredParams } from '../item/authored-params' import { planColumnEdit } from './hosted-resize' +import { FramingPostSection } from './post-section' const SELECT_CLASS = 'h-10 w-full rounded-lg border border-border/50 bg-black/4 dark:bg-[#2C2C2E] px-3 text-sm text-foreground outline-none transition-colors hover:bg-black/8 dark:hover:bg-[#3e3e3e] focus:ring-1 focus:ring-border' @@ -404,7 +405,10 @@ export default function ColumnPanel() { title={node.name || i18n._({ id: 'node.column.panel.column', message: 'Column' })} width={300} > - {node.source ? ( + {/* A framing post is a sawn post, not a styled column: its own short section. */} + {node.role === 'post' ? ( + + ) : node.source ? ( ) : ( <> diff --git a/packages/nodes/src/column/post-options.ts b/packages/nodes/src/column/post-options.ts new file mode 100644 index 0000000000..d3773ca7ad --- /dev/null +++ b/packages/nodes/src/column/post-options.ts @@ -0,0 +1,84 @@ +import { + type ColumnPostBase, + FRAMING_POST_BASE_LABELS, + type FramingPostSize, + type ToolOption, +} from '@pascal-app/core' +import { useEditor } from '@pascal-app/editor' +import { + armFramingPostTool, + dropInflightColumnPlacement, + framingPostToolChoices, +} from './post-placement' + +const subscribe = (onChange: () => void) => useEditor.subscribe(() => onChange()) + +/** The Post tool's size, or null while the column tool places ornamental columns. */ +const postChoices = () => framingPostToolChoices(useEditor.getState().toolDefaults.column) + +/** + * "Place" for the column tool, one family with the Post tool: a column of the chosen style, or a + * pressure-treated framing post of a size, which stands up to the beam over it. Picking across + * the family switches what the tool places. + */ +export const columnPlaceOption: ToolOption = { + id: 'column-place', + label: 'Place', + choices: [ + { + value: 'column', + label: 'Column', + description: 'A column of a chosen style: round, square or tapered, or a support frame', + }, + { + value: '4x4', + label: '4x4 post', + description: 'A treated 4x4 framing post, for a light porch or a deck post up to 8 ft', + }, + { + value: '6x6', + label: '6x6 post', + description: 'A treated 6x6 framing post: the post under a porch or a deck beam', + }, + { + value: '8x8', + label: '8x8 post', + description: 'A treated 8x8 framing post, for a tall post or a heavy load', + }, + ], + subscribe, + value: () => postChoices()?.size ?? 'column', + set: (value) => { + if (value !== 'column') { + armFramingPostTool(value as FramingPostSize) + return + } + // Already placing columns (perhaps a preset following the cursor): nothing to switch. + if (postChoices() === null) return + dropInflightColumnPlacement() + const editor = useEditor.getState() + editor.setToolDefaults('column', null) + if (!(editor.mode === 'build' && editor.tool === 'column')) + editor.armToolMode({ mode: 'build', tool: 'column' }) + }, +} + +/** What a framing post stands on, shown while the tool places posts. */ +export const postBaseOption: ToolOption = { + id: 'post-base', + label: 'Base', + choices: (['none', 'post-base', 'pier'] as const).map((base) => ({ + value: base, + label: FRAMING_POST_BASE_LABELS[base], + description: + base === 'none' + ? 'Straight on the floor or the footing under it' + : base === 'post-base' + ? 'A steel post base holding the wood off the concrete' + : 'A concrete pier 8 in tall under the post', + })), + subscribe, + value: () => postChoices()?.base ?? 'none', + set: (value) => armFramingPostTool(undefined, value as ColumnPostBase), + visible: { subscribe, value: () => postChoices() !== null }, +} diff --git a/packages/nodes/src/column/post-placement.ts b/packages/nodes/src/column/post-placement.ts new file mode 100644 index 0000000000..3f0b4ab261 --- /dev/null +++ b/packages/nodes/src/column/post-placement.ts @@ -0,0 +1,236 @@ +import { + type AnyNode, + type AnyNodeId, + type BeamNode, + beamBottomElevation, + type ColumnNode, + type ColumnPostBase, + createFramingPost, + DEFAULT_FRAMING_POST_SIZE, + emitter, + FRAMING_POST_SIZES, + type FramingPostSize, + framingPostFields, + framingPostSize, + framingPostTopAt, + getFloorPlacedElevation, + postStationsAlong, + type WallNode, +} from '@pascal-app/core' +import { + getMovingNode, + isGridSnapActive, + snapBuildingLocalToWorldGrid, + snapWallDraftPointDetailed, + useEditor, + type WallDraftSnapKind, + type WallPlanPoint, +} from '@pascal-app/editor' + +type Nodes = Readonly> + +/** Posts no further apart than this under a beam the panel posts: 8 ft, as a porch's are. */ +export const FRAMING_POST_SPACING = 8 * 12 * 0.0254 + +/** The post choices the Post tool draws with, kept on the column tool's defaults. */ +export type FramingPostToolChoices = { size: FramingPostSize; base: ColumnPostBase } + +/** + * The Post tool is the column tool armed with a framing post's fields (`toolDefaults.column`, + * `role: 'post'`): its size and base, or null while it places ornamental columns. + */ +export function framingPostToolChoices( + defaults: Readonly> | null | undefined, +): FramingPostToolChoices | null { + if (defaults?.role !== 'post') return null + const width = typeof defaults.width === 'number' ? defaults.width : undefined + const size = + (width !== undefined && framingPostSize({ width, depth: width })) || DEFAULT_FRAMING_POST_SIZE + const base = defaults.postBase + return { + size, + base: base === 'post-base' || base === 'pier' ? base : 'none', + } +} + +/** The column tool's defaults that make it the Post tool: a post of this size and base. */ +export function framingPostToolDefaults( + size: FramingPostSize = DEFAULT_FRAMING_POST_SIZE, + base: ColumnPostBase = 'none', +): Record { + return { ...framingPostFields(size, base) } +} + +/** + * Drops a preset still following the cursor (a column preset's clone on the move tool): while it + * moves, no build tool mounts. + */ +export function dropInflightColumnPlacement(): void { + if (!getMovingNode()) return + emitter.emit('tool:cancel') + useEditor.getState().setMovingNode(null) +} + +/** + * The size and base last picked, kept apart from the tool's defaults: a host clears those when it + * arms the column tool from a tile, and the Post tile should come back as the user left it. + */ +let lastChoices: FramingPostToolChoices = { size: DEFAULT_FRAMING_POST_SIZE, base: 'none' } + +/** + * Arms the column tool as the Post tool (the Build panel's Post tile): a post of `size` on `base`, + * else as the tool has them, else as they were last picked. + */ +export function armFramingPostTool(size?: FramingPostSize, base?: ColumnPostBase): void { + dropInflightColumnPlacement() + const editor = useEditor.getState() + const current = framingPostToolChoices(editor.toolDefaults.column) ?? lastChoices + lastChoices = { size: size ?? current.size, base: base ?? current.base } + editor.setToolDefaults('column', framingPostToolDefaults(lastChoices.size, lastChoices.base)) + if (!(editor.mode === 'build' && editor.tool === 'column')) + editor.armToolMode({ mode: 'build', tool: 'column' }) +} + +/** A point the wall snap reads as a wall: a segment of no length catches at the point. */ +function pointReference(id: string, parentId: string | null, at: WallPlanPoint): WallNode { + return { + object: 'node', + id: id as WallNode['id'], + type: 'wall', + parentId, + visible: true, + metadata: {}, + children: [], + start: at, + end: at, + frontSide: 'unknown', + backSide: 'unknown', + } +} + +/** + * What a post set on `levelId` snaps to: each beam's centreline (its ends, its middle and its run, + * so a post lands under a beam end or anywhere along it) and the other posts' and columns' + * centres. + */ +export function postSnapTargets( + nodes: Nodes, + levelId: string, + ignoreIds: readonly string[] = [], +): WallNode[] { + const targets: WallNode[] = [] + for (const node of Object.values(nodes)) { + if (node.parentId !== levelId || node.visible === false || ignoreIds.includes(node.id)) continue + if (node.type === 'beam') { + targets.push({ ...pointReference(node.id, node.parentId, node.start), end: node.end }) + } else if (node.type === 'column') { + targets.push(pointReference(node.id, node.parentId, [node.position[0], node.position[2]])) + } + } + return targets +} + +/** + * A post's plan point, snapped: a beam end, a point along a beam or another post catch it within + * the snap's reach, otherwise the grid while it snaps. `free` (Alt) places it as it is. + */ +export function snapPostPoint(args: { + point: WallPlanPoint + nodes: Nodes + levelId: string + ignoreIds?: readonly string[] + free?: boolean +}): { point: WallPlanPoint; snap: WallDraftSnapKind | null } { + if (args.free) return { point: args.point, snap: null } + const step = useEditor.getState().gridSnapStep + const grid = isGridSnapActive() + const result = snapWallDraftPointDetailed({ + point: args.point, + walls: postSnapTargets(args.nodes, args.levelId, args.ignoreIds), + // Beams and posts always catch a post; the grid is the snapping mode's to give. + magnetic: true, + gridSnap: (point) => (grid ? snapBuildingLocalToWorldGrid(point, step) : point), + }) + return { point: result.point, snap: result.snap } +} + +/** What a framing post stands on at a point: the support the floor stacking elects under it. */ +export type PostFoot = (post: ColumnNode) => number + +/** The runtime foot: the elected support's top under the post, plus its own lift. */ +export const electedPostFoot = + (nodes: Nodes, levelId: string): PostFoot => + (post) => + getFloorPlacedElevation({ + node: post as AnyNode, + nodes: nodes as Record, + position: post.position, + levelId, + }) + post.position[1] + +/** + * A framing post at a plan point, standing from its foot up to the underside of the beam over it, + * else to the ceiling plane: what the Post tool places, and its ghost. + */ +export function framingPostAt(args: { + nodes: Nodes + levelId: string + point: WallPlanPoint + choices: FramingPostToolChoices + foot: PostFoot +}): { post: ColumnNode; beamId: string | null } { + const draft = createFramingPost({ + position: args.point, + size: args.choices.size, + base: args.choices.base, + levelId: args.levelId, + }) + const base = args.foot(draft) + const { top, beamId } = framingPostTopAt(args.nodes, args.levelId, args.point, { + baseElevation: base, + side: FRAMING_POST_SIZES[args.choices.size], + }) + return { + post: createFramingPost({ + position: args.point, + size: args.choices.size, + base: args.choices.base, + levelId: args.levelId, + height: top - base, + }), + beamId, + } +} + +/** + * Posts under a beam: one at each end and evenly between, no further apart than `spacing`, each + * from its foot up to this beam's underside. Skips a station a post already stands at. + */ +export function framingPostsUnderBeam(args: { + nodes: Nodes + beam: BeamNode + choices: FramingPostToolChoices + foot: PostFoot + spacing?: number +}): ColumnNode[] { + const levelId = args.beam.parentId + if (!levelId) return [] + const standing = Object.values(args.nodes).filter( + (node): node is ColumnNode => node.type === 'column' && node.parentId === levelId, + ) + const underside = beamBottomElevation(args.nodes, args.beam) + return postStationsAlong(args.beam.start, args.beam.end, args.spacing ?? FRAMING_POST_SPACING) + .filter( + (point) => + !standing.some( + (post) => + Math.hypot(post.position[0] - point[0], post.position[2] - point[1]) < + Math.max(post.width, FRAMING_POST_SIZES[args.choices.size]), + ), + ) + .map((point) => { + const fields = { position: point, ...args.choices, levelId } + const foot = args.foot(createFramingPost(fields)) + return createFramingPost({ ...fields, height: underside - foot }) + }) +} diff --git a/packages/nodes/src/column/post-section.tsx b/packages/nodes/src/column/post-section.tsx new file mode 100644 index 0000000000..ec34f3c0ab --- /dev/null +++ b/packages/nodes/src/column/post-section.tsx @@ -0,0 +1,193 @@ +'use client' + +import { + type AnyNode, + type AnyNodeId, + type ColumnNode, + type ColumnPostBase, + FRAMING_POST_BASE_LABELS, + FRAMING_POST_MATERIAL_REF, + FRAMING_POST_SIZES, + type FramingPostSize, + framingPostBasePatch, + framingPostHeightLimit, + framingPostSize, + framingPostTopAt, + usePascalI18n, + useScene, +} from '@pascal-app/core' +import { + formatLinearMeasurement, + MetricControl, + PanelSection, + SegmentedControl, +} from '@pascal-app/editor' +import { useViewer } from '@pascal-app/viewer' +import { electedPostFoot } from './post-placement' + +/** Sawn lumber for a post kept dry inside; a post's default is treated (`FRAMING_POST_MATERIAL_REF`). */ +const UNTREATED_REF = 'library:wood-woodfine2' +const CUSTOM = 'custom' + +/** The fields that make a post another square size, its base kept in proportion. */ +export function framingPostSizePatch(post: ColumnNode, size: FramingPostSize): Partial { + const side = FRAMING_POST_SIZES[size] + return { + width: side, + depth: side, + radius: side / 2, + ...framingPostBasePatch( + { width: side, depth: side, slots: post.slots }, + post.postBase ?? 'none', + ), + } +} + +/** Where a post's top goes: the beam over it, else the ceiling plane, and its height to it from its foot. */ +export function framingPostFit( + nodes: Record, + post: ColumnNode, + foot: number, +): { height: number; beamId: string | null } | null { + if (!post.parentId) return null + const { top, beamId } = framingPostTopAt( + nodes, + post.parentId, + [post.position[0], post.position[2]], + { baseElevation: foot, side: post.width }, + ) + return { height: top - foot, beamId } +} + +/** + * A framing post's settings in the column panel, in place of a column's styles: its size, its + * base, its wood, its height with a fit to the beam over it, and the deck-post height check. + */ +export function FramingPostSection({ + node, + onUpdate, +}: { + node: ColumnNode + onUpdate: (updates: Partial) => void +}) { + const i18n = usePascalI18n() + const unit = useViewer((state) => state.unit) + const metricNotation = useViewer((state) => state.metricNotation) + const nodes = useScene((state) => state.nodes) + const size = framingPostSize(node) ?? CUSTOM + const treated = (node.slots?.shaft ?? FRAMING_POST_MATERIAL_REF) === FRAMING_POST_MATERIAL_REF + const limit = framingPostHeightLimit(node) + const length = (meters: number) => formatLinearMeasurement(meters, unit, metricNotation) + const fit = + node.parentId !== null + ? framingPostFit(nodes, node, electedPostFoot(nodes, node.parentId)(node)) + : null + const fitBeam = fit?.beamId ? nodes[fit.beamId as AnyNodeId] : undefined + + return ( + + { + if (next !== CUSTOM) onUpdate(framingPostSizePatch(node, next as FramingPostSize)) + }} + options={[ + ...(Object.keys(FRAMING_POST_SIZES) as FramingPostSize[]).map((value) => ({ + label: value, + value, + })), + ...(size === CUSTOM + ? [ + { + label: i18n._({ id: 'node.column.postSection.custom', message: 'Custom' }), + value: CUSTOM, + }, + ] + : []), + ]} + value={size} + /> + onUpdate(framingPostBasePatch(node, base))} + options={(['none', 'post-base', 'pier'] as const).map((value) => ({ + label: FRAMING_POST_BASE_LABELS[value], + value, + }))} + value={node.postBase ?? 'none'} + /> + + onUpdate({ + slots: { + ...node.slots, + shaft: wood === 'treated' ? FRAMING_POST_MATERIAL_REF : UNTREATED_REF, + }, + }) + } + options={[ + { + label: i18n._({ id: 'node.column.postSection.treated', message: 'Treated' }), + value: 'treated', + }, + { + label: i18n._({ id: 'node.column.postSection.untreated', message: 'Untreated' }), + value: 'untreated', + }, + ]} + value={treated ? 'treated' : 'untreated'} + /> + onUpdate({ height })} + precision={3} + step={0.01} + unit="m" + value={node.height} + /> + {fit && Math.abs(fit.height - node.height) > 0.001 && fit.height > 0.3 && ( + + )} + {limit && ( +

+ {i18n._({ + id: 'node.column.postSection.aSizeDeckPostStandsNo', + message: + 'A {size} deck post stands no taller than {limit} (IRC Table R507.4, by species and the area it carries): check it, or use the next size up.', + values: { size: limit.size, limit: length(limit.limit) }, + })} +

+ )} + +
+ ) +} diff --git a/packages/nodes/src/column/post-tool.tsx b/packages/nodes/src/column/post-tool.tsx new file mode 100644 index 0000000000..ca9f008222 --- /dev/null +++ b/packages/nodes/src/column/post-tool.tsx @@ -0,0 +1,135 @@ +'use client' + +import { + type AnyNodeId, + type ColumnNode, + ColumnNode as ColumnNodeSchema, + emitter, + type GridEvent, + resolveSupportSlabPatch, + useScene, +} from '@pascal-app/core' +import { + getFloorStackPreviewPosition, + triggerSFX, + useEditor, + usePlacementPreview, + useWallSnapIndicator, + type WallPlanPoint, +} from '@pascal-app/editor' +import { useViewer } from '@pascal-app/viewer' +import { useEffect, useRef, useState } from 'react' +import type { Group } from 'three' +import { + type FloorPlacementClickTriggerEvent, + stopPlacementCommitPropagation, + subscribeFloorPlacementClicks, +} from '../shared/floor-placement' +import { + electedPostFoot, + type FramingPostToolChoices, + framingPostAt, + snapPostPoint, +} from './post-placement' +import { ColumnPreview } from './renderer' + +type Placed = { point: WallPlanPoint; post: ColumnNode; beamId: string | null } + +/** + * The Post tool: the column tool armed with a framing post (`framingPostToolChoices`). The post + * snaps under a beam's end, anywhere along a beam, onto another post, else to the grid (Alt free); + * it stands from what it lands on up to the underside of the beam over it, else to the ceiling + * plane, and the ghost shows that height before the click. Repeats as the column tool does. + */ +export function FramingPostTool({ choices }: { choices: FramingPostToolChoices }) { + const levelId = useViewer((state) => state.selection.levelId) + const cursorRef = useRef(null) + const [ghost, setGhost] = useState(null) + + useEffect(() => { + if (!levelId) return + let last: Placed | null = null + setGhost(null) + + const place = (raw: WallPlanPoint, free: boolean): Placed => { + const nodes = useScene.getState().nodes + const { point, snap } = snapPostPoint({ point: raw, nodes, levelId, free }) + if (snap) useWallSnapIndicator.getState().set({ x: point[0], z: point[1], kind: snap }) + else useWallSnapIndicator.getState().clear() + return { + point, + ...framingPostAt({ nodes, levelId, point, choices, foot: electedPostFoot(nodes, levelId) }), + } + } + const show = (placed: Placed) => { + const visual = getFloorStackPreviewPosition({ + node: placed.post, + position: placed.post.position, + rotation: 0, + levelId, + }) + cursorRef.current?.position.set(...visual) + usePlacementPreview.getState().set(placed.post) + setGhost(placed.post) + } + + const onMove = (event: GridEvent) => { + const next = place( + [event.localPosition[0], event.localPosition[2]], + event.nativeEvent?.altKey === true, + ) + if ( + last && + last.point[0] === next.point[0] && + last.point[1] === next.point[1] && + Math.abs(last.post.height - next.post.height) < 1e-6 + ) + return + if (!last || last.point[0] !== next.point[0] || last.point[1] !== next.point[1]) + triggerSFX('sfx:grid-snap') + last = next + show(next) + } + + const onClick = (event: FloorPlacementClickTriggerEvent) => { + // A click on a beam or a post is a node event, its point not the level's: use the move's. + const placed = + last ?? + place([event.localPosition[0], event.localPosition[2]], event.nativeEvent?.altKey === true) + stopPlacementCommitPropagation(event) + const nodes = useScene.getState().nodes + const posts = Object.values(nodes).filter( + (node) => node.type === 'column' && node.role === 'post', + ).length + const post = ColumnNodeSchema.parse({ + ...placed.post, + name: `Post ${posts + 1}`, + ...resolveSupportSlabPatch(placed.post, { ...nodes, [placed.post.id]: placed.post }), + }) + useScene.getState().createNode(post, levelId as AnyNodeId) + triggerSFX('sfx:structure-build') + last = null + if (useEditor.getState().getContinuation('point') === 'repeat') return + useViewer.getState().setSelection({ selectedIds: [post.id] }) + usePlacementPreview.getState().clear() + useEditor.getState().setTool(null) + useEditor.getState().setMode('select') + } + + emitter.on('grid:move', onMove) + const unsubscribeClicks = subscribeFloorPlacementClicks(onClick) + return () => { + emitter.off('grid:move', onMove) + unsubscribeClicks() + usePlacementPreview.getState().clear() + useWallSnapIndicator.getState().clear() + } + }, [levelId, choices]) + + if (!levelId) return null + return ( + + {ghost && } + + ) +} diff --git a/packages/nodes/src/column/post.test.ts b/packages/nodes/src/column/post.test.ts new file mode 100644 index 0000000000..3317883303 --- /dev/null +++ b/packages/nodes/src/column/post.test.ts @@ -0,0 +1,201 @@ +import { afterEach, describe, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + BeamNode, + BuildingNode, + ColumnNode, + createFramingPost, + type FloorplanGeometry, + type GeometryContext, + LevelNode, +} from '@pascal-app/core' +import { useEditor } from '@pascal-app/editor' +import { buildColumnFloorplan } from './floorplan' +import { columnPlaceOption, postBaseOption } from './post-options' +import { + armFramingPostTool, + framingPostAt, + framingPostsUnderBeam, + framingPostToolChoices, + framingPostToolDefaults, + postSnapTargets, + snapPostPoint, +} from './post-placement' +import { framingPostFit, framingPostSizePatch } from './post-section' + +const IN = 0.0254 +type Nodes = Record +const previous = useEditor.getState() + +afterEach(() => { + useEditor.setState(previous, true) +}) + +/** A header 6x8 over a porch's front, 8 ft of it, its top at the 2.7 m plane. */ +const HEADER = BeamNode.parse({ + id: 'beam_h', + parentId: 'level_g', + start: [0, 0], + end: [4.8768, 0], + width: 5.5 * IN, + depth: 7.5 * IN, +}) + +function storey(extra: AnyNode[] = []): Nodes { + return Object.fromEntries( + [ + BuildingNode.parse({ id: 'building_a', children: ['level_g'] }), + LevelNode.parse({ + id: 'level_g', + parentId: 'building_a', + level: 0, + height: 2.7, + children: [HEADER.id, ...extra.map((node) => node.id)], + }), + HEADER, + ...extra, + ].map((node) => [node.id, node]), + ) as Nodes +} + +/** Every post stands on the floor plane here: what the floor stacking elects in the editor. */ +const onFloor = (post: ColumnNode) => post.position[1] + +describe('the Post tool', () => { + test('is the column tool armed with a framing post, at the size and base picked', () => { + expect(framingPostToolChoices(null)).toBeNull() + expect(framingPostToolChoices({ thickness: 1 })).toBeNull() + expect(framingPostToolChoices(framingPostToolDefaults('8x8', 'pier'))).toEqual({ + size: '8x8', + base: 'pier', + }) + armFramingPostTool('4x4') + const editor = useEditor.getState() + expect(editor).toMatchObject({ mode: 'build', tool: 'column' }) + expect(framingPostToolChoices(editor.toolDefaults.column)).toEqual({ + size: '4x4', + base: 'none', + }) + // the base row keeps the size; the place row reads both + postBaseOption.set('post-base') + expect(framingPostToolChoices(useEditor.getState().toolDefaults.column)).toEqual({ + size: '4x4', + base: 'post-base', + }) + expect(columnPlaceOption.value()).toBe('4x4') + expect(postBaseOption.visible!.value()).toBe(true) + // back to columns: the ornamental column tool, the base row hidden + columnPlaceOption.set('column') + expect(useEditor.getState().toolDefaults.column).toBeUndefined() + expect(columnPlaceOption.value()).toBe('column') + expect(postBaseOption.visible!.value()).toBe(false) + // the tile comes back as it was left + armFramingPostTool() + expect(framingPostToolChoices(useEditor.getState().toolDefaults.column)).toEqual({ + size: '4x4', + base: 'post-base', + }) + }) + + test("snaps under a beam's end, along a beam, and onto another post", () => { + const post = createFramingPost({ position: [2, 3], levelId: 'level_g' }) + const nodes = storey([post]) + expect( + postSnapTargets(nodes, 'level_g') + .map((target) => target.id) + .sort(), + ).toEqual([HEADER.id, post.id].sort()) + const at = (point: [number, number]) => + snapPostPoint({ point, nodes, levelId: 'level_g' }).point + expect(at([4.83, 0.05])).toEqual([4.8768, 0]) + const along = at([1.3, 0.08]) + expect(along[0]).toBeCloseTo(1.3) + expect(along[1]).toBeCloseTo(0) + expect(at([2.04, 2.97])).toEqual([2, 3]) + expect(snapPostPoint({ point: [1.3, 0.08], nodes, levelId: 'level_g', free: true })).toEqual({ + point: [1.3, 0.08], + snap: null, + }) + }) + + test('a post stands up to the underside of the beam over it, else the ceiling plane', () => { + const nodes = storey() + const under = framingPostAt({ + nodes, + levelId: 'level_g', + point: [0, 0], + choices: { size: '6x6', base: 'none' }, + foot: onFloor, + }) + expect(under.beamId).toBe(HEADER.id) + expect(under.post.height).toBeCloseTo(2.7 - 7.5 * IN) + expect(under.post).toMatchObject({ role: 'post', parentId: 'level_g', position: [0, 0, 0] }) + const open = framingPostAt({ + nodes, + levelId: 'level_g', + point: [3, 3], + choices: { size: '4x4', base: 'pier' }, + foot: () => 0.05, + }) + expect(open.beamId).toBeNull() + expect(open.post.height).toBeCloseTo(2.65) + expect(open.post.postBase).toBe('pier') + }) + + test('a beam gets posts at each end and no further apart than 8 ft, skipping one standing', () => { + const standing = createFramingPost({ position: [0, 0], levelId: 'level_g' }) + const posts = framingPostsUnderBeam({ + nodes: storey([standing]), + beam: { ...HEADER, end: [6, 0] }, + choices: { size: '6x6', base: 'none' }, + foot: onFloor, + }) + // 6 m is three bays of 2 m (two of 8 ft would not reach); the near end has its post already + expect(posts.map((post) => [post.position[0], post.position[2]])).toEqual([ + [2, 0], + [4, 0], + [6, 0], + ]) + for (const post of posts) expect(post.height).toBeCloseTo(2.7 - 7.5 * IN) + }) +}) + +describe('a framing post in the column panel and the plan', () => { + test('changes size with its base in proportion, and fits to the beam over it', () => { + const post = createFramingPost({ position: [1, 0], size: '4x4', base: 'pier', height: 2 }) + const patch = framingPostSizePatch(post, '6x6') + expect(patch.width).toBeCloseTo(5.5 * IN) + expect(patch.width! * patch.baseWidthScale!).toBeCloseTo(11.5 * IN) + const fit = framingPostFit(storey(), { ...post, parentId: 'level_g' }, 0) + expect(fit?.beamId).toBe(HEADER.id) + expect(fit?.height).toBeCloseTo(2.7 - 7.5 * IN) + }) + + test('is drawn as a framing plan draws a post: its own square crossed corner to corner', () => { + const view = { + viewState: { selected: false, highlighted: false, hovered: false, moving: false }, + } as unknown as GeometryContext + const lines = (node: ColumnNode) => { + const flat = (g: FloorplanGeometry | null): FloorplanGeometry[] => + !g ? [] : g.kind === 'group' ? g.children.flatMap(flat) : [g] + return flat(buildColumnFloorplan(node, view)).filter((g) => g.kind === 'line') + } + const post = createFramingPost({ position: [2, 2], size: '6x6', base: 'pier' }) + const cross = lines(post).filter( + (line) => line.kind === 'line' && Math.abs(Math.abs(line.x2 - line.x1) - 5.5 * IN) < 1e-9, + ) + expect(cross).toHaveLength(2) + // an ornamental column keeps its small centre mark only + expect(lines(ColumnNode.parse({ position: [2, 0, 2] }))).toHaveLength(2) + // the post's plan footprint is the post, not a capital's or a base's spread + const bare = createFramingPost({ position: [2, 2], size: '6x6' }) + const outline = (() => { + const flat = (g: FloorplanGeometry | null): FloorplanGeometry[] => + !g ? [] : g.kind === 'group' ? g.children.flatMap(flat) : [g] + return flat(buildColumnFloorplan(bare, view)).find((g) => g.kind === 'polygon') + })() + const xs = outline?.kind === 'polygon' ? outline.points.map((point) => point[0]) : [] + expect(Math.max(...xs) - Math.min(...xs)).toBeCloseTo(5.5 * IN) + }) +}) diff --git a/packages/nodes/src/column/tool.tsx b/packages/nodes/src/column/tool.tsx index c77cbd2fd9..29f7ffc70a 100644 --- a/packages/nodes/src/column/tool.tsx +++ b/packages/nodes/src/column/tool.tsx @@ -40,6 +40,8 @@ import { collectStructuralGridAxes, resolveStructuralGridSnap, } from '../structural-grid/coordination' +import { framingPostToolChoices } from './post-placement' +import { FramingPostTool } from './post-tool' import { ColumnPreview } from './renderer' const DEFAULT_COLUMN_PRESET_ID = 'basicPillar' satisfies ColumnPresetId @@ -65,7 +67,7 @@ function createColumnFromPreset(presetId: ColumnPresetId, position: [number, num * `nodes`. Wired via `def.tool`, so `ToolManager`'s registry-first path * mounts it and the legacy `` branch no longer fires. */ -const ColumnTool = () => { +const PillarTool = () => { const activeLevelId = useViewer((state) => state.selection.levelId) const camera = useThree((state) => state.camera) const cameraRef = useRef(camera) @@ -261,4 +263,17 @@ const ColumnTool = () => { ) } +/** + * The column tool, or the Post tool while the Build panel's Post tile has armed it with a framing + * post's fields (`toolDefaults.column`, `framingPostToolChoices`). + */ +const ColumnTool = () => { + const size = useEditor((state) => framingPostToolChoices(state.toolDefaults.column)?.size ?? null) + const base = useEditor( + (state) => framingPostToolChoices(state.toolDefaults.column)?.base ?? 'none', + ) + const choices = useMemo(() => (size ? { size, base } : null), [size, base]) + return choices ? : +} + export default ColumnTool diff --git a/packages/nodes/src/door/actions.tsx b/packages/nodes/src/door/actions.tsx new file mode 100644 index 0000000000..4b7c22b3cc --- /dev/null +++ b/packages/nodes/src/door/actions.tsx @@ -0,0 +1,48 @@ +'use client' +import { type AnyNodeId, usePascalI18n, useScene } from '@pascal-app/core' +import { ActionMenuButton } from '@pascal-app/editor' +import { useViewer } from '@pascal-app/viewer' +import { ArrowLeftRight, ArrowUpDown } from 'lucide-react' +import { applyOpeningSwap } from '../shared/opening-swap' +import { doorMechanism } from './mechanism' +import { canSwapDoorHinge, canSwapDoorSwing, swapDoorHingePatch, swapDoorSwingPatch } from './swing' + +/** + * The door's action-menu contributions, in 2D and 3D: swap the hinge side and swap the swing + * side without opening the panel's Swing section. One undo step each; a closed door opens so + * the new swing shows. + */ +export default function DoorActions() { + const i18n = usePascalI18n() + const selected = useViewer((s) => s.selection.selectedIds) + const door = useScene((s) => { + const node = selected.length === 1 ? s.nodes[selected[0] as AnyNodeId] : undefined + return node?.type === 'door' ? node : undefined + }) + const readOnly = useScene((s) => s.readOnly) + if (!door || readOnly || !canSwapDoorSwing(door)) return null + return ( + <> + {canSwapDoorHinge(door) ? ( + { + event.stopPropagation() + applyOpeningSwap(door, swapDoorHingePatch(door), doorMechanism) + }} + > + + + ) : null} + { + event.stopPropagation() + applyOpeningSwap(door, swapDoorSwingPatch(door), doorMechanism) + }} + > + + + + ) +} diff --git a/packages/nodes/src/door/definition.ts b/packages/nodes/src/door/definition.ts index 4c6ba27b87..d72ac1d26e 100644 --- a/packages/nodes/src/door/definition.ts +++ b/packages/nodes/src/door/definition.ts @@ -7,6 +7,7 @@ import type { WallNode, } from '@pascal-app/core' import { doorSlots } from '@pascal-app/core' +import { NEW_DOOR_FRAME_THICKNESS } from '@pascal-app/core/building' import type { FloorplanNodeExtension } from '@pascal-app/editor' import { curtainOpeningResizeMax } from '../shared/curtain-opening-limits' import { doorBatchable } from '../shared/node-batch/batchable' @@ -223,6 +224,8 @@ export const doorDefinition: NodeDefinition = { 'pascal:editor/floorplan': { contextualDimensions: buildDoorContextualDimensions, schedule: buildDoorFloorplanSchedule, + // Swap hinge / swing side from the action bar, in 2D and 3D. + actionMenu: { actions: () => import('./actions') }, } satisfies FloorplanNodeExtension, }, surfaceRole: 'joinery', @@ -231,7 +234,13 @@ export const doorDefinition: NodeDefinition = { // full default shape — door has 40+ fields, listing them inline would // duplicate the schema. Parse a minimal stub, drop id/type, return rest. defaults: () => { - const stub = DoorNode.parse({ id: 'door_default' as never, type: 'door' }) + const stub = DoorNode.parse({ + id: 'door_default' as never, + type: 'door', + frameThickness: NEW_DOOR_FRAME_THICKNESS, + casingFaceA: true, + casingFaceB: true, + }) const { id: _id, type: _type, ...rest } = stub return rest }, diff --git a/packages/nodes/src/door/floorplan-move.ts b/packages/nodes/src/door/floorplan-move.ts index b6be1f28ed..5ffb4b48aa 100644 --- a/packages/nodes/src/door/floorplan-move.ts +++ b/packages/nodes/src/door/floorplan-move.ts @@ -18,6 +18,7 @@ import { usePlacementPreview, } from '@pascal-app/editor' import { createFloorplanCursorResolver } from '../shared/floorplan-cursor' +import { movedOpeningCasingFaces } from '../shared/opening-casing-move' import { openingPlaneOffsetOnWall } from '../shared/opening-plane-offset' import { getOpeningHostLevelId, getRoofHostedOpeningPlanPoint } from '../shared/roof-opening-host' import { @@ -83,6 +84,8 @@ export const doorFloorplanMoveTarget: FloorplanMoveTarget = ({ node }) roofSegmentId: undefined roofFace: undefined visible: true + casingFaceA: boolean + casingFaceB: boolean } | null = null // R flips the door's facing (front ↔ back) mid-placement. `apply` re-derives @@ -219,6 +222,8 @@ export const doorFloorplanMoveTarget: FloorplanMoveTarget = ({ node }) // Apply the R-flip on top of the wall-derived side. const side: DoorNode['side'] = flipped ? (hit.side === 'front' ? 'back' : 'front') : hit.side const itemRotation = hit.itemRotation + (flipped ? Math.PI : 0) + // Another wall may be drawn the other way round: the casing keeps to its side. + const casing = movedOpeningCasingFaces(node, hit.wall.id, [0, itemRotation, 0], nodes) lastValid = { // Same-wall moves keep the wall-local plane offset; another host resets it. @@ -232,6 +237,7 @@ export const doorFloorplanMoveTarget: FloorplanMoveTarget = ({ node }) roofSegmentId: undefined, roofFace: undefined, visible: true, + ...casing, } setLiveOverride(`wall:${hit.wall.id}:${side}`, { @@ -241,6 +247,7 @@ export const doorFloorplanMoveTarget: FloorplanMoveTarget = ({ node }) roofSegmentId: undefined, roofFace: undefined, visible: true, + ...casing, }) useLiveTransforms.getState().set(nodeId, { position: lastValid.position, diff --git a/packages/nodes/src/door/floorplan.test.ts b/packages/nodes/src/door/floorplan.test.ts index 03751e402d..5770219a0b 100644 --- a/packages/nodes/src/door/floorplan.test.ts +++ b/packages/nodes/src/door/floorplan.test.ts @@ -1,6 +1,7 @@ import { describe, expect, test } from 'bun:test' import { DoorNode, type FloorplanGeometry, type GeometryContext, WallNode } from '@pascal-app/core' import { buildDoorFloorplan } from './floorplan' +import { placementSwing, swapDoorHingePatch, swapDoorSwingPatch } from './swing' const wall = WallNode.parse({ id: 'wall_door-plan', @@ -83,10 +84,9 @@ describe('buildDoorFloorplan wall-local plane offset', () => { expect(footprint?.max).toBeCloseTo(0.1, 9) }) - test('an auto frame offset off the wall draws at the wall thickness plus the lip', () => { - // No `frameDepth`: the frame is 0.2 m (the wall) + 0.02 m; offset -0.215 puts it past the -z face. - const spans = polygonSpans(buildDoor({ doorType: 'sliding', position: [2, 1.05, -0.215] })) - const frame = spans.find((span) => Math.abs(span.min + 0.325) < 1e-9) + test('an offset auto-depth door is exactly as deep as its wall', () => { + const spans = polygonSpans(buildDoor({ doorType: 'sliding', position: [2, 1.05, -0.205] })) + const frame = spans.find((span) => Math.abs(span.min + 0.305) < 1e-9) expect(frame).toBeDefined() expect(frame?.max).toBeCloseTo(-0.105, 9) }) @@ -109,3 +109,44 @@ describe('buildDoorFloorplan wall-local plane offset', () => { for (const panel of panels) expect(panel.max).toBeLessThanOrEqual(-0.1 + 1e-9) }) }) + +/** The plan z the open leaf reaches: + is the wall's front (+Z) side, - its back. */ +function leafSide(geometry: FloorplanGeometry[]) { + const leaf = geometry + .filter((item) => item.kind === 'line') + .reduce<{ y1: number; y2: number } | null>((best, item) => { + if (item.kind !== 'line') return best + return !best || Math.abs(item.y2 - item.y1) > Math.abs(best.y2 - best.y1) ? item : best + }, null) + return Math.sign(leaf!.y2 - leaf!.y1) +} + +describe('swing chosen while placing', () => { + const placed = (rotationY: number, cursor: 'front' | 'back', values: Partial = {}) => + buildDoor({ + ...values, + rotation: [0, rotationY, 0], + swingDirection: placementSwing(DoorNode.parse({ ...values }), rotationY, cursor), + }) + + test('the leaf swings into the side of the wall the cursor is on', () => { + expect(leafSide(placed(0, 'front'))).toBe(1) + expect(leafSide(placed(Math.PI, 'back'))).toBe(-1) + }) + + test('a door held facing out (an outside wall) still swings toward the cursor', () => { + expect(leafSide(placed(0, 'back'))).toBe(-1) + expect(leafSide(placed(Math.PI, 'front'))).toBe(1) + expect(leafSide(placed(0, 'front', { doorType: 'double' }))).toBe(1) + }) + + test('swapping the swing sends the leaf to the other side; swapping hinges keeps it there', () => { + const door = DoorNode.parse({ id: 'door_swap', hingesSide: 'left', handleSide: 'right' }) + expect(leafSide(buildDoor({ ...door, ...swapDoorSwingPatch(door) }))).toBe( + -leafSide(buildDoor(door)), + ) + const swapped = swapDoorHingePatch(door) + expect(swapped).toEqual({ hingesSide: 'right', handleSide: 'left' }) + expect(leafSide(buildDoor({ ...door, ...swapped }))).toBe(leafSide(buildDoor(door))) + }) +}) diff --git a/packages/nodes/src/door/floorplan.ts b/packages/nodes/src/door/floorplan.ts index 0cbfbb3a10..b724e08a4c 100644 --- a/packages/nodes/src/door/floorplan.ts +++ b/packages/nodes/src/door/floorplan.ts @@ -11,6 +11,7 @@ import { readFloorplanGeometryMetadata, withFloorplanGeometryMetadata, } from '@pascal-app/editor' +import { buildOpeningCasingPlan } from '../shared/opening-casing' import { buildOpeningMarkAnnotation, type OpeningFloorplanLevelData, @@ -42,6 +43,8 @@ import { resolveOpeningPlanPlane } from '../shared/opening-plane-offset' * with no swing arc. * 4. Center line through the cutout (matches the legacy's * `getOpeningCenterLine` segment for visual continuity). + * 5. Casing legs standing proud of each cased wall face beside the + * cutout (`buildOpeningCasingPlan`). * * Requires `ctx.parent` to be a wall (door.parentId is the wall it's * mounted on). Returns null when the parent isn't a wall (orphaned @@ -160,6 +163,15 @@ export function buildDoorFloorplan(node: DoorNode, ctx: GeometryContext): Floorp }, ] + // Casing legs on the wall faces beside the cutout, as the 3D door has them. + const casing = buildOpeningCasingPlan(node, wall, { + fill: fillColor, + stroke: accentMuted, + strokeWidth: showSelectedChrome ? 1.4 : 1, + vectorEffect: 'non-scaling-stroke', + }) + if (casing) children.push(casing) + if (node.openingShape !== 'rectangle') { const overheadRise = Math.min(width, node.openingShape === 'arch' ? node.archHeight : node.cornerRadius) * 0.2 @@ -305,8 +317,9 @@ export function buildDoorFloorplan(node: DoorNode, ctx: GeometryContext): Floorp // fall through to just the opening footprint (the earlier behaviour). const isSwingDoor = node.doorType === 'hinged' || isDoubleLeaf // A frameless wall opening — drawn as a bare gap, no leaf / arc / panel - // (mirrors the 3D system, which renders only the cutout for openings). - const isOpening = node.openingKind === 'opening' + // (mirrors the 3D system, which renders only the cutout for openings). A + // door on a railing is always one: a gap in the guard. + const isOpening = node.openingKind === 'opening' || wall.wallType === 'railing' if (isOpening) { // Open doorway — a frameless gap in the wall. No leaf, arc, or panel; diff --git a/packages/nodes/src/door/move-tool.tsx b/packages/nodes/src/door/move-tool.tsx index 3adc3472ee..f0867bcc55 100644 --- a/packages/nodes/src/door/move-tool.tsx +++ b/packages/nodes/src/door/move-tool.tsx @@ -41,6 +41,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { BoxGeometry, EdgesGeometry, type Group, Vector3 } from 'three' import { LineBasicNodeMaterial } from 'three/webgpu' import { commitOpeningMove } from '../shared/commit-opening-move' +import { movedOpeningCasingFaces } from '../shared/opening-casing-move' import { clearOpeningGuides3D, publishOpeningGuidesForWallEvent, @@ -162,6 +163,9 @@ const MoveDoorTool: React.FC<{ node: DoorNode }> = ({ node: movingDoorNode }) => // Same-wall moves keep the wall-local plane offset; another host resets it. const planeOffsetOn = (wallId: string) => openingPlaneOffsetOnWall(movingDoorNode, wallId) + // Another host may name its faces the other way round: the casing keeps to its side of it. + const casingOn = (hostId: string, rotation: DoorNode['rotation']) => + movedOpeningCasingFaces(movingDoorNode, hostId, rotation, useScene.getState().nodes) let currentHostId: string | null = movingDoorNode.parentId let dragAnchor: { wallId: string; rawX: number; startX: number } | null = null @@ -468,11 +472,11 @@ const MoveDoorTool: React.FC<{ node: DoorNode }> = ({ node: movingDoorNode }) => }) // Forward-facing triangle (editor-side overlay), in the same building-local // frame the ghost renders in. The door's front is its local +Z. Drop it to - // the floor under the wall (the ghost Y is the opening centre, ~1m up). + // the door's sill (the ghost Y is the opening centre, ~1m up). useFacingPose.getState().set({ position: [ ghostWorldPos[0], - getLevelYOffset() + getSlabElevation(target.event), + ghostWorldPos[1] - movingDoorNode.height / 2, ghostWorldPos[2], ], rotationY: ghostYaw, @@ -576,6 +580,7 @@ const MoveDoorTool: React.FC<{ node: DoorNode }> = ({ node: movingDoorNode }) => side: target.side, wallId: target.wallId, parentId: target.wallId, + ...casingOn(target.wallId, [0, target.itemRotation, 0]), roofSegmentId: undefined, roofFace: undefined, // The moving node is hidden during free-follow; the committed door @@ -611,6 +616,7 @@ const MoveDoorTool: React.FC<{ node: DoorNode }> = ({ node: movingDoorNode }) => side: target.side, parentId: target.wallId, wallId: target.wallId, + ...casingOn(target.wallId, [0, target.itemRotation, 0]), roofSegmentId: undefined, visible: true, }) @@ -847,6 +853,7 @@ const MoveDoorTool: React.FC<{ node: DoorNode }> = ({ node: movingDoorNode }) => roofSegmentId: segmentId, roofFace: target.face.id, parentId: segmentId, + ...casingOn(segmentId, [0, 0, 0]), visible: true, }) history.commitStep(() => { @@ -879,6 +886,7 @@ const MoveDoorTool: React.FC<{ node: DoorNode }> = ({ node: movingDoorNode }) => wallId: undefined, roofSegmentId: segmentId, roofFace: target.face.id, + ...casingOn(segmentId, [0, 0, 0]), visible: true, }) }) diff --git a/packages/nodes/src/door/paint.ts b/packages/nodes/src/door/paint.ts index 4415cfd5d5..d5f260f2a0 100644 --- a/packages/nodes/src/door/paint.ts +++ b/packages/nodes/src/door/paint.ts @@ -1,5 +1,8 @@ +import { type PaintCapability, slotDefaultPaintMaterial, slotPaintMaterial } from '@pascal-app/core' +import { openingCasingPaintLabel } from '../shared/opening-casing' import { createSlotPaintCapability, + declaredSlotLook, previewSlotByUserData, resolveSlotByReRaycast, } from '../shared/slot-paint' @@ -10,11 +13,30 @@ import { * recessed door body, so `resolveSlotByReRaycast` re-raycasts the door's own * subtree to find the part (panel / frame / glass / hardware) under the cursor. */ -export const doorPaint = createSlotPaintCapability({ +const base = createSlotPaintCapability({ resolveRole: resolveSlotByReRaycast, applyPreview: previewSlotByUserData, + erasedLook: ({ node, role, materials = {} }) => { + if (role !== 'casing-a' && role !== 'casing-b') return declaredSlotLook(node, role) + if (node.type !== 'door' || node.source) return null + const frame = + slotPaintMaterial(node.slots?.frame, materials) ?? slotDefaultPaintMaterial(node.slots?.frame) + if (frame) return frame + if (node.material) return { material: node.material } + return declaredSlotLook(node, 'frame') + }, legacyEffective: (node, role) => node.type === 'door' && !node.source && node.material && (role === 'panel' || role === 'frame') ? { material: node.material, materialPreset: undefined } : null, }) + +export const doorPaint: PaintCapability = { + ...base, + roleLabel: (_node, role) => openingCasingPaintLabel(role), + getEffectiveMaterial: (args) => { + const own = base.getEffectiveMaterial?.(args) + if (own || (args.role !== 'casing-a' && args.role !== 'casing-b')) return own ?? null + return base.getEffectiveMaterial?.({ ...args, role: 'frame' }) ?? null + }, +} diff --git a/packages/nodes/src/door/panel.tsx b/packages/nodes/src/door/panel.tsx index f2ee5084a4..fda527f63e 100644 --- a/packages/nodes/src/door/panel.tsx +++ b/packages/nodes/src/door/panel.tsx @@ -31,6 +31,7 @@ import { Copy, DoorOpen, FlipHorizontal2, Move, Trash2 } from 'lucide-react' import { useCallback, useEffect, useMemo } from 'react' import { AuthoredParams } from '../item/authored-params' import { constrainCurtainOpening, curtainOpeningLimits } from '../shared/curtain-opening-limits' +import { OpeningCasingSection } from '../shared/opening-casing-section' import { DOOR_STYLE_MESSAGES } from '../shared/opening-labels' import { createOpeningPropertyPreview } from '../shared/opening-property-preview' import { openingPropertyPreviewHost } from '../shared/opening-property-preview-host' @@ -1198,6 +1199,8 @@ export default function DoorPanel() { )} + + ((set, get) => ({ /** The door the tool places: the chips' type and style, written as add_door and the panel write them. */ export function placedDoorFields(): Partial { const { type, style } = useDoorPlacement.getState() - return { ...doorTypeFields(type), ...DOOR_TYPE_SIZES[type], ...doorStyleLook(style) } + return { + frameThickness: NEW_DOOR_FRAME_THICKNESS, + casingFaceA: true, + casingFaceB: true, + ...doorTypeFields(type), + ...DOOR_TYPE_SIZES[type], + ...doorStyleLook(style), + } } export const DOOR_PLACEMENT_HINTS: ToolHint[] = [ diff --git a/packages/nodes/src/door/swing.ts b/packages/nodes/src/door/swing.ts new file mode 100644 index 0000000000..0e547429e2 --- /dev/null +++ b/packages/nodes/src/door/swing.ts @@ -0,0 +1,47 @@ +import type { DoorNode } from '@pascal-app/core' + +type SwingDoor = Pick & + Partial> + +const flip = (side: 'left' | 'right') => (side === 'left' ? 'right' : 'left') + +/** Whether a door swings on hinges (the panel's Swing section), so its swing can be swapped. */ +export function canSwapDoorSwing(door: SwingDoor): boolean { + return ( + !door.source && + door.openingKind !== 'opening' && + (door.doorType === 'hinged' || door.doorType === 'double' || door.doorType === 'french') + ) +} + +/** Whether a door has one hinge side to swap: a single hinged leaf. */ +export function canSwapDoorHinge(door: SwingDoor): boolean { + return canSwapDoorSwing(door) && door.doorType === 'hinged' +} + +/** The leaf hung from the other jamb: hinges and handle trade sides, so the handle stays on the free edge. */ +export function swapDoorHingePatch(door: SwingDoor): Partial { + return { hingesSide: flip(door.hingesSide), handleSide: flip(door.handleSide) } +} + +/** The leaf swinging into the other side of the wall. */ +export function swapDoorSwingPatch(door: SwingDoor): Partial { + return { swingDirection: door.swingDirection === 'inward' ? 'outward' : 'inward' } +} + +/** + * The swing that opens a door's leaf toward `side` of its wall: the face under the cursor while + * placing, so the door swings into the side it is placed from (R flips it to the other side). An + * inward door opens toward the face it is hung facing (`rotationY` 0 faces front, π back), so a + * door facing that side swings inward and one facing away swings outward. A garage door has no + * swing and keeps its own. + */ +export function placementSwing( + door: Pick, + rotationY: number, + side: 'front' | 'back', +): DoorNode['swingDirection'] { + if (door.doorType?.startsWith('garage-')) return door.swingDirection + const facing = Math.cos(rotationY) >= 0 ? 'front' : 'back' + return facing === side ? 'inward' : 'outward' +} diff --git a/packages/nodes/src/door/tool.tsx b/packages/nodes/src/door/tool.tsx index 6231f453aa..63f3b24ff7 100644 --- a/packages/nodes/src/door/tool.tsx +++ b/packages/nodes/src/door/tool.tsx @@ -9,8 +9,10 @@ import { getWallThickness, holdHiddenWallPointerEvents, isCurvedWall, + isRailingWall, type RoofEvent, type RoofNode, + railingOpeningFields, resolveOpeningFrameDepth, sceneRegistry, spatialGridManager, @@ -56,6 +58,7 @@ import { import { clampToWall, hasWallChildOverlap, wallLocalToWorld } from './door-math' import { placedDoorFields, useDoorPlacement } from './placement' import DoorPreview from './preview' +import { placementSwing } from './swing' const edgeMaterial = new LineBasicNodeMaterial({ color: 0xef_44_44, @@ -351,10 +354,11 @@ const DoorTool: React.FC = () => { rawLocalX: number side: 'front' | 'back' itemRotation: number + swingSide: 'front' | 'back' cursorRotationY: number applySnap: boolean }) => { - const { wall, rawLocalX, side, itemRotation, cursorRotationY, applySnap } = args + const { wall, rawLocalX, side, itemRotation, swingSide, cursorRotationY, applySnap } = args const placed = placedDoorFields() const width = draftRef.current?.width ?? placed.width ?? 0.9 const height = draftRef.current?.height ?? placed.height ?? 2.1 @@ -381,12 +385,15 @@ const DoorTool: React.FC = () => { applySnap, draftRef.current.id, ) + // The leaf swings into the side the cursor is on (R sends it to the other side). + const swingDirection = placementSwing(draftRef.current, itemRotation, swingSide) if (wall.id === draftRef.current.parentId) { useScene.getState().updateNode(draftRef.current.id, { position: [clampedX, clampedY, 0], rotation: [0, itemRotation, 0], side, + swingDirection, }) markHostDirty(wall.id) } else { @@ -394,6 +401,7 @@ const DoorTool: React.FC = () => { position: [clampedX, clampedY, 0], rotation: [0, itemRotation, 0], side, + swingDirection, parentId: wall.id, wallId: wall.id, // The draft may arrive from a roof-segment face hover. @@ -413,7 +421,7 @@ const DoorTool: React.FC = () => { ), cursorRotationY, valid, - -clampedY, + -height / 2, getWallThickness(wall), ) @@ -441,6 +449,7 @@ const DoorTool: React.FC = () => { clampedY: number, side: 'front' | 'back', itemRotation: number, + swingSide: 'front' | 'back', ) => { const draft = draftRef.current if (!draft) return @@ -459,9 +468,15 @@ const DoorTool: React.FC = () => { return w?.parentId === levelId }).length + // On a railing the door becomes a gap in the guard, as tall as the guard. + const railingGap = isRailingWall(wall) ? railingOpeningFields(wall) : null const node = DoorNode.parse({ - name: `Door ${doorCount + 1}`, - position: [clampedX, clampedY, 0], + name: `${railingGap ? 'Opening' : 'Door'} ${doorCount + 1}`, + position: [ + clampedX, + railingGap ? clampedY + (railingGap.height - draft.height) / 2 : clampedY, + 0, + ], rotation: [0, itemRotation, 0], side, wallId: wall.id, @@ -475,11 +490,14 @@ const DoorTool: React.FC = () => { slideDirection: draft.slideDirection, trackStyle: draft.trackStyle, garagePanelCount: draft.garagePanelCount, + casingFaceA: draft.casingFaceA, + casingFaceB: draft.casingFaceB, + casingWidth: draft.casingWidth, frameThickness: draft.frameThickness, threshold: draft.threshold, thresholdHeight: draft.thresholdHeight, hingesSide: draft.hingesSide, - swingDirection: draft.swingDirection, + swingDirection: placementSwing(draft, itemRotation, swingSide), segments: draft.segments, contentPadding: draft.contentPadding, handle: draft.handle, @@ -488,6 +506,7 @@ const DoorTool: React.FC = () => { doorCloser: draft.doorCloser, panicBar: draft.panicBar, panicBarHeight: draft.panicBarHeight, + ...railingGap, }) useScene.getState().createNode(node, wall.id as AnyNodeId) @@ -519,8 +538,11 @@ const DoorTool: React.FC = () => { } lastWallEvent = event - // An outside wall's door faces out whichever face is hovered, as add_door places it. - const faceSide = placedDoorFace(event.node, getSideFromNormal(event.normal)) + // An outside wall's door faces out whichever face is hovered, as add_door places it; the + // leaf still swings into the hovered side (R flips facing and swing together). + const hovered = getSideFromNormal(event.normal) + const swingSide = sideFlip ? (hovered === 'front' ? 'back' : 'front') : hovered + const faceSide = placedDoorFace(event.node, hovered) const side = sideFlip ? (faceSide === 'front' ? 'back' : 'front') : faceSide const flipOffset = sideFlip ? Math.PI : 0 const itemRotation = (faceSide === 'back' ? Math.PI : 0) + flipOffset @@ -536,6 +558,7 @@ const DoorTool: React.FC = () => { rawLocalX: event.localPosition[0], side, itemRotation, + swingSide, cursorRotationY: cursorRotation, applySnap: isMagneticSnapActive(), }) @@ -552,7 +575,9 @@ const DoorTool: React.FC = () => { return } - const faceSide = placedDoorFace(event.node, getSideFromNormal(event.normal)) + const hovered = getSideFromNormal(event.normal) + const swingSide = sideFlip ? (hovered === 'front' ? 'back' : 'front') : hovered + const faceSide = placedDoorFace(event.node, hovered) const side = sideFlip ? (faceSide === 'front' ? 'back' : 'front') : faceSide const itemRotation = (faceSide === 'back' ? Math.PI : 0) + (sideFlip ? Math.PI : 0) const { clampedX, clampedY, valid } = resolveWallPlacement( @@ -566,7 +591,7 @@ const DoorTool: React.FC = () => { // Alt force-places over a collision (the draft stays red as a warning). if (!valid && event.nativeEvent?.altKey !== true) return - commitDoorAtWall(event.node, clampedX, clampedY, side, itemRotation) + commitDoorAtWall(event.node, clampedX, clampedY, side, itemRotation, swingSide) event.stopPropagation() } @@ -720,6 +745,9 @@ const DoorTool: React.FC = () => { slideDirection: draft.slideDirection, trackStyle: draft.trackStyle, garagePanelCount: draft.garagePanelCount, + casingFaceA: draft.casingFaceA, + casingFaceB: draft.casingFaceB, + casingWidth: draft.casingWidth, frameThickness: draft.frameThickness, threshold: draft.threshold, thresholdHeight: draft.thresholdHeight, diff --git a/packages/nodes/src/fence/drafting.ts b/packages/nodes/src/fence/drafting.ts index f4c6c41d39..4960a4c31f 100644 --- a/packages/nodes/src/fence/drafting.ts +++ b/packages/nodes/src/fence/drafting.ts @@ -244,9 +244,8 @@ export function snapFenceDraftPoint(args: { step?: number /** * Optional grid-snap function. When provided, replaces the default - * local-axis snap — lets the 2D floor-plan keep snapping to the - * world XZ grid even when the building is rotated. Wall / fence - * endpoint snap precedence is preserved. + * local-axis snap (the floor plan passes its building-grid snap, the + * same lattice). Wall / fence endpoint snap precedence is preserved. */ gridSnap?: (point: FencePlanPoint) => FencePlanPoint }): FencePlanPoint { @@ -280,9 +279,8 @@ export function snapFenceDraftPoint(args: { if (rawTarget) return rawTarget } - // The angle path snaps the distance ALONG the 15° ray — a scalar, the - // same in world and local frames — so the `gridSnap` world-grid override - // only applies when the angle lock is off. + // The angle path snaps the distance ALONG the 15° ray from `start`, so the + // `gridSnap` override only applies when the angle lock is off. const basePoint: FencePlanPoint = start && angleSnap ? [...snapPointAlongAngleRay(start, point, DEFAULT_ANGLE_STEP, gridStep)] diff --git a/packages/nodes/src/floor-opening/floorplan.test.ts b/packages/nodes/src/floor-opening/floorplan.test.ts index 805efd4faf..450ee558bb 100644 --- a/packages/nodes/src/floor-opening/floorplan.test.ts +++ b/packages/nodes/src/floor-opening/floorplan.test.ts @@ -1,6 +1,19 @@ import { expect, test } from 'bun:test' -import { FloorOpeningNode, type FloorplanGeometry, type GeometryContext } from '@pascal-app/core' -import { buildFloorOpeningFloorplan } from './floorplan' +import { + type AnyNodeId, + FloorOpeningNode, + type FloorplanGeometry, + type GeometryContext, + useLiveNodeOverrides, + useScene, +} from '@pascal-app/core' +import { + buildFloorOpeningFloorplan, + floorOpeningMoveVertexAffordance, + moveRectangleEdge, + openingRectangle, + resizeRectangleCorner, +} from './floorplan' const opening = FloorOpeningNode.parse({ polygon: [ @@ -28,3 +41,99 @@ test('an opening draws as a dashed outline, with corner handles only while selec expect(selected.filter((kind) => kind === 'endpoint-handle')).toHaveLength(4) expect(selected.filter((kind) => kind === 'edge-handle')).toHaveLength(4) }) + +test('a stair opening stays a box: solid outline, side grips, corners and sides resize it square', () => { + const rounded = FloorOpeningNode.parse({ + source: 'stair', + ownerId: 'stair_box', + // A legacy opening cut with rounded corners. + polygon: [ + [0.1, 0], + [1.9, 0], + [2, 0.1], + [2, 2.9], + [1.9, 3], + [0.1, 3], + [0, 2.9], + [0, 0.1], + ], + }) + const geometry = buildFloorOpeningFloorplan(rounded, context(true)) + const selected = kinds(geometry) + expect(selected.filter((kind) => kind === 'midpoint-handle')).toHaveLength(0) + expect(selected.filter((kind) => kind === 'edge-handle')).toHaveLength(4) + // Four side grips and four corners. + expect(selected.filter((kind) => kind === 'endpoint-handle')).toHaveLength(8) + const box = openingRectangle(rounded.polygon) + expect(box).toHaveLength(4) + const xs = box.map(([x]) => x) + const zs = box.map(([, z]) => z) + expect([Math.min(...xs), Math.max(...xs), Math.min(...zs), Math.max(...zs)]).toEqual([0, 2, 0, 3]) + const corner = box.findIndex(([x, z]) => x === 2 && z === 3) + const grown = resizeRectangleCorner(box, corner, [2.5, 3.4]) + const square = (ring: [number, number][]) => + ring.every((a, i) => { + const b = ring[(i + 1) % 4]! + const c = ring[(i + 2) % 4]! + return Math.abs((b[0] - a[0]) * (c[0] - b[0]) + (b[1] - a[1]) * (c[1] - b[1])) < 1e-9 + }) + expect(square(grown)).toBe(true) + expect(grown).toContainEqual([2.5, 3.4]) + expect(grown).toContainEqual([0, 0]) + const edge = box.findIndex(([x], i) => x === 2 && box[(i + 1) % 4]![0] === 2) + const wider = moveRectangleEdge(box, edge, 0.5) + expect(square(wider)).toBe(true) + expect(Math.max(...wider.map(([x]) => x))).toBeCloseTo(2.5) + // Never collapses past the minimum side. + expect(Math.max(...moveRectangleEdge(box, edge, -5).map(([x]) => x))).toBeCloseTo(0.2) +}) + +test("an elevator's opening keeps the free polygon handles", () => { + const elevator = FloorOpeningNode.parse({ ...opening, source: 'elevator', ownerId: 'elevator_x' }) + const selected = kinds(buildFloorOpeningFloorplan(elevator, context(true))) + expect(selected.filter((kind) => kind === 'midpoint-handle')).toHaveLength(4) + expect(selected.filter((kind) => kind === 'endpoint-handle')).toHaveLength(4) +}) + +test('a stair opening drag previews live and writes the scene once, on release', () => { + const stairOpening = FloorOpeningNode.parse({ + ...opening, + id: 'floor-opening_drag', + source: 'stair', + ownerId: 'stair_drag', + }) + const previous = useScene.getState() + const frame = globalThis.requestAnimationFrame + const cancelFrame = globalThis.cancelAnimationFrame + globalThis.requestAnimationFrame = (() => 0) as typeof requestAnimationFrame + globalThis.cancelAnimationFrame = () => {} + useScene.setState({ nodes: { [stairOpening.id]: stairOpening } as never }) + let writes = 0 + const stop = useScene.subscribe((state, before) => { + if (state.nodes !== before.nodes) writes++ + }) + try { + const nodes = useScene.getState().nodes + const session = floorOpeningMoveVertexAffordance.start({ + node: stairOpening, + payload: { vertexIndex: 2 }, + nodes, + initialPlanPoint: [2, 1], + } as never) + session.apply({ planPoint: [3, 2], modifiers: {} } as never) + session.apply({ planPoint: [3, 1.5], modifiers: {} } as never) + expect(writes).toBe(0) + expect(useLiveNodeOverrides.getState().get(stairOpening.id)?.polygon).toContainEqual([3, 1.5]) + expect(session.canCommit()).toBe(true) + session.commit?.() + expect(writes).toBe(1) + const written = useScene.getState().nodes[stairOpening.id as AnyNodeId] as FloorOpeningNode + expect(written.polygon).toContainEqual([3, 1.5]) + expect(useLiveNodeOverrides.getState().get(stairOpening.id)).toBeUndefined() + } finally { + stop() + useScene.setState({ nodes: previous.nodes }) + globalThis.requestAnimationFrame = frame + globalThis.cancelAnimationFrame = cancelFrame + } +}) diff --git a/packages/nodes/src/floor-opening/floorplan.ts b/packages/nodes/src/floor-opening/floorplan.ts index 7ebc223c41..848fe07c87 100644 --- a/packages/nodes/src/floor-opening/floorplan.ts +++ b/packages/nodes/src/floor-opening/floorplan.ts @@ -1,4 +1,15 @@ -import type { FloorOpeningNode, FloorplanGeometry, GeometryContext } from '@pascal-app/core' +import { + type AnyNodeId, + authorStairOpeningPatches, + type FloorOpeningNode, + type FloorplanAffordance, + type FloorplanAffordanceSession, + type FloorplanGeometry, + type GeometryContext, + useLiveNodeOverrides, + useScene, +} from '@pascal-app/core' +import { getSegmentGridStep, snapPointToGrid, snapScalarToGrid } from '@pascal-app/editor' import { createPolygonAddVertexAffordance, createPolygonDeleteVertexAffordance, @@ -7,17 +18,172 @@ import { } from '../shared/polygon-vertex-affordance' const COLOR = '#f59e0b' +/** A side of a stair opening never shrinks below this (metres). */ +const MIN_OPENING_SIDE = 0.2 + +type Ring = [number, number][] + +/** + * A stair's opening: a box its stair cut, resized as a box. An elevator's opening keeps the free + * polygon handles: its cut comes from the car, so a drawn shape would not stick. + */ +export function isOwnedOpening(node: FloorOpeningNode): boolean { + return node.source === 'stair' && !!node.ownerId +} + +/** + * The square-cornered rectangle an owned opening is edited as: the ring itself when it already is + * one, otherwise (an opening cut with rounded corners before they were square) the box around it, + * aligned with its longest side. + */ +export function openingRectangle(polygon: ReadonlyArray): Ring { + const ring = polygon.map(([x, z]) => [x, z] as [number, number]) + let longest = 0 + let axis: [number, number] = [1, 0] + for (const [i, a] of ring.entries()) { + const b = ring[(i + 1) % ring.length]! + const length = Math.hypot(b[0] - a[0], b[1] - a[1]) + if (length > longest) { + longest = length + axis = [(b[0] - a[0]) / length, (b[1] - a[1]) / length] + } + } + const normal: [number, number] = [-axis[1], axis[0]] + const along = ring.map(([x, z]) => x * axis[0] + z * axis[1]) + const across = ring.map(([x, z]) => x * normal[0] + z * normal[1]) + const [u0, u1, v0, v1] = [ + Math.min(...along), + Math.max(...along), + Math.min(...across), + Math.max(...across), + ] + const at = (u: number, v: number): [number, number] => [ + u * axis[0] + v * normal[0], + u * axis[1] + v * normal[1], + ] + return [at(u0, v0), at(u1, v0), at(u1, v1), at(u0, v1)] +} + +/** + * `rectangle` with corner `index` dragged to `point`: the opposite corner stays, the two sides + * through the dragged corner keep their directions, so the box stays a box. + */ +export function resizeRectangleCorner( + rectangle: Ring, + index: number, + point: readonly [number, number], +): Ring { + const at = (offset: number) => rectangle[(index + offset) % 4]! + const origin = at(2) + const unit = (to: [number, number]) => { + const dx = to[0] - origin[0] + const dz = to[1] - origin[1] + const length = Math.hypot(dx, dz) || 1 + return [dx / length, dz / length] as const + } + const a = unit(at(1)) + const b = unit(at(3)) + const dx = point[0] - origin[0] + const dz = point[1] - origin[1] + const sideA = Math.max(MIN_OPENING_SIDE, dx * a[0] + dz * a[1]) + const sideB = Math.max(MIN_OPENING_SIDE, dx * b[0] + dz * b[1]) + const next = [...rectangle] as Ring + next[(index + 1) % 4] = [origin[0] + a[0] * sideA, origin[1] + a[1] * sideA] + next[(index + 3) % 4] = [origin[0] + b[0] * sideB, origin[1] + b[1] * sideB] + next[index] = [origin[0] + a[0] * sideA + b[0] * sideB, origin[1] + a[1] * sideA + b[1] * sideB] + return next +} + +/** `rectangle` with side `edgeIndex` moved parallel by `distance` along its outward normal. */ +export function moveRectangleEdge(rectangle: Ring, edgeIndex: number, distance: number): Ring { + const start = rectangle[edgeIndex]! + const end = rectangle[(edgeIndex + 1) % 4]! + const opposite = rectangle[(edgeIndex + 2) % 4]! + const length = Math.hypot(end[0] - start[0], end[1] - start[1]) || 1 + let normal: [number, number] = [-(end[1] - start[1]) / length, (end[0] - start[0]) / length] + // Point the normal away from the box, whichever way the ring winds. + if ((opposite[0] - start[0]) * normal[0] + (opposite[1] - start[1]) * normal[1] > 0) + normal = [-normal[0], -normal[1]] + const depth = (opposite[0] - start[0]) * -normal[0] + (opposite[1] - start[1]) * -normal[1] + const travel = Math.max(MIN_OPENING_SIDE - depth, distance) + return rectangle.map((point, i) => + i === edgeIndex || i === (edgeIndex + 1) % 4 + ? ([point[0] + normal[0] * travel, point[1] + normal[1] * travel] as [number, number]) + : point, + ) +} + +/** Every write for `ring` on a stair's opening: its floor and ceiling cuts take it as drawn. */ +function ownedOpeningUpdates(id: AnyNodeId, ring: Ring) { + const authored = authorStairOpeningPatches(useScene.getState().nodes, id, ring) + return authored.length ? authored : [{ id, data: { polygon: ring } }] +} + +function ownedOpeningSession( + node: FloorOpeningNode, + next: (rectangle: Ring, planPoint: readonly [number, number]) => Ring, +): FloorplanAffordanceSession { + const rectangle = openingRectangle(node.polygon) + const affectedIds = [ + ...new Set([ + node.id as AnyNodeId, + ...authorStairOpeningPatches(useScene.getState().nodes, node.id, rectangle).map( + (patch) => patch.id, + ), + ]), + ] + let ring: Ring | null = null + // The drag previews through live overrides; the scene is written once, on release. + return { + affectedIds, + apply({ planPoint }) { + ring = next(rectangle, planPoint) + useLiveNodeOverrides + .getState() + .setMany( + ownedOpeningUpdates(node.id as AnyNodeId, ring).map( + ({ id, data }) => [id, data as Record] as const, + ), + ) + }, + canCommit: () => ring !== null, + commit() { + const overrides = useLiveNodeOverrides.getState() + if (ring) + useScene.getState().updateNodes(ownedOpeningUpdates(node.id as AnyNodeId, ring) as never) + for (const id of affectedIds) overrides.clear(id) + }, + } +} + +/** Owned openings resize as a box; every other opening keeps the free polygon handles. */ +function ownedOr( + owned: FloorplanAffordance['start'], + free: FloorplanAffordance, +): FloorplanAffordance { + return { start: (args) => (isOwnedOpening(args.node) ? owned(args) : free.start(args)) } +} + +const inert = (node: FloorOpeningNode): FloorplanAffordanceSession => ({ + affectedIds: [node.id as AnyNodeId], + apply() {}, + canCommit: () => false, +}) /** * A floor opening on the plan: a dashed amber outline (the void the surfaces * around it show), and — while selected — the same corner, midpoint and edge - * handles slabs and zones use. + * handles slabs and zones use. A stair's opening is a box: its + * selected outline is solid, its sides carry a grip each to move them + * parallel and its corners resize it, all at a fixed screen size; it has no + * midpoint handles to add a vertex. */ export function buildFloorOpeningFloorplan( node: FloorOpeningNode, ctx: GeometryContext, ): FloorplanGeometry | null { - const polygon = node.polygon + const owned = isOwnedOpening(node) + const polygon = owned && ctx.viewState?.selected ? openingRectangle(node.polygon) : node.polygon if (polygon.length < 3) return null const selected = ctx.viewState?.selected ?? false const d = `M ${polygon.map(([x, z]) => `${x} ${z}`).join(' L ')} Z` @@ -28,9 +194,9 @@ export function buildFloorOpeningFloorplan( fill: COLOR, fillOpacity: selected ? 0.22 : 0.1, stroke: COLOR, - strokeWidth: selected ? 0.04 : 0.03, + strokeWidth: selected ? (owned ? 0.06 : 0.04) : 0.03, strokeOpacity: 0.95, - strokeDasharray: '0.12 0.08', + ...(selected && owned ? {} : { strokeDasharray: '0.12 0.08' }), }, ] if (selected) { @@ -48,18 +214,31 @@ export function buildFloorOpeningFloorplan( }) polygon.forEach((a, i) => { const b = polygon[(i + 1) % polygon.length]! - children.push({ - kind: 'midpoint-handle', - point: [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2], - affordance: 'add-vertex', - payload: { edgeIndex: i }, - }) + const point: [number, number] = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2] + children.push( + owned + ? { + kind: 'endpoint-handle', + point, + state: 'idle', + screenSized: true, + affordance: 'move-edge', + payload: { edgeIndex: i }, + } + : { + kind: 'midpoint-handle', + point, + affordance: 'add-vertex', + payload: { edgeIndex: i }, + }, + ) }) polygon.forEach(([x, z], i) => { children.push({ kind: 'endpoint-handle', point: [x, z], state: 'idle', + ...(owned ? { screenSized: true } : {}), affordance: 'move-vertex', payload: { vertexIndex: i }, }) @@ -68,11 +247,39 @@ export function buildFloorOpeningFloorplan( return { kind: 'group', children } } -export const floorOpeningMoveVertexAffordance = - createPolygonVertexAffordance('floor-opening') -export const floorOpeningAddVertexAffordance = - createPolygonAddVertexAffordance('floor-opening') -export const floorOpeningMoveEdgeAffordance = - createPolygonMoveEdgeAffordance('floor-opening') -export const floorOpeningDeleteVertexAffordance = - createPolygonDeleteVertexAffordance('floor-opening') +export const floorOpeningMoveVertexAffordance = ownedOr(({ node, payload }) => { + const { vertexIndex } = payload as { vertexIndex: number } + return ownedOpeningSession(node, (rectangle, planPoint) => + resizeRectangleCorner( + rectangle, + vertexIndex % 4, + snapPointToGrid([planPoint[0], planPoint[1]], getSegmentGridStep()), + ), + ) +}, createPolygonVertexAffordance('floor-opening')) +export const floorOpeningAddVertexAffordance = ownedOr( + ({ node }) => inert(node), + createPolygonAddVertexAffordance('floor-opening'), +) +export const floorOpeningMoveEdgeAffordance = ownedOr(({ node, payload, initialPlanPoint }) => { + const { edgeIndex } = payload as { edgeIndex: number } + return ownedOpeningSession(node, (rectangle, planPoint) => { + const start = rectangle[edgeIndex % 4]! + const end = rectangle[(edgeIndex + 1) % 4]! + const opposite = rectangle[(edgeIndex + 2) % 4]! + const length = Math.hypot(end[0] - start[0], end[1] - start[1]) || 1 + let normal: [number, number] = [-(end[1] - start[1]) / length, (end[0] - start[0]) / length] + if ((opposite[0] - start[0]) * normal[0] + (opposite[1] - start[1]) * normal[1] > 0) + normal = [-normal[0], -normal[1]] + const distance = snapScalarToGrid( + (planPoint[0] - initialPlanPoint[0]) * normal[0] + + (planPoint[1] - initialPlanPoint[1]) * normal[1], + getSegmentGridStep(), + ) + return moveRectangleEdge(rectangle, edgeIndex % 4, distance) + }) +}, createPolygonMoveEdgeAffordance('floor-opening')) +export const floorOpeningDeleteVertexAffordance = ownedOr( + ({ node }) => inert(node), + createPolygonDeleteVertexAffordance('floor-opening'), +) diff --git a/packages/nodes/src/i18n/definition-messages.ts b/packages/nodes/src/i18n/definition-messages.ts index c162a8c316..215acf4635 100644 --- a/packages/nodes/src/i18n/definition-messages.ts +++ b/packages/nodes/src/i18n/definition-messages.ts @@ -494,6 +494,7 @@ export const definitionMessages = [ /* i18n */ { id: "editor.toolHint.dropDownspoutFromOutlet.1k4h1m4", message: "Drop downspout from outlet" }, /* i18n */ { id: "editor.toolHint.ductDiameterDownUp.1wdz5vq", message: "Duct diameter down / up" }, /* i18n */ { id: "editor.toolHint.endRunCancel.59dh2w", message: "End run / cancel" }, + /* i18n */ { id: "editor.toolHint.endTheRun.1c1raig", message: "End the run" }, /* i18n */ { id: "editor.toolHint.exit.engmg5", message: "Exit" }, /* i18n */ { id: "editor.toolHint.exitDrawing.9noxyb", message: "Exit drawing" }, /* i18n */ { id: "editor.toolHint.finishAndContinue.1gpfsks", message: "Finish and continue" }, @@ -505,6 +506,8 @@ export const definitionMessages = [ /* i18n */ { id: "editor.toolHint.flipSide.172xku9", message: "Flip side" }, /* i18n */ { id: "editor.toolHint.followTraceALineset.mgquwe", message: "Follow: trace a lineset" }, /* i18n */ { id: "editor.toolHint.forcePlace.1hq1nr", message: "Force place" }, + /* i18n */ { id: "editor.toolHint.freeAngle.1ptblho", message: "Free angle" }, + /* i18n */ { id: "editor.toolHint.freePlace.1s1uusw", message: "Free place" }, /* i18n */ { id: "editor.toolHint.freePlacement.1nztdac", message: "Free placement" }, /* i18n */ { id: "editor.toolHint.goVerticalClickToPlace.dg8g6m", message: "Go vertical ↕, click to place" }, /* i18n */ { id: "editor.toolHint.highlightOutlet.65hoq8", message: "Highlight outlet" }, @@ -526,6 +529,7 @@ export const definitionMessages = [ /* i18n */ { id: "editor.toolHint.key.leftClick.s4gwfc", message: "Left click" }, /* i18n */ { id: "editor.toolHint.key.middleClick.1jbaan4", message: "Middle click" }, /* i18n */ { id: "editor.toolHint.key.rightClick.1ovld0h", message: "Right click" }, + /* i18n */ { id: "editor.toolHint.key.room.1f3jkpm", message: "Room" }, /* i18n */ { id: "editor.toolHint.key.rShiftR.13bnobh", message: "R / Shift+R" }, /* i18n */ { id: "editor.toolHint.key.scroll.ai6wr0", message: "Scroll" }, /* i18n */ { id: "editor.toolHint.key.scrollWheel.18j0ix7", message: "Scroll wheel" }, @@ -533,6 +537,7 @@ export const definitionMessages = [ /* i18n */ { id: "editor.toolHint.key.tab.1xsal0s", message: "Tab" }, /* i18n */ { id: "editor.toolHint.mountFloorCeilingWall.32dxpv", message: "Mount: floor / ceiling / wall" }, /* i18n */ { id: "editor.toolHint.noRoomForTheMatchingWindow.1755948", message: "No room for the matching window on the other wall" }, + /* i18n */ { id: "editor.toolHint.notARectangleDrawThisRoof.100pa5g", message: "Not a rectangle: draw this roof instead" }, /* i18n */ { id: "editor.toolHint.noWallMeetsHere.19n99yc", message: "No wall meets here" }, /* i18n */ { id: "editor.toolHint.numberOfCutsScrollOrClick.1kqe84b", message: "Number of cuts — scroll or click to change" }, /* i18n */ { id: "editor.toolHint.pickWitnessPoint.k3hgh1", message: "Pick witness point" }, @@ -575,16 +580,21 @@ export const definitionMessages = [ /* i18n */ { id: "editor.toolHint.placeUnit.8zkx4q", message: "Place unit" }, /* i18n */ { id: "editor.toolHint.placeWindowOnWall.1k3qnfb", message: "Place window on wall" }, /* i18n */ { id: "editor.toolHint.placeWithoutTheCornerSnap.1nifqew", message: "Place without the corner snap" }, + /* i18n */ { id: "editor.toolHint.pointInsideARoomPorchOr.58w64l", message: "Point inside a room, porch or deck" }, /* i18n */ { id: "editor.toolHint.removeLastPoint.2dmdcx", message: "Remove last point" }, /* i18n */ { id: "editor.toolHint.removeLastWitness.1b6vvzw", message: "Remove last witness" }, + /* i18n */ { id: "editor.toolHint.ridgeDirection.5m1369", message: "Ridge direction" }, + /* i18n */ { id: "editor.toolHint.ridgeDirectionClickOrPressR.1t14dyk", message: "Ridge direction - click or press R to turn it 90°" }, + /* i18n */ { id: "editor.toolHint.ridgeLongSide.ew0euv", message: "Ridge: Long side" }, + /* i18n */ { id: "editor.toolHint.ridgeShortSide.gye8pb", message: "Ridge: Short side" }, /* i18n */ { id: "editor.toolHint.rotate.1thqa0a", message: "Rotate" }, /* i18n */ { id: "editor.toolHint.rotate45.9zq68u", message: "Rotate ±45°" }, /* i18n */ { id: "editor.toolHint.rotate45FloorCeiling.m9t57d", message: "Rotate ±45° (floor / ceiling)" }, /* i18n */ { id: "editor.toolHint.rotateGhost15.rsa52c", message: "Rotate ghost ±15°" }, /* i18n */ { id: "editor.toolHint.rotateOrFlipTheRunSide.t5ior7", message: "Rotate or flip the run side" }, - /* i18n */ { id: "editor.toolHint.rotateRoofDirection90.tvbji2", message: "Rotate roof direction 90°" }, /* i18n */ { id: "editor.toolHint.rotateSpawnPoint.1opcuu7", message: "Rotate spawn point" }, /* i18n */ { id: "editor.toolHint.roundRectangularOval.e4nh6x", message: "Round / rectangular / oval" }, + /* i18n */ { id: "editor.toolHint.setBeamStartEndTheNext.di3bzj", message: "Set beam start / end; the next beam starts there" }, /* i18n */ { id: "editor.toolHint.setFenceStartEnd.1phbwsq", message: "Set fence start / end" }, /* i18n */ { id: "editor.toolHint.setOneCornerThenTheOpposite.8tsl49", message: "Set one corner, then the opposite" }, /* i18n */ { id: "editor.toolHint.setRoofFootprint.p50n0o", message: "Set roof footprint" }, @@ -647,6 +657,8 @@ export const definitionMessages = [ /* i18n */ { id: "editor.toolHint.wasteVent.1hvi3vj", message: "Waste / vent" }, /* i18n */ { id: "editor.toolHint.windowStyleClickOrPressL.ah7qm9", message: "Window style — click or press L to cycle" }, /* i18n */ { id: "editor.toolHint.windowTypeClickOrPressO.wv4x35", message: "Window type — click or press O to cycle" }, + /* i18n */ { id: "node.beam.description", message: "A framing beam drawn end to end: a porch header, a deck beam, a girder." }, + /* i18n */ { id: "node.beam.label", message: "Beam" }, /* i18n */ { id: "node.block.description", message: "A topology-backed solid edited directly in the canvas." }, /* i18n */ { id: "node.block.label", message: "Block" }, /* i18n */ { id: "node.boxVent.description", message: "Small louvered exhaust vent that sits on a roof slope." }, diff --git a/packages/nodes/src/index.ts b/packages/nodes/src/index.ts index 50687c9914..d9b2840ec8 100644 --- a/packages/nodes/src/index.ts +++ b/packages/nodes/src/index.ts @@ -1,4 +1,5 @@ import type { AnyNodeDefinition, Plugin } from '@pascal-app/core' +import { beamDefinition } from './beam' import { blockDefinition } from './block/definition' import { boxVentDefinition } from './box-vent' import { buildingDefinition } from './building' @@ -96,6 +97,7 @@ export const builtinPlugin: Plugin = { // Stage A — wrap-exports the legacy renderer + system. Legacy // panels / move tools / floorplan branches still serve these. columnDefinition as unknown as AnyNodeDefinition, + beamDefinition as unknown as AnyNodeDefinition, elevatorDefinition as unknown as AnyNodeDefinition, unitDefinition as unknown as AnyNodeDefinition, roofDefinition as unknown as AnyNodeDefinition, @@ -137,6 +139,8 @@ export const builtinPlugin: Plugin = { ], } +export { beamDefinition } from './beam' +export { useBeamDraft } from './beam/draft-settings' export { applyBlockCommand, type BlockCommand, @@ -177,6 +181,13 @@ export { export { ceilingDefinition } from './ceiling' export { chimneyDefinition } from './chimney' export { columnDefinition } from './column' +export { + armFramingPostTool, + type FramingPostToolChoices, + framingPostsUnderBeam, + framingPostToolChoices, + framingPostToolDefaults, +} from './column/post-placement' export { constructionDimensionDefinition } from './construction-dimension' export { cupolaDefinition } from './cupola' export { doorDefinition } from './door' diff --git a/packages/nodes/src/roof-segment/build-up-section.tsx b/packages/nodes/src/roof-segment/build-up-section.tsx new file mode 100644 index 0000000000..f46db20b77 --- /dev/null +++ b/packages/nodes/src/roof-segment/build-up-section.tsx @@ -0,0 +1,420 @@ +'use client' + +import { + LUMBER_DEPTH, + type MessageDescriptor, + type PascalI18n, + ROOFING_THICKNESS, + type RoofBuildUp, + type RoofingKind, + type RoofSegmentNode, + roofBuildUpDepths, + roofBuildUpPatch, + UNDERLAYMENT_THICKNESS, + type UnderlaymentKind, + usePascalI18n, +} from '@pascal-app/core' +import { ActionButton, PanelSection, SegmentedControl, SelectControl } from '@pascal-app/editor' +import { useState } from 'react' +import { + BuildUpReadout, + editedBuildUp, + FinishFields, + FramingSizeFields, + formatSpacing, + InsulationFields, + LAYER_KIND_LABELS, + NONE, + PanelFields, +} from '../shared/build-up-controls' +import { formatLayerDepth, formatLayerThickness } from '../shared/layer-thickness' +import { + keptName, + namedLayer, + roofBuildUpOfDeck, + roofBuildUpPresetOptions, + roofBuildUpPresetPatch, + roofBuildUpPresetValue, +} from './panel-model' + +const ROOFING_OPTIONS: { label: MessageDescriptor; value: RoofingKind }[] = [ + { + label: /* i18n */ { + id: 'node.roofSegment.buildUpSection.asphalt3Tab', + message: 'Asphalt 3-tab', + }, + value: 'asphalt-3-tab', + }, + { + label: /* i18n */ { + id: 'node.roofSegment.buildUpSection.architecturalShingle', + message: 'Architectural shingle', + }, + value: 'architectural-shingle', + }, + { + label: /* i18n */ { + id: 'node.roofSegment.buildUpSection.standingSeamMetal', + message: 'Standing-seam metal', + }, + value: 'standing-seam-metal', + }, + { + label: /* i18n */ { + id: 'node.roofSegment.buildUpSection.concreteTile', + message: 'Concrete tile', + }, + value: 'concrete-tile', + }, + { + label: /* i18n */ { id: 'node.roofSegment.buildUpSection.clayTile', message: 'Clay tile' }, + value: 'clay-tile', + }, + { + label: /* i18n */ { id: 'node.roofSegment.buildUpSection.woodShake', message: 'Wood shake' }, + value: 'wood-shake', + }, + { + label: /* i18n */ { id: 'node.roofSegment.buildUpSection.slate', message: 'Slate' }, + value: 'slate', + }, +] + +const UNDERLAYMENT_OPTIONS: { label: MessageDescriptor; value: UnderlaymentKind | typeof NONE }[] = + [ + { + label: /* i18n */ { id: 'node.roofSegment.buildUpSection.none', message: 'None' }, + value: NONE, + }, + { + label: /* i18n */ { id: 'node.roofSegment.buildUpSection.n15Felt', message: '#15 felt' }, + value: 'felt-15', + }, + { + label: /* i18n */ { id: 'node.roofSegment.buildUpSection.n30Felt', message: '#30 felt' }, + value: 'felt-30', + }, + { + label: /* i18n */ { id: 'node.roofSegment.buildUpSection.synthetic', message: 'Synthetic' }, + value: 'synthetic', + }, + { + label: /* i18n */ { + id: 'node.roofSegment.buildUpSection.iceAndWaterShield', + message: 'Ice and water shield', + }, + value: 'ice-and-water', + }, + ] + +/** What each kind is called where the layer has no name of its own. */ +const KIND_LABELS: Record = { + ...Object.fromEntries( + [...ROOFING_OPTIONS, ...UNDERLAYMENT_OPTIONS].map((o) => [o.value, o.label]), + ), + ...LAYER_KIND_LABELS, +} + +const kindLabel = (kind: string, i18n: PascalI18n) => { + const label = KIND_LABELS[kind] + return label ? i18n._(label) : kind +} + +type NamedLayerKey = 'roofing' | 'underlayment' | 'sheathing' | 'insulation' | 'finish' + +/** + * A layer's own name for its material ("GAF Timberline HDZ"), under its kind: the kind's name + * shows until one is typed, and emptied the name goes. + */ +function LayerNameField({ + label, + layer, + onCommit, +}: { + label: string + layer: { kind: string; name?: string } + onCommit: (name: string) => void +}) { + const i18n = usePascalI18n() + const [draft, setDraft] = useState(null) + return ( + + ) +} + +/** A layer as a line of the readout: its name, else its kind's. */ +const layerLabel = (layer: { kind: string; name?: string }, i18n: PascalI18n) => + layer.name ?? kindLabel(layer.kind, i18n) + +/** + * A plane without layers draws its deck and shingle thicknesses as they are. The readout says + * which layers that deck is (`roofBuildUpOfDeck`: the default preset over the framing it holds), + * and "Edit layers" gives the plane those layers to edit. + */ +function DrawnLayers({ + node, + onUpdate, + unit, +}: { + node: RoofSegmentNode + onUpdate: (patch: Partial) => void + unit: 'metric' | 'imperial' +}) { + const i18n = usePascalI18n() + const drawn = roofBuildUpOfDeck(node.deckThickness) + const { structure } = drawn + return ( + <> + + {drawn.underlayment && ( + + )} + + + + + onUpdate(roofBuildUpPatch(drawn))} + /> + + ) +} + +export function RoofBuildUpSection({ + node, + onApplyToRoof, + onUpdate, + unit, +}: { + node: RoofSegmentNode + /** Present when the plane's roof has other planes to take the same layers. */ + onApplyToRoof?: () => void + onUpdate: (patch: Partial) => void + unit: 'metric' | 'imperial' +}) { + const i18n = usePascalI18n() + const buildUp = node.buildUp + const edit = (change: Partial) => { + if (buildUp) onUpdate(roofBuildUpPatch(editedBuildUp(buildUp, change))) + } + // a name is no change of material: the preset the layers came from stays theirs + const rename = (key: NamedLayerKey, name: string) => { + const layer = buildUp?.[key] + if (buildUp && layer) onUpdate(roofBuildUpPatch({ ...buildUp, [key]: namedLayer(layer, name) })) + } + const depths = buildUp ? roofBuildUpDepths(buildUp) : null + + return ( + + { + const patch = roofBuildUpPresetPatch(id) + if (patch) onUpdate(patch) + }} + options={roofBuildUpPresetOptions(roofBuildUpPresetValue(buildUp))} + value={roofBuildUpPresetValue(buildUp)} + /> + {!buildUp && } + {buildUp && depths && ( + <> + edit({ roofing: { kind, thickness: ROOFING_THICKNESS[kind] } })} + options={ROOFING_OPTIONS.map((option) => ({ ...option, label: i18n._(option.label) }))} + value={buildUp.roofing.kind} + /> + rename('roofing', name)} + /> + + edit({ + underlayment: + kind === NONE ? undefined : { kind, thickness: UNDERLAYMENT_THICKNESS[kind] }, + }) + } + options={UNDERLAYMENT_OPTIONS.map((option) => ({ + ...option, + label: i18n._(option.label), + }))} + value={buildUp.underlayment?.kind ?? NONE} + /> + {buildUp.underlayment && ( + rename('underlayment', name)} + /> + )} + + sheathing && edit({ sheathing: keptName(buildUp.sheathing, sheathing) }) + } + unit={unit} + /> + rename('sheathing', name)} + /> + edit({ structure: { ...buildUp.structure, system } })} + options={[ + { + label: i18n._({ + id: 'node.roofSegment.buildUpSection.rafters', + message: 'Rafters', + }), + value: 'rafters', + }, + { + label: i18n._({ + id: 'node.roofSegment.buildUpSection.trusses', + message: 'Trusses', + }), + value: 'trusses', + }, + ]} + value={buildUp.structure.system} + /> + edit({ structure: { ...buildUp.structure, ...change } })} + sizeLabel={ + buildUp.structure.system === 'trusses' + ? i18n._({ id: 'node.roofSegment.buildUpSection.topChord', message: 'Top chord' }) + : i18n._({ id: 'node.roofSegment.buildUpSection.rafters', message: 'Rafters' }) + } + unit={unit} + /> + + edit({ insulation: keptName(buildUp.insulation, insulation) }) + } + unit={unit} + /> + {buildUp.insulation && ( + rename('insulation', name)} + /> + )} + edit({ finish: keptName(buildUp.finish, finish) })} + unit={unit} + /> + {buildUp.finish && ( + rename('finish', name)} + /> + )} + + + {onApplyToRoof && ( + + )} + + )} + + ) +} diff --git a/packages/nodes/src/roof-segment/definition.test.ts b/packages/nodes/src/roof-segment/definition.test.ts index 4ec752d38d..8cceaf9705 100644 --- a/packages/nodes/src/roof-segment/definition.test.ts +++ b/packages/nodes/src/roof-segment/definition.test.ts @@ -1,16 +1,23 @@ -import { describe, expect, test } from 'bun:test' +import { afterEach, describe, expect, test } from 'bun:test' import { + type AnyNode, + type AnyNodeId, + BuildingNode, getActiveRoofHeight, type HandleDescriptor, + LevelNode, type LinearResizeHandle, + nodeRegistry, type RadialResizeHandle, + RoofNode, type RoofSegmentNode, + registerNode, + type SceneApi, + useScene, + WallNode, } from '@pascal-app/core' -import { builtinPlugin } from '@pascal-app/nodes' - -const roofSegmentDefinition = builtinPlugin.nodes.find( - (definition) => definition.kind === 'roof-segment', -)! +import { useEditor, useInteractionScope } from '@pascal-app/editor' +import { roofSegmentDefinition } from './definition' function segment(overrides: Partial = {}): RoofSegmentNode { return { @@ -156,3 +163,115 @@ test('barrel handles preserve rise on span resize and adjust the crown without c expect(getActiveRoofHeight(raised)).toBe(1.5) expect(raised.pitch).toBe(node.pitch) }) + +describe('roof-segment paint: one gable at a time', () => { + const paint = roofSegmentDefinition.capabilities!.paint! + const red = { preset: 'custom', properties: { color: '#aa2222' } } as const + + test('the wall-band slots resolve to the heel band and each gable', () => { + const node = segment({ roofType: 'gable' }) + const role = (materialIndex: number) => paint.resolveRole({ node, materialIndex }) + expect([role(0), role(4), role(5), role(6)]).toEqual([ + 'edge', + 'heel', + 'gable-left', + 'gable-right', + ]) + }) + + test('painting one gable leaves the other gable and the edge role alone', () => { + const node = segment({ roofType: 'gable' }) + const patch = paint.buildPatch({ + node, + role: 'gable-left', + material: red, + }) as Partial + expect(patch).toEqual({ gableLeftMaterial: red, gableLeftMaterialPreset: undefined }) + const painted = { ...node, ...patch } as RoofSegmentNode + expect(paint.getEffectiveMaterial?.({ node: painted, role: 'gable-left' })).toEqual({ + material: red, + materialPreset: undefined, + }) + // the other gable still shows the edge role (here unpainted) + expect(paint.getEffectiveMaterial?.({ node: painted, role: 'gable-right' })).toEqual({ + material: undefined, + materialPreset: undefined, + }) + }) +}) + +describe('roof-segment 3D side arrows onto the walls below', () => { + afterEach(() => { + useInteractionScope.getState().end() + useScene.setState({ nodes: {}, rootNodeIds: [] } as never) + }) + + // A room just off the grid, its roof on the Roof level, wall line x 1..11 by z 0..8. + function scene(mode: 'grid' | 'off', thickness?: number) { + const corners: [number, number][] = [ + [0.2, 0], + [10.2, 0], + [10.2, 8], + [0.2, 8], + ] + const walls = corners.map((start, i) => + WallNode.parse({ parentId: 'level_g', start, end: corners[(i + 1) % 4], thickness }), + ) + const node = segment({ parentId: 'roof_w', position: [0, 0, 0], width: 10, depth: 8 }) + const roof = RoofNode.parse({ + id: 'roof_w', + parentId: 'level_r', + position: [6, 0, 4], + children: [node.id], + }) + const ground = LevelNode.parse({ + id: 'level_g', + parentId: 'building_w', + level: 0, + children: walls.map((wall) => wall.id), + }) + const roofLevel = LevelNode.parse({ + id: 'level_r', + parentId: 'building_w', + level: 1, + children: [roof.id], + }) + const building = BuildingNode.parse({ id: 'building_w', children: [ground.id, roofLevel.id] }) + const nodes = Object.fromEntries( + [building, ground, roofLevel, ...walls, roof, node].map((n) => [n.id, n as AnyNode]), + ) as Record + useScene.setState({ nodes, rootNodeIds: [building.id] } as never) + if (!nodeRegistry.has(roofSegmentDefinition.kind)) registerNode(roofSegmentDefinition) + useEditor.setState((state) => ({ + gridSnapStep: 0.5, + snappingModeByContext: { ...state.snappingModeByContext, polygon: mode }, + })) + useInteractionScope.getState().begin({ kind: 'handle-drag', nodeId: node.id, handle: 'resize' }) + const sceneApi = { + get: (id: AnyNodeId) => nodes[id], + nodes: () => nodes, + } as unknown as SceneApi + return { node, sceneApi } + } + + test('the left arrow lands its side on the wall centre near it, else on the grid', () => { + const { node, sceneApi } = scene('grid') + const snap = linear('x', 'max').connectionSnap! + expect(snap(node, 10.7, sceneApi)).toBeCloseTo(10.8) + expect(snap(node, 10.3, sceneApi)).toBeCloseTo(10.5) + }) + + test('with snapping off the side follows the cursor', () => { + const { node, sceneApi } = scene('off') + expect(linear('x', 'max').connectionSnap!(node, 10.7, sceneApi)).toBeCloseTo(10.7) + }) + + test('sized onto the walls its gable and heel walls take their thickness, off them its own', () => { + const { node, sceneApi } = scene('grid', 0.1826) + const handle = linear('x', 'max') + expect(handle.apply(node, 10.8, sceneApi).wallThickness).toBeCloseTo(0.1826) + // A metre off the walls along z, and its left side pulled in off the wall at x 0.2. + const off = { ...node, position: [0, 0, 1] as [number, number, number] } + expect(handle.apply(off, 9, sceneApi).wallThickness).toBeCloseTo(0.1) + }) +}) diff --git a/packages/nodes/src/roof-segment/definition.ts b/packages/nodes/src/roof-segment/definition.ts index 17024a27eb..b2abad9376 100644 --- a/packages/nodes/src/roof-segment/definition.ts +++ b/packages/nodes/src/roof-segment/definition.ts @@ -1,12 +1,29 @@ import { + type AnyNodeId, getActiveRoofHeight, getPitchFromActiveRoofHeight, getRoofSegmentResizePatch, type HandleDescriptor, type NodeDefinition, + type RoofNode, RoofSegmentNode as RoofSegmentNodeSchema, type RoofSegmentNode as RoofSegmentNodeType, + type SceneApi, + snapScalar, } from '@pascal-app/core' +import { + getSegmentGridStep, + isGridSnapActive, + isMagneticSnapActive, + PANEL_MODEL_EXTENSION, +} from '@pascal-app/editor' +import { roofFloorplanAffectedIds } from '../roof/floorplan-overrides' +import { + bearingWallThickness, + catchRoofSideOnWalls, + roofCatchWalls, + segmentWallLine, +} from '../roof/wall-catch' import { buildRoofSegmentFloorplan } from './floorplan' import { roofSegmentMoveTarget, @@ -15,6 +32,7 @@ import { } from './floorplan-affordances' import { matchRoofSegmentMeasurementFeature, roofSegmentMeasurementFeatures } from './measurement' import { roofSegmentPaint, roofSegmentSlots } from './paint' +import { roofSegmentPanelModel } from './panel-model' import { roofSegmentParametrics } from './parametrics' import { RoofSegmentNode } from './schema' @@ -49,6 +67,49 @@ function getSideResizeHandleY(n: RoofSegmentNodeType, localZ: number): number { return Math.max(roofY, MIN_WALL_DISPLAY) + ROOF_HANDLE_CLEARANCE } +function roofOf(n: RoofSegmentNodeType, sceneApi: SceneApi | undefined): RoofNode | undefined { + const roof = n.parentId ? sceneApi?.get(n.parentId as AnyNodeId) : undefined + return roof?.type === 'roof' ? roof : undefined +} + +// A dragged side lands on a wall under it in grid and lines, ahead of the grid, as a move does. +// The arrows leave `gridSnap` off so the catch sees the raw size, and grid it here when nothing +// catches; Alt skips this hook, so the side follows the cursor. +function snapSideOntoWalls(axis: 'x' | 'z', side: 1 | -1) { + return (n: RoofSegmentNodeType, value: number, sceneApi: SceneApi): number => { + const grid = isGridSnapActive() + if (!grid && !isMagneticSnapActive()) return value + const roof = roofOf(n, sceneApi) + if (roof) { + const caught = catchRoofSideOnWalls({ + line: segmentWallLine(roof, n), + axis, + side, + value, + walls: roofCatchWalls(sceneApi.nodes(), roof.parentId), + }) + if (caught !== null) return caught + } + return grid ? snapScalar(value, getSegmentGridStep()) : value + } +} + +// Sized onto the walls under it, a segment's gable and heel walls take their thickness; off them, +// its own (written either way, so a drag back off the walls drops the thickness it previewed). +function onBearingWalls( + n: RoofSegmentNodeType, + patch: Partial, + sceneApi: SceneApi | undefined, +): Partial { + const roof = roofOf(n, sceneApi) + if (!(roof && sceneApi)) return patch + const thickness = bearingWallThickness( + segmentWallLine(roof, { ...n, ...patch }), + roofCatchWalls(sceneApi.nodes(), roof.parentId), + ) + return { ...patch, wallThickness: thickness ?? n.wallThickness } +} + // Width arrow on the +X (right) or -X (left) side. Asymmetric resize: // dragging one arrow grows the segment outward from its own edge while // the opposite edge stays world-fixed — the same pattern doors use @@ -70,9 +131,10 @@ function roofSegmentWidthHandle(side: 'left' | 'right'): HandleDescriptor n.width, - apply: (initial, newWidth) => getRoofSegmentResizePatch(initial, 'x', sign, newWidth), + apply: (initial, newWidth, sceneApi) => + onBearingWalls(initial, getRoofSegmentResizePatch(initial, 'x', sign, newWidth), sceneApi), placement: { position: (n) => [sign * (n.width / 2 + SIDE_HANDLE_OFFSET), getSideResizeHandleY(n, 0), 0], // Flip the left chevron so it points outward toward -X. The @@ -99,9 +161,10 @@ function roofSegmentDepthHandle(side: 'front' | 'back'): HandleDescriptor n.depth, - apply: (initial, newDepth) => getRoofSegmentResizePatch(initial, 'z', sign, newDepth), + apply: (initial, newDepth, sceneApi) => + onBearingWalls(initial, getRoofSegmentResizePatch(initial, 'z', sign, newDepth), sceneApi), placement: { position: (n) => [ 0, @@ -273,6 +336,9 @@ export const roofSegmentDefinition: NodeDefinition = { // snapping chip and honours the active mode like every other structural // move. Resize / rotate run through their own reshaping scope. snapProfile: 'structural', + extensions: { + [PANEL_MODEL_EXTENSION]: roofSegmentPanelModel, + }, defaults: () => { const stub = RoofSegmentNodeSchema.parse({ @@ -322,6 +388,8 @@ export const roofSegmentDefinition: NodeDefinition = { module: () => import('./renderer'), }, floorplan: buildRoofSegmentFloorplan, + // Its roof draws the outline and creases from it: a live edit rebuilds that roof's plan. + floorplanAffectedIds: roofFloorplanAffectedIds, measurement: { features: (node, ctx) => roofSegmentMeasurementFeatures(node, ctx.parent?.type === 'roof' ? ctx.parent : null), diff --git a/packages/nodes/src/roof-segment/floorplan-affordances.test.ts b/packages/nodes/src/roof-segment/floorplan-affordances.test.ts index f2da90de9c..8fd3790df7 100644 --- a/packages/nodes/src/roof-segment/floorplan-affordances.test.ts +++ b/packages/nodes/src/roof-segment/floorplan-affordances.test.ts @@ -4,17 +4,19 @@ import { type AnyNodeId, BuildingNode, LevelNode, + nodeRegistry, RoofNode, RoofSegmentNode, + registerNode, useLiveNodeOverrides, useScene, WallNode, ZoneNode, } from '@pascal-app/core' +import { useEditor, useInteractionScope } from '@pascal-app/editor' import { builtinPlugin } from '@pascal-app/nodes' - -const roofSegmentResizeAffordance = builtinPlugin.nodes.find((def) => def.kind === 'roof-segment')! - .floorplanAffordances!['roof-segment-resize']! +import { roofSegmentDefinition } from './definition' +import { roofSegmentMoveTarget, roofSegmentResizeAffordance } from './floorplan-affordances' globalThis.requestAnimationFrame ??= (callback) => { callback(0) @@ -25,6 +27,7 @@ globalThis.cancelAnimationFrame ??= () => {} const modifiers = { shiftKey: false, altKey: false, ctrlKey: false, metaKey: false } afterEach(() => { + useInteractionScope.getState().end() useLiveNodeOverrides.getState().clearAll() useScene.setState({ nodes: {}, rootNodeIds: [] } as never) }) @@ -146,3 +149,147 @@ describe('roof-segment floor-plan resize onto the walls', () => { expect(after[segment.id]).toMatchObject({ width: 9 }) }) }) + +describe('roof-segment floor-plan move and resize onto the walls below', () => { + // A room just off the grid, and its roof on the Roof level above, 1 m off to the +x. + function scene(thickness?: number) { + const corners: [number, number][] = [ + [0.2, 0], + [10.2, 0], + [10.2, 8], + [0.2, 8], + ] + const walls = corners.map((start, i) => + WallNode.parse({ + parentId: 'level_g', + start, + end: corners[(i + 1) % 4], + height: 2.7, + thickness, + }), + ) + const segment = RoofSegmentNode.parse({ + id: 'rseg_move', + parentId: 'roof_move', + width: 10, + depth: 8, + }) + const roof = RoofNode.parse({ + id: 'roof_move', + parentId: 'level_r', + position: [6, 0, 4], + children: [segment.id], + }) + const ground = LevelNode.parse({ + id: 'level_g', + parentId: 'building_m', + level: 0, + height: 3, + children: walls.map((wall) => wall.id), + }) + const roofLevel = LevelNode.parse({ + id: 'level_r', + parentId: 'building_m', + level: 1, + metadata: { role: 'roof' }, + children: [roof.id], + }) + const building = BuildingNode.parse({ id: 'building_m', children: [ground.id, roofLevel.id] }) + const nodes = Object.fromEntries( + [building, ground, roofLevel, ...walls, roof, segment].map((node) => [ + node.id, + node as AnyNode, + ]), + ) as Record + useScene.setState({ nodes, rootNodeIds: [building.id] } as never) + if (!nodeRegistry.has(roofSegmentDefinition.kind)) registerNode(roofSegmentDefinition) + useEditor.setState((state) => ({ + gridSnapStep: 0.5, + snappingModeByContext: { ...state.snappingModeByContext, polygon: 'grid' }, + })) + useInteractionScope.getState().begin({ + kind: 'moving', + node: segment, + nodeId: segment.id, + nodeType: segment.type, + view: '2d', + }) + return { nodes, segment } + } + + test('its wall line lands on the wall centres instead of the grid near them', () => { + const { nodes, segment } = scene() + const session = roofSegmentMoveTarget({ node: segment, nodes, sceneApi: {} as never }) + session.apply({ planPoint: [6, 4], modifiers }) + session.apply({ planPoint: [5.15, 4.1], modifiers }) + const position = useLiveNodeOverrides.getState().get(segment.id as AnyNodeId)?.position as + | number[] + | undefined + // Edges at x 0.2 / 10.2 and z 0 / 8: the room's walls, not the grid's 0 / 10. + expect(position?.[0]).toBeCloseTo(-0.8) + expect(position?.[2]).toBeCloseTo(0) + }) + + test('moved onto the walls, its gable and heel walls take their thickness', () => { + const { nodes, segment } = scene(0.1826) + const session = roofSegmentMoveTarget({ node: segment, nodes, sceneApi: {} as never }) + session.apply({ planPoint: [6, 4], modifiers }) + session.apply({ planPoint: [5.15, 4.1], modifiers }) + expect(useLiveNodeOverrides.getState().get(segment.id as AnyNodeId)?.wallThickness).toBeCloseTo( + 0.1826, + ) + // Off the walls again, it goes back to its own. + session.apply({ planPoint: [8, 6], modifiers }) + expect(useLiveNodeOverrides.getState().get(segment.id as AnyNodeId)?.wallThickness).toBeCloseTo( + 0.1, + ) + }) + + test('Alt holds the raw cursor, past the walls and the grid', () => { + const { nodes, segment } = scene() + const session = roofSegmentMoveTarget({ node: segment, nodes, sceneApi: {} as never }) + const alt = { ...modifiers, altKey: true } + session.apply({ planPoint: [6, 4], modifiers: alt }) + session.apply({ planPoint: [5.15, 4.1], modifiers: alt }) + const position = useLiveNodeOverrides.getState().get(segment.id as AnyNodeId)?.position as + | number[] + | undefined + expect(position?.[0]).toBeCloseTo(-0.85) + expect(position?.[2]).toBeCloseTo(0.1) + }) + + // Its wall line runs x 1..11: the -x arrow pulled out to 0.3, near the wall at 0.2. + function pullLeftSide(altKey: boolean, thickness?: number) { + const { nodes, segment } = scene(thickness) + useInteractionScope.getState().end() + useInteractionScope + .getState() + .begin({ kind: 'reshaping', nodeId: segment.id, reshape: 'boundary', driver: 'floorplan' }) + const session = roofSegmentResizeAffordance.start({ + node: segment, + payload: { axis: 'x', side: -1 }, + nodes, + initialPlanPoint: [1, 4], + gridSnapStep: 0.5, + }) + session.apply({ planPoint: [0.3, 4], modifiers: { ...modifiers, altKey } }) + return useLiveNodeOverrides.getState().get(segment.id as AnyNodeId) as + | { width: number; position: number[]; wallThickness?: number } + | undefined + } + + test('a side arrow pulled near a wall lands that side on the wall centre, not the grid', () => { + const live = pullLeftSide(false) + // Grid alone would give 10.5; the wall at x 0.2 gives 10.8, the +x side held at 11. + expect(live?.width).toBeCloseTo(10.8) + expect(live?.position[0]).toBeCloseTo(-0.4) + }) + + test('Alt pulls the side to the raw cursor', () => { + expect(pullLeftSide(true)?.width).toBeCloseTo(10.7) + }) + + test('a side pulled onto the walls gives its gable and heel walls their thickness', () => { + expect(pullLeftSide(false, 0.1826)?.wallThickness).toBeCloseTo(0.1826) + }) +}) diff --git a/packages/nodes/src/roof-segment/floorplan-affordances.ts b/packages/nodes/src/roof-segment/floorplan-affordances.ts index 9f9ae25e69..d407cd568a 100644 --- a/packages/nodes/src/roof-segment/floorplan-affordances.ts +++ b/packages/nodes/src/roof-segment/floorplan-affordances.ts @@ -9,8 +9,21 @@ import { useLiveNodeOverrides, useScene, } from '@pascal-app/core' -import { getSegmentGridStep, isAngleSnapActive, isGridSnapActive } from '@pascal-app/editor' +import { + getSegmentGridStep, + isAngleSnapActive, + isGridSnapActive, + isMagneticSnapActive, +} from '@pascal-app/editor' import { commitSeatedRoofEdit } from '../roof/roof-level-target' +import { + bearingWallThickness, + catchRoofOnWalls, + catchRoofSideOnWalls, + placeRoofOnWalls, + roofCatchWalls, + segmentWallLine, +} from '../roof/wall-catch' import { createFloorplanCursorResolver } from '../shared/floorplan-cursor' import { rotateAffordanceDelta } from '../shared/rotate-affordance' @@ -101,6 +114,16 @@ export const roofSegmentResizeAffordance: FloorplanAffordance = const { axis, side } = resize const initialValue = axis === 'x' ? node.width : node.depth const { effRot } = resolveSegmentFrame(node, nodes) + const roofId = (node as unknown as { parentId?: AnyNodeId | null }).parentId + const roof = roofId ? (nodes[roofId] as RoofNode | undefined) : undefined + const walls = roofCatchWalls(nodes, roof?.parentId) + const line = { + center: [cx, cz] as const, + angle: effRot, + hw: node.width / 2, + hd: node.depth / 2, + wallThickness: node.wallThickness, + } const cosEff = Math.cos(effRot) const sinEff = Math.sin(effRot) // Project (planPoint - center) onto the segment's local X or Z axis @@ -113,23 +136,38 @@ export const roofSegmentResizeAffordance: FloorplanAffordance = } const initialLocal = projectLocalAxis(initialPlanPoint[0], initialPlanPoint[1]) let lastValue = initialValue + // Sized onto the walls under it, its gable and heel walls take their thickness; off them, it + // keeps its own (the live override merges, so it is always written). + const resized = (value: number): Partial => { + const patch = getRoofSegmentResizePatch(node, axis, side, value) + const thickness = bearingWallThickness( + segmentWallLine(roof ?? { position: [0, 0, 0], rotation: 0 }, { ...node, ...patch }), + walls, + ) + return { ...patch, wallThickness: thickness ?? node.wallThickness } + } return { affectedIds: [segmentId], - apply({ planPoint }) { + apply({ planPoint, modifiers }) { const currentLocal = projectLocalAxis(planPoint[0], planPoint[1]) const delta = (currentLocal - initialLocal) * side const rawValue = initialValue + delta // Mode-aware grid step (0 outside grid mode, so `lines` / `off` resize // freely — the "smooth" behaviour that used to need a held Shift). The // reshaping scope opened by the dispatcher resolves the `polygon` set. - const step = isGridSnapActive() ? getSegmentGridStep() : 0 - const snappedValue = step > 0 ? snapScalar(rawValue, step) : rawValue + // Alt holds the raw cursor, as in 3D. + const free = modifiers.altKey + const step = !free && isGridSnapActive() ? getSegmentGridStep() : 0 + let snappedValue = step > 0 ? snapScalar(rawValue, step) : rawValue + // The dragged side lands on a wall under it in grid and lines, as a move does. + if (!free && (isGridSnapActive() || isMagneticSnapActive())) { + snappedValue = + catchRoofSideOnWalls({ line, axis, side, value: rawValue, walls }) ?? snappedValue + } const newValue = Math.max(MIN_ROOF_DIM, snappedValue) lastValue = newValue - useLiveNodeOverrides - .getState() - .set(segmentId, getRoofSegmentResizePatch(node, axis, side, newValue)) + useLiveNodeOverrides.getState().set(segmentId, resized(newValue)) useScene.getState().markDirty(segmentId) }, canCommit() { @@ -137,10 +175,7 @@ export const roofSegmentResizeAffordance: FloorplanAffordance = }, commit() { useLiveNodeOverrides.getState().clear(segmentId) - commitSeatedRoofEdit( - [{ id: segmentId, data: getRoofSegmentResizePatch(node, axis, side, lastValue) }], - segmentId, - ) + commitSeatedRoofEdit([{ id: segmentId, data: resized(lastValue) }], segmentId) }, } }, @@ -198,7 +233,7 @@ export const roofSegmentRotateAffordance: FloorplanAffordance = export const roofSegmentMoveTarget: FloorplanMoveTarget = ({ node, nodes }) => { const segmentId = node.id as AnyNodeId const initialY = node.position[1] - const { cx, cz, roofRot, cosRoof, sinRoof } = resolveSegmentFrame(node, nodes) + const { cx, cz, effRot, cosRoof, sinRoof } = resolveSegmentFrame(node, nodes) const roofId = (node as unknown as { parentId?: AnyNodeId | null }).parentId const roof = roofId ? (nodes[roofId] as RoofNode | undefined) : undefined const roofPosX = roof?.position[0] ?? 0 @@ -207,27 +242,56 @@ export const roofSegmentMoveTarget: FloorplanMoveTarget = ({ no original: [cx, cz], metadata: node.metadata, }) - // Inverse of the forward transform `[cosRoof, -sinRoof; sinRoof, cosRoof]` - // is `[cosRoof, sinRoof; -sinRoof, cosRoof]`. Used to project world cursor - // back into roof-local coords. - void roofRot + const walls = roofCatchWalls(nodes, roof?.parentId) let lastLocal: [number, number, number] = [node.position[0], node.position[1], node.position[2]] + // Off them again, it keeps its own (the live override merges, so it is always written). + let lastThickness = node.wallThickness + const moved = (): Partial => ({ + position: lastLocal, + wallThickness: lastThickness, + }) return { affectedIds: [segmentId], - apply({ planPoint }) { + apply({ planPoint, modifiers }) { // Mode-aware: `getSegmentGridStep()` is 0 outside grid mode (so `lines` / // `off` move freely), and the `moving` scope resolves the `polygon` set - // via the kind's `snapProfile` — no held-Shift bypass. - const step = isGridSnapActive() ? getSegmentGridStep() : 0 + // via the kind's `snapProfile` — no held-Shift bypass. Alt holds the raw cursor, as in 3D. + const free = modifiers.altKey + const step = !free && isGridSnapActive() ? getSegmentGridStep() : 0 const snap = (value: number) => snapScalar(value, step) - const worldPoint = resolveCursor(planPoint, { snap }) + const raw = resolveCursor(planPoint) + let worldPoint = resolveCursor(planPoint, { snap }) + // Its wall line lands on the walls under it in grid and lines, its outer face on a porch's + // invisible walls or a deck's railings. + if (!free && (isGridSnapActive() || isMagneticSnapActive())) { + const caught = catchRoofOnWalls({ + lines: [ + { + center: raw, + angle: effRot, + hw: node.width / 2, + hd: node.depth / 2, + wallThickness: node.wallThickness, + }, + ], + walls, + angle: effRot, + }) + worldPoint = placeRoofOnWalls(raw, worldPoint, caught, effRot) + } const dx = worldPoint[0] - roofPosX const dz = worldPoint[1] - roofPosZ let localX = dx * cosRoof + dz * sinRoof let localZ = -dx * sinRoof + dz * cosRoof lastLocal = [localX, initialY, localZ] - useLiveNodeOverrides.getState().set(segmentId, { position: lastLocal }) + // Moved onto the walls under it, its gable and heel walls take their thickness. + lastThickness = + bearingWallThickness( + { center: worldPoint, angle: effRot, hw: node.width / 2, hd: node.depth / 2 }, + walls, + ) ?? node.wallThickness + useLiveNodeOverrides.getState().set(segmentId, moved()) useScene.getState().markDirty(segmentId) }, canCommit() { @@ -236,7 +300,7 @@ export const roofSegmentMoveTarget: FloorplanMoveTarget = ({ no commit() { useLiveNodeOverrides.getState().clear(segmentId) // Dragged onto the walls that carry it, its roof goes to the level above them. - commitSeatedRoofEdit([{ id: segmentId, data: { position: lastLocal } }], segmentId) + commitSeatedRoofEdit([{ id: segmentId, data: moved() }], segmentId) }, } } diff --git a/packages/nodes/src/roof-segment/floorplan.test.ts b/packages/nodes/src/roof-segment/floorplan.test.ts index 418b161c5d..5b737a018a 100644 --- a/packages/nodes/src/roof-segment/floorplan.test.ts +++ b/packages/nodes/src/roof-segment/floorplan.test.ts @@ -2,6 +2,7 @@ import { describe, expect, test } from 'bun:test' import { type FloorplanGeometry, type GeometryContext, + getRoofSegmentVisibleTopBounds, RoofNode, type RoofSegmentNode, } from '@pascal-app/core' @@ -215,3 +216,37 @@ describe('getRoofSegmentPlanLinework', () => { ]) }) }) + +describe("a selected roof plane's handles", () => { + const roof = RoofNode.parse({ id: 'roof_test', children: ['rseg_test'] }) + const node = dutchSegment({ parentId: roof.id, roofType: 'gable' }) + const geometry = buildRoofSegmentFloorplan(node, { + parent: roof, + viewState: { selected: true }, + } as GeometryContext) as Extract + const eave = getRoofSegmentVisibleTopBounds(node) + + test('the rotate handle sits past the eave corner, sized to a roof', () => { + const rotate = geometry.children.find((child) => child.kind === 'rotate-arrow') + expect(rotate).toMatchObject({ scale: 2 }) + const [x, z] = (rotate as Extract).point + expect(x).toBeGreaterThan(eave.maxX) + expect(z).toBeGreaterThan(eave.maxZ) + }) + + test('the resize arrows sit past the eaves and rakes', () => { + const arrows = geometry.children.filter( + (child): child is Extract => + child.kind === 'move-arrow', + ) + expect(arrows).toHaveLength(4) + for (const { point } of arrows) { + expect( + point[0] > eave.maxX || + point[0] < eave.minX || + point[1] > eave.maxZ || + point[1] < eave.minZ, + ).toBe(true) + } + }) +}) diff --git a/packages/nodes/src/roof-segment/floorplan.ts b/packages/nodes/src/roof-segment/floorplan.ts index 2034c115e0..cc9dd6eb55 100644 --- a/packages/nodes/src/roof-segment/floorplan.ts +++ b/packages/nodes/src/roof-segment/floorplan.ts @@ -4,6 +4,7 @@ import { type GeometryContext, getConicalRoofCoverage, getDutchRoofMetrics, + getRoofSegmentVisibleTopBounds, type RoofNode, type RoofSegmentNode, } from '@pascal-app/core' @@ -68,7 +69,8 @@ export function buildRoofSegmentFloorplan( const palette = view?.palette const isSelected = view?.selected ?? false const isHighlighted = view?.highlighted ?? false - const showSelectedChrome = isSelected || isHighlighted + // Moved too: the wall line shows whether it lands on the walls' centre lines. + const showSelectedChrome = isSelected || isHighlighted || (view?.moving ?? false) // Black architectural outline by default; palette accent on select. // Mirrors the elevator / column style so all structural elements read @@ -154,9 +156,8 @@ export function buildRoofSegmentFloorplan( }) const sideArrowOffset = 0.12 - const rotateCornerOffset = 0.22 + const rotateCornerOffset = 0.3 const halfW = node.width / 2 - const halfD = node.depth / 2 // Effective rotation = parent roof rotation + segment-local rotation. // Reuse `cos` / `sin` from the corner computation above (they were // computed for the same `rotation` value). @@ -175,16 +176,18 @@ export function buildRoofSegmentFloorplan( payload: { mode: 'radial' }, }) } else { + // Past the eaves and rakes the plan outlines, so the arrows sit clear of the roof's edge. + const eave = getRoofSegmentVisibleTopBounds(node) const sides: Array<{ local: [number, number] localAngle: number axis: 'x' | 'z' side: 1 | -1 }> = [ - { local: [halfW + sideArrowOffset, 0], localAngle: 0, axis: 'x', side: 1 }, - { local: [-(halfW + sideArrowOffset), 0], localAngle: Math.PI, axis: 'x', side: -1 }, - { local: [0, halfD + sideArrowOffset], localAngle: Math.PI / 2, axis: 'z', side: 1 }, - { local: [0, -(halfD + sideArrowOffset)], localAngle: -Math.PI / 2, axis: 'z', side: -1 }, + { local: [eave.maxX + sideArrowOffset, 0], localAngle: 0, axis: 'x', side: 1 }, + { local: [eave.minX - sideArrowOffset, 0], localAngle: Math.PI, axis: 'x', side: -1 }, + { local: [0, eave.maxZ + sideArrowOffset], localAngle: Math.PI / 2, axis: 'z', side: 1 }, + { local: [0, eave.minZ - sideArrowOffset], localAngle: -Math.PI / 2, axis: 'z', side: -1 }, ] for (const side of sides) { const [ox, oz] = rotateLocal(side.local[0], side.local[1]) @@ -199,11 +202,15 @@ export function buildRoofSegmentFloorplan( } } - // Rotate-arrow at the +X / +Z corner. Local angle π/4 puts the - // curved arrow's bow at the diagonal corner so it reads as a - // rotation gizmo around the segment centre. + // Rotate-arrow off the +X / +Z corner of the eaves, clear of the plan's + // outline, sized to a roof. Local angle π/4 puts the curved arrow's bow + // on the diagonal so it reads as a rotation gizmo around the centre. if (node.roofType !== 'conical') { - const [cornerX, cornerZ] = rotateLocal(halfW + rotateCornerOffset, halfD + rotateCornerOffset) + const eave = getRoofSegmentVisibleTopBounds(node) + const [cornerX, cornerZ] = rotateLocal( + eave.maxX + rotateCornerOffset, + eave.maxZ + rotateCornerOffset, + ) const [radialX, radialZ] = rotateLocal(1, 1) children.push({ kind: 'rotate-arrow', @@ -211,6 +218,7 @@ export function buildRoofSegmentFloorplan( angle: Math.atan2(radialZ, radialX), affordance: 'roof-segment-rotate', pivot: [cx, cz], + scale: 2, }) } } diff --git a/packages/nodes/src/roof-segment/multi-layers.test.ts b/packages/nodes/src/roof-segment/multi-layers.test.ts new file mode 100644 index 0000000000..c08bff77f9 --- /dev/null +++ b/packages/nodes/src/roof-segment/multi-layers.test.ts @@ -0,0 +1,110 @@ +import { afterEach, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + LUMBER_DEPTH, + ROOF_BUILD_UP_PRESETS, + RoofSegmentNode, + roofBuildUpDepths, + roofBuildUpPatch, + useScene, +} from '@pascal-app/core' +import { getNodePanelModel, type MultiPanelControl } from '@pascal-app/editor' +import { roofSegmentDefinition } from './definition' +import { keptName, namedLayer, roofBuildUpOfDeck, roofBuildUpPresetValue } from './panel-model' + +globalThis.requestAnimationFrame ??= () => 0 +globalThis.cancelAnimationFrame ??= () => {} + +const originalState = useScene.getState() +afterEach(() => useScene.setState(originalState)) + +type Choice = Extract + +const load = (nodes: AnyNode[]) => { + useScene.setState({ + nodes: Object.fromEntries(nodes.map((n) => [n.id, n])) as Record, + rootNodeIds: [], + }) + useScene.temporal.getState().clear() + useScene.temporal.getState().resume() +} +const current = (nodes: T[]) => + nodes.map((n) => useScene.getState().nodes[n.id as AnyNodeId] as T) + +test('multi-selected roof planes take one layers preset, their deck and covering with it, in one step', () => { + const planes = [RoofSegmentNode.parse({}), RoofSegmentNode.parse({ deckThickness: 0.2 })] + load(planes) + const [preset] = getNodePanelModel(roofSegmentDefinition)!.multiControls!({ + selection: planes, + nodes: useScene.getState().nodes, + }) as Choice[] + expect(preset).toMatchObject({ section: 'Layers', value: 'none' }) + const chosen = ROOF_BUILD_UP_PRESETS[2]! + preset!.onChange(chosen.id) + expect(useScene.temporal.getState().pastStates).toHaveLength(1) + const { deck, covering } = roofBuildUpDepths(chosen.buildUp) + for (const plane of current(planes)) { + expect(plane.buildUp).toEqual(chosen.buildUp) + expect([plane.deckThickness, plane.shingleThickness]).toEqual([deck, covering]) + } + preset!.onChange('none') + for (const plane of current(planes)) expect(plane.buildUp).toBeUndefined() +}) + +test("a layer's own name rides the plane: through the schema, a save and the preset it came from; emptied it goes", () => { + const preset = ROOF_BUILD_UP_PRESETS[0]!.buildUp + const named = { ...preset, roofing: namedLayer(preset.roofing, ' GAF Timberline HDZ ') } + const plane = RoofSegmentNode.parse(roofBuildUpPatch(named)) + expect(plane.buildUp?.roofing).toEqual({ ...preset.roofing, name: 'GAF Timberline HDZ' }) + // a name is no change of material: still the preset + expect(roofBuildUpPresetValue(plane.buildUp)).toBe(preset.presetId!) + expect([plane.deckThickness, plane.shingleThickness]).toEqual([ + roofBuildUpDepths(preset).deck, + roofBuildUpDepths(preset).covering, + ]) + expect(RoofSegmentNode.parse(JSON.parse(JSON.stringify(plane))).buildUp).toEqual(plane.buildUp) + // emptied, the kind's own name stands for it again + expect(namedLayer(plane.buildUp!.roofing, ' ')).toEqual(preset.roofing) + expect(namedLayer(preset.roofing, 'x'.repeat(80)).name).toHaveLength(60) + expect(() => + RoofSegmentNode.parse( + roofBuildUpPatch({ ...preset, roofing: { ...preset.roofing, name: 'x'.repeat(61) } }), + ), + ).toThrow() + // a new thickness of the same panel keeps its name; another material does not + const sheathing = namedLayer(preset.sheathing, 'AdvanTech') + expect(keptName(sheathing, { kind: 'osb' as const, thickness: 0.0127 })).toEqual({ + kind: 'osb', + thickness: 0.0127, + name: 'AdvanTech', + }) + expect(keptName(sheathing, { kind: 'plywood' as const, thickness: 0.0127 })).toEqual({ + kind: 'plywood', + thickness: 0.0127, + }) +}) + +test('a plane without layers reads as the layers its deck holds, which Edit layers writes with its deck', () => { + const preset = ROOF_BUILD_UP_PRESETS[0]!.buildUp + // the default trusses on their heel, and the schema's 0.100 m deck: one chord before the heel + // counted, which Edit layers deepens to the heel + expect(roofBuildUpOfDeck(roofBuildUpDepths(preset).deck)).toBe(preset) + expect(roofBuildUpOfDeck(RoofSegmentNode.parse({}).deckThickness)).toBe(preset) + expect(roofBuildUpDepths(preset).deck).toBeCloseTo( + 2 * LUMBER_DEPTH['2x4'] + preset.sheathing.thickness, + 9, + ) + // a generated roof's 2x6 rafters and their sheathing + const generated = LUMBER_DEPTH['2x6'] + preset.sheathing.thickness + const layers = roofBuildUpOfDeck(generated) + expect(layers.structure).toEqual({ + system: 'rafters', + size: '2x6', + spacing: preset.structure.spacing, + }) + expect(layers.presetId).toBeUndefined() + expect(roofBuildUpDepths(layers).deck).toBeCloseTo(generated, 9) + // a deck no framing makes reads as the default preset + expect(roofBuildUpOfDeck(0.25)).toBe(preset) +}) diff --git a/packages/nodes/src/roof-segment/paint.ts b/packages/nodes/src/roof-segment/paint.ts index 9044248a4a..b69a9db103 100644 --- a/packages/nodes/src/roof-segment/paint.ts +++ b/packages/nodes/src/roof-segment/paint.ts @@ -3,9 +3,12 @@ import { getEffectiveRoofSurfaceMaterial, getEffectiveSegmentSurfaceMaterial, getRoofGlazing, + getRoofWallBandMaterial, isGlazedRoofSegment, type PaintCapability, type RoofSegmentNode, + type RoofWallBand, + roofWallBandFields, sceneRegistry, useScene, } from '@pascal-app/core' @@ -52,10 +55,37 @@ const glazingPaint = createSlotPaintCapability({ }, }) +// Slots 4–6 are the wall bands split off the wall/trim slot (the viewer's `ROOF_HEEL_MATERIAL_INDEX`…). +const WALL_BAND_BY_INDEX: Record = { + 4: 'heel', + 5: 'gable-left', + 6: 'gable-right', +} +const WALL_BAND_LABELS: Record = { + heel: 'Heel band', + 'gable-left': 'Left gable', + 'gable-right': 'Right gable', +} + function standardRole(index: number | null) { + if (index !== null && WALL_BAND_BY_INDEX[index]) return WALL_BAND_BY_INDEX[index] return index === 3 ? 'top' : index === 0 ? 'edge' : index === 1 || index === 2 ? 'wall' : null } +function isWallBand(role: string): role is RoofWallBand { + return role === 'heel' || role === 'gable-left' || role === 'gable-right' +} + +/** A heel or gable paints on its own: its own finish, cleared back to its fallback by the eraser. */ +export function wallBandPatch( + band: RoofWallBand, + material: RoofSegmentNode['material'], + materialPreset: string | undefined, +): Partial { + const fields = roofWallBandFields(band) + return { [fields.material]: material, [fields.materialPreset]: materialPreset } +} + export const roofSegmentPaint: PaintCapability = { materialTarget: 'roof', resolveRole(args) { @@ -63,9 +93,15 @@ export const roofSegmentPaint: PaintCapability = { ? glazingPaint.resolveRole(args) : standardRole(args.materialIndex) }, + roleLabel(node, role) { + return isWallBand(role) && !isGlazedRoofSegment(node as RoofSegmentNode) + ? WALL_BAND_LABELS[role] + : null + }, buildPatch(args) { if (isGlazedRoofSegment(args.node as RoofSegmentNode)) return glazingPaint.buildPatch(args) const role = args.role + if (isWallBand(role)) return wallBandPatch(role, args.material, args.materialPreset) if (role !== 'top' && role !== 'edge' && role !== 'wall') return {} return buildRoofSegmentSurfaceMaterialPatch( args.node as RoofSegmentNode, @@ -93,8 +129,24 @@ export const roofSegmentPaint: PaintCapability = { const node = args.node as RoofSegmentNode if (isGlazedRoofSegment(node)) return glazingPaint.getEffectiveMaterial?.(args) ?? null const role = args.role - if (role !== 'top' && role !== 'edge' && role !== 'wall') return null const parent = node.parentId ? args.nodes?.[node.parentId as AnyNodeId] : undefined + if (isWallBand(role)) { + // Unpainted, a gable shows the edge role and the heel band the roof's (else the walls'). + const own = + getRoofWallBandMaterial(node, role) ?? + (role === 'heel' && parent?.type === 'roof' + ? getRoofWallBandMaterial(parent, 'heel') + : null) + if (own) return { material: own.material, materialPreset: own.materialPreset } + if (role === 'heel') return null + const edge = getEffectiveSegmentSurfaceMaterial( + node, + 'edge', + parent?.type === 'roof' ? getEffectiveRoofSurfaceMaterial(parent, 'edge') : undefined, + ) + return { material: edge.material, materialPreset: edge.materialPreset } + } + if (role !== 'top' && role !== 'edge' && role !== 'wall') return null const spec = getEffectiveSegmentSurfaceMaterial( node, role, diff --git a/packages/nodes/src/roof-segment/panel-model.ts b/packages/nodes/src/roof-segment/panel-model.ts new file mode 100644 index 0000000000..1dc790d130 --- /dev/null +++ b/packages/nodes/src/roof-segment/panel-model.ts @@ -0,0 +1,83 @@ +import { + type AnyNodeId, + isGlazedRoofSegment, + ROOF_BUILD_UP_PRESETS, + type RoofBuildUp, + type RoofSegmentNode, + roofBuildUpPatch, + runAsSingleSceneHistoryStep, + useScene, +} from '@pascal-app/core' +import type { NodePanelModel } from '@pascal-app/editor' + +const NONE = 'none' +const CUSTOM = 'custom' + +/** The Preset choices for the `current` value: none, the presets, and Custom while it is. */ +export function roofBuildUpPresetOptions(current: string | null) { + return [ + { label: 'None (deck and shingle)', value: NONE }, + ...(current === CUSTOM ? [{ label: 'Custom', value: CUSTOM }] : []), + ...ROOF_BUILD_UP_PRESETS.map((preset) => ({ label: preset.label, value: preset.id })), + ] +} + +export function roofBuildUpPresetValue(buildUp: RoofBuildUp | undefined): string { + return buildUp ? (buildUp.presetId ?? CUSTOM) : NONE +} + +/** The patch a Preset choice writes; `null` for Custom, which is no choice. */ +export function roofBuildUpPresetPatch(id: string): Partial | null { + if (id === NONE) return { buildUp: undefined } + const preset = ROOF_BUILD_UP_PRESETS.find((entry) => entry.id === id) + return preset ? roofBuildUpPatch(preset.buildUp) : null +} + +// The layers a plane without any is drawn as live in core, where Bones frames such a plane by them. +export { roofBuildUpOfDeck } from '@pascal-app/core' + +/** A layer with `name`, trimmed; empty takes the name off, the kind's own name standing for it. */ +export function namedLayer(layer: T, name: string): T { + const { name: _name, ...rest } = layer + const trimmed = name.trim().slice(0, 60) + return (trimmed ? { ...rest, name: trimmed } : rest) as T +} + +/** `next` keeps `previous`'s name while it is the same kind of material (a new thickness, say). */ +export function keptName( + previous: T | undefined, + next: T | undefined, +): T | undefined { + if (!next || next.name !== undefined || previous?.name === undefined) return next + return next.kind === previous.kind ? { ...next, name: previous.name } : next +} + +/** Multi-selected planes take one layers preset together, in one undo step. */ +export const roofSegmentPanelModel: NodePanelModel = { + rows: () => [], + multiControls: ({ selection }) => { + const planes = selection.filter((plane) => !isGlazedRoofSegment(plane)) + if (planes.length === 0) return [] + const values = planes.map((plane) => roofBuildUpPresetValue(plane.buildUp)) + const value = values.every((entry) => entry === values[0]) ? values[0]! : null + return [ + { + id: 'roof-segment-layers-preset', + kind: 'select', + section: 'Layers', + label: 'Preset', + options: roofBuildUpPresetOptions(value), + value, + onChange: (id) => { + const patch = roofBuildUpPresetPatch(id) + if (!patch) return + runAsSingleSceneHistoryStep(useScene, () => + useScene + .getState() + .updateNodes(planes.map((plane) => ({ id: plane.id as AnyNodeId, data: patch }))), + ) + }, + }, + ] + }, +} diff --git a/packages/nodes/src/roof-segment/panel.tsx b/packages/nodes/src/roof-segment/panel.tsx index bb521f9896..2332c4cc0f 100644 --- a/packages/nodes/src/roof-segment/panel.tsx +++ b/packages/nodes/src/roof-segment/panel.tsx @@ -14,9 +14,12 @@ import { type MessageDescriptor, normalizeRoofSegmentTrim, ROOF_SHAPE_DEFAULTS, + type RoofEaveCut, type RoofSegmentNode, type RoofSegmentTrim, type RoofType, + roofBuildUpPatch, + roofSegmentEaveProfile, roofTypeHasRakes, usePascalI18n, useScene, @@ -39,6 +42,7 @@ import { useCallback } from 'react' import { BarrelRoofPanel } from '../roof/barrel-panel' import { RoofGlazingPanel } from '../roof/glazing-panel' import { commitSeatedRoofEdit } from '../roof/roof-level-target' +import { RoofBuildUpSection } from './build-up-section' const ROOF_TYPE_OPTIONS: { label: MessageDescriptor; value: RoofType }[] = [ { label: /* i18n */ { id: 'node.roofSegment.panel.hip', message: 'Hip' }, value: 'hip' }, @@ -67,6 +71,19 @@ const ROOF_TYPE_OPTIONS_3: { label: MessageDescriptor; value: RoofType }[] = [ { label: /* i18n */ { id: 'node.roofSegment.panel.barrel', message: 'Barrel' }, value: 'barrel' }, ] +// How the rafter tails are cut at the eaves, the fascia and soffit with them (core's `roofEaveProfile`). +const EAVE_CUT_OPTIONS: { label: MessageDescriptor; value: RoofEaveCut }[] = [ + { label: /* i18n */ { id: 'node.roofSegment.panel.plumb', message: 'Plumb' }, value: 'plumb' }, + { label: /* i18n */ { id: 'node.roofSegment.panel.square', message: 'Square' }, value: 'square' }, + { + label: /* i18n */ { id: 'node.roofSegment.panel.plumbLevel', message: 'Plumb + level' }, + value: 'plumb-level', + }, +] + +/** The sloped forms whose tails are cut at their eaves by the plane's eave cut. */ +const EAVE_CUT_ROOF_TYPES: ReadonlySet = new Set(['gable', 'hip', 'shed']) + // Carpenter / roofer convention: rise over a 12" run, converted to degrees. // atan(3/12) ≈ 14.04°, atan(6/12) ≈ 26.57°, atan(9/12) ≈ 36.87°, atan(12/12) = 45°. const PITCH_PRESETS: { label: string; deg: number }[] = [ @@ -95,6 +112,17 @@ const EMPTY_TRIM: RoofSegmentTrim = { backRightZ: 0, } +/** The planes of a roof that take layers: its segments, glazed ones aside. */ +function roofLayerPlaneIds( + children: readonly string[], + nodes: Record, +): AnyNodeId[] { + return children.filter((id) => { + const child = nodes[id as AnyNodeId] + return child?.type === 'roof-segment' && !isGlazedRoofSegment(child) + }) as AnyNodeId[] +} + function hasSegmentTrim(node: RoofSegmentNode): boolean { return Object.values(normalizeRoofSegmentTrim(node)).some((value) => value > 0) } @@ -122,6 +150,7 @@ export default function RoofSegmentPanel() { const updateNode = useScene((s) => s.updateNode) const setMovingNode = useEditor((s) => s.setMovingNode) const setRoofHostDragArmedId = useEditor((s) => s.setRoofHostDragArmedId) + const unit = useViewer((s) => s.unit) const node = useScene((s) => selectedId ? (s.nodes[selectedId as AnyNode['id']] as RoofSegmentNode | undefined) : undefined, @@ -133,6 +162,14 @@ export default function RoofSegmentPanel() { if (current?.type !== 'roof-segment') return false return isAutoRidgeVentEnabled(current, s.nodes) }) + // How many planes of this roof take layers: "Apply to all planes" shows once there are two. + const roofPlaneCount = useScene((s) => { + const current = selectedId + ? (s.nodes[selectedId as AnyNode['id']] as RoofSegmentNode | undefined) + : undefined + const roof = current?.parentId ? s.nodes[current.parentId as AnyNodeId] : undefined + return roof?.type === 'roof' ? roofLayerPlaneIds(roof.children, s.nodes).length : 0 + }) const autoGutterEnabled = useScene((s) => { const current = selectedId ? (s.nodes[selectedId as AnyNode['id']] as RoofSegmentNode | undefined) @@ -153,6 +190,18 @@ export default function RoofSegmentPanel() { [selectedId], ) + const handleApplyToRoof = useCallback(() => { + const scene = useScene.getState() + const current = selectedId ? scene.nodes[selectedId as AnyNodeId] : undefined + if (current?.type !== 'roof-segment' || !current.buildUp) return + const roof = current.parentId ? scene.nodes[current.parentId as AnyNodeId] : undefined + if (roof?.type !== 'roof') return + const patch = roofBuildUpPatch(current.buildUp) + scene.updateNodes( + roofLayerPlaneIds(roof.children, scene.nodes).map((id) => ({ id, data: patch })), + ) + }, [selectedId]) + const handleRoofTypeChange = useCallback( (roofType: RoofType) => { if (isManagedLeanToRoofSegment(node?.metadata)) return @@ -679,7 +728,8 @@ export default function RoofSegmentPanel() { unit="m" value={node.wallThickness} /> - {!isGlazedRoofSegment(node) && ( + {/* With layers, the Layers section sets it and shows it. */} + {!(isGlazedRoofSegment(node) || node.buildUp) && ( )} - {!isGlazedRoofSegment(node) && ( + {!(isGlazedRoofSegment(node) || node.buildUp) && ( )} + {EAVE_CUT_ROOF_TYPES.has(node.roofType) && node.pitch > 0 && ( +
+
+ {i18n._({ id: 'node.roofSegment.panel.eaveCut', message: 'Eave cut' })} +
+ handleUpdate({ eaveCut: v })} + options={EAVE_CUT_OPTIONS.map((option) => ({ + ...option, + label: i18n._(option.label), + }))} + value={node.eaveCut ?? 'plumb'} + /> +
+ )} )}
+ {!isGlazedRoofSegment(node) && ( + 1 ? handleApplyToRoof : undefined} + onUpdate={handleUpdate} + unit={unit} + /> + )} + = { min: 0.04, max: 0.3, step: 0.01, + // Layers set it: edited here it would part from them. + visibleIf: (node) => !node.buildUp, }, { key: 'overhang', kind: 'number', unit: 'm', min: 0, max: 1, step: 0.05 }, { @@ -161,6 +163,8 @@ export const roofSegmentParametrics: ParametricDescriptor = { min: 0.02, max: 0.3, step: 0.01, + // Layers set it: edited here it would part from them. + visibleIf: (node) => !node.buildUp, }, { key: 'wallShell', diff --git a/packages/nodes/src/roof-segment/renderer.tsx b/packages/nodes/src/roof-segment/renderer.tsx index 779f20e069..d9603838c6 100644 --- a/packages/nodes/src/roof-segment/renderer.tsx +++ b/packages/nodes/src/roof-segment/renderer.tsx @@ -5,6 +5,7 @@ import { getEffectiveNode, getEffectiveRoofSurfaceMaterial, getEffectiveSegmentSurfaceMaterial, + getRoofWallBandMaterial, getSegmentFasciaMaterial, isGlazedRoofSegment, type RoofNode, @@ -18,6 +19,7 @@ import { createMaterial, getRoofMaterialArray, levelWallCladdingRef, + levelWallFaceRef, resolveMaterialRef, SHADOW_ONLY_LAYER, useNodeEvents, @@ -76,10 +78,15 @@ export const RoofSegmentRenderer = ({ node: storedNode }: { node: RoofSegmentNod // slot 1 → 'wall' (deck top & shingle eave bands) // slot 2 → 'wall' (interior) // slot 3 → 'top' (shingle / roof surface) + // slot 4 → the heel band (its own, the roof's, else the walls' below) + // slot 5 / 6 → the left / right gable (its own, else slot 0's) // The gable band is clad like the walls below it (their assemblies). const wallCladdingRef = useScene((state) => parentNode ? levelWallCladdingRef(state.nodes, parentNode) : null, ) + const wallFaceRef = useScene((state) => + parentNode ? levelWallFaceRef(state.nodes, parentNode) : null, + ) // biome-ignore lint/correctness/useExhaustiveDependencies: deps deliberately list the build inputs; depending on the whole object would rebuild on unrelated field changes. const customMaterial = useMemo(() => { const resolveSlot = (role: RoofSegmentSurfaceMaterialRole): THREE.Material | null => { @@ -104,9 +111,19 @@ export const RoofSegmentRenderer = ({ node: storedNode }: { node: RoofSegmentNod sceneTheme, wallCladdingRef, sceneMaterials, + wallFaceRef, ) : null + const resolveSpec = (spec: ReturnType) => + spec + ? (resolveMaterialRef(spec.materialPreset, sceneMaterials, shading) ?? + (spec.material !== undefined ? createMaterial(spec.material, shading) : null)) + : null + const heel = resolveSpec(getRoofWallBandMaterial(node, 'heel')) + const gableLeft = resolveSpec(getRoofWallBandMaterial(node, 'gable-left')) + const gableRight = resolveSpec(getRoofWallBandMaterial(node, 'gable-right')) + const edge = resolveSlot('edge') const wall = resolveSlot('wall') const top = resolveSlot('top') @@ -117,7 +134,7 @@ export const RoofSegmentRenderer = ({ node: storedNode }: { node: RoofSegmentNod (fasciaSpec.material !== undefined ? createMaterial(fasciaSpec.material, shading) : null)) : null - if (!(edge || wall || top || fascia)) { + if (!(edge || wall || top || fascia || heel || gableLeft || gableRight)) { return themedArray } @@ -126,11 +143,15 @@ export const RoofSegmentRenderer = ({ node: storedNode }: { node: RoofSegmentNod // Per-role only, then the themed parent slot — no cross-role fallback, so // painting one segment surface never bleeds onto its other surfaces. const slot = (i: number) => themedArray?.[i] ?? new THREE.MeshStandardMaterial() + const trim = edge ?? slot(0) return [ - edge ?? slot(0), + trim, wall ?? slot(1), fascia ?? wall ?? slot(2), top ?? slot(3), + heel ?? slot(4), + gableLeft ?? trim, + gableRight ?? trim, ] as THREE.Material[] }, [ node.material, @@ -144,6 +165,13 @@ export const RoofSegmentRenderer = ({ node: storedNode }: { node: RoofSegmentNod node.wallMaterialPreset, node.fasciaMaterial, node.fasciaMaterialPreset, + node.heelMaterial, + node.heelMaterialPreset, + node.gableLeftMaterial, + node.gableLeftMaterialPreset, + node.gableRightMaterial, + node.gableRightMaterialPreset, + wallFaceRef, parentNode, sceneMaterials, shading, diff --git a/packages/nodes/src/roof/definition.test.ts b/packages/nodes/src/roof/definition.test.ts index 3364bd07e8..1a49078d02 100644 --- a/packages/nodes/src/roof/definition.test.ts +++ b/packages/nodes/src/roof/definition.test.ts @@ -1,7 +1,16 @@ -import { describe, expect, test } from 'bun:test' -import type { HandleDescriptor, RoofNode } from '@pascal-app/core' +import { afterEach, beforeEach, describe, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + getEffectiveRoofSurfaceMaterial, + type HandleDescriptor, + type RoofNode, + type RoofSegmentNode, + RoofSegmentNode as RoofSegmentSchema, + useScene, +} from '@pascal-app/core' +import { useEditor } from '@pascal-app/editor' import { roofDefinition } from './definition' -import useRoofPlacementMode from './roof-placement-mode' function roof(overrides: Partial = {}): RoofNode { return { @@ -73,14 +82,23 @@ describe('roof tool registration', () => { const placementHint = roofDefinition.toolHints?.find((hint) => hint.key === 'P') const rotationHint = roofDefinition.toolHints?.find((hint) => hint.key === 'R') - useRoofPlacementMode.setState({ conical: false, mode: 'auto' }) - expect(placementHint?.visible?.value()).toBe(false) - expect(rotationHint?.visible?.value()).toBe(true) + const previousDefaults = useEditor.getState().toolDefaults + let changes = 0 + const unsubscribe = placementHint?.visible?.subscribe(() => changes++) + try { + useEditor.getState().setToolDefaults('roof', { roofType: 'gable' }) + expect(placementHint?.visible?.value()).toBe(false) + expect(rotationHint?.visible?.value()).toBe(true) - useRoofPlacementMode.setState({ conical: true }) - expect(placementHint?.visible?.value()).toBe(true) - expect(rotationHint?.visible?.value()).toBe(false) - useRoofPlacementMode.setState({ conical: false, mode: 'auto' }) + // Armed with a cone and no tool mounted yet, as in a 2D-only session. + useEditor.getState().setToolDefaults('roof', { roofType: 'conical' }) + expect(placementHint?.visible?.value()).toBe(true) + expect(rotationHint?.visible?.value()).toBe(false) + expect(changes).toBe(1) + } finally { + unsubscribe?.() + useEditor.setState({ toolDefaults: previousDefaults }) + } }) }) @@ -93,3 +111,82 @@ describe('roof assembly host', () => { expect(host?.body(roof())).toBeNull() }) }) + +describe('roof paint: gables on the merged shell', () => { + const paint = roofDefinition.capabilities!.paint! + const red = { preset: 'custom', properties: { color: '#aa2222' } } as const + let previousRaf: typeof requestAnimationFrame + let previousCancelRaf: typeof cancelAnimationFrame + + beforeEach(() => { + previousRaf = globalThis.requestAnimationFrame + previousCancelRaf = globalThis.cancelAnimationFrame + globalThis.requestAnimationFrame = () => 0 + globalThis.cancelAnimationFrame = () => {} + }) + + afterEach(() => { + useScene.getState().unloadScene() + useScene.temporal.getState().clear() + globalThis.requestAnimationFrame = previousRaf + globalThis.cancelAnimationFrame = previousCancelRaf + }) + + function seed() { + const left = RoofSegmentSchema.parse({ + id: 'rseg_left', + type: 'roof-segment', + parentId: 'roof_test', + roofType: 'gable', + gableLeftMaterialPreset: 'library:brick', + }) + const right = RoofSegmentSchema.parse({ + id: 'rseg_right', + type: 'roof-segment', + parentId: 'roof_test', + roofType: 'gable', + }) + const node = roof({ children: [left.id, right.id] as RoofNode['children'] }) + useScene.setState({ + nodes: Object.fromEntries( + [node, left, right].map((entry) => [entry.id, entry as AnyNode]), + ) as Record, + rootNodeIds: [node.id as AnyNodeId], + readOnly: false, + } as never) + return node + } + const segmentOf = (id: string) => useScene.getState().nodes[id as AnyNodeId] as RoofSegmentNode + + test('a gable offers itself or every gable of the roof', () => { + const scopes = paint.scopes?.(roof(), 'gable-right:rseg_right') + expect(scopes?.scopes).toEqual(['single', 'matching']) + expect(scopes?.labels).toEqual({ matching: 'All gables' }) + expect(paint.roleLabel?.(roof(), 'gable-right:rseg_right')).toBe('Right gable') + expect(paint.roleLabel?.(roof(), 'heel')).toBe('Heel band') + // the roof's own surfaces keep the derived single scope + expect(paint.scopes?.(roof(), 'edge')).toBeNull() + }) + + test('one gable paints only its segment', () => { + const node = seed() + const role = paint.scopes?.(node, 'gable-right:rseg_right')?.roleFor?.('single') + paint.commit?.({ node, role: role!, material: red, materialPreset: undefined }) + expect(segmentOf('rseg_right').gableRightMaterial).toMatchObject(red) + expect(segmentOf('rseg_left').gableLeftMaterialPreset).toBe('library:brick') + const after = useScene.getState().nodes[node.id as AnyNodeId] as RoofNode + expect(getEffectiveRoofSurfaceMaterial(after, 'edge')).toEqual( + getEffectiveRoofSurfaceMaterial(node, 'edge'), + ) + }) + + test('every gable paints the roof edge and clears each segment gable', () => { + const node = seed() + const role = paint.scopes?.(node, 'gable-right:rseg_right')?.roleFor?.('matching') + paint.commit?.({ node, role: role!, material: red, materialPreset: undefined }) + const after = useScene.getState().nodes[node.id as AnyNodeId] as RoofNode + expect(getEffectiveRoofSurfaceMaterial(after, 'edge').material).toMatchObject(red) + expect(segmentOf('rseg_left').gableLeftMaterialPreset).toBeUndefined() + expect(segmentOf('rseg_right').gableRightMaterial).toBeUndefined() + }) +}) diff --git a/packages/nodes/src/roof/definition.ts b/packages/nodes/src/roof/definition.ts index 657b5f7718..4c339490ea 100644 --- a/packages/nodes/src/roof/definition.ts +++ b/packages/nodes/src/roof/definition.ts @@ -10,16 +10,24 @@ import { import { DRAFTING_SURFACE_EXTENSION_KEY, type DraftingSurfaceExtension, + FLOORPLAN_NODE_EXTENSION_KEY, + type FloorplanNodeExtension, PANEL_MODEL_EXTENSION, } from '@pascal-app/editor' import { buildRoofFloorplan } from './floorplan' +import { roofFloorplanAffectedIds, roofFloorplanSiblingOverrides } from './floorplan-overrides' +import { roofPaint } from './paint' import { roofPanelModel } from './panel-model' import { roofParametrics } from './parametrics' -import useRoofFootprintSource from './roof-footprint-source' +import useRoofFootprintSource, { + irregularRoomHintVisibility, + noRoomHintVisibility, +} from './roof-footprint-source' import useRoofPlacementMode, { conicalRoofToolHintVisibility, standardRoofToolHintVisibility, } from './roof-placement-mode' +import useRoofRidgeMode from './roof-ridge-mode' import { RoofNode } from './schema' const MOVE_FRONT_OFFSET = 0.35 @@ -126,6 +134,9 @@ export const roofDefinition: NodeDefinition = { [DRAFTING_SURFACE_EXTENSION_KEY]: { kind: 'roof', } satisfies DraftingSurfaceExtension, + [FLOORPLAN_NODE_EXTENSION_KEY]: { + tool: () => import('./floorplan-tool'), + } satisfies FloorplanNodeExtension, }, defaults: () => { @@ -136,6 +147,7 @@ export const roofDefinition: NodeDefinition = { capabilities: { exterior: true, + paint: roofPaint, reveal: { phase: 'roof', style: 'assemble', @@ -229,9 +241,30 @@ export const roofDefinition: NodeDefinition = { }, { key: 'R', - label: 'Rotate roof direction 90°', + label: 'Ridge direction', visible: standardRoofToolHintVisibility, + chip: { + subscribe: (onChange) => useRoofRidgeMode.subscribe(onChange), + value: () => useRoofRidgeMode.getState().mode, + cycle: () => useRoofRidgeMode.getState().toggle(), + labels: { + long: 'Ridge: Long side', + short: 'Ridge: Short side', + }, + icons: { + long: 'lucide:rectangle-horizontal', + short: 'lucide:rectangle-vertical', + }, + tooltip: 'Ridge direction - click or press R to turn it 90°', + }, + }, + // Room makes nothing where there is no room to roof: say why, where a click would do nothing. + { + key: 'Room', + label: 'Not a rectangle: draw this roof instead', + visible: irregularRoomHintVisibility, }, + { key: 'Room', label: 'Point inside a room, porch or deck', visible: noRoomHintVisibility }, { key: 'Esc', label: 'Cancel' }, ], toolOptions: [ @@ -262,6 +295,8 @@ export const roofDefinition: NodeDefinition = { parametrics: roofParametrics, handles: resolveRoofHandles, floorplan: buildRoofFloorplan, + floorplanSiblingOverrides: roofFloorplanSiblingOverrides, + floorplanAffectedIds: roofFloorplanAffectedIds, rendersChildren: false, renderer: { diff --git a/packages/nodes/src/roof/floorplan-overrides.test.ts b/packages/nodes/src/roof/floorplan-overrides.test.ts new file mode 100644 index 0000000000..95c61b86ea --- /dev/null +++ b/packages/nodes/src/roof/floorplan-overrides.test.ts @@ -0,0 +1,96 @@ +import { describe, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + LevelNode, + RoofNode, + RoofSegmentNode, + WallNode, +} from '@pascal-app/core' +import { roofFloorplanAffectedIds, roofFloorplanSiblingOverrides } from './floorplan-overrides' + +function scene() { + const level = LevelNode.parse({ + id: 'level_roof', + type: 'level', + children: ['roof_main', 'roof_wing', 'wall_a'], + }) + const main = RoofNode.parse({ + id: 'roof_main', + type: 'roof', + parentId: level.id, + children: ['rseg_main'], + }) + const wing = RoofNode.parse({ + id: 'roof_wing', + type: 'roof', + parentId: level.id, + children: ['rseg_wing'], + }) + const mainSegment = RoofSegmentNode.parse({ + id: 'rseg_main', + type: 'roof-segment', + parentId: main.id, + }) + const wingSegment = RoofSegmentNode.parse({ + id: 'rseg_wing', + type: 'roof-segment', + parentId: wing.id, + }) + const wall = WallNode.parse({ + id: 'wall_a', + type: 'wall', + parentId: level.id, + start: [0, 0], + end: [4, 0], + }) + return Object.fromEntries( + [level, main, wing, mainSegment, wingSegment, wall].map((node) => [node.id, node]), + ) as Record +} + +const project = ( + nodes: Record, + live: { + overrides?: [string, Record][] + transforms?: [string, { position: [number, number, number]; rotation: number }][] + }, +) => + roofFloorplanSiblingOverrides({ + nodeId: 'roof_main' as AnyNodeId, + nodes, + liveOverrides: new Map(live.overrides ?? []), + liveTransforms: new Map(live.transforms ?? []), + }) + +describe('roof plan during a live edit', () => { + test("a segment's live move reaches the roof's builder snapshot", () => { + const nodes = scene() + const projected = project(nodes, { overrides: [['rseg_main', { position: [2, 0, 1] }]] }) + expect((projected['rseg_main' as AnyNodeId] as RoofSegmentNode).position).toEqual([2, 0, 1]) + expect(projected['rseg_wing' as AnyNodeId]).toBe(nodes['rseg_wing' as AnyNodeId]) + }) + + test("a roof's live transform from the 3D move tool moves it in the snapshot", () => { + const nodes = scene() + const projected = project(nodes, { + transforms: [['roof_wing', { position: [1, 0, 3], rotation: 0.5 }]], + }) + const wing = projected['roof_wing' as AnyNodeId] as RoofNode + expect(wing.position).toEqual([1, 0, 3]) + expect(wing.rotation).toBe(0.5) + }) + + test('nothing live, or only other kinds live, leaves the scene as it is', () => { + const nodes = scene() + expect(project(nodes, {})).toBe(nodes) + expect(project(nodes, { overrides: [['wall_a', { start: [1, 1] }]] })).toBe(nodes) + }) + + test("a segment's edit rebuilds its roof and the level's other roofs", () => { + const nodes = scene() + const affected = roofFloorplanAffectedIds({ node: nodes['rseg_wing' as AnyNodeId]!, nodes }) + expect([...affected].sort()).toEqual(['roof_main', 'roof_wing']) + expect(roofFloorplanAffectedIds({ node: nodes['wall_a' as AnyNodeId]!, nodes })).toEqual([]) + }) +}) diff --git a/packages/nodes/src/roof/floorplan-overrides.ts b/packages/nodes/src/roof/floorplan-overrides.ts new file mode 100644 index 0000000000..478a82e9b0 --- /dev/null +++ b/packages/nodes/src/roof/floorplan-overrides.ts @@ -0,0 +1,57 @@ +import type { AnyNode, AnyNodeId, LiveTransformLike } from '@pascal-app/core' + +const isRoofPart = (node: AnyNode | undefined) => + node?.type === 'roof' || node?.type === 'roof-segment' + +/** + * A roof's plan is drawn by the roof node from its segments (`ctx.children`) and its level's + * other roofs (`ctx.siblings`), which a drag moves through live overrides and transforms, not the + * scene. Projecting those into the builder's snapshot keeps the outline, ridges, hips and valleys + * on the segment while it is moved, resized or turned, in 2D or 3D. + */ +export function roofFloorplanSiblingOverrides(args: { + nodeId: AnyNodeId + nodes: Record + liveTransforms: Map + liveOverrides: Map> +}): Record { + const { nodes, liveOverrides, liveTransforms } = args + if (liveOverrides.size === 0 && liveTransforms.size === 0) return nodes + + let out: Record | null = null + for (const [id, live] of liveTransforms) { + const existing = nodes[id as AnyNodeId] + if (!isRoofPart(existing)) continue + out ??= { ...nodes } + out[id as AnyNodeId] = { + ...existing, + position: live.position, + rotation: live.rotation, + } as AnyNode + } + for (const [id, override] of liveOverrides) { + const existing = out?.[id as AnyNodeId] ?? nodes[id as AnyNodeId] + if (!isRoofPart(existing) || Object.keys(override).length === 0) continue + out ??= { ...nodes } + out[id as AnyNodeId] = { ...existing, ...override } as AnyNode + } + return out ?? nodes +} + +/** + * The roofs whose plan a live roof or segment edit changes: every roof on its level, since a + * wing's ridge runs on to the main roof's slope and their valleys are drawn by one of the two. + */ +export function roofFloorplanAffectedIds(args: { + node: AnyNode + nodes: Record +}): readonly AnyNodeId[] { + const { node, nodes } = args + const roof = + node.type === 'roof-segment' && node.parentId ? nodes[node.parentId as AnyNodeId] : node + if (roof?.type !== 'roof') return [] + const level = roof.parentId ? nodes[roof.parentId as AnyNodeId] : undefined + const onLevel = (level as { children?: AnyNodeId[] } | undefined)?.children ?? [] + const roofs = onLevel.filter((id) => id !== roof.id && nodes[id]?.type === 'roof') + return [roof.id as AnyNodeId, ...roofs] +} diff --git a/packages/nodes/src/roof/floorplan-tool.test.ts b/packages/nodes/src/roof/floorplan-tool.test.ts new file mode 100644 index 0000000000..acb89d20b5 --- /dev/null +++ b/packages/nodes/src/roof/floorplan-tool.test.ts @@ -0,0 +1,516 @@ +import { afterEach, beforeEach, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + BuildingNode, + clearSceneHistory, + createSceneApi, + emitter, + type GridEvent, + getLevelElevations, + getWallCurveFrameAt, + LevelNode, + type RoofNode, + type RoofSegmentNode, + SeparatorNode, + useScene, + WallNode, + ZoneNode, +} from '@pascal-app/core' +import { + type FloorplanToolContext, + sceneLayout, + useEditor, + useFloorplanDraftPreview, +} from '@pascal-app/editor' +import { useViewer } from '@pascal-app/viewer' +import { act, create } from '@react-three/test-renderer' +import { createElement } from 'react' +import RoofFloorplanTool from './floorplan-tool' +import useRoofFootprintSource from './roof-footprint-source' +import { segmentWallLine } from './wall-catch' + +type RafFn = (cb: (time: number) => void) => number +;(globalThis as unknown as { requestAnimationFrame?: RafFn }).requestAnimationFrame ??= (cb) => { + cb(0) + return 0 +} +;(globalThis as unknown as { cancelAnimationFrame?: (id: number) => void }).cancelAnimationFrame ??= + () => {} +;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true + +const previous = { editor: useEditor.getState(), viewer: useViewer.getState() } +const windowDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'window') + +beforeEach(() => { + globalThis.window = new EventTarget() as Window & typeof globalThis +}) + +afterEach(() => { + useEditor.setState(previous.editor, true) + useViewer.setState(previous.viewer, true) + useRoofFootprintSource.setState({ source: 'draw', roomPick: null }) + if (windowDescriptor) Object.defineProperty(globalThis, 'window', windowDescriptor) + else Reflect.deleteProperty(globalThis, 'window') +}) + +const RECTANGLE: Array<[number, number]> = [ + [0, 0], + [4, 0], + [4, 3], + [0, 3], +] + +function setScene( + polygon: Array<[number, number]>, + { upperLevel = true, rotation = 0 }: { upperLevel?: boolean; rotation?: number } = {}, +) { + const building = BuildingNode.parse({ rotation: [0, rotation, 0] }) + const level = LevelNode.parse({ parentId: building.id, level: 0, height: 3 }) + const upper = LevelNode.parse({ parentId: building.id, level: 1, height: 3 }) + building.children = upperLevel ? [level.id, upper.id] : [level.id] + const walls = polygon.map((start, index) => + WallNode.parse({ + parentId: level.id, + start, + end: polygon[(index + 1) % polygon.length], + height: 2.5, + }), + ) + level.children = walls.map((wall) => wall.id) + const nodes = Object.fromEntries( + [building, level, ...(upperLevel ? [upper] : []), ...walls].map((n) => [n.id, n]), + ) + useScene.getState().setScene(nodes as Record, [building.id as AnyNodeId], { + installedPlugins: [], + hasExplicitPluginInstallState: false, + }) + clearSceneHistory() + useViewer.getState().setSelection({ buildingId: building.id, levelId: level.id }) + useEditor.setState({ phase: 'structure', mode: 'build', tool: 'roof', workspaceMode: 'edit' }) + return { level, upper } +} + +const roofs = () => Object.values(useScene.getState().nodes).filter((n) => n.type === 'roof') + +const showViews = (scene: '2d' | 'split') => + act(async () => useEditor.setState({ viewLayouts: { edit: sceneLayout(scene) } })) + +async function mountTool(levelId: LevelNode['id']) { + const context: FloorplanToolContext = { + sceneApi: createSceneApi(useScene), + activeLevelId: levelId, + unit: 'metric', + metricNotation: 'meters', + gridSnapStep: 0.5, + toolDefaults: null, + selectNode: (id) => useViewer.getState().setSelection({ selectedIds: [id] }), + finishTool: () => {}, + } + return create(createElement(RoofFloorplanTool, context)) +} + +const gridEvent = (x: number, z: number) => + ({ + position: [x, 0, z], + localPosition: [x, 0, z], + nativeEvent: {} as GridEvent['nativeEvent'], + }) satisfies GridEvent + +const move = (x: number, z: number) => act(async () => emitter.emit('grid:move', gridEvent(x, z))) + +const click = (x: number, z: number) => + act(async () => { + emitter.emit('grid:move', gridEvent(x, z)) + emitter.emit('grid:click', gridEvent(x, z)) + }) + +// The 3D roof tool lives in the canvas, which never renders while its pane is hidden: in 2D-only +// view a roof drawn on the plan was never written. In split view the 3D tool stays its one owner. +test('a roof drawn on the plan in 2D-only view is made; split view leaves it to the 3D tool', async () => { + const { level } = setScene(RECTANGLE) + await showViews('2d') + const renderer = await mountTool(level.id) + try { + await click(0, 0) + expect(roofs()).toHaveLength(0) + await click(4, 3) + expect(roofs()).toHaveLength(1) + expect(useViewer.getState().selection.selectedIds).toEqual([roofs()[0]!.id]) + + await act(async () => useViewer.getState().setSelection({ selectedIds: [] })) + await showViews('split') + await click(6, 0) + await click(9, 3) + expect(roofs()).toHaveLength(1) + } finally { + await act(async () => renderer.unmount()) + } +}) + +test('Room roofs the room clicked, and says why an L-shaped one makes nothing', async () => { + await showViews('2d') + useRoofFootprintSource.setState({ source: 'room' }) + const rectangle = await mountTool(setScene(RECTANGLE).level.id) + try { + await click(2, 1) + expect(roofs()).toHaveLength(1) + expect(useRoofFootprintSource.getState().roomPick).toBe('room') + await click(9, 9) + expect(useRoofFootprintSource.getState().roomPick).toBe('none') + } finally { + await act(async () => rectangle.unmount()) + } + + const ell = await mountTool( + setScene([ + [0, 0], + [6, 0], + [6, 2], + [2, 2], + [2, 6], + [0, 6], + ]).level.id, + ) + try { + await click(1, 1) + expect(roofs()).toHaveLength(0) + expect(useRoofFootprintSource.getState().roomPick).toBe('irregular') + } finally { + await act(async () => ell.unmount()) + } + expect(useRoofFootprintSource.getState().roomPick).toBeNull() +}) + +// Switching to 2D-only with a rectangle open in 3D left the plan's draft with a first corner this +// tool never had: every click then started one and ended the other, a roof each second click. +test('a rectangle left open by the 3D tool is dropped when the plan takes over', async () => { + const { level } = setScene(RECTANGLE) + await showViews('2d') + useFloorplanDraftPreview.getState().setRoofDraftStart([1, 1]) + useFloorplanDraftPreview.getState().setRoofDraftEnd([2, 2]) + const renderer = await mountTool(level.id) + try { + expect(useFloorplanDraftPreview.getState().roofDraftStart).toBeNull() + expect(useFloorplanDraftPreview.getState().roofDraftEnd).toBeNull() + } finally { + await act(async () => renderer.unmount()) + } +}) + +// Split view's 3D tool snaps the drafted corners onto the walls below; the plan tool took the +// plan's point as it came, so on the Roof level the same clicks made a roof a few cm off the house. +test('a roof drawn on the level over the walls snaps to their corners, as in split view', async () => { + const { upper } = setScene(RECTANGLE) + await showViews('2d') + const renderer = await mountTool(upper.id) + try { + await click(0.03, 0.02) + await click(3.97, 2.98) + const roof = roofs()[0] as RoofNode + expect(roof.position[0]).toBeCloseTo(2) + expect(roof.position[2]).toBeCloseTo(1.5) + const segment = useScene.getState().nodes[roof.children[0]!] as RoofSegmentNode + expect([segment.width, segment.depth].sort()).toEqual([3, 4]) + } finally { + await act(async () => renderer.unmount()) + } +}) + +// The plan drew its draft from its own grid point while the roof committed at the corner the tool +// snapped: the dashed rectangle must be the roof the next click makes. +test('the plan’s draft rectangle runs between the corners the roof commits at', async () => { + const { upper } = setScene(RECTANGLE) + await showViews('2d') + const renderer = await mountTool(upper.id) + const draft = () => { + const { roofDraftStart, roofDraftEnd } = useFloorplanDraftPreview.getState() + return { roofDraftStart, roofDraftEnd } + } + try { + await click(0.03, 0.02) + expect(draft()).toEqual({ roofDraftStart: [0, 0], roofDraftEnd: [0, 0] }) + await move(3.97, 2.98) + expect(draft()).toEqual({ roofDraftStart: [0, 0], roofDraftEnd: [4, 3] }) + await click(3.97, 2.98) + expect(roofs()[0]!.position[0]).toBeCloseTo(2) + expect(draft()).toEqual({ roofDraftStart: null, roofDraftEnd: null }) + } finally { + await act(async () => renderer.unmount()) + } +}) + +// The plan clears its draft when Room is picked, but the tool kept its first corner: back on Draw, +// the next click made a roof from a corner nothing showed. +test('a first corner is dropped when the footprint source changes', async () => { + const { level } = setScene(RECTANGLE) + await showViews('2d') + const renderer = await mountTool(level.id) + try { + await click(0, 0) + await act(async () => useRoofFootprintSource.setState({ source: 'room' })) + await act(async () => useRoofFootprintSource.setState({ source: 'draw' })) + await click(6, 5) + expect(roofs()).toHaveLength(0) + expect(useFloorplanDraftPreview.getState().roofDraftStart).toEqual([6, 5]) + } finally { + await act(async () => renderer.unmount()) + } +}) + +// Reported on a turned building: the roof came out thin and the Roof level at grade. Drawn on the +// plan over the top storey's walls, it is the rectangle drawn, on a Roof level made at the +// storey's top, its eave on the wall tops. +test('on a turned building, a roof drawn over the top storey lands on a new Roof level', async () => { + const { level } = setScene(RECTANGLE, { upperLevel: false, rotation: Math.PI / 5 }) + await showViews('2d') + const renderer = await mountTool(level.id) + try { + await click(0, 0) + await click(4, 3) + const nodes = useScene.getState().nodes + const roof = roofs()[0] as RoofNode + const roofLevel = nodes[roof.parentId as AnyNodeId] as LevelNode + expect(roofLevel).toMatchObject({ name: 'Roof', level: 1, metadata: { role: 'roof' } }) + expect(getLevelElevations(nodes).get(roofLevel.id)?.baseY).toBeCloseTo(3) + // 2.5 m walls under a 3 m storey: the eave 0.5 m below the roof level's floor. + expect(roof).toMatchObject({ support: { kind: 'walls' }, rotation: 0 }) + expect(roof.position[1]).toBeCloseTo(-0.5) + const segment = nodes[roof.children[0]!] as RoofSegmentNode + expect([segment.width, segment.depth].sort()).toEqual([3, 4]) + } finally { + await act(async () => renderer.unmount()) + } +}) + +// A cone builds over a curved wall, and the plan raises no wall events for one: in a 2D-only +// session the clicks made nothing. +test('a cone is built over the curved wall clicked on the plan in 2D-only view', async () => { + const { level } = setScene(RECTANGLE) + const curved = WallNode.parse({ + parentId: level.id, + start: [8, 0], + end: [12, 0], + curveOffset: 1, + height: 2.5, + }) + useScene.getState().createNode(curved, level.id) + clearSceneHistory() + useEditor.getState().setToolDefaults('roof', { roofType: 'conical' }) + await showViews('2d') + const renderer = await mountTool(level.id) + try { + await click(2, 1) + expect(roofs()).toHaveLength(0) + + const onArc = getWallCurveFrameAt(curved, 0.5).point + await move(onArc.x, onArc.y + 0.1) + expect(useViewer.getState().previewSelectedIds).toEqual([curved.id]) + await click(onArc.x, onArc.y + 0.1) + expect(roofs().map((roof) => roof.metadata)).toEqual([ + expect.objectContaining({ conicalSourceWallId: curved.id }), + ]) + expect(useViewer.getState().previewSelectedIds).toEqual([]) + } finally { + await act(async () => renderer.unmount()) + } +}) + +const RAIL = 3.5 * 0.0254 +const H = RAIL / 2 + +// A porch: a 10 x 8 m house of 0.2 m walls, a porch off its south wall (z 0) +// closed by invisible walls at x 2.2 and 7.8 and z -2.4, or a deck fenced there by railings. +function setPorchScene(open: 'separators' | 'railings') { + const building = BuildingNode.parse({}) + const level = LevelNode.parse({ parentId: building.id, level: 0, height: 3 }) + const upper = LevelNode.parse({ parentId: building.id, level: 1, height: 3 }) + building.children = [level.id, upper.id] + const corners: Array<[number, number]> = [ + [0, 0], + [10, 0], + [10, 8], + [0, 8], + ] + const house = corners.map((start, index) => + WallNode.parse({ + parentId: level.id, + start, + end: corners[(index + 1) % 4], + height: 2.5, + thickness: 0.2, + }), + ) + const sides: Array<[[number, number], [number, number]]> = [ + [ + [2.2, 0], + [2.2, -2.4], + ], + [ + [2.2, -2.4], + [7.8, -2.4], + ], + [ + [7.8, -2.4], + [7.8, 0], + ], + ] + const edges = sides.map(([start, end]) => + open === 'separators' + ? SeparatorNode.parse({ parentId: level.id, start, end }) + : WallNode.parse({ + parentId: level.id, + start, + end, + wallType: 'railing', + thickness: RAIL, + height: 36 * 0.0254, + }), + ) + const rooms = [ + ZoneNode.parse({ parentId: level.id, name: 'Living', polygon: corners }), + ZoneNode.parse({ + parentId: level.id, + name: open === 'separators' ? 'Porch' : 'Deck', + roomType: open === 'separators' ? 'porch' : 'deck', + polygon: [ + [2.2, 0], + [2.2, -2.4], + [7.8, -2.4], + [7.8, 0], + ], + }), + ] + level.children = [...house, ...edges, ...rooms].map((node) => node.id) as LevelNode['children'] + const nodes = Object.fromEntries( + [building, level, upper, ...house, ...edges, ...rooms].map((node) => [node.id, node]), + ) + useScene.getState().setScene(nodes as Record, [building.id as AnyNodeId], { + installedPlugins: [], + hasExplicitPluginInstallState: false, + }) + clearSceneHistory() + useViewer.getState().setSelection({ buildingId: building.id, levelId: upper.id }) + useEditor.setState({ + phase: 'structure', + mode: 'build', + tool: 'roof', + workspaceMode: 'edit', + snappingModeByContext: { ...useEditor.getState().snappingModeByContext, polygon: 'lines' }, + }) + return { level, upper, edges } +} + +/** A roof's one segment's wall line in the plan: its x and z extents. */ +function wallLineExtents(roof: RoofNode) { + const segment = useScene.getState().nodes[roof.children[0]!] as RoofSegmentNode + const line = segmentWallLine(roof, segment) + const along = Math.abs(Math.cos(line.angle)) > 0.5 + const [hx, hz] = along ? [line.hw, line.hd] : [line.hd, line.hw] + return { + x: [line.center[0] - hx, line.center[0] + hx], + z: [line.center[1] - hz, line.center[1] + hz], + wallThickness: segment.wallThickness, + } +} + +const expectExtents = ( + actual: ReturnType, + x: [number, number], + z: [number, number], +) => { + for (const [i, value] of [...actual.x, ...actual.z].entries()) + expect(value).toBeCloseTo([...x, ...z][i]!, 6) +} + +// A roof drawn over a porch from the Roof level: before, its corners caught the house's +// walls below but not the porch's invisible walls, and the roof's walls stood out past them. +test("a roof drawn over a porch snaps to its invisible walls, its outer faces on the porch's edge", async () => { + const { upper } = setPorchScene('separators') + await showViews('2d') + const renderer = await mountTool(upper.id) + try { + await click(2.23, -2.37) + await click(7.77, 0.03) + const roof = roofs()[0] as RoofNode + expect(roof.parentId).toBe(upper.id) + // The house wall's centre line at z 0; 0.2 m walls, their outer faces on x 2.2, 7.8, z -2.4. + const extents = wallLineExtents(roof) + expect(extents.wallThickness).toBeCloseTo(0.2, 6) + expectExtents(extents, [2.3, 7.7], [-2.3, 0]) + } finally { + await act(async () => renderer.unmount()) + } +}) + +// The owner's porch clause still holds: drawn on the porch's own storey, the roof stays there on +// its posts rather than going up to the Roof level, its outer faces on the porch's edge. +test("drawn on the porch's own storey, the roof stays on it, flush with the porch", async () => { + const { level } = setPorchScene('separators') + await showViews('2d') + const renderer = await mountTool(level.id) + try { + await click(2.23, -2.37) + await click(7.77, 0.03) + const roof = roofs()[0] as RoofNode + expect(roof.parentId).toBe(level.id) + expect(roof.support).toEqual({ kind: 'level' }) + expectExtents(wallLineExtents(roof), [2.3, 7.7], [-2.3, 0]) + } finally { + await act(async () => renderer.unmount()) + } +}) + +test("a roof drawn over a deck snaps to its railings' outside faces and corners", async () => { + const { upper } = setPorchScene('railings') + await showViews('2d') + const renderer = await mountTool(upper.id) + try { + await click(2.2 - H + 0.03, -2.4 - H + 0.03) + await click(7.8 + H - 0.03, 0.03) + const extents = wallLineExtents(roofs()[0] as RoofNode) + expect(extents.wallThickness).toBeCloseTo(0.2, 6) + expectExtents(extents, [2.3 - H, 7.7 + H], [-2.3 - H, 0]) + } finally { + await act(async () => renderer.unmount()) + } +}) + +test("Room over a porch roofs it to its outside edge, on the house wall's top", async () => { + const { upper, edges } = setPorchScene('separators') + await showViews('2d') + useRoofFootprintSource.setState({ source: 'room' }) + const renderer = await mountTool(upper.id) + try { + await move(5, -1) + expect(useRoofFootprintSource.getState().roomPick).toBe('room') + expect(useViewer.getState().previewSelectedIds).toEqual( + expect.arrayContaining(edges.map((edge) => edge.id)), + ) + await click(5, -1) + const roof = roofs()[0] as RoofNode + expect(roof.parentId).toBe(upper.id) + // 2.5 m walls under a 3 m storey: the eave on the house wall's top, 0.5 m below the level. + expect(roof.position[1]).toBeCloseTo(-0.5, 6) + expectExtents(wallLineExtents(roof), [2.3, 7.7], [-2.3, 0]) + } finally { + await act(async () => renderer.unmount()) + } +}) + +test("Room over a deck roofs it to its railings' outside faces, never on their tops", async () => { + const { upper } = setPorchScene('railings') + await showViews('2d') + useRoofFootprintSource.setState({ source: 'room' }) + const renderer = await mountTool(upper.id) + try { + await click(5, -1) + const roof = roofs()[0] as RoofNode + expect(roof.position[1]).toBeCloseTo(-0.5, 6) + const extents = wallLineExtents(roof) + expect(extents.wallThickness).toBeCloseTo(0.2, 6) + expectExtents(extents, [2.3 - H, 7.7 + H], [-2.3 - H, 0]) + } finally { + await act(async () => renderer.unmount()) + } +}) diff --git a/packages/nodes/src/roof/floorplan-tool.tsx b/packages/nodes/src/roof/floorplan-tool.tsx new file mode 100644 index 0000000000..bd6a8017dd --- /dev/null +++ b/packages/nodes/src/roof/floorplan-tool.tsx @@ -0,0 +1,226 @@ +'use client' + +import { + type AnyNodeId, + emitter, + type GridEvent, + type LevelNode, + RoofType as RoofTypeSchema, +} from '@pascal-app/core' +import { + clearSurfacePlanSnapFeedback, + type FloorplanToolContext, + markToolCancelConsumed, + triggerSFX, + useEditor, + useFloorplanDraftPreview, + visibleScene, +} from '@pascal-app/editor' +import { useViewer } from '@pascal-app/viewer' +import { useEffect } from 'react' +import { createConicalRoofSectorAboveWall } from './conical-roof' +import { + parseRoofFootprintSource, + pickConicalRoofWall, + pickRoofRoom, + roofFootprintPreviewIds, +} from './roof-footprint' +import useRoofFootprintSource from './roof-footprint-source' +import useRoofPlacementMode from './roof-placement-mode' +import useRoofRidgeMode, { ridgeQuarterTurn } from './roof-ridge-mode' +import { + collectRoofAlignmentAnchors, + commitRoofFootprint, + commitRoofPlacement, + resolveRoofDraftPoint, +} from './tool' + +/** + * The roof tool in 2D-only view. The 3D `RoofTool` lives in the canvas, which never renders while + * its pane is hidden, so in 2D-only view this commits instead, from the plan's own grid events: it + * snaps the corners, writes them into the plan's draft rectangle (or hovers the room, or for a cone + * the curved wall) and writes the roof. Split and 3D views keep the 3D tool as the one owner. + */ +export default function RoofFloorplanTool({ + activeLevelId, + sceneApi, + selectNode, +}: FloorplanToolContext) { + const planOwnsInput = useEditor((state) => visibleScene(state) === '2d') + const levelId = planOwnsInput ? (activeLevelId as LevelNode['id'] | null) : null + const roofType = useEditor((state) => { + const parsed = RoofTypeSchema.safeParse(state.toolDefaults.roof?.roofType) + return parsed.success ? parsed.data : 'gable' + }) + // A new source or roof type starts over, as the 3D tool does: a first corner kept across it + // would end the next rectangle with no draft on the plan to show it. + const source = useRoofFootprintSource((state) => parseRoofFootprintSource(state.source, roofType)) + + useEffect(() => { + if (!levelId) return + let corner1: [number, number, number] | null = null + const draft = useFloorplanDraftPreview.getState + // A rectangle the 3D tool opened before the view changed has no first corner here: drop it, or + // the plan's draft and this tool's corner fall out of step (each click starts one, ends the other). + const clearDraft = () => { + draft().setRoofDraftStart(null) + draft().setRoofDraftEnd(null) + draft().setRoofDraftQuarterTurn(false) + } + clearDraft() + // Snapped as the 3D tool snaps in split view (onto the walls below too), so the same clicks + // make the same roof in either view. + let alignmentCandidates = collectRoofAlignmentAnchors(sceneApi.nodes(), levelId, roofType) + const planPoint = (event: GridEvent) => + resolveRoofDraftPoint(event, levelId, sceneApi.nodes(), roofType, alignmentCandidates) + let previewedId: string | null = null + const preview = (target: { id: string; ids: string[] } | null) => { + if ((target?.id ?? null) === previewedId) return + previewedId = target?.id ?? null + useViewer.getState().setPreviewSelectedIds(target?.ids ?? []) + } + const conicalWall = (event: GridEvent) => + pickConicalRoofWall(levelId, sceneApi.nodes(), [ + event.localPosition[0], + event.localPosition[2], + ]) + + const onMove = (event: GridEvent) => { + if (source === 'walls') { + const wall = conicalWall(event) + preview(wall && { id: wall.id, ids: [wall.id] }) + return + } + if (source === 'room') { + const room = pickRoofRoom(levelId, sceneApi.nodes(), planPoint(event)) + useRoofFootprintSource.getState().setRoomPick(room.pick) + preview(room.target && { id: room.target.id, ids: roofFootprintPreviewIds(room.target) }) + return + } + const [x, z] = planPoint(event) + if (!corner1) return + draft().setRoofDraftEnd([x, z]) + draft().setRoofDraftQuarterTurn( + ridgeQuarterTurn( + Math.abs(x - corner1[0]), + Math.abs(z - corner1[2]), + useRoofRidgeMode.getState().mode, + ), + ) + } + + const onClick = (event: GridEvent) => { + if (source === 'walls') { + const wall = conicalWall(event) + if (!wall) return + preview(null) + const segmentId = createConicalRoofSectorAboveWall( + wall, + sceneApi.nodes(), + sceneApi, + levelId, + ) + if (segmentId) selectNode(segmentId) + return + } + if (source === 'room') { + const { target, pick } = pickRoofRoom(levelId, sceneApi.nodes(), planPoint(event)) + useRoofFootprintSource.getState().setRoomPick(pick) + if (!target) return + const roofId = commitRoofFootprint( + sceneApi, + levelId, + target, + useRoofRidgeMode.getState().mode, + ) + if (roofId) selectNode(roofId as AnyNodeId) + return + } + const [x, z] = planPoint(event) + const corner: [number, number, number] = [x, event.localPosition[1], z] + if (!corner1) { + corner1 = corner + draft().setRoofDraftStart([x, z]) + draft().setRoofDraftEnd([x, z]) + triggerSFX('sfx:structure-build-start') + return + } + const roofId = commitRoofPlacement( + sceneApi, + levelId, + corner1, + corner, + useViewer.getState().selection.selectedIds, + useRoofRidgeMode.getState().mode, + useRoofPlacementMode.getState().mode, + ) + corner1 = null + clearDraft() + alignmentCandidates = collectRoofAlignmentAnchors(sceneApi.nodes(), levelId, roofType) + clearSurfacePlanSnapFeedback() + if (roofId) selectNode(roofId as AnyNodeId) + } + + const onCancel = () => { + if (!corner1) return + markToolCancelConsumed() + corner1 = null + clearDraft() + } + + const onKeyDown = (event: KeyboardEvent) => { + const target = event.target + if ( + target instanceof HTMLInputElement || + target instanceof HTMLTextAreaElement || + (target instanceof HTMLElement && target.isContentEditable) + ) + return + if (event.repeat || event.metaKey || event.ctrlKey || event.altKey) return + const key = event.key.toLowerCase() + // As in 3D: P cycles a cone's placement surface, R turns a drawn roof's ridge. + if (source === 'walls') { + if (key !== 'p') return + event.preventDefault() + useRoofPlacementMode.getState().cycleMode() + triggerSFX('sfx:grid-snap') + return + } + if (key !== 'r') return + event.preventDefault() + useRoofRidgeMode.getState().toggle() + triggerSFX('sfx:item-rotate') + } + // The HUD chip flips the ridge too; the draft's ridge line follows either way. + const unsubscribeRidgeMode = useRoofRidgeMode.subscribe(() => { + const start = draft().roofDraftStart + const end = draft().roofDraftEnd + if (!(corner1 && start && end)) return + draft().setRoofDraftQuarterTurn( + ridgeQuarterTurn( + Math.abs(end[0] - start[0]), + Math.abs(end[1] - start[1]), + useRoofRidgeMode.getState().mode, + ), + ) + }) + + emitter.on('grid:move', onMove) + emitter.on('grid:click', onClick) + emitter.on('tool:cancel', onCancel) + window.addEventListener('keydown', onKeyDown) + return () => { + emitter.off('grid:move', onMove) + emitter.off('grid:click', onClick) + emitter.off('tool:cancel', onCancel) + window.removeEventListener('keydown', onKeyDown) + unsubscribeRidgeMode() + useRoofFootprintSource.getState().setRoomPick(null) + preview(null) + clearDraft() + clearSurfacePlanSnapFeedback() + } + }, [levelId, roofType, sceneApi, selectNode, source]) + + return null +} diff --git a/packages/nodes/src/roof/floorplan.test.ts b/packages/nodes/src/roof/floorplan.test.ts index 6e79655063..9acd0e4045 100644 --- a/packages/nodes/src/roof/floorplan.test.ts +++ b/packages/nodes/src/roof/floorplan.test.ts @@ -4,12 +4,19 @@ import { type AnyNodeId, type FloorplanGeometry, type GeometryContext, + getRoofSegmentVisibleTopBounds, RoofNode, RoofSegmentNode, } from '@pascal-app/core' import { createFloorplanContextExtensions } from '@pascal-app/editor' import { buildRoofFloorplan } from './floorplan' +/** + * No overhang, wall or shingle reach: the eave sits on the wall line, so a test about clipping or + * creases reads in round numbers. Otherwise the editor plan runs out to the eave. + */ +const FLUSH = { overhang: 0, wallThickness: 0, shingleThickness: 0 } + function buildContext( node: ReturnType, children: AnyNode[], @@ -90,6 +97,7 @@ describe('buildRoofFloorplan roof intersections', () => { roofType: 'mansard', width: 10, depth: 8, + ...FLUSH, }) const enteringSegment = RoofSegmentNode.parse({ id: 'rseg_entering', @@ -98,6 +106,7 @@ describe('buildRoofFloorplan roof intersections', () => { roofType: 'gable', width: 8, depth: 4, + ...FLUSH, }) const nodes = { [hostRoof.id]: hostRoof, @@ -175,6 +184,167 @@ describe('buildRoofFloorplan roof intersections', () => { }) }) +/** Every straight line the plan draws, as rounded endpoint pairs in either order. */ +function lineKey(from: [number, number], to: [number, number]): string { + const key = (point: [number, number]) => + point.map((value) => (Math.abs(value) < 0.005 ? 0 : value).toFixed(2)).join(',') + const a = key(from) + const b = key(to) + return a < b ? `${a} ${b}` : `${b} ${a}` +} + +function planLines(geometry: FloorplanGeometry | null): string[] { + return flat(geometry).flatMap((child) => + child.kind === 'line' ? [lineKey([child.x1, child.y1], [child.x2, child.y2])] : [], + ) +} + +describe('roof plan creases from the roof surface', () => { + // A 10 × 8 gable, ridge along x, and a 4-wide wing roof running into it from +z, + // its ridge along z: both on the same plate at the same pitch. + function wingedHouse() { + const main = RoofNode.parse({ id: 'roof_main', type: 'roof', children: ['rseg_main'] }) + const wing = RoofNode.parse({ + id: 'roof_wing', + type: 'roof', + position: [0, 0, 5], + children: ['rseg_wing'], + }) + const mainSegment = RoofSegmentNode.parse({ + id: 'rseg_main', + type: 'roof-segment', + parentId: main.id, + roofType: 'gable', + width: 10, + depth: 8, + pitch: 30, + wallHeight: 0, + + ...FLUSH, + }) + const wingSegment = RoofSegmentNode.parse({ + id: 'rseg_wing', + type: 'roof-segment', + parentId: wing.id, + roofType: 'gable', + width: 10, + depth: 4, + pitch: 30, + wallHeight: 0, + rotation: Math.PI / 2, + + ...FLUSH, + }) + const nodes = { + [main.id]: main, + [wing.id]: wing, + [mainSegment.id]: mainSegment, + [wingSegment.id]: wingSegment, + } + return { + main: buildRoofFloorplan(main, buildContext(main, [mainSegment], [wing], nodes)), + wing: buildRoofFloorplan(wing, buildContext(wing, [wingSegment], [main], nodes)), + } + } + + test("a wing's ridge runs on past the main roof's wall line to where it meets the main slope", () => { + const { wing } = wingedHouse() + expect(planLines(wing)).toContain(lineKey([0, 10], [0, 2])) + }) + + test('the valleys run from where the eaves cross up to the ridge, drawn once', () => { + const { main, wing } = wingedHouse() + expect(planLines(main)).toEqual( + expect.arrayContaining([ + lineKey([-5, 0], [5, 0]), + lineKey([0, 2], [2, 4]), + lineKey([0, 2], [-2, 4]), + ]), + ) + expect(planLines(wing)).not.toContain(lineKey([0, 2], [2, 4])) + }) + + test('a hip draws its ridge and four hips', () => { + const roof = RoofNode.parse({ id: 'roof_h', type: 'roof', children: ['rseg_h'] }) + const segment = RoofSegmentNode.parse({ + id: 'rseg_h', + type: 'roof-segment', + parentId: roof.id, + roofType: 'hip', + width: 10, + depth: 6, + ...FLUSH, + }) + const nodes = { [roof.id]: roof, [segment.id]: segment } + const lines = planLines(buildRoofFloorplan(roof, buildContext(roof, [segment], [], nodes))) + expect(lines).toEqual( + expect.arrayContaining([ + lineKey([-2, 0], [2, 0]), + lineKey([-5, -3], [-2, 0]), + lineKey([-5, 3], [-2, 0]), + lineKey([5, -3], [2, 0]), + lineKey([5, 3], [2, 0]), + ]), + ) + expect(lines).toHaveLength(5) + }) +}) + +describe('the editor plan runs out to the eave', () => { + function singleRoof(roofType: 'gable' | 'hip', drafting = false) { + const roof = RoofNode.parse({ id: 'roof_e', type: 'roof', children: ['rseg_e'] }) + const segment = RoofSegmentNode.parse({ + id: 'rseg_e', + type: 'roof-segment', + parentId: roof.id, + roofType, + width: 10, + depth: 6, + }) + const nodes = { [roof.id]: roof, [segment.id]: segment } + return { + edge: getRoofSegmentVisibleTopBounds(segment), + geometry: buildRoofFloorplan(roof, buildContext(roof, [segment], [], nodes, drafting)), + } + } + + test('the outline is the eave and rake, overhang included, not the wall line', () => { + const { edge, geometry } = singleRoof('gable') + const outline = outlinePoints(geometry) + expect(edge.minX).toBeLessThan(-5.1) + expect(Math.min(...outline.map(([x]) => x))).toBeCloseTo(edge.minX, 6) + expect(Math.max(...outline.map(([x]) => x))).toBeCloseTo(edge.maxX, 6) + expect(Math.min(...outline.map(([, z]) => z))).toBeCloseTo(edge.minZ, 6) + expect(Math.max(...outline.map(([, z]) => z))).toBeCloseTo(edge.maxZ, 6) + }) + + test("a gable's ridge runs out to both rakes", () => { + const { edge, geometry } = singleRoof('gable') + expect(planLines(geometry)).toEqual([lineKey([edge.minX, 0], [edge.maxX, 0])]) + }) + + test("a hip's hips run out to the eave corners", () => { + const { edge, geometry } = singleRoof('hip') + expect(planLines(geometry)).toEqual( + expect.arrayContaining([ + lineKey([-2, 0], [2, 0]), + lineKey([edge.minX, edge.minZ], [-2, 0]), + lineKey([edge.minX, edge.maxZ], [-2, 0]), + lineKey([edge.maxX, edge.minZ], [2, 0]), + lineKey([edge.maxX, edge.maxZ], [2, 0]), + ]), + ) + }) + + test('a drafted sheet still outlines the wall line and dashes the eave past it', () => { + const { edge, geometry } = singleRoof('hip', true) + const outline = outlinePoints(geometry) + expect(Math.min(...outline.map(([x]) => x))).toBeCloseTo(-5, 6) + expect(Math.min(...eavePoints(geometry).map(([x]) => x))).toBeCloseTo(edge.minX, 6) + expect(planLines(geometry)).toContain(lineKey([-5, -3], [-2, 0])) + }) +}) + /** A 46' × 32' gable at a 7:12 pitch. */ function cottageRoof(overrides: Record = {}, drafting = true) { const roof = RoofNode.parse({ id: 'roof_c', type: 'roof', children: ['rseg_c'] }) @@ -250,3 +420,49 @@ describe('roof plan slope annotation', () => { expect(labels(geometry).filter((label) => /:12$/.test(label.text))).toHaveLength(0) }) }) + +describe("the roof's wall line while it is selected or moved", () => { + const BLUE = '#2563eb' + function wallLines(view: { selected?: boolean; moving?: boolean }) { + const roof = RoofNode.parse({ id: 'roof_w', type: 'roof', children: ['rseg_w'] }) + const segment = RoofSegmentNode.parse({ + id: 'rseg_w', + type: 'roof-segment', + parentId: roof.id, + roofType: 'gable', + width: 10, + depth: 6, + }) + const nodes = { [roof.id]: roof, [segment.id]: segment } + const geometry = buildRoofFloorplan(roof, { + ...buildContext(roof, [segment], [], nodes), + viewState: { + selected: false, + highlighted: false, + hovered: false, + moving: false, + unit: 'metric', + ...view, + palette: { selectedStroke: BLUE } as never, + }, + }) + return flat(geometry).filter( + (child) => child.kind === 'polygon' && child.stroke === BLUE && child.fill === 'none', + ) + } + + test('a selected or moved roof draws each segment where it stands on the walls', () => { + for (const view of [{ selected: true }, { moving: true }]) { + const lines = wallLines(view).filter((child) => + child.kind === 'polygon' + ? child.points.every(([x, z]) => Math.abs(x) === 5 && Math.abs(z) === 3) + : false, + ) + expect(lines).toHaveLength(1) + } + }) + + test('at rest it draws only the eaves', () => { + expect(wallLines({})).toHaveLength(0) + }) +}) diff --git a/packages/nodes/src/roof/floorplan.ts b/packages/nodes/src/roof/floorplan.ts index 7d749509de..90e9474402 100644 --- a/packages/nodes/src/roof/floorplan.ts +++ b/packages/nodes/src/roof/floorplan.ts @@ -4,6 +4,7 @@ import { type GeometryContext, getGlazedRoofPlanLines, getRoofSegmentVisibleTopBounds, + getSegmentSlopeFrame, type RoofNode, type RoofSegmentNode, roofPlanOverlapEntryOwns, @@ -12,6 +13,7 @@ import { } from '@pascal-app/core' import { floorplanGeometryMetadata, readFloorplanContext } from '@pascal-app/editor' import { getConicalRoofPlanFootprint, getRoofSegmentPlanLinework } from '../roof-segment/floorplan' +import { getRoofSurfaceCreases, type RoofCreaseSurface, type RoofPlane } from './roof-plan-creases' type Pt = [number, number] type Seg = [Pt, Pt] @@ -23,11 +25,24 @@ type SegPlan = { footprint: Pt[] /** The visible roof edge — the footprint plus the eave / rake overhang. */ eave: Pt[] + /** + * The edge the plan outlines, and the reach of its ridges, hips and + * valleys. The editor draws the roof as the 3D shows it from above, out to + * the eave and rake; a drafted sheet outlines the wall line and dashes the + * overhang past it (`eave`). + */ + outline: Pt[] ridges: Seg[] hips: Seg[] breaks: Seg[] glazing: Seg[] slopes: SlopeArrow[] + /** + * The segment's top as planes, for a form made only of planes (gable, hip, + * shed, flat): the plan then draws its ridges, hips and valleys off the + * unioned surface (`getRoofSurfaceCreases`) instead of `ridges` / `hips`. + */ + surface: RoofCreaseSurface | null } type PlanEntry = { @@ -117,6 +132,35 @@ function overlapEntry(entry: PlanEntry, ctx: GeometryContext) { } } +/** + * A planar form's roof planes in segment-local plan coordinates, each as + * `[gx, gz, c]` with height `c + gx·lx + gz·lz` above the eave: every slope + * rises at the pitch from its eave line. `null` for the forms with curved or + * broken slopes, which keep their own linework. + */ +function localRoofPlanes(seg: RoofSegmentNode): [number, number, number][] | null { + const hw = Math.max(seg.width, 0.01) / 2 + const hd = Math.max(seg.depth, 0.01) / 2 + const tan = getSegmentSlopeFrame(seg).tanTheta + const towardPlusZ: [number, number, number] = [0, -tan, tan * hd] + const towardMinusZ: [number, number, number] = [0, tan, tan * hd] + const towardPlusX: [number, number, number] = [-tan, 0, tan * hw] + const towardMinusX: [number, number, number] = [tan, 0, tan * hw] + switch (seg.roofType) { + case 'flat': + return [[0, 0, 0]] + case 'shed': + // high eave at lz = −hd, falling to +hd, as the 3D builder slopes it + return [towardPlusZ] + case 'gable': + return [towardPlusZ, towardMinusZ] + case 'hip': + return [towardPlusZ, towardMinusZ, towardPlusX, towardMinusX] + default: + return null + } +} + /** A segment's footprint + ridge/hip/break/slope linework, in world plan coords. */ function buildSegPlan(roof: RoofNode, seg: RoofSegmentNode, drafting: boolean): SegPlan { const cosRoof = Math.cos(-roof.rotation) @@ -132,19 +176,52 @@ function buildSegPlan(roof: RoofNode, seg: RoofSegmentNode, drafting: boolean): ] const hw = Math.max(seg.width, 0.01) / 2 const hd = Math.max(seg.depth, 0.01) / 2 + const conical = seg.roofType === 'conical' + // The drip edge: core's own visible-top bounds, which add the horizontal + // component of `overhang` (plus half the wall thickness and, on the sloped + // faces, the shingle projection) to the footprint on each side. + const edge = getRoofSegmentVisibleTopBounds(seg) + // In the editor a line that ends on the wall line runs on to the eave or + // rake, as the 3D's hips, ridges and slope breaks do. + const toEdge = (v: number, half: number, min: number, max: number) => + Math.abs(v - half) < 1e-6 ? max : Math.abs(v + half) < 1e-6 ? min : v + const reach = drafting || conical ? null : edge + const mapSeg = (s: readonly [readonly [number, number], readonly [number, number]]): Seg => + s.map(([lx, lz]) => + reach + ? tp(toEdge(lx, hw, reach.minX, reach.maxX), toEdge(lz, hd, reach.minZ, reach.maxZ)) + : tp(lx, lz), + ) as Seg const lw = getRoofSegmentPlanLinework(seg) - const mapSeg = (s: readonly [readonly [number, number], readonly [number, number]]): Seg => [ - tp(s[0][0], s[0][1]), - tp(s[1][0], s[1][1]), + const footprint = conical + ? getConicalRoofPlanFootprint(seg).map(([x, z]) => tp(x, z)) + : [tp(-hw, -hd), tp(hw, -hd), tp(hw, hd), tp(-hw, hd)] + const eave = [ + tp(edge.minX, edge.minZ), + tp(edge.maxX, edge.minZ), + tp(edge.maxX, edge.maxZ), + tp(edge.minX, edge.maxZ), ] - const footprint = - seg.roofType === 'conical' - ? getConicalRoofPlanFootprint(seg).map(([x, z]) => tp(x, z)) - : [tp(-hw, -hd), tp(hw, -hd), tp(hw, hd), tp(-hw, hd)] + const outline = reach ? eave : footprint const ridges = lw.ridges.map(mapSeg) const hips = lw.hips.map(mapSeg) const breaks = lw.breaks.map(mapSeg) - const glazing = getGlazedRoofPlanLines(seg).map(mapSeg) + const glazing = getGlazedRoofPlanLines(seg).map(([a, b]): Seg => [tp(a[0], a[1]), tp(b[0], b[1])]) + const local = localRoofPlanes(seg) + // Heights in the roof's level frame, so the planes of two roofs side by side + // compare. The planes run on past the wall line, as the overhang does. + const base = roof.position[1] + seg.position[1] + seg.wallHeight + const surface: RoofCreaseSurface | null = local + ? { + roofId: String(roof.id), + footprint: outline, + planes: local.map(([gx, gz, c0]): RoofPlane => { + const a = gx * cos - gz * sin + const b = gx * sin + gz * cos + return { a, b, c: base + c0 - a * segCx - b * segCz } + }), + } + : null if (!drafting) { const slopes = lw.slope ? [ @@ -155,25 +232,18 @@ function buildSegPlan(roof: RoofNode, seg: RoofSegmentNode, drafting: boolean): }, ] : [] - return { footprint, eave: footprint, ridges, hips, breaks, glazing, slopes } + return { footprint, eave, outline, ridges, hips, breaks, glazing, slopes, surface } } - // The drip edge: core's own visible-top bounds, which add the horizontal - // component of `overhang` (plus half the wall thickness and, on the sloped - // faces, the shingle projection) to the footprint on each side. - const edge = getRoofSegmentVisibleTopBounds(seg) const pitch = seg.roofType === 'barrel' ? '' : roofPitchLabel(seg.pitch) return { footprint, - eave: [ - tp(edge.minX, edge.minZ), - tp(edge.maxX, edge.minZ), - tp(edge.maxX, edge.maxZ), - tp(edge.minX, edge.maxZ), - ], + eave, + outline, ridges, hips, breaks, glazing, + surface, slopes: slopeArrows(seg).map((arrow) => ({ tail: tp(arrow.tail[0], arrow.tail[1]), head: tp(arrow.head[0], arrow.head[1]), @@ -272,25 +342,25 @@ export function buildRoofFloorplan(node: RoofNode, ctx: GeometryContext): Floorp } const currentEntries = entries.filter((entry) => entry.roof.id === node.id) + const owningCandidates = (entry: PlanEntry) => + entries.filter((candidate) => { + if (candidate.segment.id === entry.segment.id) return false + if (candidate.segment.roofType === 'shed') return false + return roofPlanOverlapEntryOwns(overlapEntry(candidate, ctx), overlapEntry(entry, ctx)) + }) const visiblePlans = currentEntries.map((entry) => { - const cutters = entries - .filter((candidate) => { - if (candidate.segment.id === entry.segment.id) return false - if (candidate.segment.roofType === 'shed') return false - return roofPlanOverlapEntryOwns(overlapEntry(candidate, ctx), overlapEntry(entry, ctx)) - }) - .map((candidate) => candidate.plan.footprint) + const cutters = owningCandidates(entry).map((candidate) => candidate.plan.outline) return { plan: entry.plan, cutters, - footprints: subtractPolygonsFromPolygon(entry.plan.footprint, cutters) as Pt[][], + outlines: subtractPolygonsFromPolygon(entry.plan.outline, cutters) as Pt[][], eaves: subtractPolygonsFromPolygon(entry.plan.eave, cutters) as Pt[][], /** True when the drip edge is far enough outside the wall line to draw. */ hasOverhang: drafting && polygonSpread(entry.plan.eave) - polygonSpread(entry.plan.footprint) > 0.04, } }) - const rings = unionPolygons(visiblePlans.flatMap(({ footprints }) => footprints)) as Pt[][] + const rings = unionPolygons(visiblePlans.flatMap(({ outlines }) => outlines)) as Pt[][] if (rings.length === 0) return null const eaveRings = unionPolygons( visiblePlans.flatMap(({ eaves, hasOverhang }) => (hasOverhang ? eaves : [])), @@ -344,7 +414,7 @@ export function buildRoofFloorplan(node: RoofNode, ctx: GeometryContext): Floorp }) } - // Merged outline (wall line under the roof). + // Merged outline: the eave and rake in the editor, the wall line on a sheet. for (const ring of rings) { if (ring.length < 3) continue children.push({ @@ -358,24 +428,65 @@ export function buildRoofFloorplan(node: RoofNode, ctx: GeometryContext): Floorp }) } + // Selected or moved, the wall line each segment stands on: whether the roof sits on the walls' + // centre lines (a selected segment draws its own). + if (!drafting && palette && ((view?.moving ?? false) || showSelectedChrome)) { + for (const { plan } of visiblePlans) { + children.push({ + kind: 'polygon', + points: plan.footprint.map(([x, z]) => [x, z] as FloorplanPoint), + fill: 'none', + stroke: palette.selectedStroke, + strokeWidth: 0.035, + strokeLinejoin: 'miter', + pointerEvents: 'none', + }) + } + } + + // Ridges, hips and valleys of the planar segments, off the surface they make + // together with this level's other roofs: a wing's ridge runs on until it + // meets the main roof's slope, and a valley runs where the two slopes meet. + // The curved and broken forms are not in that surface: where one owns an + // overlap it cuts these lines as before. + const planarEntries = entries.filter((entry) => entry.plan.surface) + const curvedCutters = (entry: PlanEntry) => + owningCandidates(entry) + .filter((candidate) => !candidate.plan.surface) + .map((candidate) => candidate.plan.outline) + for (const crease of getRoofSurfaceCreases(planarEntries.map((entry) => entry.plan.surface!))) { + if (crease.roofId !== String(node.id)) continue + const [i, k] = crease.between + const cutters = [ + ...curvedCutters(planarEntries[i]!), + ...(k === i ? [] : curvedCutters(planarEntries[k]!)), + ] + const width = crease.kind === 'ridge' ? ridgeWidth : hipWidth + for (const visible of clipLineByCutters([crease.from, crease.to], cutters)) + pushLine(visible[0], visible[1], width) + } + for (const { plan, cutters } of visiblePlans) { for (const line of plan.glazing) { for (const visible of clipLineByCutters(line, cutters)) pushLine(visible[0], visible[1], hipWidth) } - for (const line of plan.breaks) { - for (const visible of clipLineByCutters(line, cutters)) { - pushLine(visible[0], visible[1], hipWidth) + // A planar segment's ridges and hips were drawn off the shared surface above. + if (!plan.surface) { + for (const line of plan.breaks) { + for (const visible of clipLineByCutters(line, cutters)) { + pushLine(visible[0], visible[1], hipWidth) + } } - } - for (const line of plan.hips) { - for (const visible of clipLineByCutters(line, cutters)) { - pushLine(visible[0], visible[1], hipWidth) + for (const line of plan.hips) { + for (const visible of clipLineByCutters(line, cutters)) { + pushLine(visible[0], visible[1], hipWidth) + } } - } - for (const line of plan.ridges) { - for (const visible of clipLineByCutters(line, cutters)) { - pushLine(visible[0], visible[1], ridgeWidth) + for (const line of plan.ridges) { + for (const visible of clipLineByCutters(line, cutters)) { + pushLine(visible[0], visible[1], ridgeWidth) + } } } diff --git a/packages/nodes/src/roof/paint.ts b/packages/nodes/src/roof/paint.ts new file mode 100644 index 0000000000..1ae3ef1765 --- /dev/null +++ b/packages/nodes/src/roof/paint.ts @@ -0,0 +1,196 @@ +import { + type AnyNode, + type AnyNodeId, + getEffectiveRoofSurfaceMaterial, + getEffectiveSegmentSurfaceMaterial, + getRoofWallBandMaterial, + type PaintCapability, + type RoofNode, + type RoofSegmentNode, + type RoofSurfaceMaterialRole, + useScene, +} from '@pascal-app/core' +import { buildRoofSurfaceMaterialPatch, resolveRoofWallHit } from '@pascal-app/editor' +import { + getRoofMaterialArray, + levelWallCladdingRef, + levelWallFaceRef, + ROOF_HEEL_MATERIAL_INDEX, + useViewer, +} from '@pascal-app/viewer' +import { type Mesh, Vector3 } from 'three' +import { wallBandPatch } from '../roof-segment/paint' +import { swapPreviewMaterial } from '../shared/swap-preview-material' + +type RoofGableBand = 'gable-left' | 'gable-right' + +/** Every gable of the roof: the `matching` scope of a gable hit. */ +export const ROOF_ALL_GABLES_ROLE = 'gables:all' + +/** One gable of the merged shell: `gable-left:` / `gable-right:`. */ +export function roofGableRole(band: RoofGableBand, segmentId: string): string { + return `${band}:${segmentId}` +} + +export function parseRoofGableRole( + role: string, +): { band: RoofGableBand; segmentId: AnyNodeId } | null { + const split = role.indexOf(':') + if (split < 0) return null + const band = role.slice(0, split) + if (band !== 'gable-left' && band !== 'gable-right') return null + return { band, segmentId: role.slice(split + 1) as AnyNodeId } +} + +const isSurfaceRole = (role: string): role is RoofSurfaceMaterialRole => + role === 'top' || role === 'edge' || role === 'wall' + +const hitWorldPoint = new Vector3() + +/** The merged shell's surface under the cursor: its material slot, else the hit normal. */ +function surfaceRole( + materialIndex: number | null, + normal: readonly [number, number, number] | undefined, +): RoofSurfaceMaterialRole | 'heel' | null { + if (materialIndex === 3) return 'top' + if (materialIndex === ROOF_HEEL_MATERIAL_INDEX) return 'heel' + if (materialIndex === 0) return 'edge' + if (materialIndex === 1 || materialIndex === 2) return 'wall' + + const normalY = normal?.[1] + if (normalY !== undefined && normalY > 0.35) return 'top' + if (normalY !== undefined && Math.abs(normalY) <= 0.35) return 'edge' + if (normalY !== undefined && normalY < -0.35) return 'wall' + return null +} + +/** The merged roof with `role` repainted, so the preview draws it the way a commit would. */ +function previewRoof( + roof: RoofNode, + role: string, + material: RoofNode['material'], + preset?: string, +) { + if (role === 'heel') return { ...roof, ...wallBandPatch('heel', material, preset) } as RoofNode + const surface = role === ROOF_ALL_GABLES_ROLE ? 'edge' : role + if (!isSurfaceRole(surface)) return null + return { ...roof, ...buildRoofSurfaceMaterialPatch(roof, surface, material, preset) } +} + +/** + * The merged roof shell's paint. Its surfaces are the roof's top / edge / wall + * finishes and the heel band; an edge hit on a segment's ±x end wall is that + * gable alone (its segment's gable finish), and the `matching` scope widens it + * to every gable — the roof's edge, with no segment keeping a gable of its own. + */ +export const roofPaint: PaintCapability = { + materialTarget: 'roof', + resolveRole(args) { + const role = surfaceRole(args.materialIndex, args.normal) + if (role !== 'edge' || !(args.localPosition && args.hitObject)) return role + args.hitObject.updateWorldMatrix(true, false) + const position = args.hitObject.localToWorld(hitWorldPoint.set(...args.localPosition)) + const hit = resolveRoofWallHit( + args.node as RoofNode, + [position.x, position.y, position.z], + args.normal as [number, number, number] | undefined, + args.hitObject, + ) + if (!hit || (hit.face.id !== 'left' && hit.face.id !== 'right')) return role + return roofGableRole(hit.face.id === 'left' ? 'gable-left' : 'gable-right', hit.segment.id) + }, + roleLabel(_node, role) { + if (role === 'heel') return 'Heel band' + if (role === ROOF_ALL_GABLES_ROLE) return 'All gables' + const gable = parseRoofGableRole(role) + if (!gable) return null + return gable.band === 'gable-left' ? 'Left gable' : 'Right gable' + }, + scopes(_node, role) { + if (!parseRoofGableRole(role)) return null + return { + scopes: ['single', 'matching'], + labels: { matching: 'All gables' }, + roleFor: (scope) => (scope === 'matching' ? ROOF_ALL_GABLES_ROLE : role), + } + }, + buildPatch({ node, role, material, materialPreset }) { + const roof = node as RoofNode + if (role === 'heel') return wallBandPatch('heel', material, materialPreset) as Partial + if (role === ROOF_ALL_GABLES_ROLE) + return buildRoofSurfaceMaterialPatch(roof, 'edge', material, materialPreset) + if (!isSurfaceRole(role)) return {} + return buildRoofSurfaceMaterialPatch(roof, role, material, materialPreset) + }, + commit(args) { + const scene = useScene.getState() + const gable = parseRoofGableRole(args.role) + if (gable) { + scene.updateNode( + gable.segmentId, + wallBandPatch(gable.band, args.material, args.materialPreset), + ) + return + } + if (args.role !== ROOF_ALL_GABLES_ROLE) { + scene.updateNode(args.node.id as AnyNodeId, roofPaint.buildPatch(args)) + return + } + // Every gable: the roof's edge, and no segment keeping a gable of its own. + const cleared: Partial = { + ...wallBandPatch('gable-left', undefined, undefined), + ...wallBandPatch('gable-right', undefined, undefined), + } + scene.updateNodes([ + { id: args.node.id as AnyNodeId, data: roofPaint.buildPatch(args) }, + ...((args.node as RoofNode).children ?? []).flatMap((childId) => + scene.nodes[childId as AnyNodeId]?.type === 'roof-segment' + ? [{ id: childId as AnyNodeId, data: cleared as Partial }] + : [], + ), + ]) + }, + applyPreview(args) { + // One gable has no surface of its own on the merged shell until it is painted. + if (parseRoofGableRole(args.role)) return null + const mesh = args.root.getObjectByName('merged-roof') as Mesh | undefined + if (!mesh) return null + const roof = args.node as RoofNode + const preview = previewRoof(roof, args.role, args.material, args.materialPreset) + if (!preview) return null + // The renderer's wall-derived defaults, so the surfaces not being painted hold still. + const nodes = args.nodes ?? useScene.getState().nodes + const viewer = useViewer.getState() + const material = getRoofMaterialArray( + preview, + viewer.shading, + viewer.textures, + viewer.colorPreset, + viewer.sceneTheme, + levelWallCladdingRef(nodes, roof), + args.materials ?? useScene.getState().materials, + levelWallFaceRef(nodes, roof), + ) + return material ? swapPreviewMaterial(mesh, material) : null + }, + // The top / edge / wall finishes return null here and resolve through the + // editor's roof surface fallback (`resolveActivePaintMaterialFromSelection`). + getEffectiveMaterial({ node, role, nodes }) { + if (role === 'heel') { + const own = getRoofWallBandMaterial(node as RoofNode, 'heel') + return own ? { material: own.material, materialPreset: own.materialPreset } : null + } + const gable = parseRoofGableRole(role) + const segment = gable ? (nodes?.[gable.segmentId] as RoofSegmentNode | undefined) : undefined + if (!(gable && segment?.type === 'roof-segment')) return null + // Unpainted, a gable shows the segment's edge, falling back to the roof's. + const own = getRoofWallBandMaterial(segment, gable.band) + if (own) return { material: own.material, materialPreset: own.materialPreset } + const edge = getEffectiveSegmentSurfaceMaterial( + segment, + 'edge', + getEffectiveRoofSurfaceMaterial(node as RoofNode, 'edge'), + ) + return { material: edge.material, materialPreset: edge.materialPreset } + }, +} diff --git a/packages/nodes/src/roof/panel.tsx b/packages/nodes/src/roof/panel.tsx index d60ae54981..c429035d6f 100644 --- a/packages/nodes/src/roof/panel.tsx +++ b/packages/nodes/src/roof/panel.tsx @@ -7,6 +7,8 @@ import { type ChimneyNode, type DormerNode, type GutterNode, + getRoofSegmentDeckReach, + getSegmentSlopeFrame, isRoofOnStoreyWalls, type LevelNode, type PascalI18n, @@ -15,6 +17,7 @@ import { type RoofNode, type RoofSegmentNode, roofLevelAbove, + roofTypeHasRakes, type SkylightNode, type SolarPanelNode, type TurbineVentNode, @@ -221,6 +224,19 @@ export default function RoofPanel() { [selectedId], ) + // The eaves are each segment's: the roof's sliders set them on all of its segments at once. + const handleSegmentsUpdate = useCallback( + (patch: (segment: RoofSegmentNode) => Partial | null) => { + if (!selectedId) return + const update = segments.flatMap((segment) => { + const data = patch(segment) + return data ? [{ id: segment.id as AnyNodeId, data: data as Partial }] : [] + }) + if (update.length > 0) commitSeatedRoofEdit(update, selectedId as AnyNodeId) + }, + [segments, selectedId], + ) + const handleClose = useCallback(() => { setSelection({ selectedIds: [] }) }, [setSelection]) @@ -294,6 +310,12 @@ export default function RoofPanel() { if (!(node && node.type === 'roof' && selectedId)) return null + // Shown as the segment panel shows them: in plan, past the walls' outside faces. + const eaveSegment = segments.find((segment) => segment.roofType !== 'barrel') + const rakedSegment = segments.find((segment) => roofTypeHasRakes(segment.roofType)) + const overhangPastWall = (segment: RoofSegmentNode, axis: 'x' | 'z') => + getRoofSegmentDeckReach(segment)[axis] - segment.wallThickness / 2 + return ( + {eaveSegment && ( + + + handleSegmentsUpdate((segment) => + segment.roofType === 'barrel' + ? null + : { overhang: v / getSegmentSlopeFrame(segment).cosTheta }, + ) + } + precision={2} + step={0.05} + unit="m" + value={overhangPastWall(eaveSegment, 'z')} + /> + {rakedSegment && ( + + handleSegmentsUpdate((segment) => + roofTypeHasRakes(segment.roofType) ? { gableOverhang: v } : null, + ) + } + precision={2} + step={0.05} + unit="m" + value={overhangPastWall(rakedSegment, 'x')} + /> + )} + + )} + { // The gable band is clad like the walls below it (their assemblies). const wallCladdingRef = useScene((state) => levelWallCladdingRef(state.nodes, node)) + // The heel band, under the eaves, is wall: it shows what the walls below show outside. + const wallFaceRef = useScene((state) => levelWallFaceRef(state.nodes, node)) const sceneMaterials = useScene((state) => state.materials) const customMaterial = useMemo( () => @@ -133,8 +136,18 @@ export const RoofRenderer = ({ node: rawNode }: { node: RoofNode }) => { sceneTheme, wallCladdingRef, sceneMaterials, + wallFaceRef, ), - [node, shading, textures, colorPreset, sceneTheme, wallCladdingRef, sceneMaterials], + [ + node, + shading, + textures, + colorPreset, + sceneTheme, + wallCladdingRef, + sceneMaterials, + wallFaceRef, + ], ) const material = debugColors diff --git a/packages/nodes/src/roof/roof-footprint-source.ts b/packages/nodes/src/roof/roof-footprint-source.ts index 2d17d69550..0b38a5e502 100644 --- a/packages/nodes/src/roof/roof-footprint-source.ts +++ b/packages/nodes/src/roof/roof-footprint-source.ts @@ -2,9 +2,18 @@ import { create } from 'zustand' export type RoofFootprintSourceChoice = 'draw' | 'room' +/** + * What a Room pick finds under the cursor: a room it can roof, a room that is + * not a rectangle (Room roofs only rectangles), or no closed room at all. + */ +export type RoofRoomPick = 'room' | 'irregular' | 'none' + type RoofFootprintSourceState = { source: RoofFootprintSourceChoice setSource: (source: RoofFootprintSourceChoice) => void + /** The hovered Room pick, for the HUD to say why a click would do nothing; null off Room. */ + roomPick: RoofRoomPick | null + setRoomPick: (roomPick: RoofRoomPick | null) => void } /** @@ -18,6 +27,23 @@ type RoofFootprintSourceState = { const useRoofFootprintSource = create((set) => ({ source: 'draw', setSource: (source) => set({ source }), + roomPick: null, + setRoomPick: (roomPick) => set({ roomPick }), })) +const subscribeToRoomPick = (onChange: () => void) => + useRoofFootprintSource.subscribe((state, previous) => { + if (state.roomPick !== previous.roomPick) onChange() + }) + +export const irregularRoomHintVisibility = { + subscribe: subscribeToRoomPick, + value: () => useRoofFootprintSource.getState().roomPick === 'irregular', +} + +export const noRoomHintVisibility = { + subscribe: subscribeToRoomPick, + value: () => useRoofFootprintSource.getState().roomPick === 'none', +} + export default useRoofFootprintSource diff --git a/packages/nodes/src/roof/roof-footprint.test.ts b/packages/nodes/src/roof/roof-footprint.test.ts index cc1529a4e5..98b231bd57 100644 --- a/packages/nodes/src/roof/roof-footprint.test.ts +++ b/packages/nodes/src/roof/roof-footprint.test.ts @@ -4,8 +4,10 @@ import { fitRoofFootprint, LevelNode, resolveRoomRoofFootprint, + SeparatorNode, type WallEvent, WallNode, + ZoneNode, } from '@pascal-app/core' import { isStandardRoofWallEligible, @@ -13,6 +15,9 @@ import { resolveRoofFootprintElevation, resolveRoofFootprintWorldElevation, resolveRoofWallTopWorldElevation, + roofEdgeAnchors, + roofFootprintPreviewIds, + roofSnapEdges, subscribeToConicalRoofWallClicks, } from './roof-footprint' @@ -274,3 +279,127 @@ describe('roof footprint sources', () => { expect(selected).toEqual([]) }) }) + +const RAIL = 3.5 * 0.0254 +const H = RAIL / 2 +const r6 = (value: number) => Math.round(value * 1e6) / 1e6 + +// A porch 6 m along a 0.2 m house wall at z 0, 2.5 m deep: invisible walls or railings round it. +function porchLevel(open: 'separators' | 'railings') { + const level = LevelNode.parse({ id: 'level_porch', level: 0 }) + const house = WallNode.parse({ + id: 'wall_house', + parentId: level.id, + start: [0, 0], + end: [10, 0], + thickness: 0.2, + }) + const sides: Array<[[number, number], [number, number]]> = [ + [ + [2, 0], + [2, -2.5], + ], + [ + [2, -2.5], + [8, -2.5], + ], + [ + [8, -2.5], + [8, 0], + ], + ] + const edges = sides.map(([start, end], i) => + open === 'separators' + ? SeparatorNode.parse({ id: `separator_${i}`, parentId: level.id, start, end }) + : WallNode.parse({ + id: `wall_rail${i}`, + parentId: level.id, + start, + end, + wallType: 'railing', + thickness: RAIL, + }), + ) + const zone = ZoneNode.parse({ + id: 'zone_porch', + parentId: level.id, + name: 'Porch', + roomType: open === 'separators' ? 'porch' : 'deck', + polygon: [ + [2, 0], + [2, -2.5], + [8, -2.5], + [8, 0], + ], + }) + level.children = [house, ...edges, zone].map((node) => node.id) as LevelNode['children'] + return Object.fromEntries([level, house, ...edges, zone].map((node) => [node.id, node])) +} + +const ends = (wall: WallNode) => [...wall.start, ...wall.end].map(r6) + +describe("the rooms' edges a drawn roof snaps to", () => { + test("a porch's invisible walls snap as walls do, on their lines", () => { + const { references, faced } = roofSnapEdges(porchLevel('separators'), ['level_porch']) + expect(references.map((reference) => reference.id)).toEqual([ + 'separator_0', + 'separator_1', + 'separator_2', + ]) + expect(references.map(ends)).toEqual([ + [2, 0, 2, -2.5], + [2, -2.5, 8, -2.5], + [8, -2.5, 8, 0], + ]) + expect(references.every((reference) => isStandardRoofWallEligible(reference))).toBe(true) + expect(faced.size).toBe(0) + }) + + test("a deck's railings snap at their outside faces, post corner to post corner", () => { + const { references, faced } = roofSnapEdges(porchLevel('railings'), ['level_porch']) + expect(references.map(ends)).toEqual([ + [2 - H, 0, 2 - H, -2.5 - H].map(r6), + [2 - H, -2.5 - H, 8 + H, -2.5 - H].map(r6), + [8 + H, -2.5 - H, 8 + H, 0].map(r6), + ]) + expect([...faced].sort()).toEqual(['wall_rail0', 'wall_rail1', 'wall_rail2']) + }) + + test("a porch's corners and invisible walls' ends line a drawn roof up", () => { + const deck = roofEdgeAnchors(porchLevel('railings'), ['level_porch']) + const corner = deck.find((anchor) => anchor.nodeId === 'zone_porch' && anchor.x > 8) + expect(corner && [r6(corner.x), r6(corner.z)]).toEqual([r6(8 + H), r6(-2.5 - H)]) + const porch = roofEdgeAnchors(porchLevel('separators'), ['level_porch']) + expect(porch).toContainEqual({ nodeId: 'separator_1', kind: 'center', x: 5, z: -2.5 }) + expect(porch).toContainEqual({ nodeId: 'separator_0', kind: 'corner', x: 2, z: -2.5 }) + }) + + test('the Room pick lights up a porch with its edges, a room with its walls', () => { + const porch = resolveRoomRoofFootprint('level_porch', porchLevel('separators'), [5, -1]) + expect(roofFootprintPreviewIds(porch).sort()).toEqual([ + 'separator_0', + 'separator_1', + 'separator_2', + 'wall_house', + ]) + expect(roofFootprintPreviewIds(null)).toEqual([]) + }) + + test("a railing's top never sets its roof's height", () => { + const nodes = porchLevel('railings') + const target = fitRoofFootprint( + 'deck', + [ + [2, 0], + [2, -2.5], + [8, -2.5], + [8, 0], + ], + ['wall_rail1' as WallNode['id']], + )! + const railing = { ...nodes.wall_rail1, height: 0.9 } as WallNode + expect( + resolveRoofFootprintElevation('level_porch', target, { ...nodes, wall_rail1: railing }), + ).toBe(0) + }) +}) diff --git a/packages/nodes/src/roof/roof-footprint.ts b/packages/nodes/src/roof/roof-footprint.ts index a887a957af..2b202a5708 100644 --- a/packages/nodes/src/roof/roof-footprint.ts +++ b/packages/nodes/src/roof/roof-footprint.ts @@ -1,29 +1,152 @@ import { + type AlignmentAnchor, type AnyNode, emitter, getLevelBelow, getLevelElevations, + getWallCurveFrameAt, + getWallCurveStationAtPoint, isCurvedWall, + isOutdoorRoomType, + isRailingWall, type LevelNode, + outdoorRoomRoofOutline, + polygonAnchors, type RoofFootprintTarget, type RoofType, resolveLevelId, resolveRoofWallTopElevation, + resolveRoomRoofFootprint, + type SeparatorNode, type WallEvent, type WallNode, + wallSegmentAnchors, + type ZoneNode, } from '@pascal-app/core' +import type { RoofRoomPick } from './roof-footprint-source' export type RoofFootprintSource = 'room' | 'walls' | 'draw' const ROOF_AXIS_ALIGNMENT_EPSILON = 1e-4 -export function isStandardRoofWallEligible(wall: WallNode): boolean { +export function isStandardRoofWallEligible( + wall: Pick, +): boolean { if (isCurvedWall(wall)) return false const deltaX = Math.abs(wall.end[0] - wall.start[0]) const deltaZ = Math.abs(wall.end[1] - wall.start[1]) return deltaX <= ROOF_AXIS_ALIGNMENT_EPSILON || deltaZ <= ROOF_AXIS_ALIGNMENT_EPSILON } +/** A room's edge as the wall snap reads a wall: its ends, its middle and its run catch a point. */ +function edgeReference( + id: string, + parentId: string | null, + start: [number, number], + end: [number, number], +): WallNode { + return { + object: 'node', + id: id as WallNode['id'], + type: 'wall', + parentId, + visible: true, + metadata: {}, + children: [], + start, + end, + frontSide: 'unknown', + backSide: 'unknown', + } +} + +/** The levels' invisible walls, and their porches', decks' and patios' outside edges. */ +function levelEdges(nodes: Readonly>, levelIds: readonly string[]) { + return levelIds.flatMap((levelId) => { + const level = nodes[levelId] + if (level?.type !== 'level') return [] + const children = level.children.map((id) => nodes[id]) + const walls = children.filter((node): node is WallNode => node?.type === 'wall') + const separators = children.filter((node): node is SeparatorNode => node?.type === 'separator') + const rooms = children + .filter( + (node): node is ZoneNode => + node?.type === 'zone' && isOutdoorRoomType(node.roomType) && node.polygon.length >= 3, + ) + .map((zone) => ({ zone, ...outdoorRoomRoofOutline(zone, walls, separators) })) + return [{ levelId, separators, rooms }] + }) +} + +const snapEdgesMemo = new WeakMap>>() + +function computeRoofSnapEdges( + nodes: Readonly>, + levelIds: readonly string[], +) { + const references: WallNode[] = [] + const faced = new Set() + for (const { levelId, separators, rooms } of levelEdges(nodes, levelIds)) { + for (const separator of separators) + references.push(edgeReference(separator.id, levelId, separator.start, separator.end)) + for (const { polygon, edges } of rooms) + edges.forEach((edge, index) => { + if (edge?.kind !== 'railing') return + faced.add(edge.id) + const next = polygon[(index + 1) % polygon.length]! + references.push(edgeReference(edge.id, levelId, polygon[index]!, next)) + }) + } + return { references, faced } +} + +/** + * The rooms' edges on `levelIds` a drawn roof snaps to, as it snaps to walls (their corners, + * middles, crossings and runs): each invisible wall's line, and each railing round a porch, deck + * or patio at its outside face, from post corner to post corner (`outdoorRoomRoofOutline`), so a + * roof drawn over the room reaches its outside edge as one drawn over the house reaches its walls'. + * `faced` holds those railings: their faces stand in for their centre lines. Kept per scene, so a + * pointer move asks once. + */ +export function roofSnapEdges( + nodes: Readonly>, + levelIds: readonly string[], +): { references: WallNode[]; faced: Set } { + const key = levelIds.join('|') + let byKey = snapEdgesMemo.get(nodes) + if (!byKey) { + byKey = new Map() + snapEdgesMemo.set(nodes, byKey) + } + const cached = byKey.get(key) + if (cached) return cached + const edges = computeRoofSnapEdges(nodes, levelIds) + byKey.set(key, edges) + return edges +} + +/** + * The rooms' edges on `levelIds` as alignment anchors for a roof drawn over them: each straight + * invisible wall's ends and middle (as a wall's), and each porch's, deck's or patio's outside + * corners, railings' post corners included. + */ +export function roofEdgeAnchors( + nodes: Readonly>, + levelIds: readonly string[], +): AlignmentAnchor[] { + return levelEdges(nodes, levelIds).flatMap(({ separators, rooms }) => [ + ...separators + .filter((separator) => isStandardRoofWallEligible(separator)) + .flatMap((separator) => wallSegmentAnchors(separator.id, separator.start, separator.end)), + ...rooms.flatMap(({ zone, polygon }) => polygonAnchors(zone.id, polygon)), + ]) +} + +/** What a Room pick lights up while it hovers a room: its walls, a porch's edges with them. */ +export function roofFootprintPreviewIds(target: RoofFootprintTarget | null): string[] { + return target ? [...target.wallIds, ...(target.edgeIds ?? [])] : [] +} + export function isConicalRoofWallEligible( targetLevelId: LevelNode['id'], wall: WallNode, @@ -36,11 +159,51 @@ export function isConicalRoofWallEligible( return getLevelBelow(targetLevelId, completeNodes)?.id === sourceLevelId } +// As far off the wall's centreline as the plan reaches for a wall a door or window goes in. +const CONICAL_WALL_PICK_DISTANCE = 0.5 + +/** + * The curved wall a cone would be built over from a plan point: the nearest one in reach on the + * level or the level below. The plan raises no wall events, so its tool picks the wall itself. + */ +export function pickConicalRoofWall( + levelId: LevelNode['id'], + nodes: Readonly>, + point: [number, number], +): WallNode | null { + let picked: WallNode | null = null + let pickedDistance = CONICAL_WALL_PICK_DISTANCE + for (const node of Object.values(nodes)) { + if (!(node.type === 'wall' && isCurvedWall(node))) continue + if (!isConicalRoofWallEligible(levelId, node, nodes)) continue + const nearest = getWallCurveFrameAt(node, getWallCurveStationAtPoint(node, point)).point + const distance = Math.hypot(point[0] - nearest.x, point[1] - nearest.y) + if (distance > pickedDistance) continue + picked = node + pickedDistance = distance + } + return picked +} + export function parseRoofFootprintSource(value: unknown, roofType: RoofType): RoofFootprintSource { if (roofType === 'conical') return 'walls' return value === 'room' ? 'room' : 'draw' } +/** + * The room a Room pick at `point` roofs (the smallest one on the level, else on the level below), + * and what the pick found: a rectangle it roofs, a room it can't (not a rectangle), or none. + */ +export function pickRoofRoom( + levelId: LevelNode['id'], + nodes: Readonly>, + point: [number, number], +): { target: RoofFootprintTarget | null; pick: RoofRoomPick } { + const found = resolveRoomRoofFootprint(levelId, nodes, point) + if (!found) return { target: null, pick: 'none' } + return found.rectangular ? { target: found, pick: 'room' } : { target: null, pick: 'irregular' } +} + export function subscribeToConicalRoofWallClicks(options: { footprintSource: RoofFootprintSource currentLevelId: LevelNode['id'] | null @@ -99,9 +262,10 @@ export function resolveRoofFootprintElevation( ): number { const completeNodes = nodes as Record const elevations = getLevelElevations(completeNodes) + // A railing is a guard round a deck or a porch, not a wall: the roof never sits on its top. const tops = target.wallIds.flatMap((id) => { const wall = nodes[id] - return wall?.type === 'wall' + return wall?.type === 'wall' && !isRailingWall(wall) ? [resolveRoofWallTopElevation(targetLevelId, wall, completeNodes, elevations)] : [] }) diff --git a/packages/nodes/src/roof/roof-materials.ts b/packages/nodes/src/roof/roof-materials.ts index 940ae3bf1c..db7676caa6 100644 --- a/packages/nodes/src/roof/roof-materials.ts +++ b/packages/nodes/src/roof/roof-materials.ts @@ -8,7 +8,7 @@ import { import * as THREE from 'three' // Production materials — match the rest of the scene (white walls, light-gray slabs). -// Indices: 0 = Wall/Trim, 1 = Deck, 2 = Interior, 3 = Shingle +// Indices: 0 = Wall/Trim, 1 = Deck, 2 = Interior, 3 = Shingle, 4 = Heel band, 5/6 = Gables const roofMaterialsCache = new Map() export function getRoofMaterials( @@ -28,12 +28,18 @@ export function getRoofMaterials( resolveSlotDefaultMaterial('library:preset-softwhite', shading), // 1: Deck resolveSlotDefaultMaterial('library:preset-softwhite', shading), // 2: Interior resolveSlotDefaultMaterial('library:roof-terracottatiles', shading), // 3: Shingle + resolveSlotDefaultMaterial('library:concrete-drywall', shading), // 4: Heel band + resolveSlotDefaultMaterial('library:concrete-drywall', shading), // 5: Left gable + resolveSlotDefaultMaterial('library:concrete-drywall', shading), // 6: Right gable ] : [ createSurfaceRoleMaterial('roof', colorPreset), createSurfaceRoleMaterial('ceiling', colorPreset), createSurfaceRoleMaterial('ceiling', colorPreset), createSurfaceRoleMaterial('roof', colorPreset), + createSurfaceRoleMaterial('wall', colorPreset), + createSurfaceRoleMaterial('roof', colorPreset), + createSurfaceRoleMaterial('roof', colorPreset), ] roofMaterialsCache.set(cacheKey, materials) return materials @@ -51,6 +57,9 @@ export function getRoofDebugMaterials(shading: RenderShading = 'rendered'): THRE createDefaultMaterial('#000000', 0.9, shading, THREE.FrontSide), // 1: Deck createDefaultMaterial('#dddddd', 0.9, shading, THREE.DoubleSide), // 2: Interior createDefaultMaterial('#4ade80', 0.9, shading, THREE.FrontSide), // 3: Shingle + createDefaultMaterial('#f5d0a9', 0.8, shading, THREE.DoubleSide), // 4: Heel band + createDefaultMaterial('#93c5fd', 0.8, shading, THREE.DoubleSide), // 5: Left gable + createDefaultMaterial('#c4b5fd', 0.8, shading, THREE.DoubleSide), // 6: Right gable ] roofDebugMaterialsCache.set(shading, materials) return materials diff --git a/packages/nodes/src/roof/roof-placement-mode.test.ts b/packages/nodes/src/roof/roof-placement-mode.test.ts index 01b0abe48c..9fe5a4ca18 100644 --- a/packages/nodes/src/roof/roof-placement-mode.test.ts +++ b/packages/nodes/src/roof/roof-placement-mode.test.ts @@ -2,7 +2,7 @@ import { beforeEach, describe, expect, test } from 'bun:test' import useRoofPlacementMode from './roof-placement-mode' describe('roof placement mode', () => { - beforeEach(() => useRoofPlacementMode.setState({ conical: false, mode: 'auto' })) + beforeEach(() => useRoofPlacementMode.setState({ mode: 'auto' })) test('cycles through auto, ground, and roof placement', () => { const state = useRoofPlacementMode.getState() @@ -13,11 +13,4 @@ describe('roof placement mode', () => { useRoofPlacementMode.getState().cycleMode() expect(useRoofPlacementMode.getState().mode).toBe('auto') }) - - test('publishes whether conical placement hints apply', () => { - useRoofPlacementMode.getState().setConical(true) - expect(useRoofPlacementMode.getState().conical).toBe(true) - useRoofPlacementMode.getState().setConical(false) - expect(useRoofPlacementMode.getState().conical).toBe(false) - }) }) diff --git a/packages/nodes/src/roof/roof-placement-mode.ts b/packages/nodes/src/roof/roof-placement-mode.ts index 605bc1948c..9a223cd1c7 100644 --- a/packages/nodes/src/roof/roof-placement-mode.ts +++ b/packages/nodes/src/roof/roof-placement-mode.ts @@ -1,3 +1,4 @@ +import { useEditor } from '@pascal-app/editor' import { create } from 'zustand' export type RoofPlacementMode = 'auto' | 'ground' | 'roof' @@ -5,35 +6,36 @@ export type RoofPlacementMode = 'auto' | 'ground' | 'roof' const MODES: RoofPlacementMode[] = ['auto', 'ground', 'roof'] type RoofPlacementModeState = { - conical: boolean mode: RoofPlacementMode cycleMode: () => void - setConical: (conical: boolean) => void } const useRoofPlacementMode = create((set, get) => ({ - conical: false, mode: 'auto', cycleMode: () => { const current = MODES.indexOf(get().mode) set({ mode: MODES[(current + 1) % MODES.length] ?? 'auto' }) }, - setConical: (conical) => set({ conical }), })) +// Read from the roof type the tool is armed with, not from whichever roof tool mounted: in a +// 2D-only session the 3D tool never mounts, and the HUD showed a cone the standard rows. +const isConicalRoof = (state: ReturnType) => + state.toolDefaults.roof?.roofType === 'conical' + const subscribeToRoofKind = (onChange: () => void) => - useRoofPlacementMode.subscribe((state, previous) => { - if (state.conical !== previous.conical) onChange() + useEditor.subscribe((state, previous) => { + if (isConicalRoof(state) !== isConicalRoof(previous)) onChange() }) export const conicalRoofToolHintVisibility = { subscribe: subscribeToRoofKind, - value: () => useRoofPlacementMode.getState().conical, + value: () => isConicalRoof(useEditor.getState()), } export const standardRoofToolHintVisibility = { subscribe: subscribeToRoofKind, - value: () => !useRoofPlacementMode.getState().conical, + value: () => !isConicalRoof(useEditor.getState()), } export default useRoofPlacementMode diff --git a/packages/nodes/src/roof/roof-plan-creases.ts b/packages/nodes/src/roof/roof-plan-creases.ts new file mode 100644 index 0000000000..81d9710c81 --- /dev/null +++ b/packages/nodes/src/roof/roof-plan-creases.ts @@ -0,0 +1,228 @@ +/** + * The ridges, hips and valleys a roof plan draws, read off the roof surface + * itself rather than off each segment on its own. + * + * A planar segment (gable, hip, shed, flat) is a convex solid: over its + * footprint its top is the lowest of its planes. Segments that overlap are + * unioned, so the roof's top is the highest of the segments there. The lines + * a plan draws are that surface's creases: + * + * - two planes of one segment meeting where both are its top: a ridge + * (level) or a hip (sloped), drawn wherever no other segment rises over + * it, so a wing's ridge runs on past the main roof's wall line until it + * dives under the main roof's slope; + * - two segments' tops meeting: always a valley (the higher of two planes + * is a V), from the corner where their eaves cross up to where it meets + * the ridges. + * + * Everything is linear, so each crease is solved exactly along its line. + */ + +export type PlanPoint = [number, number] + +/** A plane over the plan: its height is `a·x + b·z + c`. */ +export type RoofPlane = { a: number; b: number; c: number } + +export type RoofCreaseSurface = { + /** The roof node the segment belongs to: valleys between two roofs are drawn by one of them. */ + roofId: string + /** The segment's footprint in plan: a convex polygon. */ + footprint: PlanPoint[] + /** The segment's roof planes; its top over the footprint is the lowest of them. */ + planes: RoofPlane[] +} + +export type RoofCreaseKind = 'ridge' | 'hip' | 'valley' + +export type RoofCrease = { + kind: RoofCreaseKind + from: PlanPoint + to: PlanPoint + /** The roof that draws the line: the segment's own roof, or the lesser id of a valley's two. */ + roofId: string + /** The indices of the surfaces that meet there (the same one twice for a ridge or hip). */ + between: [number, number] +} + +type Interval = [number, number] + +const EPS = 1e-6 +/** Shorter than this, a crease is a point where planes meet, not a line. */ +const MIN_CREASE = 0.01 + +const heightAt = (plane: RoofPlane, x: number, z: number) => plane.a * x + plane.b * z + plane.c + +/** The `t` where `slope·t + offset >= 0`, as an interval (empty as `null`). */ +function halfLine(slope: number, offset: number): Interval | null { + if (Math.abs(slope) <= 1e-12) return offset >= -EPS ? [-Infinity, Infinity] : null + const root = -offset / slope + return slope > 0 ? [root, Infinity] : [-Infinity, root] +} + +function intersect(a: Interval | null, b: Interval | null): Interval | null { + if (!(a && b)) return null + const lo = Math.max(a[0], b[0]) + const hi = Math.min(a[1], b[1]) + return hi > lo ? [lo, hi] : null +} + +function subtract(intervals: Interval[], cut: Interval): Interval[] { + return intervals.flatMap(([lo, hi]) => { + if (cut[1] <= lo || cut[0] >= hi) return [[lo, hi] as Interval] + const kept: Interval[] = [] + if (cut[0] > lo) kept.push([lo, cut[0]]) + if (cut[1] < hi) kept.push([cut[1], hi]) + return kept + }) +} + +type Line = { origin: PlanPoint; dir: PlanPoint } + +/** The plan line along which two planes stand at one height, or `null` when they never cross. */ +function meetingLine(p: RoofPlane, q: RoofPlane): Line | null { + const na = p.a - q.a + const nb = p.b - q.b + const norm2 = na * na + nb * nb + if (norm2 <= 1e-12) return null + const dc = p.c - q.c + const norm = Math.sqrt(norm2) + return { + origin: [(-dc * na) / norm2, (-dc * nb) / norm2], + dir: [-nb / norm, na / norm], + } +} + +/** The stretch of a line inside a convex polygon. */ +function clipToPolygon(line: Line, polygon: PlanPoint[]): Interval | null { + if (polygon.length < 3) return null + let area = 0 + for (let i = 0; i < polygon.length; i++) { + const [x0, z0] = polygon[i]! + const [x1, z1] = polygon[(i + 1) % polygon.length]! + area += x0 * z1 - x1 * z0 + } + const sign = area >= 0 ? 1 : -1 + let range: Interval | null = [-Infinity, Infinity] + for (let i = 0; i < polygon.length && range; i++) { + const [x0, z0] = polygon[i]! + const [x1, z1] = polygon[(i + 1) % polygon.length]! + const ex = x1 - x0 + const ez = z1 - z0 + // inside: sign · cross(edge, point − start) >= 0, linear in t + const slope = sign * (ex * line.dir[1] - ez * line.dir[0]) + const offset = sign * (ex * (line.origin[1] - z0) - ez * (line.origin[0] - x0)) + range = intersect(range, halfLine(slope, offset + EPS)) + } + return range +} + +/** Along a line, the height of a plane as `slope·t + offset`. */ +function along(plane: RoofPlane, line: Line): [number, number] { + return [ + plane.a * line.dir[0] + plane.b * line.dir[1], + heightAt(plane, line.origin[0], line.origin[1]), + ] +} + +/** Where `plane` is the lowest of the surface's planes, so the surface's top, along the line. */ +function activeRange(surface: RoofCreaseSurface, plane: RoofPlane, line: Line): Interval | null { + const [ps, po] = along(plane, line) + let range: Interval | null = [-Infinity, Infinity] + for (const other of surface.planes) { + if (other === plane) continue + const [os, oo] = along(other, line) + range = intersect(range, halfLine(os - ps, oo - po + EPS)) + if (!range) return null + } + return range +} + +/** Where `surface` stands higher than the crease (on `plane`) along the line. */ +function buriedRange(surface: RoofCreaseSurface, plane: RoofPlane, line: Line): Interval | null { + const [ps, po] = along(plane, line) + let range = clipToPolygon(line, surface.footprint) + for (const other of surface.planes) { + if (!range) return null + const [os, oo] = along(other, line) + range = intersect(range, halfLine(os - ps, oo - po - EPS * 10)) + } + return range +} + +function pointAt(line: Line, t: number): PlanPoint { + return [line.origin[0] + line.dir[0] * t, line.origin[1] + line.dir[1] * t] +} + +/** The visible stretches of the line where plane `p` of surface `i` meets plane `q` of surface `k`. */ +function visibleStretches( + surfaces: RoofCreaseSurface[], + i: number, + p: RoofPlane, + k: number, + q: RoofPlane, + line: Line, +): Interval[] { + const si = surfaces[i]! + const sk = surfaces[k]! + let range = intersect(clipToPolygon(line, si.footprint), activeRange(si, p, line)) + if (k !== i) range = intersect(range, clipToPolygon(line, sk.footprint)) + range = intersect(range, activeRange(sk, q, line)) + if (!range) return [] + let stretches: Interval[] = [range] + for (let m = 0; m < surfaces.length && stretches.length > 0; m++) { + if (m === i || m === k) continue + const buried = buriedRange(surfaces[m]!, p, line) + if (buried) stretches = subtract(stretches, buried) + } + return stretches.filter(([lo, hi]) => hi - lo >= MIN_CREASE) +} + +/** + * Every ridge, hip and valley of the roof surface the planar segments make + * together. Each crease is reported once, under the roof that draws it. + */ +export function getRoofSurfaceCreases(surfaces: RoofCreaseSurface[]): RoofCrease[] { + const creases: RoofCrease[] = [] + for (let i = 0; i < surfaces.length; i++) { + const si = surfaces[i]! + // Within one segment: ridges and hips. + for (let pi = 0; pi < si.planes.length; pi++) { + for (let qi = pi + 1; qi < si.planes.length; qi++) { + const p = si.planes[pi]! + const q = si.planes[qi]! + const line = meetingLine(p, q) + if (!line) continue + const level = Math.abs(along(p, line)[0]) <= 1e-6 + for (const [lo, hi] of visibleStretches(surfaces, i, p, i, q, line)) { + creases.push({ + kind: level ? 'ridge' : 'hip', + from: pointAt(line, lo), + to: pointAt(line, hi), + roofId: si.roofId, + between: [i, i], + }) + } + } + } + // Between two segments: valleys. + for (let k = i + 1; k < surfaces.length; k++) { + const sk = surfaces[k]! + for (const p of si.planes) { + for (const q of sk.planes) { + const line = meetingLine(p, q) + if (!line) continue + for (const [lo, hi] of visibleStretches(surfaces, i, p, k, q, line)) { + creases.push({ + kind: 'valley', + from: pointAt(line, lo), + to: pointAt(line, hi), + roofId: si.roofId < sk.roofId ? si.roofId : sk.roofId, + between: [i, k], + }) + } + } + } + } + } + return creases +} diff --git a/packages/nodes/src/roof/roof-ridge-mode.ts b/packages/nodes/src/roof/roof-ridge-mode.ts new file mode 100644 index 0000000000..29159e61a2 --- /dev/null +++ b/packages/nodes/src/roof/roof-ridge-mode.ts @@ -0,0 +1,36 @@ +import { create } from 'zustand' + +/** + * Which way a placed roof's ridge runs over the drawn footprint: along its + * long side (the default, as a wing's roof usually does) or across it. The + * roof tool's R key and HUD chip flip it while placing. + */ +export type RoofRidgeMode = 'long' | 'short' + +type RoofRidgeModeState = { + mode: RoofRidgeMode + toggle: () => void + reset: () => void +} + +const useRoofRidgeMode = create((set, get) => ({ + mode: 'long', + toggle: () => set({ mode: get().mode === 'long' ? 'short' : 'long' }), + reset: () => set({ mode: 'long' }), +})) + +/** + * Whether the segment turns a quarter so its ridge runs along z. A segment's + * ridge runs along its own x (its width), so a footprint deeper than it is + * wide turns for a long-side ridge; a square one keeps x. + */ +export function ridgeQuarterTurn( + footprintWidth: number, + footprintDepth: number, + mode: RoofRidgeMode, +): boolean { + const alongDepth = footprintDepth > footprintWidth + 1e-6 + return mode === 'long' ? alongDepth : !alongDepth +} + +export default useRoofRidgeMode diff --git a/packages/nodes/src/roof/tool.test.ts b/packages/nodes/src/roof/tool.test.ts index bc921f3d64..71a57af696 100644 --- a/packages/nodes/src/roof/tool.test.ts +++ b/packages/nodes/src/roof/tool.test.ts @@ -2,21 +2,31 @@ import { afterEach, expect, test } from 'bun:test' import { type AnyNode, type AnyNodeId, + BuildingNode, + clearSceneHistory, + createSceneApi, + emitter, + type GridEvent, LevelNode, - type RoofNode, + RoofNode, + type RoofSegmentNode, resolveRoomRoofFootprint, type SceneApi, + useScene, WallNode, ZoneNode, } from '@pascal-app/core' -import { useEditor } from '@pascal-app/editor' -import { commitRoofFootprint, commitRoofPlacement } from './tool' +import { RegistryToolProvider, sceneLayout, useEditor } from '@pascal-app/editor' +import { useViewer } from '@pascal-app/viewer' +import { act, create } from '@react-three/test-renderer' +import { createElement } from 'react' +import { commitRoofFootprint, commitRoofPlacement, RoofTool } from './tool' const originalDefaults = useEditor.getState().toolDefaults afterEach(() => useEditor.setState({ toolDefaults: originalDefaults })) -function setup() { +function setup(thickness?: number) { const level = LevelNode.parse({ level: 0, height: 3 }) const upper = LevelNode.parse({ level: 1, height: 3 }) const polygon: Array<[number, number]> = [ @@ -31,6 +41,7 @@ function setup() { start, end: polygon[(index + 1) % polygon.length], height: 2.5, + thickness, }), ) level.children = walls.map((wall) => wall.id) @@ -40,6 +51,7 @@ function setup() { const sceneApi = { nodes: () => nodes, createMany: (ops) => created.push(...ops), + upsert: (node, parentId) => created.push({ node, parentId }), update: (id, data) => updated.push({ id, data }), } as SceneApi return { level, upper, nodes, created, updated, sceneApi } @@ -121,3 +133,141 @@ test('a porch drawn against the house over posts stays on its storey', () => { expect(roof.node).toMatchObject({ support: { kind: 'level' } }) expect(updated).toEqual([]) }) + +// Standard trusses bear on the top plate: a raised heel is an explicit Wall Height, never a default. +test('a drawn roof bears on the top plate, and a raised heel stays a setting', () => { + const { level, created, sceneApi } = setup() + commitRoofPlacement(sceneApi, level.id, [0, 0, 0], [4, 0, 3], [], false, 'ground') + const segment = created.find(({ node }) => node.type === 'roof-segment')?.node + expect(segment).toMatchObject({ type: 'roof-segment', wallHeight: 0 }) + + const raised = setup() + useEditor.getState().setToolDefaults('roof', { roofType: 'gable', wallHeight: 0.45 }) + commitRoofPlacement(raised.sceneApi, raised.level.id, [0, 0, 0], [4, 0, 3], [], false, 'ground') + const heeled = raised.created.find(({ node }) => node.type === 'roof-segment')?.node + expect(heeled).toMatchObject({ type: 'roof-segment', wallHeight: 0.45 }) +}) + +// A segment's ridge runs along its width (local x): a long-side ridge over a deep rectangle turns a quarter. +test('a drawn gable runs its ridge along the long side by default, and across it on request', () => { + const ridgeOf = (corner2: [number, number, number], ridge: 'long' | 'short') => { + const { level, created, sceneApi } = setup() + commitRoofPlacement(sceneApi, level.id, [0, 0, 0], corner2, [], ridge, 'ground') + return created.find(({ node }) => node.type === 'roof-segment')?.node + } + expect(ridgeOf([2, 0, 6], 'long')).toMatchObject({ width: 6, depth: 2, rotation: Math.PI / 2 }) + expect(ridgeOf([6, 0, 2], 'long')).toMatchObject({ width: 6, depth: 2, rotation: 0 }) + expect(ridgeOf([2, 0, 6], 'short')).toMatchObject({ width: 2, depth: 6, rotation: 0 }) +}) + +const segmentOf = (created: Array<{ node: AnyNode }>) => + created.find(({ node }) => node.type === 'roof-segment')?.node as RoofSegmentNode | undefined + +// Gable and heel walls 0.1 m thick on 0.18 m walls stood a ledge proud of the walls below. +test('a roof drawn or made over walls gives its gable and heel walls their thickness', () => { + const drawn = setup(0.18) + commitRoofPlacement(drawn.sceneApi, drawn.level.id, [0, 0, 0], [4, 0, 3], [], false, 'ground') + expect(segmentOf(drawn.created)?.wallThickness).toBeCloseTo(0.18) + + const room = setup(0.18) + const target = resolveRoomRoofFootprint(room.level.id, room.nodes, [2, 1])! + commitRoofFootprint(room.sceneApi, room.level.id, target, false) + expect(segmentOf(room.created)?.wallThickness).toBeCloseTo(0.18) + + // Off the walls, a plane keeps the default. + const porch = setup(0.18) + commitRoofPlacement(porch.sceneApi, porch.level.id, [5, 0, 0.5], [7, 0, 2.5], [], false, 'ground') + expect(segmentOf(porch.created)?.wallThickness).toBeCloseTo(0.1) +}) + +test('a plane added to a selected roof over the walls takes their thickness', () => { + const { upper, nodes, created, sceneApi } = setup(0.18) + const roof = RoofNode.parse({ parentId: upper.id, position: [2, 0, 1.5], children: [] }) + const scene = nodes as Record + scene[roof.id] = roof + scene[upper.id] = { ...upper, children: [roof.id] } + commitRoofPlacement(sceneApi, upper.id, [0, 0, 0], [4, 0, 3], [roof.id], false, 'ground') + const segment = segmentOf(created) + expect(segment?.position).toEqual([0, 0, 0]) + expect(segment?.wallThickness).toBeCloseTo(0.18) +}) + +type RafFn = (cb: (time: number) => void) => number + +// Hidden behind the canvas in 2D-only view, the 3D tool kept a first corner from before the view +// changed: back in split view, the next click made a roof from that corner. +test('a corner opened before the view went 2D-only does not end the next roof in split view', async () => { + const globals = globalThis as unknown as { + IS_REACT_ACT_ENVIRONMENT?: boolean + requestAnimationFrame?: RafFn + cancelAnimationFrame?: (id: number) => void + } + globals.IS_REACT_ACT_ENVIRONMENT = true + globals.requestAnimationFrame ??= (cb) => { + cb(0) + return 0 + } + globals.cancelAnimationFrame ??= () => {} + const previous = { editor: useEditor.getState(), viewer: useViewer.getState() } + const windowDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'window') + globalThis.window = new EventTarget() as Window & typeof globalThis + + const { level, upper, nodes } = setup() + delete nodes[upper.id] + const building = BuildingNode.parse({ children: [level.id] }) + useScene.getState().setScene( + { + ...nodes, + [building.id]: building, + [level.id]: { ...level, parentId: building.id }, + } as Record, + [building.id as AnyNodeId], + { installedPlugins: [], hasExplicitPluginInstallState: false }, + ) + clearSceneHistory() + useViewer.getState().setSelection({ buildingId: building.id, levelId: level.id }) + // Over the plan, the cursor's DOM tooltip stays out of the canvas. + useEditor.setState({ mode: 'build', tool: 'roof', isFloorplanHovered: true }) + const showViews = (scene: '2d' | 'split') => + act(async () => useEditor.setState({ viewLayouts: { edit: sceneLayout(scene) } })) + const click = (x: number, z: number) => + act(async () => { + const event = { + position: [x, 0, z], + localPosition: [x, 0, z], + nativeEvent: {} as GridEvent['nativeEvent'], + } satisfies GridEvent + emitter.emit('grid:move', event) + emitter.emit('grid:click', event) + }) + const roofs = () => Object.values(useScene.getState().nodes).filter((n) => n.type === 'roof') + + await showViews('split') + const renderer = await create( + createElement(RegistryToolProvider, { + value: { + activeLevelId: level.id, + isCameraDragging: () => false, + sceneApi: createSceneApi(useScene), + selectNode: (id) => useViewer.getState().setSelection({ selectedIds: [id] }), + unit: 'metric', + }, + children: createElement(RoofTool), + }), + ) + try { + await click(0, 0) + await showViews('2d') + await showViews('split') + await click(4, 3) + expect(roofs()).toHaveLength(0) + await click(8, 6) + expect(roofs()).toHaveLength(1) + } finally { + await act(async () => renderer.unmount()) + useEditor.setState(previous.editor, true) + useViewer.setState(previous.viewer, true) + if (windowDescriptor) Object.defineProperty(globalThis, 'window', windowDescriptor) + else Reflect.deleteProperty(globalThis, 'window') + } +}) diff --git a/packages/nodes/src/roof/tool.tsx b/packages/nodes/src/roof/tool.tsx index 8c8a047c08..032bfc99dd 100644 --- a/packages/nodes/src/roof/tool.tsx +++ b/packages/nodes/src/roof/tool.tsx @@ -9,6 +9,7 @@ import { getWallArcData, getWallBaseElevationForNodes, getWallEffectiveHeightForNodes, + getWallThickness, isCurvedWall, type LevelNode, type RoofFootprintTarget, @@ -18,9 +19,7 @@ import { RoofType as RoofTypeSchema, resolveBuildingForLevel, resolveLevelId, - resolveRoomRoofFootprint, type SceneApi, - sceneRegistry, type WallEvent, type WallNode, wallSegmentAnchors, @@ -39,6 +38,7 @@ import { useFloorplanDraftPreview, useInteractionScope, useRegistryToolContext, + visibleScene, } from '@pascal-app/editor' import { generateRoofSegmentGeometry, useViewer } from '@pascal-app/viewer' import { useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react' @@ -56,9 +56,13 @@ import { resolveConicalRoofPlacement } from './conical-roof-placement' import { isStandardRoofWallEligible, parseRoofFootprintSource, + pickRoofRoom, resolveRoofFootprintElevation, resolveRoofFootprintWorldElevation, resolveRoofWallTopWorldElevation, + roofEdgeAnchors, + roofFootprintPreviewIds, + roofSnapEdges, subscribeToConicalRoofWallClicks, } from './roof-footprint' import useRoofFootprintSource from './roof-footprint-source' @@ -72,8 +76,19 @@ import { writeSeatedRoofEdit, } from './roof-level-target' import useRoofPlacementMode, { type RoofPlacementMode } from './roof-placement-mode' - -const DEFAULT_WALL_HEIGHT = 0.5 +import useRoofRidgeMode, { type RoofRidgeMode, ridgeQuarterTurn } from './roof-ridge-mode' +import { + bearingWallThickness, + type RoofCatchLine, + roofCatchWalls, + segmentWallLine, + settleSegmentOnEdges, +} from './wall-catch' + +// Rafters bear on the top plate, as standard trusses do; a raised heel is the segment's Wall Height. +const DEFAULT_HEEL_HEIGHT = 0 +// A cone's curb: it stands on the ground or on another roof, not on a plate. +const DEFAULT_CONICAL_CURB_HEIGHT = 0.5 const DEFAULT_PITCH_DEG = 40 const GRID_OFFSET = 0.02 @@ -84,10 +99,24 @@ function placementOptions(mode: RoofPlacementMode) { } } +/** + * A placed segment's quarter turn: given outright, or from a ridge mode, which + * runs the ridge along the footprint's long side ('long') or across it. + */ +function resolveQuarterTurn( + ridge: boolean | RoofRidgeMode, + footprintWidth: number, + footprintDepth: number, +): boolean { + return typeof ridge === 'boolean' + ? ridge + : ridgeQuarterTurn(footprintWidth, footprintDepth, ridge) +} + function resolveRoofDraftPlacement( footprintWidth: number, footprintDepth: number, - quarterTurn: boolean, + ridge: boolean | RoofRidgeMode, parentRotation = 0, roofType: RoofType = 'gable', ) { @@ -95,6 +124,7 @@ function resolveRoofDraftPlacement( const diameter = Math.max(footprintWidth, footprintDepth) return { width: diameter, depth: diameter, rotation: -parentRotation } } + const quarterTurn = resolveQuarterTurn(ridge, footprintWidth, footprintDepth) return { width: quarterTurn ? footprintDepth : footprintWidth, depth: quarterTurn ? footprintWidth : footprintDepth, @@ -115,33 +145,51 @@ function getLevelWalls( .filter((node): node is WallNode => node?.type === 'wall') } -// Walls on the level directly beneath the active one. Levels share the same -// local XZ origin (they only differ in world Y), so these walls live in the -// identical coordinate frame and feed straight into both the alignment pool -// and the magnetic wall-snap pipeline — letting a roof drawn on the upper -// floor snap onto the wall corners of the floor below. -function getBelowLevelWalls( +// The level directly beneath the active one. Levels share the same local XZ +// origin (they only differ in world Y), so its walls live in the identical +// coordinate frame and feed straight into both the alignment pool and the +// magnetic wall-snap pipeline — letting a roof drawn on the upper floor snap +// onto the wall corners of the floor below. +function getBelowLevel( currentLevelId: string | null, nodes: Readonly>, -): WallNode[] { - if (!currentLevelId) return [] +): LevelNode | undefined { + if (!currentLevelId) return undefined const currentLevel = nodes[currentLevelId] - if (currentLevel?.type !== 'level') return [] + if (currentLevel?.type !== 'level') return undefined const buildingId = resolveBuildingForLevel(currentLevel.id, nodes) - if (!buildingId) return [] + if (!buildingId) return undefined const building = nodes[buildingId] - if (building?.type !== 'building') return [] + if (building?.type !== 'building') return undefined const currentIndex = (currentLevel as LevelNode).level - const belowLevel = (building.children ?? []) + return (building.children ?? []) .map((childId) => nodes[childId]) .filter((node): node is LevelNode => node?.type === 'level' && node.level < currentIndex) .sort((a, b) => b.level - a.level)[0] - return getLevelWalls(belowLevel?.id ?? null, nodes) +} + +// Walls on the level directly beneath the active one. +function getBelowLevelWalls( + currentLevelId: string | null, + nodes: Readonly>, +): WallNode[] { + return getLevelWalls(getBelowLevel(currentLevelId, nodes)?.id ?? null, nodes) +} + +// The active level and the one beneath it, whose rooms' edges a roof draws to. +function roofEdgeLevelIds( + currentLevelId: string | null, + nodes: Readonly>, +): string[] { + const below = getBelowLevel(currentLevelId, nodes) + return [currentLevelId, below?.id].filter((id): id is string => !!id) } // Current-level + floor-below walls — the magnetic snap targets the roof draft // locks onto (corners, midpoints, crossings, wall bodies), matching the wall -// tool. Same coordinate frame, so no transform is needed. +// tool. Same coordinate frame, so no transform is needed. A porch, deck or +// patio is drawn to as the house is: its invisible walls, and its railings at +// their outside faces in place of their centre lines (`roofSnapEdges`). function getRoofSnapWalls( currentLevelId: string | null, nodes: Readonly>, @@ -151,13 +199,16 @@ function getRoofSnapWalls( ...getLevelWalls(currentLevelId, nodes), ...getBelowLevelWalls(currentLevelId, nodes), ] - return roofType === 'conical' - ? walls.filter((wall) => isCurvedWall(wall)) - : walls.filter(isStandardRoofWallEligible) + if (roofType === 'conical') return walls.filter((wall) => isCurvedWall(wall)) + const edges = roofSnapEdges(nodes, roofEdgeLevelIds(currentLevelId, nodes)) + return [...walls.filter((wall) => !edges.faced.has(wall.id)), ...edges.references].filter( + isStandardRoofWallEligible, + ) } -// Current-level alignment anchors plus the floor-below wall corners. -function collectRoofAlignmentAnchors( +// Current-level alignment anchors plus the floor-below wall corners, and both +// levels' invisible walls and porch, deck and patio corners. +export function collectRoofAlignmentAnchors( nodes: Readonly>, currentLevelId: string | null, roofType: RoofType, @@ -165,8 +216,11 @@ function collectRoofAlignmentAnchors( const anchors = [ ...collectAlignmentAnchors(nodes, '', currentLevelId), ...getBelowLevelWalls(currentLevelId, nodes).flatMap((wall) => - wallSegmentAnchors(wall.id, wall.start, wall.end, wall.thickness), + wallSegmentAnchors(wall.id, wall.start, wall.end, wall.thickness, wall.justification), ), + ...(roofType === 'conical' + ? [] + : roofEdgeAnchors(nodes, roofEdgeLevelIds(currentLevelId, nodes))), ] if (roofType === 'conical') { return anchors.filter((anchor) => { @@ -181,7 +235,69 @@ function collectRoofAlignmentAnchors( } /** - * Creates a roof group with one default gable segment + * A grid event's point as the roof tools draft and commit it, the 3D tool and the plan's alike: + * through the shared surface snap pipeline, magnetic lock onto wall corners / midpoints / crossings + * / bodies on the active level and the floor below (raising the green beacon), falling back to + * alignment guides, then to the building-grid snap. The pipeline reads the active snapping mode + * (grid / lines / angles / off). `levelId` is intentionally omitted so the explicit floor-below + * `walls` aren't filtered back out. + */ +export function resolveRoofDraftPoint( + event: GridEvent, + levelId: string, + nodes: Readonly>, + roofType: RoofType, + candidates: readonly AlignmentAnchor[], +): [number, number] { + const rawPoint: [number, number] = [event.localPosition[0], event.localPosition[2]] + const gridFallback: [number, number] = isGridSnapActive() + ? snapWorldXZForActiveBuilding( + event.position[0], + event.position[2], + useEditor.getState().gridSnapStep, + ).local + : rawPoint + return resolveSurfacePlanPointSnap({ + rawPoint, + fallbackPoint: gridFallback, + walls: getRoofSnapWalls(levelId, nodes, roofType), + candidates, + movingId: '__roof-draft__', + highlightWalls: true, + }).point +} + +/** + * A drawn segment whose gable and heel walls stand flush on the walls it is drawn over, and whose + * walls' outer faces stand on the rooms' edges it is drawn out to: a porch's invisible walls, a + * deck's railings at their outside faces (`settleSegmentOnEdges`). + */ +function onBearingWalls( + segment: RoofSegmentNode, + roof: Pick, + walls: readonly RoofCatchLine[], +): RoofSegmentNode { + const thickness = bearingWallThickness(segmentWallLine(roof, segment), walls) + const bearing = thickness === null ? segment : { ...segment, wallThickness: thickness } + return { ...bearing, ...settleSegmentOnEdges(roof, bearing, walls) } +} + +/** + * A new roof's place, and its one segment centred in it: the segment settled onto a room's edge + * (`onBearingWalls`) moves off the roof's centre, so the roof moves with it. + */ +function centredRoof( + roof: Pick, + segment: RoofSegmentNode, +): { center: [number, number]; segment: RoofSegmentNode } { + const [x, z] = segmentWallLine(roof, segment).center + return { center: [x, z], segment: { ...segment, position: [0, segment.position[1], 0] } } +} + +/** + * Creates a roof group with one default gable segment. `ridge` is a quarter + * turn outright, or a ridge mode: 'long' runs the ridge along the drawn + * rectangle's long side, 'short' across it. */ export const commitRoofPlacement = ( sceneApi: SceneApi, @@ -189,7 +305,7 @@ export const commitRoofPlacement = ( corner1: [number, number, number], corner2: [number, number, number], selectedIds: string[], - quarterTurn: boolean, + ridge: boolean | RoofRidgeMode, placementMode: RoofPlacementMode, ): AnyNode['id'] | null => { const nodes = sceneApi.nodes() @@ -212,7 +328,7 @@ export const commitRoofPlacement = ( if (roofType === 'conical') { const diameter = Math.max(footprintWidth, footprintDepth) const curbHeight = - typeof defaults.wallHeight === 'number' ? defaults.wallHeight : DEFAULT_WALL_HEIGHT + typeof defaults.wallHeight === 'number' ? defaults.wallHeight : DEFAULT_CONICAL_CURB_HEIGHT const cone = RoofSegmentNode.parse({ pitch: DEFAULT_PITCH_DEG, ...defaults, @@ -277,29 +393,18 @@ export const commitRoofPlacement = ( if (targetRoofId) { const targetRoof = nodes[targetRoofId] as RoofNode - let localX = centerX - let localZ = centerZ - - // Convert world coordinates to the local space of the parent roof - const targetObj = sceneRegistry.nodes.get(targetRoofId) - if (targetObj) { - const worldVec = new THREE.Vector3(centerX, 0, centerZ) - targetObj.worldToLocal(worldVec) - localX = worldVec.x - localZ = worldVec.z - } else { - // Math fallback if mesh isn't ready - const dx = centerX - targetRoof.position[0] - const dz = centerZ - targetRoof.position[2] - const angle = -targetRoof.rotation - localX = dx * Math.cos(angle) - dz * Math.sin(angle) - localZ = dx * Math.sin(angle) + dz * Math.cos(angle) - } + // The corners are in the level's plan, the roof's frame: its own place and turn in it. (Its + // mesh's world matrix also carries the building's, which would throw the plane off.) + const dx = centerX - targetRoof.position[0] + const dz = centerZ - targetRoof.position[2] + const angle = -targetRoof.rotation + const localX = dx * Math.cos(angle) - dz * Math.sin(angle) + const localZ = dx * Math.sin(angle) + dz * Math.cos(angle) const placement = resolveRoofDraftPlacement( footprintWidth, footprintDepth, - quarterTurn, + ridge, targetRoof.rotation, roofType, ) @@ -307,12 +412,13 @@ export const commitRoofPlacement = ( const sibling = targetRoof.children .map((id) => nodes[id]) .find((node) => node?.type === 'roof-segment') - const segment = RoofSegmentNode.parse({ + const drawn = RoofSegmentNode.parse({ roofSystem: sibling?.type === 'roof-segment' ? sibling.roofSystem : undefined, glazing: sibling?.type === 'roof-segment' ? sibling.glazing : undefined, barrelRise: sibling?.type === 'roof-segment' ? sibling.barrelRise : undefined, barrelSegments: sibling?.type === 'roof-segment' ? sibling.barrelSegments : undefined, - wallHeight: DEFAULT_WALL_HEIGHT, + // A wing bears where the roof it joins does: on the plate, or on the same raised heel. + wallHeight: sibling?.type === 'roof-segment' ? sibling.wallHeight : DEFAULT_HEEL_HEIGHT, pitch: DEFAULT_PITCH_DEG, roofType: 'gable', ...defaults, @@ -321,6 +427,7 @@ export const commitRoofPlacement = ( position: [localX, 0, localZ], rotation: placement.rotation, }) + const segment = onBearingWalls(drawn, targetRoof, roofCatchWalls(nodes, targetRoof.parentId)) writeSeatedRoofEdit(sceneApi, { create: [{ node: segment, parentId: targetRoofId as AnyNode['id'] }], @@ -336,22 +443,36 @@ export const commitRoofPlacement = ( const placement = resolveRoofDraftPlacement( footprintWidth, footprintDepth, - quarterTurn, + ridge, roofRotation, roofType, ) // Create the segment first (centered in its new parent) - const segment = RoofSegmentNode.parse({ - wallHeight: DEFAULT_WALL_HEIGHT, - pitch: DEFAULT_PITCH_DEG, - roofType: 'gable', - ...defaults, - width: placement.width, - depth: placement.depth, - position: [0, 0, 0], - rotation: placement.rotation, - }) + const drawnRoof = { + position: [centerX, 0, centerZ] as [number, number, number], + rotation: roofRotation, + } + const { + center: [roofX, roofZ], + segment, + } = centredRoof( + drawnRoof, + onBearingWalls( + RoofSegmentNode.parse({ + wallHeight: DEFAULT_HEEL_HEIGHT, + pitch: DEFAULT_PITCH_DEG, + roofType: 'gable', + ...defaults, + width: placement.width, + depth: placement.depth, + position: [0, 0, 0], + rotation: placement.rotation, + }), + drawnRoof, + roofCatchWalls(nodes, levelId), + ), + ) // Drawn over a storey's walls, the roof goes on the level above them. const target = drawnRoofLevelTarget( @@ -366,7 +487,7 @@ export const commitRoofPlacement = ( const placed = RoofNode.parse({ ...defaults, name, - position: [centerX, 0, centerZ], + position: [roofX, 0, roofZ], support, children: [segment.id], }) @@ -374,7 +495,7 @@ export const commitRoofPlacement = ( support.kind === 'walls' ? RoofNode.parse({ ...placed, - position: [centerX, seatedRoofElevation(target, placed, [segment]), centerZ], + position: [roofX, seatedRoofElevation(target, placed, [segment]), roofZ], }) : placed // Create roof first (so segment can be parented to it), then segment @@ -391,19 +512,25 @@ export const commitRoofFootprint = ( sceneApi: SceneApi, levelId: LevelNode['id'], target: RoofFootprintTarget, - quarterTurn: boolean, + ridge: boolean | RoofRidgeMode, ): AnyNode['id'] | null => { if (!target.rectangular) return null + const quarterTurn = resolveQuarterTurn(ridge, target.width, target.depth) const nodes = sceneApi.nodes() const defaults = useEditor.getState().toolDefaults.roof ?? {} const parsedRoofType = RoofTypeSchema.safeParse(defaults.roofType) const roofType = parsedRoofType.success ? parsedRoofType.data : 'gable' if (roofType === 'conical') return null const roofCount = Object.values(nodes).filter((node) => node.type === 'roof').length - const segment = RoofSegmentNode.parse({ + const walls = target.wallIds + .map((id) => nodes[id]) + .filter((node): node is WallNode => node?.type === 'wall') + const picked = RoofSegmentNode.parse({ pitch: DEFAULT_PITCH_DEG, roofType: 'gable', ...defaults, + // Its gable and heel walls stand flush on the room's walls. + ...(walls.length > 0 && { wallThickness: Math.max(...walls.map(getWallThickness)) }), wallHeight: 0, width: quarterTurn ? target.depth : target.width, depth: quarterTurn ? target.width : target.depth, @@ -412,16 +539,27 @@ export const commitRoofFootprint = ( }) // A roof belongs to the level above the walls it covers, whichever level the tool was armed // on: over the top floor, the building's roof level. - const firstWall = target.wallIds.map((id) => nodes[id]).find((node) => node?.type === 'wall') - const wallsLevelId = (firstWall ? resolveLevelId(firstWall, nodes) : levelId) as LevelNode['id'] + const firstWall = walls[0] + const wallsLevelId = (target.levelId ?? + (firstWall ? resolveLevelId(firstWall, nodes) : levelId)) as LevelNode['id'] + // Over a porch, deck or patio, the roof's walls stand their outer faces on the room's outside + // edge, as a house roof's stand on the walls' outside faces. + const pickedRoof = { + position: [target.center[0], 0, target.center[1]] as [number, number, number], + rotation: target.rotation, + } + const { center, segment } = centredRoof(pickedRoof, { + ...picked, + ...settleSegmentOnEdges(pickedRoof, picked, roofCatchWalls(nodes, wallsLevelId)), + }) const level = roofLevelTarget(nodes, wallsLevelId, getActiveRoofHeight(segment)) const roof = RoofNode.parse({ ...defaults, name: `Roof ${roofCount + 1}`, position: [ - target.center[0], + center[0], resolveRoofFootprintElevation(level.levelId, target, level.nodes), - target.center[1], + center[1], ], rotation: target.rotation, support: { kind: 'walls' }, @@ -638,7 +776,11 @@ export const RoofTool: React.FC = () => { const footprintSourceChoice = useRoofFootprintSource((state) => state.source) const footprintSource = parseRoofFootprintSource(footprintSourceChoice, roofType) const previewWallHeight = - typeof roofDefaults?.wallHeight === 'number' ? roofDefaults.wallHeight : DEFAULT_WALL_HEIGHT + typeof roofDefaults?.wallHeight === 'number' + ? roofDefaults.wallHeight + : roofType === 'conical' + ? DEFAULT_CONICAL_CURB_HEIGHT + : DEFAULT_HEEL_HEIGHT const previewPitch = typeof roofDefaults?.pitch === 'number' ? roofDefaults.pitch : DEFAULT_PITCH_DEG @@ -647,11 +789,6 @@ export const RoofTool: React.FC = () => { selectedIdsRef.current = selectedIds }, [selectedIds]) - useEffect(() => { - useRoofPlacementMode.getState().setConical(roofType === 'conical') - return () => useRoofPlacementMode.getState().setConical(false) - }, [roofType]) - useEffect(() => { if (!currentLevelId) return const draft = RoofNode.parse({ @@ -678,11 +815,12 @@ export const RoofTool: React.FC = () => { // Clear preset-seeded defaults on deactivation so a later manual roof draw // isn't built with a stale preset's parameters. Unmount-only. useEffect(() => () => useEditor.getState().setToolDefaults('roof', null), []) + // Each arming starts with the ridge along the long side. Unmount-only. + useEffect(() => () => useRoofRidgeMode.getState().reset(), []) const corner1Ref = useRef<[number, number, number] | null>(null) const previousGridPosRef = useRef<[number, number] | null>(null) - const quarterTurnRef = useRef(false) - const [quarterTurn, setQuarterTurn] = useState(false) + const ridgeMode = useRoofRidgeMode((state) => state.mode) const [footprintTarget, setFootprintTarget] = useState(null) const previewTargetIdRef = useRef(null) const [previewedConicalWallId, setPreviewedConicalWallId] = useState(null) @@ -703,7 +841,18 @@ export const RoofTool: React.FC = () => { if (!currentLevelId) return outlineRef.current.geometry = new BufferGeometry() - useFloorplanDraftPreview.getState().setRoofDraftQuarterTurn(quarterTurnRef.current) + // The 2D draft's ridge line follows the drawn rectangle and the ridge mode. + const syncDraftRidge = (corner1: [number, number, number], corner2: [number, number, number]) => + useFloorplanDraftPreview + .getState() + .setRoofDraftQuarterTurn( + ridgeQuarterTurn( + Math.abs(corner2[0] - corner1[0]), + Math.abs(corner2[2] - corner1[2]), + useRoofRidgeMode.getState().mode, + ), + ) + let lastCursor: [number, number, number] | null = null // Alignment candidates — anchors of every alignable object on the active // level plus the wall corners of the floor directly below, so a roof drawn @@ -715,39 +864,14 @@ export const RoofTool: React.FC = () => { roofType, ) - // Resolve a grid:move/click into the drafted corner via the shared surface - // snap pipeline: magnetic lock onto wall corners / midpoints / crossings / - // bodies on the active level + floor below (raising the green beacon), - // falling back to alignment guides, then to the world-grid snap. The same - // path the slab/ceiling tools use, so the beacon and coloring match. The - // pipeline reads the active snapping mode (grid / lines / angles / off), - // so this tool never inspects the flags. `levelId` is intentionally omitted - // so the explicit floor-below `walls` aren't filtered back out. - const resolveDraftPoint = (event: GridEvent): [number, number] => { - const rawPoint: [number, number] = [event.localPosition[0], event.localPosition[2]] - const gridFallback: [number, number] = isGridSnapActive() - ? snapWorldXZForActiveBuilding( - event.position[0], - event.position[2], - useEditor.getState().gridSnapStep, - ).local - : rawPoint - const nodes = sceneApi.nodes() - return resolveSurfacePlanPointSnap({ - rawPoint, - fallbackPoint: gridFallback, - walls: getRoofSnapWalls(currentLevelId, nodes, roofType), - candidates: alignmentCandidates, - movingId: '__roof-draft__', - highlightWalls: true, - }).point - } + const resolveDraftPoint = (event: GridEvent) => + resolveRoofDraftPoint(event, currentLevelId, sceneApi.nodes(), roofType, alignmentCandidates) const updateFootprintPreview = (target: RoofFootprintTarget | null) => { setFootprintTarget((previous) => (previous?.id === target?.id ? previous : target)) if (previewTargetIdRef.current === (target?.id ?? null)) return previewTargetIdRef.current = target?.id ?? null - setPreviewSelectedIds(target?.wallIds ?? []) + setPreviewSelectedIds(roofFootprintPreviewIds(target)) } const updateOutline = ( @@ -765,7 +889,9 @@ export const RoofTool: React.FC = () => { ) const defaults = useEditor.getState().toolDefaults.roof const curbHeight = - typeof defaults?.wallHeight === 'number' ? defaults.wallHeight : DEFAULT_WALL_HEIGHT + typeof defaults?.wallHeight === 'number' + ? defaults.wallHeight + : DEFAULT_CONICAL_CURB_HEIGHT const target = drawnRoofLevelTarget(sceneApi.nodes(), currentLevelId, 0, { center: [centerX, centerZ], width: diameter, @@ -821,21 +947,21 @@ export const RoofTool: React.FC = () => { outlineRef.current.visible = true } + // In 2D-only view the plan's own roof tool owns the input (`floorplan-tool.tsx`); this tool, + // mounted behind the hidden canvas from an earlier visit, still hears the plan's grid events, + // so it must not also draft or commit (every roof would be made twice). + const planOwnsInput = () => visibleScene(useEditor.getState()) === '2d' + const onGridMove = (event: GridEvent) => { - if (!cursorRef.current) return + if (!cursorRef.current || planOwnsInput()) return if (footprintSource !== 'draw') { const [snappedX, snappedZ] = resolveDraftPoint(event) let target: RoofFootprintTarget | null = null if (footprintSource === 'room') { - target = resolveRoomRoofFootprint( - currentLevelId, - sceneApi.nodes(), - [snappedX, snappedZ], - { - rectangularOnly: true, - }, - ) + const room = pickRoofRoom(currentLevelId, sceneApi.nodes(), [snappedX, snappedZ]) + target = room.target + useRoofFootprintSource.getState().setRoomPick(room.pick) updateFootprintPreview(target) } cursorRef.current.position.set( @@ -878,24 +1004,30 @@ export const RoofTool: React.FC = () => { const draftPreview = useFloorplanDraftPreview.getState() draftPreview.setRoofDraftStart([corner1Ref.current[0], corner1Ref.current[2]]) draftPreview.setRoofDraftEnd([gridX, gridZ]) + syncDraftRidge(corner1Ref.current, cursorPosition) updateOutline(corner1Ref.current, cursorPosition) } + lastCursor = cursorPosition } const onGridClick = (event: GridEvent) => { - if (!currentLevelId) return + if (!currentLevelId || planOwnsInput()) return if (footprintSource !== 'draw') { if (footprintSource !== 'room') return const [snappedX, snappedZ] = resolveDraftPoint(event) - const target = resolveRoomRoofFootprint( + const { target, pick } = pickRoofRoom(currentLevelId, sceneApi.nodes(), [ + snappedX, + snappedZ, + ]) + useRoofFootprintSource.getState().setRoomPick(pick) + if (!target) return + const roofId = commitRoofFootprint( + sceneApi, currentLevelId, - sceneApi.nodes(), - [snappedX, snappedZ], - { rectangularOnly: true }, + target, + useRoofRidgeMode.getState().mode, ) - if (!target) return - const roofId = commitRoofFootprint(sceneApi, currentLevelId, target, quarterTurnRef.current) if (roofId) selectNode(roofId) return } @@ -910,7 +1042,7 @@ export const RoofTool: React.FC = () => { corner1Ref.current, [gridX, y, gridZ], selectedIdsRef.current, - quarterTurnRef.current, + useRoofRidgeMode.getState().mode, useRoofPlacementMode.getState().mode, ) @@ -942,15 +1074,25 @@ export const RoofTool: React.FC = () => { } } + const dropCorner = () => { + corner1Ref.current = null + outlineRef.current.visible = false + setPreview((prev) => ({ ...prev, corner1: null })) + } + + // A corner opened before the view went 2D-only would end the next rectangle drawn back in + // split view. The plan's tool clears the shared draft as it takes over. + const unsubscribeView = useEditor.subscribe((state) => { + if (corner1Ref.current && visibleScene(state) === '2d') dropCorner() + }) + const onCancel = () => { if (corner1Ref.current) { markToolCancelConsumed() - corner1Ref.current = null + dropCorner() const draftPreview = useFloorplanDraftPreview.getState() draftPreview.setRoofDraftStart(null) draftPreview.setRoofDraftEnd(null) - outlineRef.current.visible = false - setPreview((prev) => ({ ...prev, corner1: null })) } clearSurfacePlanSnapFeedback() previewTargetIdRef.current = null @@ -958,6 +1100,7 @@ export const RoofTool: React.FC = () => { } const onKeyDown = (event: KeyboardEvent) => { + if (planOwnsInput()) return if ( event.target instanceof HTMLInputElement || event.target instanceof HTMLTextAreaElement || @@ -990,12 +1133,13 @@ export const RoofTool: React.FC = () => { } event.preventDefault() - const nextQuarterTurn = !quarterTurnRef.current - quarterTurnRef.current = nextQuarterTurn - setQuarterTurn(nextQuarterTurn) - useFloorplanDraftPreview.getState().setRoofDraftQuarterTurn(nextQuarterTurn) + useRoofRidgeMode.getState().toggle() triggerSFX('sfx:item-rotate') } + // The HUD chip flips the mode too; either way the 2D draft follows. + const unsubscribeRidgeMode = useRoofRidgeMode.subscribe(() => { + if (corner1Ref.current && lastCursor) syncDraftRidge(corner1Ref.current, lastCursor) + }) emitter.on('grid:move', onGridMove) emitter.on('grid:click', onGridClick) @@ -1043,11 +1187,14 @@ export const RoofTool: React.FC = () => { emitter.off('wall:leave', onWallLeave) unsubscribeConicalRoofWallClicks() window.removeEventListener('keydown', onKeyDown) + unsubscribeRidgeMode() + unsubscribeView() clearSurfacePlanSnapFeedback() previewTargetIdRef.current = null setPreviewedConicalWallId(null) setInvalidStandardWallHover(false) setPreviewSelectedIds([]) + useRoofFootprintSource.getState().setRoomPick(null) corner1Ref.current = null const draftPreview = useFloorplanDraftPreview.getState() @@ -1173,7 +1320,7 @@ export const RoofTool: React.FC = () => { const placement = resolveRoofDraftPlacement( resolvedPreviewDimensions.length, resolvedPreviewDimensions.width, - quarterTurn, + ridgeMode, 0, roofType, ) @@ -1189,7 +1336,7 @@ export const RoofTool: React.FC = () => { ghostWallHeight, invalidStandardWallHover, previewPitch, - quarterTurn, + ridgeMode, resolvedPreviewDimensions, roofType, ]) @@ -1204,7 +1351,7 @@ export const RoofTool: React.FC = () => { const placement = resolveRoofDraftPlacement( resolvedPreviewDimensions.length, resolvedPreviewDimensions.width, - quarterTurn, + ridgeMode, 0, roofType, ) @@ -1220,7 +1367,7 @@ export const RoofTool: React.FC = () => { ghostWallHeight, invalidStandardWallHover, previewPitch, - quarterTurn, + ridgeMode, resolvedPreviewDimensions, roofType, ]) @@ -1322,7 +1469,14 @@ export const RoofTool: React.FC = () => { rotation={[ 0, (footprintSource !== 'draw' ? (footprintTarget?.rotation ?? 0) : 0) + - (roofType === 'conical' ? 0 : quarterTurn ? Math.PI / 2 : 0), + (roofType !== 'conical' && + ridgeQuarterTurn( + resolvedPreviewDimensions.length, + resolvedPreviewDimensions.width, + ridgeMode, + ) + ? Math.PI / 2 + : 0), 0, ]} > diff --git a/packages/nodes/src/roof/wall-catch.test.ts b/packages/nodes/src/roof/wall-catch.test.ts new file mode 100644 index 0000000000..4353e044d0 --- /dev/null +++ b/packages/nodes/src/roof/wall-catch.test.ts @@ -0,0 +1,345 @@ +import { describe, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + BuildingNode, + LevelNode, + RoofNode, + RoofSegmentNode, + SeparatorNode, + WallNode, +} from '@pascal-app/core' +import { + bearingWallThickness, + catchRoofOnWalls, + catchRoofSideOnWalls, + placeRoofOnWalls, + type RoofCatchLine, + type RoofWallLine, + roofCatchWalls, + segmentWallLine, + settleRoofOnEdges, + settleSegmentOnEdges, +} from './wall-catch' + +const room: [number, number][] = [ + [0, 0], + [10, 0], + [10, 8], + [0, 8], +] +const roomWalls = room.map((start, i) => + WallNode.parse({ id: `wall_${i}`, parentId: 'level_g', start, end: room[(i + 1) % 4] }), +) + +const near = (value: readonly number[], expected: number[]) => { + for (const [i, v] of value.entries()) expect(v).toBeCloseTo(expected[i]!, 6) +} + +describe('a roof catching on the walls under it', () => { + test('wall lines a little off the walls lay onto their centre lines', () => { + const line: RoofWallLine = { center: [5.15, 4.1], angle: 0, hw: 5, hd: 4 } + const caught = catchRoofOnWalls({ lines: [line], walls: roomWalls, angle: 0 }) + expect(caught).toMatchObject({ u: true, v: true }) + near(caught.shift, [-0.15, -0.1]) + }) + + test('a segment turned a quarter catches the same walls on its own axes', () => { + const line: RoofWallLine = { center: [5.15, 4.1], angle: -Math.PI / 2, hw: 4, hd: 5 } + const caught = catchRoofOnWalls({ lines: [line], walls: roomWalls, angle: -Math.PI / 2 }) + expect(caught).toMatchObject({ u: true, v: true }) + near(caught.shift, [-0.15, -0.1]) + }) + + test('too far off, or past the end of a wall, it does not catch', () => { + const far: RoofWallLine = { center: [5.4, 4], angle: 0, hw: 5, hd: 4 } + expect(catchRoofOnWalls({ lines: [far], walls: roomWalls, angle: 0 })).toMatchObject({ + u: false, + v: true, + }) + const beyond = WallNode.parse({ parentId: 'level_g', start: [20, 0.1], end: [30, 0.1] }) + const line: RoofWallLine = { center: [5, 4], angle: 0, hw: 5, hd: 4 } + expect(catchRoofOnWalls({ lines: [line], walls: [beyond], angle: 0 })).toMatchObject({ + u: false, + v: false, + }) + }) + + test('a wall drawn by its face catches on its body centre, half its thickness in', () => { + // Drawn along its outer face at z 0, a 0.2 m wall's body centre runs at z 0.1. + const faced = WallNode.parse({ + parentId: 'level_g', + start: [0, 0], + end: [10, 0], + thickness: 0.2, + justification: 'a', + }) + const line: RoofWallLine = { center: [5, 4.05], angle: 0, hw: 5, hd: 4 } + const caught = catchRoofOnWalls({ lines: [line], walls: [faced], angle: 0 }) + expect(caught).toMatchObject({ u: false, v: true }) + near(caught.shift, [0, 0.05]) + }) + + test('a caught axis beats the grid, the other keeps the grid', () => { + const placed = placeRoofOnWalls( + [5.12, 4.3], + [5.5, 4.5], + { shift: [-0.12, 0], u: true, v: false }, + 0, + ) + near(placed, [5, 4.5]) + }) + + test('a side pulled near a wall sizes the segment onto its centre line, the other side held', () => { + // Wall line x 1..9 by z 1..7: the +x side pulled to 9.85, the -x side to 0.2. + const line: RoofWallLine = { center: [5, 4], angle: 0, hw: 4, hd: 3 } + expect( + catchRoofSideOnWalls({ line, axis: 'x', side: 1, value: 8.85, walls: roomWalls }), + ).toBeCloseTo(9, 6) + expect( + catchRoofSideOnWalls({ line, axis: 'x', side: -1, value: 8.8, walls: roomWalls }), + ).toBeCloseTo(9, 6) + expect( + catchRoofSideOnWalls({ line, axis: 'z', side: 1, value: 6.9, walls: roomWalls }), + ).toBeCloseTo(7, 6) + expect( + catchRoofSideOnWalls({ line, axis: 'x', side: 1, value: 8.5, walls: roomWalls }), + ).toBeNull() + }) + + test('a quarter-turned segment pulls its own x side onto the wall across it', () => { + // Its x axis runs along plan -z, so its +x side faces the wall at z 0. + const line: RoofWallLine = { center: [5, 4], angle: -Math.PI / 2, hw: 3, hd: 4 } + expect( + catchRoofSideOnWalls({ line, axis: 'x', side: 1, value: 6.9, walls: roomWalls }), + ).toBeCloseTo(7, 6) + }) + + test('a wall line on the walls takes the thickest of the walls it stands on', () => { + const thick = (thickness: number, i: number) => WallNode.parse({ ...roomWalls[i], thickness }) + const walls = [thick(0.18, 0), thick(0.18, 1), thick(0.24, 2), thick(0.18, 3)] + const on: RoofWallLine = { center: [5.1, 4], angle: 0, hw: 5, hd: 4 } + expect(bearingWallThickness(on, walls)).toBeCloseTo(0.24, 6) + // Only its -z edge on the wall at z 0: that wall's thickness. + const half: RoofWallLine = { center: [5, 2], angle: 0, hw: 3, hd: 2 } + expect(bearingWallThickness(half, walls)).toBeCloseTo(0.18, 6) + const off: RoofWallLine = { center: [5, 4], angle: 0, hw: 3, hd: 2 } + expect(bearingWallThickness(off, walls)).toBeNull() + }) + + test("a segment's wall line goes through its roof's place and turn", () => { + const line = segmentWallLine( + { position: [2, 0, 3], rotation: Math.PI / 2 }, + { position: [1, 0, 0], rotation: 0, width: 6, depth: 4 }, + ) + near(line.center, [2, 2]) + expect(line.angle).toBeCloseTo(-Math.PI / 2, 6) + expect([line.hw, line.hd]).toEqual([3, 2]) + }) + + test("the walls are the roof level's and the storey's below, never curved ones", () => { + const curved = WallNode.parse({ + parentId: 'level_g', + start: [0, 0], + end: [0, -4], + curveOffset: 1, + }) + const upstairs = WallNode.parse({ parentId: 'level_roof', start: [2, 2], end: [6, 2] }) + const ground = LevelNode.parse({ + id: 'level_g', + parentId: 'building_h', + level: 0, + children: [...roomWalls.map((wall) => wall.id), curved.id], + }) + const roofLevel = LevelNode.parse({ + id: 'level_roof', + parentId: 'building_h', + level: 1, + children: [upstairs.id, 'roof_r'], + }) + const segment = RoofSegmentNode.parse({ id: 'rseg_r', parentId: 'roof_r' }) + const roof = RoofNode.parse({ id: 'roof_r', parentId: roofLevel.id, children: [segment.id] }) + const building = BuildingNode.parse({ id: 'building_h', children: [ground.id, roofLevel.id] }) + const nodes = Object.fromEntries( + [building, ground, roofLevel, roof, segment, curved, upstairs, ...roomWalls].map((node) => [ + node.id, + node as AnyNode, + ]), + ) as Record + const ids = roofCatchWalls(nodes, roofLevel.id).map((wall) => wall.id) + expect(ids.sort()).toEqual([upstairs.id, ...roomWalls.map((wall) => wall.id)].sort()) + }) +}) + +// A porch 6 m along a 0.2 m house wall at z 0, 2.5 m deep, closed by invisible walls or fenced by +// railings: its edges at x 2 and 8 and z -2.5. +const RAIL = 3.5 * 0.0254 +const H = RAIL / 2 +const houseWall = WallNode.parse({ + id: 'wall_house', + parentId: 'level_g', + start: [0, 0], + end: [10, 0], + thickness: 0.2, +}) +const porchSides: [[number, number], [number, number]][] = [ + [ + [2, 0], + [2, -2.5], + ], + [ + [2, -2.5], + [8, -2.5], + ], + [ + [8, -2.5], + [8, 0], + ], +] +function porchLines(open: 'separators' | 'railings'): RoofCatchLine[] { + const ground = LevelNode.parse({ id: 'level_g', level: 0 }) + const sides = porchSides.map(([start, end], i) => + open === 'separators' + ? SeparatorNode.parse({ id: `separator_${i}`, parentId: ground.id, start, end }) + : WallNode.parse({ + id: `wall_rail${i}`, + parentId: ground.id, + start, + end, + wallType: 'railing', + thickness: RAIL, + }), + ) + ground.children = [houseWall.id, ...sides.map((side) => side.id)] as LevelNode['children'] + const nodes = Object.fromEntries( + [ground, houseWall, ...sides].map((node) => [node.id, node as AnyNode]), + ) as Record + return roofCatchWalls(nodes, ground.id) +} + +describe("a roof catching on a porch's invisible walls and a deck's railings", () => { + test('invisible walls and railings are edges, the house wall a wall it stands on', () => { + const porch = porchLines('separators') + expect(porch.map((line) => line.type).sort()).toEqual([ + 'roof-edge', + 'roof-edge', + 'roof-edge', + 'wall', + ]) + const deck = porchLines('railings').filter((line) => line.type === 'roof-edge') + expect(deck.map((line) => line.type === 'roof-edge' && line.thickness)).toEqual([ + RAIL, + RAIL, + RAIL, + ]) + }) + + test("drawn out to a porch's invisible walls, its walls' outer faces stand on them", () => { + // Drawn from the house wall's centre line out to the porch's corners, with walls 0.2 m thick. + const drawn: RoofWallLine = { center: [5, -1.25], angle: 0, hw: 3, hd: 1.25 } + const settled = settleRoofOnEdges(drawn, porchLines('separators'), 0.2) + near(settled.center, [5, -1.2]) + near([settled.hw, settled.hd], [2.9, 1.2]) + }) + + test("drawn out to a deck's railings, its outer faces stand on the railings' outside faces", () => { + const drawn: RoofWallLine = { + center: [5, -(2.5 + H) / 2], + angle: 0, + hw: 3 + H, + hd: (2.5 + H) / 2, + } + const settled = settleRoofOnEdges(drawn, porchLines('railings'), 0.2) + near(settled.center, [5, -(2.4 + H) / 2]) + near([settled.hw, settled.hd], [2.9 + H, (2.4 + H) / 2]) + // Drawn on the grid, on the railings' centre lines, it takes their outside faces all the same. + const gridded: RoofWallLine = { center: [5, -1.25], angle: 0, hw: 3, hd: 1.25 } + const onGrid = settleRoofOnEdges(gridded, porchLines('railings'), 0.2) + near(onGrid.center, [5, -(2.4 + H) / 2]) + near([onGrid.hw, onGrid.hd], [2.9 + H, (2.4 + H) / 2]) + }) + + test('a segment settles in its roof, a quarter-turned one on its own axes', () => { + const roof = { position: [5, 0, -1.25] as [number, number, number], rotation: 0 } + const lines = porchLines('separators') + const flat = { position: [0, 0, 0] as [number, number, number], rotation: 0 } + const settled = settleSegmentOnEdges( + roof, + { ...flat, width: 6, depth: 2.5, wallThickness: 0.2 }, + lines, + ) + near(settled.position, [0, 0, 0.05]) + near([settled.width, settled.depth], [5.8, 2.4]) + const turned = settleSegmentOnEdges( + roof, + { ...flat, rotation: Math.PI / 2, width: 2.5, depth: 6, wallThickness: 0.2 }, + lines, + ) + near(turned.position, [0, 0, 0.05]) + near([turned.width, turned.depth], [2.4, 5.8]) + }) + + test('moved a little off, it catches with its outer faces on the edges', () => { + // On the house wall's centre line at z 0, its outer faces on x 2 and 8 and z -2.5. + const off: RoofWallLine = { center: [5.1, -1.15], angle: 0, hw: 2.9, hd: 1.2 } + const porch = catchRoofOnWalls({ lines: [off], walls: porchLines('separators'), angle: 0 }) + expect(porch).toMatchObject({ u: true, v: true }) + near(porch.shift, [-0.1, -0.05]) + // A deck: the outer faces on the railings' outside faces, x 2 - H and 8 + H and z -2.5 - H. + const deckOff: RoofWallLine = { + center: [5.08, -(2.4 + H) / 2 - 0.04], + angle: 0, + hw: 2.9 + H, + hd: (2.4 + H) / 2, + } + const deck = catchRoofOnWalls({ lines: [deckOff], walls: porchLines('railings'), angle: 0 }) + expect(deck).toMatchObject({ u: true, v: true }) + near(deck.shift, [-0.08, 0.04]) + }) + + test("a side arrow pulled near an invisible wall stops with the roof's outer face on it", () => { + const line: RoofWallLine = { + center: [5, -1.2], + angle: 0, + hw: 2.9, + hd: 1.2, + wallThickness: 0.2, + } + const walls = porchLines('separators') + expect(catchRoofSideOnWalls({ line, axis: 'x', side: 1, value: 5.7, walls })).toBeCloseTo( + 5.8, + 6, + ) + expect(catchRoofSideOnWalls({ line, axis: 'z', side: -1, value: 2.3, walls })).toBeCloseTo( + 2.4, + 6, + ) + }) + + test('with no wall under it, a roof keeps its own walls, their outer faces on the edges', () => { + const lines = porchLines('separators').filter((line) => line.type === 'roof-edge') + const free: RoofWallLine = { + center: [5.1, -1.3], + angle: 0, + hw: 2.95, + hd: 1.2, + wallThickness: 0.1, + } + expect(bearingWallThickness(free, lines)).toBeNull() + // Its 0.1 m walls' outer faces on x 2 and 8 and z -2.5: its line 0.05 m in from them. + const caught = catchRoofOnWalls({ lines: [free], walls: lines, angle: 0 }) + expect(caught).toMatchObject({ u: true, v: true }) + near(caught.shift, [-0.1, 0.05]) + }) + + test('neither an invisible wall nor a railing gives the roof its wall thickness', () => { + const along: RoofWallLine = { center: [5, -1.25], angle: 0, hw: 3, hd: 1.25 } + expect(bearingWallThickness(along, porchLines('separators'))).toBeCloseTo(0.2, 6) + expect( + bearingWallThickness( + along, + porchLines('railings').filter((line) => line.type === 'roof-edge'), + ), + ).toBeNull() + }) +}) diff --git a/packages/nodes/src/roof/wall-catch.ts b/packages/nodes/src/roof/wall-catch.ts new file mode 100644 index 0000000000..65c74a82a5 --- /dev/null +++ b/packages/nodes/src/roof/wall-catch.ts @@ -0,0 +1,372 @@ +import { + type AnyNode, + type AnyNodeId, + getLevelBelow, + getWallBodyLine, + getWallThickness, + isCurvedWall, + isRailingWall, + type RoofNode, + type RoofSegmentNode, + type WallNode, +} from '@pascal-app/core' + +type Pt = readonly [number, number] + +/** How near a roof's wall line comes to a wall's centre line before it catches on it (metres). */ +export const ROOF_WALL_CATCH_M = 0.25 + +/** + * A side drawn or picked this near a room's edge stands on it (metres): as near as a drawn corner + * sticks to a wall in grid (the wall snap's connect radius), so one drawn on a railing's centre + * line, a grid point, still takes its outside face. + */ +export const ROOF_EDGE_ON_M = 0.05 + +/** A wall within this of parallel (the sine of 1°) runs along a roof edge. */ +const PARALLEL = Math.sin(Math.PI / 180) + +/** + * A segment's footprint at its wall centre lines, in its level's plan: its centre, the plan angle + * of its own x axis (the floor plan's `-(roof.rotation + segment.rotation)`), and its own walls' + * thickness, their outer faces half of it outside the line (absent, none). + */ +export type RoofWallLine = { + center: Pt + angle: number + hw: number + hd: number + wallThickness?: number +} + +/** + * A room's edge a roof lines up with but does not stand on: an invisible wall (its line, no + * thickness), or a railing (a guard round a deck or a porch, its faces half its thickness either + * side of its line). A wall takes a roof's wall line on its centre line, the roof's walls as thick + * as it, so their outer faces meet its outside face; an edge takes the roof's outer face itself, + * on the edge's face on the roof's outer side, so the roof reaches the room's edge as it reaches + * the house's walls' outside faces. + */ +export type RoofEdgeLine = { type: 'roof-edge'; id: string; start: Pt; end: Pt; thickness: number } + +/** A line a roof catches on: a wall's centre line, or a room's edge (`RoofEdgeLine`). */ +export type RoofCatchLine = WallNode | RoofEdgeLine + +/** Which axes of the dragged frame caught on a wall, and the plan shift that lays them there. */ +export type RoofWallCatch = { shift: [number, number]; u: boolean; v: boolean } + +const NO_CATCH: RoofWallCatch = { shift: [0, 0], u: false, v: false } + +const dot = (a: Pt, b: Pt) => a[0] * b[0] + a[1] * b[1] + +/** + * A catch line's ends: a wall's body centre line (a wall drawn by a face has it half its thickness + * off the middle), an edge's own. + */ +function lineEnds(line: RoofCatchLine): [Pt, Pt] { + if (line.type === 'roof-edge') return [line.start, line.end] + const body = getWallBodyLine(line) + return [ + [body.start.x, body.start.y], + [body.end.x, body.end.y], + ] +} + +/** A railing as a room's edge: its body's centre line, its faces half its thickness off it. */ +function railingEdge(wall: WallNode): RoofEdgeLine { + const [start, end] = lineEnds(wall) + return { type: 'roof-edge', id: wall.id, start, end, thickness: getWallThickness(wall) } +} + +/** + * The line nearest an edge through `mid`, and how far along `n` the edge moves onto it: lines + * parallel to the edge, within `threshold` of it, and overlapping its `half` length either side of + * `mid` along `t`. Null when none does. A wall takes the edge on its centre line; a room's edge + * takes the outer face of the roof's walls, `thickness` thick, on its face on the outer side. + */ +function nearestLine( + mid: Pt, + n: Pt, + t: Pt, + half: number, + lines: readonly RoofCatchLine[], + threshold: number, + thickness: number, +): { gap: number; line: RoofCatchLine } | null { + let best: { gap: number; line: RoofCatchLine } | null = null + for (const line of lines) { + const [from, to] = lineEnds(line) + const run: Pt = [to[0] - from[0], to[1] - from[1]] + const length = Math.hypot(run[0], run[1]) + if (length < 1e-6 || Math.abs(dot(run, n)) / length > PARALLEL) continue + const start: Pt = [from[0] - mid[0], from[1] - mid[1]] + const end: Pt = [to[0] - mid[0], to[1] - mid[1]] + const gap = dot(start, n) + (line.type === 'roof-edge' ? (line.thickness - thickness) / 2 : 0) + if (Math.abs(gap) > threshold) continue + const a = dot(start, t) + const b = dot(end, t) + if (Math.max(a, b) <= -half || Math.min(a, b) >= half) continue + if (best === null || Math.abs(gap) < Math.abs(best.gap)) best = { gap, line } + } + return best +} + +/** A wall line's four edges: outward normal, run, distance from the centre, half length. */ +function lineEdges(line: RoofWallLine) { + const ex: Pt = [Math.cos(line.angle), Math.sin(line.angle)] + const ez: Pt = [-ex[1], ex[0]] + return [ + { n: ex, t: ez, offset: line.hw, half: line.hd }, + { n: [-ex[0], -ex[1]] as Pt, t: ez, offset: line.hw, half: line.hd }, + { n: ez, t: ex, offset: line.hd, half: line.hw }, + { n: [-ez[0], -ez[1]] as Pt, t: ex, offset: line.hd, half: line.hw }, + ] +} + +/** A segment's wall line with its roof at `roof`'s place, which a drag may be proposing. */ +export function segmentWallLine( + roof: Pick, + segment: Pick & + Partial>, +): RoofWallLine { + const cos = Math.cos(-roof.rotation) + const sin = Math.sin(-roof.rotation) + const [lx, , lz] = segment.position + return { + center: [roof.position[0] + lx * cos - lz * sin, roof.position[2] + lx * sin + lz * cos], + angle: -(roof.rotation + segment.rotation), + hw: segment.width / 2, + hd: segment.depth / 2, + wallThickness: segment.wallThickness, + } +} + +/** + * What a roof on `levelId` catches on, on its own level and the storey below, which the roof plan + * draws dashed: the walls it sits on, and the rooms' edges there, their invisible walls and + * railings (`RoofEdgeLine`): a porch's, a deck's, a patio's. Curved walls have no straight line to + * catch on. + */ +export function roofCatchWalls( + nodes: Readonly>, + levelId: string | null | undefined, +): RoofCatchLine[] { + if (!levelId) return [] + const below = getLevelBelow(levelId, nodes as Record) + const lines: RoofCatchLine[] = [] + for (const id of [levelId, below?.id]) { + const level = id ? nodes[id as AnyNodeId] : undefined + if (level?.type !== 'level') continue + for (const childId of level.children) { + const node = nodes[childId as AnyNodeId] + if (node?.type === 'separator') + lines.push({ + type: 'roof-edge', + id: node.id, + start: node.start, + end: node.end, + thickness: 0, + }) + else if (node?.type === 'wall' && !isCurvedWall(node)) + lines.push(isRailingWall(node) ? railingEdge(node) : node) + } + } + return lines +} + +/** + * Where a dragged roof's wall lines catch on the walls under it. Along each axis of the frame at + * `angle` (the dragged segment's or roof's x and z), the edge nearest the centre line of a wall + * that runs alongside it, parallel and within `threshold`, sets the shift onto that wall; one + * nearest a room's edge (`RoofEdgeLine`) stands the outer face of the walls the segment takes + * there on it. + */ +export function catchRoofOnWalls(args: { + lines: readonly RoofWallLine[] + walls: readonly RoofCatchLine[] + angle: number + threshold?: number +}): RoofWallCatch { + const threshold = args.threshold ?? ROOF_WALL_CATCH_M + const u: Pt = [Math.cos(args.angle), Math.sin(args.angle)] + const v: Pt = [-u[1], u[0]] + let bestU: number | null = null + let bestV: number | null = null + + for (const line of args.lines) { + const thickness = landedWallThickness(line, args.walls, threshold) + for (const { n, t, offset, half } of lineEdges(line)) { + // An edge of a segment turned off the dragged frame moves along neither axis alone. + const alongU = dot(n, u) + const alongV = dot(n, v) + const axis = Math.abs(alongV) <= PARALLEL ? 'u' : Math.abs(alongU) <= PARALLEL ? 'v' : null + if (!axis) continue + const mid: Pt = [line.center[0] + n[0] * offset, line.center[1] + n[1] * offset] + const gap = nearestLine(mid, n, t, half, args.walls, threshold, thickness)?.gap + if (gap === undefined) continue + const amount = gap * (axis === 'u' ? alongU : alongV) + if (axis === 'u') { + if (bestU === null || Math.abs(amount) < Math.abs(bestU)) bestU = amount + } else if (bestV === null || Math.abs(amount) < Math.abs(bestV)) bestV = amount + } + } + + if (bestU === null && bestV === null) return NO_CATCH + const du = bestU ?? 0 + const dv = bestV ?? 0 + return { + shift: [u[0] * du + v[0] * dv, u[1] * du + v[1] * dv], + u: bestU !== null, + v: bestV !== null, + } +} + +/** + * A dragged roof's place: along an axis its wall line caught on, the raw place shifted onto the + * wall; along the other, the snapped place (the grid's, or the raw cursor's with no grid). + */ +export function placeRoofOnWalls( + raw: Pt, + snapped: Pt, + caught: RoofWallCatch, + angle: number, +): [number, number] { + const out: [number, number] = [snapped[0], snapped[1]] + const target: Pt = [raw[0] + caught.shift[0], raw[1] + caught.shift[1]] + const u: Pt = [Math.cos(angle), Math.sin(angle)] + const v: Pt = [-u[1], u[0]] + for (const [axis, on] of [ + [u, caught.u], + [v, caught.v], + ] as const) { + if (!on) continue + const k = (target[0] - out[0]) * axis[0] + (target[1] - out[1]) * axis[1] + out[0] += axis[0] * k + out[1] += axis[1] * k + } + return out +} + +/** + * A side dragged out from `line` (the segment's wall line before the drag), its opposite side held: + * the size along `axis` that lays the dragged side on the centre line of a wall alongside it, or + * stands its outer face on a room's edge there (`RoofEdgeLine`); null when neither is within + * `threshold` of `value`. + */ +export function catchRoofSideOnWalls(args: { + line: RoofWallLine + axis: 'x' | 'z' + side: 1 | -1 + value: number + walls: readonly RoofCatchLine[] + threshold?: number +}): number | null { + const { line, axis, side, value } = args + const threshold = args.threshold ?? ROOF_WALL_CATCH_M + const ex: Pt = [Math.cos(line.angle), Math.sin(line.angle)] + const ez: Pt = [-ex[1], ex[0]] + const along = axis === 'x' ? ex : ez + const n: Pt = [along[0] * side, along[1] * side] + const half = axis === 'x' ? line.hw : line.hd + const reach = value - half + const mid: Pt = [line.center[0] + n[0] * reach, line.center[1] + n[1] * reach] + // Sized to `value`, the opposite side held: the thickness its walls take there. + const shift = value / 2 - half + const sized: RoofWallLine = { + ...line, + center: [line.center[0] + n[0] * shift, line.center[1] + n[1] * shift], + hw: axis === 'x' ? value / 2 : line.hw, + hd: axis === 'z' ? value / 2 : line.hd, + } + const caught = nearestLine( + mid, + n, + axis === 'x' ? ez : ex, + axis === 'x' ? line.hd : line.hw, + args.walls, + threshold, + landedWallThickness(sized, args.walls, threshold), + ) + return caught ? value + caught.gap : null +} + +/** + * The thickness a segment's walls take to stand flush on the walls under it: the thickest wall + * whose centre line runs along an edge of its wall line, within `threshold`. A room's edge (an + * invisible wall, a railing) carries no roof and gives none. Null when no wall does. + */ +export function bearingWallThickness( + line: RoofWallLine, + walls: readonly RoofCatchLine[], + threshold = ROOF_WALL_CATCH_M, +): number | null { + const bearing = walls.filter((wall): wall is WallNode => wall.type === 'wall') + let thickest: number | null = null + for (const { n, t, offset, half } of lineEdges(line)) { + const mid: Pt = [line.center[0] + n[0] * offset, line.center[1] + n[1] * offset] + const wall = nearestLine(mid, n, t, half, bearing, threshold, 0)?.line + if (wall?.type === 'wall' && (thickest === null || getWallThickness(wall) > thickest)) + thickest = getWallThickness(wall) + } + return thickest +} + +/** The thickness a wall line's walls take where it stands: the walls' under it, else its own. */ +function landedWallThickness( + line: RoofWallLine, + walls: readonly RoofCatchLine[], + threshold: number, +): number { + return bearingWallThickness(line, walls, threshold) ?? line.wallThickness ?? 0 +} + +/** + * A wall line drawn or picked out to a room's edges (`RoofEdgeLine`): each side lying on one, + * within `tolerance`, moved in so the outer face of its walls, `thickness` thick, stands there, as + * the house's roof stands its walls' outer faces on the walls' outside faces. A side on a wall's + * centre line, or on nothing, stays. + */ +export function settleRoofOnEdges( + line: RoofWallLine, + walls: readonly RoofCatchLine[], + thickness: number, + tolerance = ROOF_EDGE_ON_M, +): RoofWallLine { + const ex: Pt = [Math.cos(line.angle), Math.sin(line.angle)] + const ez: Pt = [-ex[1], ex[0]] + // How far each side (+x, -x, +z, -z) moves out along its own normal. + const [px = 0, nx = 0, pz = 0, nz = 0] = lineEdges(line).map(({ n, t, offset, half }) => { + const mid: Pt = [line.center[0] + n[0] * offset, line.center[1] + n[1] * offset] + const on = nearestLine(mid, n, t, half, walls, tolerance, 0) + return on?.line.type === 'roof-edge' ? on.gap - thickness / 2 : 0 + }) + const du = (px - nx) / 2 + const dv = (pz - nz) / 2 + return { + ...line, + center: [line.center[0] + ex[0] * du + ez[0] * dv, line.center[1] + ex[1] * du + ez[1] * dv], + hw: Math.max(1e-3, line.hw + (px + nx) / 2), + hd: Math.max(1e-3, line.hd + (pz + nz) / 2), + } +} + +/** + * A segment drawn or picked out to a room's edges, in its roof at `roof`'s place: its size and + * place in its roof with its walls' outer faces on them (`settleRoofOnEdges`). + */ +export function settleSegmentOnEdges( + roof: Pick, + segment: Pick, + walls: readonly RoofCatchLine[], +): Pick { + const settled = settleRoofOnEdges(segmentWallLine(roof, segment), walls, segment.wallThickness) + const dx = settled.center[0] - roof.position[0] + const dz = settled.center[1] - roof.position[2] + const cos = Math.cos(-roof.rotation) + const sin = Math.sin(-roof.rotation) + return { + position: [dx * cos + dz * sin, segment.position[1], -dx * sin + dz * cos], + width: settled.hw * 2, + depth: settled.hd * 2, + } +} diff --git a/packages/nodes/src/separator/definition.test.ts b/packages/nodes/src/separator/definition.test.ts index 9d204b32c5..198967780d 100644 --- a/packages/nodes/src/separator/definition.test.ts +++ b/packages/nodes/src/separator/definition.test.ts @@ -34,3 +34,31 @@ test('separator registers selectable dashed plan and 3D renderers, without movem restore() } }) + +test('a selected separator shows a wall’s handles on the plan: its two ends and a push arrow off each side', () => { + const node = separatorDefinition.schema.parse({ + ...separatorDefinition.defaults(), + start: [0, 0], + end: [4, 0], + }) + const geometry = separatorDefinition.floorplan!(node, { viewState: { selected: true } } as never) + const children = geometry?.kind === 'group' ? geometry.children : [] + expect(children[0]).toMatchObject({ kind: 'line', strokeDasharray: '6 4' }) + expect( + children.flatMap((child) => + child.kind === 'endpoint-handle' ? [[child.affordance, child.payload]] : [], + ), + ).toEqual([ + ['move-endpoint', { separatorId: node.id, endpoint: 'start' }], + ['move-endpoint', { separatorId: node.id, endpoint: 'end' }], + ]) + const arrows = children.flatMap((child) => (child.kind === 'move-arrow' ? [child] : [])) + expect(arrows.map((arrow) => arrow.payload)).toEqual([ + { wallId: node.id, side: 'a' }, + { wallId: node.id, side: 'b' }, + ]) + // One off each side of the line. + expect(arrows.map((arrow) => Math.sign(arrow.point[1]))).toEqual([1, -1]) + expect(separatorDefinition.floorplanAffordances?.['move-endpoint']).toBeDefined() + expect(separatorDefinition.snapProfile).toBe('structural') +}) diff --git a/packages/nodes/src/separator/definition.ts b/packages/nodes/src/separator/definition.ts index db9fd058a6..5aef4d1783 100644 --- a/packages/nodes/src/separator/definition.ts +++ b/packages/nodes/src/separator/definition.ts @@ -1,7 +1,11 @@ import { type NodeDefinition, SeparatorNode } from '@pascal-app/core' +import { buildSeparatorFloorplan } from './floorplan' +import { separatorMoveEndpointAffordance } from './floorplan-affordances' export const separatorDefinition: NodeDefinition = { kind: 'separator', + // Its pushes and end drags snap as a wall's do. + snapProfile: 'structural', bake: 'strip', schemaVersion: 1, schema: SeparatorNode, @@ -19,18 +23,12 @@ export const separatorDefinition: NodeDefinition = { dirtyTracking: false, rendersChildren: false, renderer: { kind: 'parametric', module: () => import('./renderer') }, - floorplan: (node) => ({ - kind: 'line', - x1: node.start[0], - y1: node.start[1], - x2: node.end[0], - y2: node.end[1], - stroke: '#818cf8', - strokeWidth: 2, - strokeDasharray: '6 4', - vectorEffect: 'non-scaling-stroke', - pointerEvents: 'stroke', - }), + floorplan: buildSeparatorFloorplan, + // An invisible wall moves as a wall does, taking the ones joined to it along: + // its side arrows push it (the plan's `move-arrow`s, the 3D selection + // handles) and its ends drag, on the plan and in 3D. + floorplanAffordances: { 'move-endpoint': separatorMoveEndpointAffordance }, + affordanceTools: { selection: () => import('./selection') }, presentation: { icon: { kind: 'iconify', name: 'lucide:split' }, label: 'Separator', diff --git a/packages/nodes/src/separator/floorplan-affordances.ts b/packages/nodes/src/separator/floorplan-affordances.ts new file mode 100644 index 0000000000..8cc4cdaecd --- /dev/null +++ b/packages/nodes/src/separator/floorplan-affordances.ts @@ -0,0 +1,32 @@ +import type { + AnyNodeId, + FloorplanAffordance, + FloorplanAffordanceSession, + SeparatorNode, +} from '@pascal-app/core' +import { beginSeparatorEndDrag } from '@pascal-app/editor' + +type SeparatorEndpointPayload = { separatorId: AnyNodeId; endpoint: 'start' | 'end' } + +/** + * An invisible wall's end handle on the plan, the 2D twin of its 3D grip: the + * same snapping, preview and commit (`beginSeparatorEndDrag`), the pointer read + * by the floor plan. The invisible walls joined at that end follow it; Alt + * leaves them where they are. + */ +export const separatorMoveEndpointAffordance: FloorplanAffordance = { + start({ node, payload }): FloorplanAffordanceSession { + const { endpoint } = payload as SeparatorEndpointPayload + const drag = beginSeparatorEndDrag(node.id, endpoint) + return { + affectedIds: drag?.affectedIds ?? [node.id], + apply({ planPoint, modifiers }) { + drag?.move([planPoint[0], planPoint[1]], modifiers.altKey) + }, + canCommit: () => drag?.canCommit() ?? false, + commit() { + drag?.commit() + }, + } + }, +} diff --git a/packages/nodes/src/separator/floorplan.ts b/packages/nodes/src/separator/floorplan.ts new file mode 100644 index 0000000000..c1e7f5ea2f --- /dev/null +++ b/packages/nodes/src/separator/floorplan.ts @@ -0,0 +1,59 @@ +import type { FloorplanGeometry, GeometryContext, SeparatorNode } from '@pascal-app/core' +import { WALL_PUSH_AFFORDANCE, type WallPushArrowPayload } from '@pascal-app/editor' + +/** How far off the line (m) a selected invisible wall's side arrows sit. */ +const SIDE_ARROW_OFFSET = 0.12 + +/** + * An invisible wall on the plan: a dashed line. Selected, it shows a wall's own + * handles — an end handle at each end (drag it; the invisible walls joined + * there follow) and a push arrow off each side (the wall push, the ones joined + * to it following). + */ +export function buildSeparatorFloorplan( + node: SeparatorNode, + ctx: GeometryContext, +): FloorplanGeometry { + const line: FloorplanGeometry = { + kind: 'line', + x1: node.start[0], + y1: node.start[1], + x2: node.end[0], + y2: node.end[1], + stroke: '#818cf8', + strokeWidth: 2, + strokeDasharray: '6 4', + vectorEffect: 'non-scaling-stroke', + pointerEvents: 'stroke', + } + if (!ctx.viewState?.selected) return line + const children: FloorplanGeometry[] = [line] + for (const endpoint of ['start', 'end'] as const) + children.push({ + kind: 'endpoint-handle', + point: [node[endpoint][0], node[endpoint][1]], + state: 'idle', + affordance: 'move-endpoint', + payload: { separatorId: node.id, endpoint }, + }) + const dx = node.end[0] - node.start[0] + const dz = node.end[1] - node.start[1] + const length = Math.hypot(dx, dz) + if (length > 1e-6) { + const middle = [(node.start[0] + node.end[0]) / 2, (node.start[1] + node.end[1]) / 2] as const + for (const side of ['a', 'b'] as const) { + // Side `a` is the +normal one, as a wall's front. + const sign = side === 'a' ? 1 : -1 + const nx = (-dz / length) * sign + const nz = (dx / length) * sign + children.push({ + kind: 'move-arrow', + point: [middle[0] + nx * SIDE_ARROW_OFFSET, middle[1] + nz * SIDE_ARROW_OFFSET], + angle: Math.atan2(nz, nx), + affordance: WALL_PUSH_AFFORDANCE, + payload: { wallId: node.id, side } satisfies WallPushArrowPayload, + }) + } + } + return { kind: 'group', children } +} diff --git a/packages/nodes/src/separator/renderer.tsx b/packages/nodes/src/separator/renderer.tsx index 06cc1a0c8b..d26377b6ae 100644 --- a/packages/nodes/src/separator/renderer.tsx +++ b/packages/nodes/src/separator/renderer.tsx @@ -1,7 +1,7 @@ 'use client' -import { type SeparatorNode, useRegistry, useScene } from '@pascal-app/core' -import { useEditor } from '@pascal-app/editor' +import { type SeparatorNode, useLiveNodeOverrides, useRegistry, useScene } from '@pascal-app/core' +import { separatorFloorElevation, useEditor } from '@pascal-app/editor' import { useNodeEvents, useViewer } from '@pascal-app/viewer' import { useEffect, useMemo, useRef } from 'react' import { BufferGeometry, Float32BufferAttribute, type Group } from 'three' @@ -10,20 +10,40 @@ import { LineBasicNodeMaterial, MeshBasicNodeMaterial } from 'three/webgpu' const separatorMaterial = new LineBasicNodeMaterial({ color: '#818cf8', depthWrite: false }) const hitMaterial = new MeshBasicNodeMaterial({ transparent: true, opacity: 0, depthWrite: false }) +/** + * An invisible wall in 3D: a dashed line on the floor, shown while its room or + * it is selected. A push or end drag moves it live (`useLiveNodeOverrides`). + */ export default function SeparatorRenderer({ node }: { node: SeparatorNode }) { const ref = useRef(null!) useRegistry(node.id, 'separator', ref) const roomId = useEditor((s) => s.room?.zoneId) const viewerRoomId = useViewer((s) => s.selection.zoneId) + const selected = useViewer((s) => s.selection.selectedIds.includes(node.id)) const zone = useScene((s) => { const id = roomId ?? viewerRoomId return id ? s.nodes[id as keyof typeof s.nodes] : undefined }) - const visible = zone?.type === 'zone' && zone.boundarySeparatorIds.includes(node.id) + const inRoom = zone?.type === 'zone' && zone.boundarySeparatorIds.includes(node.id) + const visible = inRoom || selected + // Selected on its own, it lies on the floor of a room it closes. + const ownFloor = useScene((s) => + selected && !inRoom ? separatorFloorElevation(s.nodes, node.id) : null, + ) + const live = useLiveNodeOverrides((s) => s.overrides.get(node.id)) as + | Partial + | undefined + const start = live?.start ?? node.start + const end = live?.end ?? node.end const events = useNodeEvents(node, 'separator') - const y = zone?.type === 'zone' ? (zone.floor?.elevation ?? 0.05) + 0.02 : 0.07 - const dx = node.end[0] - node.start[0], - dz = node.end[1] - node.start[1] + const y = + zone?.type === 'zone' && inRoom + ? (zone.floor?.elevation ?? 0.05) + 0.02 + : ownFloor !== null + ? ownFloor + 0.02 + : 0.07 + const dx = end[0] - start[0], + dz = end[1] - start[1] const length = Math.hypot(dx, dz) const geometry = useMemo(() => { const positions: number[] = [] @@ -42,14 +62,14 @@ export default function SeparatorRenderer({ node }: { node: SeparatorNode }) { {}} /> diff --git a/packages/nodes/src/separator/selection.tsx b/packages/nodes/src/separator/selection.tsx new file mode 100644 index 0000000000..dd3d8dd25e --- /dev/null +++ b/packages/nodes/src/separator/selection.tsx @@ -0,0 +1,59 @@ +'use client' + +import { type AnyNodeId, type SeparatorNode, sceneRegistry, useScene } from '@pascal-app/core' +import { + type SelectionAffordanceProps, + SeparatorEndGrip, + separatorFloorElevation, + separatorPushHandles, + useEditor, + useInteractionScope, + WallPushArrow, +} from '@pascal-app/editor' +import { createPortal } from '@react-three/fiber' +import { useEffect, useState } from 'react' +import type { Object3D } from 'three' + +/** + * A selected invisible wall's 3D handles, the twins of its plan ones: a push + * arrow off each side (the wall push: the invisible walls joined to it follow + * and those T'd into it stretch) and a grip at each end (drag it across the + * floor; the ones joined there follow). They lie on the floor of the room it + * closes, where its dashed line is drawn, and hide while a drag runs. + */ +export default function SeparatorSelectionAffordance({ node, readOnly }: SelectionAffordanceProps) { + const editing = useEditor((s) => s.mode === 'select' && !s.isFloorplanHovered) + const idle = useInteractionScope((s) => s.scope.kind === 'idle') + const floor = useScene((s) => separatorFloorElevation(s.nodes, node.id)) + const levelId = node.parentId + const [level, setLevel] = useState(null) + useEffect(() => { + let frame = 0 + const resolve = () => { + const next = levelId ? (sceneRegistry.nodes.get(levelId as AnyNodeId) ?? null) : null + setLevel((current) => (current === next ? current : next)) + if (!next && levelId) frame = window.requestAnimationFrame(resolve) + } + resolve() + return () => window.cancelAnimationFrame(frame) + }, [levelId]) + if (node.type !== 'separator' || readOnly || !editing || !idle || !level || !levelId) return null + const separator = node as SeparatorNode + return createPortal( + <> + {separatorPushHandles(separator, floor).map((handle) => ( + + ))} + {(['start', 'end'] as const).map((endpoint) => ( + + ))} + , + level, + ) +} diff --git a/packages/nodes/src/shared/build-up-controls.tsx b/packages/nodes/src/shared/build-up-controls.tsx new file mode 100644 index 0000000000..c1d88f9451 --- /dev/null +++ b/packages/nodes/src/shared/build-up-controls.tsx @@ -0,0 +1,343 @@ +'use client' + +import { + DRYWALL_THICKNESSES, + FRAMING_SPACINGS, + type InsulationKind, + type InteriorFinishKind, + LUMBER_DEPTH, + type MessageDescriptor, + type NominalLumber, + PANEL_THICKNESSES, + type PanelKind, + type PascalI18n, + PLASTER_THICKNESS, + usePascalI18n, + WOOD_PLANK_THICKNESS, +} from '@pascal-app/core' +import { SelectControl } from '@pascal-app/editor' +import { useState } from 'react' +import { formatLayerThickness, parseLayerThickness } from './layer-thickness' + +type LinearUnit = 'metric' | 'imperial' + +const key = (value: number) => value.toFixed(6) + +/** + * A select over standard sizes (panel thicknesses, spacings). A stored value + * off the list stays selectable, so a scene written elsewhere reads back as + * it is. + */ +export function SizeSelect({ + label, + value, + sizes, + format, + onChange, +}: { + label: string + value: number + sizes: readonly number[] + format: (value: number) => string + onChange: (value: number) => void +}) { + const listed = sizes.some((size) => Math.abs(size - value) < 1e-6) + const choices = listed ? sizes : [value, ...sizes] + const current = choices.find((size) => Math.abs(size - value) < 1e-6) ?? value + return ( + { + const picked = choices.find((size) => key(size) === next) + if (picked !== undefined) onChange(picked) + }} + options={choices.map((size) => ({ label: format(size), value: key(size) }))} + value={key(current)} + /> + ) +} + +/** A free thickness, typed as `5/8`, `3 1/2"` or `90mm`; a bare number is inches or millimetres. */ +export function ThicknessField({ + label, + metres, + onCommit, + unit, +}: { + label: string + metres: number + onCommit: (metres: number) => void + unit: LinearUnit +}) { + const [draft, setDraft] = useState(null) + return ( + + ) +} + +export function BuildUpReadout({ label, value }: { label: string; value: string }) { + return ( +
+ + {label} + + {value} +
+ ) +} + +/** A spacing on centre, as the viewer's unit names it: `16" o.c.` or `406 mm o.c.`. */ +export function formatSpacing(metres: number, unit: LinearUnit, i18n: PascalI18n): string { + const spacing = + unit === 'imperial' ? formatLayerThickness(metres, unit) : `${Math.round(metres * 1000)} mm` + return i18n._({ + id: 'node.shared.buildUpControls.spacingOC', + message: '{spacing} o.c.', + comment: 'A framing spacing on centre (centre of one member to the next), e.g. 16" o.c.', + values: { spacing }, + }) +} + +export const NONE = 'none' +const INCH = 0.0254 + +const NONE_LABEL: MessageDescriptor = /* i18n */ { + id: 'node.shared.buildUpControls.none', + message: 'None', +} + +/** What each panel, insulation and finish kind is called. */ +export const LAYER_KIND_LABELS: Record< + PanelKind | InsulationKind | InteriorFinishKind, + MessageDescriptor +> = { + osb: /* i18n */ { id: 'node.shared.buildUpControls.osb', message: 'OSB' }, + plywood: /* i18n */ { id: 'node.shared.buildUpControls.plywood', message: 'Plywood' }, + batt: /* i18n */ { id: 'node.shared.buildUpControls.batt', message: 'Batt' }, + blown: /* i18n */ { id: 'node.shared.buildUpControls.blown', message: 'Blown' }, + rigid: /* i18n */ { id: 'node.shared.buildUpControls.rigidBoard', message: 'Rigid board' }, + drywall: /* i18n */ { id: 'node.shared.buildUpControls.drywall', message: 'Drywall' }, + plaster: /* i18n */ { id: 'node.shared.buildUpControls.plaster', message: 'Plaster' }, + 'wood-plank': /* i18n */ { id: 'node.shared.buildUpControls.woodPlank', message: 'Wood plank' }, +} + +const PANEL_OPTIONS: { label: MessageDescriptor; value: PanelKind | typeof NONE }[] = [ + { label: LAYER_KIND_LABELS.osb, value: 'osb' }, + { label: LAYER_KIND_LABELS.plywood, value: 'plywood' }, +] +const OPTIONAL_PANEL_OPTIONS: typeof PANEL_OPTIONS = [ + { label: NONE_LABEL, value: NONE }, + ...PANEL_OPTIONS, +] + +const LUMBER_OPTIONS: { label: string; value: NominalLumber }[] = ( + Object.keys(LUMBER_DEPTH) as NominalLumber[] +).map((size) => ({ label: size, value: size })) + +const INSULATION_OPTIONS: { label: MessageDescriptor; value: InsulationKind | typeof NONE }[] = [ + { label: NONE_LABEL, value: NONE }, + { label: LAYER_KIND_LABELS.batt, value: 'batt' }, + { label: LAYER_KIND_LABELS.blown, value: 'blown' }, + { label: LAYER_KIND_LABELS.rigid, value: 'rigid' }, +] + +const FINISH_OPTIONS: { label: MessageDescriptor; value: InteriorFinishKind | typeof NONE }[] = [ + { label: NONE_LABEL, value: NONE }, + { label: LAYER_KIND_LABELS.drywall, value: 'drywall' }, + { label: LAYER_KIND_LABELS.plaster, value: 'plaster' }, + { label: LAYER_KIND_LABELS['wood-plank'], value: 'wood-plank' }, +] + +const FINISH_THICKNESS: Record = { + drywall: DRYWALL_THICKNESSES[0]!, + plaster: PLASTER_THICKNESS, + 'wood-plank': WOOD_PLANK_THICKNESS, +} + +/** `base` with `change` applied and no longer a preset; a layer set to `undefined` goes. */ +export function editedBuildUp(base: T, change: Partial): T { + const next: Record = { ...base, ...change } + delete next.presetId + for (const field of Object.keys(next)) if (next[field] === undefined) delete next[field] + return next as T +} + +export function FramingSizeFields({ + framing, + onChange, + sizeLabel, + unit, +}: { + framing: { size: NominalLumber; spacing: number } + onChange: (change: { size?: NominalLumber; spacing?: number }) => void + sizeLabel: string + unit: LinearUnit +}) { + const i18n = usePascalI18n() + return ( + <> + onChange({ size })} + options={LUMBER_OPTIONS} + value={framing.size} + /> + formatSpacing(value, unit, i18n)} + label={i18n._({ id: 'node.shared.buildUpControls.spacing', message: 'Spacing' })} + onChange={(spacing) => onChange({ spacing })} + sizes={FRAMING_SPACINGS} + value={framing.spacing} + /> + + ) +} + +/** A structural panel; with `optional`, None takes it out and a new one is `added`. */ +export function PanelFields({ + added = PANEL_THICKNESSES[0]!, + label, + layer, + onChange, + optional = false, + unit, +}: { + added?: number + label: string + layer: { kind: PanelKind; thickness: number } | undefined + onChange: (layer: { kind: PanelKind; thickness: number } | undefined) => void + optional?: boolean + unit: LinearUnit +}) { + const i18n = usePascalI18n() + return ( + <> + + onChange(kind === NONE ? undefined : { thickness: layer?.thickness ?? added, kind }) + } + options={(optional ? OPTIONAL_PANEL_OPTIONS : PANEL_OPTIONS).map((option) => ({ + ...option, + label: i18n._(option.label), + }))} + value={layer?.kind ?? NONE} + /> + {layer && ( + formatLayerThickness(value, unit)} + label={i18n._({ + id: 'node.shared.buildUpControls.labelThickness', + message: '{label} thickness', + values: { label }, + })} + onChange={(thickness) => onChange({ ...layer, thickness })} + sizes={PANEL_THICKNESSES} + value={layer.thickness} + /> + )} + + ) +} + +/** A new insulation layer is cavity fill as deep as the framing, or 2 in of rigid board. */ +export function InsulationFields({ + framingDepth, + layer, + onChange, + unit, +}: { + framingDepth: number + layer: { kind: InsulationKind; thickness: number } | undefined + onChange: (layer: { kind: InsulationKind; thickness: number } | undefined) => void + unit: LinearUnit +}) { + const i18n = usePascalI18n() + return ( + <> + + onChange( + kind === NONE + ? undefined + : { kind, thickness: kind === 'rigid' ? 2 * INCH : framingDepth }, + ) + } + options={INSULATION_OPTIONS.map((option) => ({ ...option, label: i18n._(option.label) }))} + value={layer?.kind ?? NONE} + /> + {layer && ( + onChange({ ...layer, thickness })} + unit={unit} + /> + )} + + ) +} + +export function FinishFields({ + label, + layer, + onChange, + unit, +}: { + label: string + layer: { kind: InteriorFinishKind; thickness: number } | undefined + onChange: (layer: { kind: InteriorFinishKind; thickness: number } | undefined) => void + unit: LinearUnit +}) { + const i18n = usePascalI18n() + return ( + <> + + onChange(kind === NONE ? undefined : { kind, thickness: FINISH_THICKNESS[kind] }) + } + options={FINISH_OPTIONS.map((option) => ({ ...option, label: i18n._(option.label) }))} + value={layer?.kind ?? NONE} + /> + {layer?.kind === 'drywall' && ( + formatLayerThickness(value, unit)} + label={i18n._({ + id: 'node.shared.buildUpControls.drywallThickness', + message: 'Drywall thickness', + })} + onChange={(thickness) => onChange({ kind: 'drywall', thickness })} + sizes={DRYWALL_THICKNESSES} + value={layer.thickness} + /> + )} + + ) +} diff --git a/packages/nodes/src/shared/contextual-floorplan-dimensions.test.ts b/packages/nodes/src/shared/contextual-floorplan-dimensions.test.ts index efdee5dff3..75e7f4d3b5 100644 --- a/packages/nodes/src/shared/contextual-floorplan-dimensions.test.ts +++ b/packages/nodes/src/shared/contextual-floorplan-dimensions.test.ts @@ -7,7 +7,10 @@ import { WindowNode, ZoneNode, } from '@pascal-app/core' -import { createFloorplanContextExtensions } from '@pascal-app/editor' +import { + createFloorplanContextExtensions, + type FloorplanWallDimensionFaces, +} from '@pascal-app/editor' import { buildDoorContextualDimensions } from '../door/contextual-dimensions' import { buildItemContextualDimensions } from '../item/floorplan' import { buildWallContextualDimensions } from '../wall/contextual-dimensions' @@ -18,6 +21,7 @@ function context( parent: GeometryContext['parent'] = null, siblings: GeometryContext['siblings'] = [], moving = false, + wallDimensionFaces: FloorplanWallDimensionFaces = 'both', ): GeometryContext { return { resolve: () => undefined, @@ -27,7 +31,7 @@ function context( extensions: createFloorplanContextExtensions({ metricNotation: 'meters', purpose: 'edit', - wallDimensionReference: 'centerline', + wallDimensionFaces, }), viewState: moving ? { @@ -42,7 +46,7 @@ function context( } describe('contextual floor-plan dimensions', () => { - test('uses modeled centerline length for a straight wall', () => { + test('a free-standing wall reads its full length along its face', () => { const wall = WallNode.parse({ id: 'wall_primary', start: [0, 0], @@ -51,8 +55,8 @@ describe('contextual floor-plan dimensions', () => { expect(buildWallContextualDimensions(wall, context())).toMatchObject({ kind: 'dimension', - start: [0, 0], - end: [4, 0], + start: [0, 0.05], + end: [4, 0.05], text: '4m', }) }) @@ -84,12 +88,31 @@ describe('contextual floor-plan dimensions', () => { WallNode.parse({ id: 'wall_left', start: [0, 6], end: [0, 0] }), ] + // ID inside the room, between the corner walls' inner faces; OD outside, to their outer faces. expect(buildWallContextualDimensions(wall, context(null, siblings))).toMatchObject({ - kind: 'dimension', - offsetNormal: [1, 0], + kind: 'group', + children: [ + { kind: 'dimension', offsetNormal: [-1, 0], start: [3.95, 0.05], text: '5.9m' }, + { kind: 'dimension', offsetNormal: [1, 0], start: [4.05, -0.05], text: '6.1m' }, + ], }) }) + test('the dimension-faces preference keeps only the interior or the exterior length', () => { + const wall = WallNode.parse({ id: 'wall_right', start: [4, 0], end: [4, 6] }) + const siblings = [ + WallNode.parse({ id: 'wall_top', start: [0, 0], end: [4, 0] }), + WallNode.parse({ id: 'wall_bottom', start: [4, 6], end: [0, 6] }), + WallNode.parse({ id: 'wall_left', start: [0, 6], end: [0, 0] }), + ] + expect( + buildWallContextualDimensions(wall, context(null, siblings, false, 'interior')), + ).toMatchObject({ kind: 'dimension', offsetNormal: [-1, 0], text: '5.9m' }) + expect( + buildWallContextualDimensions(wall, context(null, siblings, false, 'exterior')), + ).toMatchObject({ kind: 'dimension', offsetNormal: [1, 0], text: '6.1m' }) + }) + test('shows one internal-wall dimension between the connected stud faces', () => { const wall = WallNode.parse({ id: 'wall_internal', @@ -123,7 +146,7 @@ describe('contextual floor-plan dimensions', () => { ) }) - test('measures a selected perimeter wall between connected stud centerlines', () => { + test('measures a perimeter wall that abuts its neighbours between their near faces', () => { const wall = WallNode.parse({ id: 'wall_perimeter', start: [0, 0], @@ -146,10 +169,10 @@ describe('contextual floor-plan dimensions', () => { expect(buildWallContextualDimensions(wall, context(null, [startWall, endWall]))).toMatchObject({ kind: 'dimension', - start: [0, 0], - end: [0, 4], + start: [0.05, 0.1], + end: [0.05, 3.9], offsetNormal: [1, 0], - text: '4m', + text: '3.8m', }) }) diff --git a/packages/nodes/src/shared/eyedropper.test.ts b/packages/nodes/src/shared/eyedropper.test.ts index 035abf2708..72e3f3bbe1 100644 --- a/packages/nodes/src/shared/eyedropper.test.ts +++ b/packages/nodes/src/shared/eyedropper.test.ts @@ -89,7 +89,7 @@ test('walls: a face region, a room override, the room finish, then the face defa useScene.setState({ nodes: { ...nodes, [zone.id]: plain as AnyNode } }) expect(preset(wall, wallRoomFaceRole(zone.id, 'a'))).toBe('library:brick') useScene.setState({ nodes }) - expect(preset(wall, 'b')).toBe('library:concrete-drywall') + expect(preset(wall, 'b')).toBe('library:preset-seattlegrey') }) test('floors: a region, the room floor, and an unpainted room shows the plate top', () => { diff --git a/packages/nodes/src/shared/layer-thickness.ts b/packages/nodes/src/shared/layer-thickness.ts new file mode 100644 index 0000000000..bfcddca748 --- /dev/null +++ b/packages/nodes/src/shared/layer-thickness.ts @@ -0,0 +1,3 @@ +// The layer thickness reader and writer live in the editor, which the floor panels share with +// the roof, ceiling and wall layers here. +export { formatLayerDepth, formatLayerThickness, parseLayerThickness } from '@pascal-app/editor' diff --git a/packages/nodes/src/shared/move-roof-tool.tsx b/packages/nodes/src/shared/move-roof-tool.tsx index 08c1212b3f..da05699c85 100644 --- a/packages/nodes/src/shared/move-roof-tool.tsx +++ b/packages/nodes/src/shared/move-roof-tool.tsx @@ -28,6 +28,7 @@ import { consumePlacementDragRelease, DragBoundingBox, getFloorStackPreviewPosition, + isGridSnapActive, isMagneticSnapActive, isTypingTarget, resolvePlanarCursorPosition, @@ -43,6 +44,13 @@ import { useViewer } from '@pascal-app/viewer' import { useCallback, useEffect, useRef, useState } from 'react' import * as THREE from 'three' import { snapFenceDraftPoint } from '../fence/drafting' +import { + bearingWallThickness, + catchRoofOnWalls, + placeRoofOnWalls, + roofCatchWalls, + segmentWallLine, +} from '../roof/wall-catch' import { clearStairMovePreview, publishStairMovePreview } from '../stair/surface-move-preview' /** Figma-style alignment-snap threshold (meters), matching the other tools. */ @@ -276,6 +284,88 @@ export const MoveRoofTool: React.FC<{ return ar.snap && isMagneticSnapActive() ? [lx + ar.snap.dx, lz + ar.snap.dz] : [lx, lz] } + // A roof's wall line lands on the walls under it, as in the plan's segment move + // (`catchRoofOnWalls`); that catch replaces the cursor's own snap onto a wall. + const catchesWalls = movingNode.type === 'roof' || movingNode.type === 'roof-segment' + const catchWalls = catchesWalls ? roofCatchWalls(useScene.getState().nodes, levelId) : [] + let rawAnchor: [number, number] | null = null + const catchOnWalls = ( + raw: [number, number], + snapped: [number, number], + ): [number, number] | null => { + const nodes = useScene.getState().nodes + const roof = + movingNode.type === 'roof' + ? movingNode + : (nodes[movingNode.parentId as AnyNodeId] as RoofNode | undefined) + if (roof?.type !== 'roof' || catchWalls.length === 0) return null + // A segment's place is in its roof's frame; the walls are in the level's plan. + const cos = Math.cos(-roof.rotation) + const sin = Math.sin(-roof.rotation) + const toPlan = ([x, z]: [number, number]): [number, number] => + movingNode.type === 'roof' + ? [x, z] + : [roof.position[0] + x * cos - z * sin, roof.position[2] + x * sin + z * cos] + const fromPlan = ([x, z]: [number, number]): [number, number] => { + if (movingNode.type === 'roof') return [x, z] + const dx = x - roof.position[0] + const dz = z - roof.position[2] + return [dx * cos + dz * sin, -dx * sin + dz * cos] + } + const lines = + movingNode.type === 'roof' + ? roof.children + .map((id) => nodes[id as AnyNodeId]) + .filter((child): child is RoofSegmentNode => child?.type === 'roof-segment') + .map((segment) => + segmentWallLine( + { position: [raw[0], 0, raw[1]], rotation: pendingRotation }, + segment, + ), + ) + : movingNode.type === 'roof-segment' + ? [ + segmentWallLine(roof, { + ...movingNode, + position: [raw[0], 0, raw[1]], + rotation: pendingRotation, + }), + ] + : [] + const angle = + movingNode.type === 'roof' ? -pendingRotation : -(roof.rotation + pendingRotation) + const caught = catchRoofOnWalls({ lines, walls: catchWalls, angle }) + if (!(caught.u || caught.v)) return null + return fromPlan(placeRoofOnWalls(toPlan(raw), toPlan(snapped), caught, angle)) + } + // Dropped onto the walls under it, a roof's segments take their thickness for their gable + // and heel walls. + const bearingThicknesses = ( + position: [number, number, number], + rotation: number, + ): { id: AnyNodeId; data: Partial }[] => { + const nodes = useScene.getState().nodes + const roof = + movingNode.type === 'roof' + ? { ...movingNode, position, rotation } + : (nodes[movingNode.parentId as AnyNodeId] as RoofNode | undefined) + if (roof?.type !== 'roof' || catchWalls.length === 0) return [] + const segments = + movingNode.type === 'roof' + ? roof.children + .map((id) => nodes[id as AnyNodeId]) + .filter((child): child is RoofSegmentNode => child?.type === 'roof-segment') + : movingNode.type === 'roof-segment' + ? [{ ...movingNode, position, rotation }] + : [] + return segments.flatMap((segment) => { + const thickness = bearingWallThickness(segmentWallLine(roof, segment), catchWalls) + return thickness === null || thickness === segment.wallThickness + ? [] + : [{ id: segment.id as AnyNodeId, data: { wallThickness: thickness } }] + }) + } + const localToWorldPoint = (localPoint: WallPlanPoint, y: number): [number, number, number] => { if (buildingObj) { const worldPoint = buildingObj.localToWorld( @@ -348,9 +438,10 @@ export const MoveRoofTool: React.FC<{ const y = event.position[1] const roofBypassSnap = event.nativeEvent?.altKey === true + const cursor: WallPlanPoint = [event.localPosition[0], event.localPosition[2]] const snappedLocal = snapFenceDraftPoint({ - point: [event.localPosition[0], event.localPosition[2]], - walls: levelWalls, + point: cursor, + walls: catchesWalls ? [] : levelWalls, fences: levelFences, bypassSnap: roofBypassSnap, magnetic: !roofBypassSnap && isMagneticSnapActive(), @@ -372,7 +463,24 @@ export const MoveRoofTool: React.FC<{ dragAnchorRef.current = resolved.anchor let [localX, localZ] = resolved.point - if (alignTopLevel) { + // The catch reads the unsnapped place, so the walls win over the grid near them. + let caught: [number, number] | null = null + if (catchesWalls) { + const [cursorX, , cursorZ] = localToWorldPoint(cursor, y) + const raw = resolvePlanarCursorPosition({ + cursor: computeLocal(cursorX, cursorZ, y, cursor[0], cursor[1]), + original: [movingNode.position[0], movingNode.position[2]], + anchor: rawAnchor, + mode: useAbsoluteCursorPlacement ? 'absolute' : 'relative', + }) + rawAnchor = raw.anchor + if (!roofBypassSnap && (isGridSnapActive() || isMagneticSnapActive())) + caught = catchOnWalls(raw.point, [localX, localZ]) + } + if (caught) { + ;[localX, localZ] = caught + useAlignmentGuides.getState().clear() + } else if (alignTopLevel) { const aligned = alignLocalPoint(localX, localZ, event.nativeEvent?.altKey === true) localX = aligned[0] localZ = aligned[1] @@ -525,9 +633,13 @@ export const MoveRoofTool: React.FC<{ if (movingNode.type === 'roof' || movingNode.type === 'roof-segment') { // Moved or turned onto the walls that carry it, a roof goes to the level above them. const scene = useScene.getState() - scene.applyNodeChanges( - seatRoofs(scene.nodes, { update: [{ id: movingNode.id, data: patch }] }).changes, - ) + const thicknesses = bearingThicknesses(position, pendingRotation) + const own = thicknesses.find(({ id }) => id === movingNode.id)?.data + const update = [ + { id: movingNode.id, data: { ...patch, ...own } }, + ...thicknesses.filter(({ id }) => id !== movingNode.id), + ] + scene.applyNodeChanges(seatRoofs(scene.nodes, { update }).changes) } else { useScene.getState().updateNodes([ { diff --git a/packages/nodes/src/shared/node-batch/candidates.ts b/packages/nodes/src/shared/node-batch/candidates.ts index a6d8ce4ed4..0686c26a10 100644 --- a/packages/nodes/src/shared/node-batch/candidates.ts +++ b/packages/nodes/src/shared/node-batch/candidates.ts @@ -61,7 +61,9 @@ const hiddenMeshesByNode = new Map() * variant, a cutout group) — and at any HOSTED child node's registered group: * an item can host other items (a shelf's books), whose groups mount inside * the host's. Packing those would freeze the child at the host's join pose - * with no release of its own (it is not a store member). + * with no release of its own (it is not a store member). A ceiling's cap draws + * itself: it shows and hides with a viewer flag that rebuilds nothing, so a + * batched copy would stay drawn after it hides. */ function collectMeshes(object: Object3D, out: Mesh[], hostedRoots: ReadonlySet): void { if (object.visible === false || hostedRoots.has(object)) return @@ -70,6 +72,7 @@ function collectMeshes(object: Object3D, out: Mesh[], hostedRoots: ReadonlySet +let savedEditor: ReturnType +let savedViewer: ReturnType + +/** Walls A and B, both drawn left to right, with what each face (`a`, `b`) looks onto. */ +function walls(sides: { a: WallNode['frontSide']; b: WallNode['backSide'] }[]) { + return [ + { id: WALL_A_ID, start: [0, 0], end: [6, 0] }, + { id: WALL_B_ID, start: [0, 4], end: [6, 4] }, + ].map((wall, index) => + WallNode.parse({ + ...wall, + parentId: LEVEL_ID, + thickness: 0.2, + height: 3, + frontSide: sides[index]!.a, + backSide: sides[index]!.b, + children: [], + }), + ) +} + +const OUTSIDE_WALLS = walls([ + { a: 'interior', b: 'exterior' }, + { a: 'exterior', b: 'interior' }, +]) + +function opening(kind: 'door' | 'window'): DoorNode | WindowNode { + const shared = { id: OPENING_ID[kind], parentId: WALL_A_ID, wallId: WALL_A_ID, width: 1.2 } + return kind === 'door' + ? DoorNode.parse({ ...shared, ...ON_A, position: [2, 1.05, 0], height: 2.1 }) + : WindowNode.parse({ ...shared, ...ON_A, position: [2, 1.5, 0], height: 1.2 }) +} + +function seedScene(kind: 'door' | 'window'): DoorNode | WindowNode { + const node = opening(kind) + const [wallA, wallB] = OUTSIDE_WALLS as [WallNode, WallNode] + const level = LevelNode.parse({ id: LEVEL_ID, children: [WALL_A_ID, WALL_B_ID], level: 0 }) + const building = BuildingNode.parse({ id: 'building_casing-move', children: [LEVEL_ID] }) + useScene.setState({ + nodes: { + [building.id]: building, + [LEVEL_ID]: { ...level, parentId: building.id }, + [WALL_A_ID]: { ...wallA, children: [node.id] }, + [WALL_B_ID]: wallB, + [node.id]: node, + }, + rootNodeIds: [building.id], + dirtyNodes: new Set(), + readOnly: false, + } as never) + return node +} + +function current(id: AnyNodeId): AnyNode { + const found = useScene.getState().nodes[id] + if (!found) throw new Error(`missing ${id}`) + return found +} + +beforeEach(() => { + savedScene = useScene.getState() + savedEditor = useEditor.getState() + savedViewer = useViewer.getState() + savedWindow = Object.getOwnPropertyDescriptor(globalThis, 'window') + savedDocument = globalThis.document + savedRaf = globalThis.requestAnimationFrame + savedCancelRaf = globalThis.cancelAnimationFrame + globalThis.window = new EventTarget() as Window & typeof globalThis + globalThis.document = { body: { style: { cursor: '' } } } as Document + globalThis.requestAnimationFrame = (cb: FrameRequestCallback) => { + cb(0) + return 0 + } + globalThis.cancelAnimationFrame = () => {} + spatialGridManager.clear() + useLiveNodeOverrides.getState().clearAll() + useLiveTransforms.getState().clearAll() + useEditor.setState({ mode: 'build', placementDragMode: false }) + useEditor.getState().setSnappingMode('item', 'off') + useViewer.setState({ + selection: { buildingId: null, levelId: LEVEL_ID, zoneId: null, selectedIds: [] }, + }) + sceneRegistry.nodes.set(LEVEL_ID, new Group()) +}) + +afterEach(() => { + sceneRegistry.nodes.clear() + spatialGridManager.clear() + useLiveNodeOverrides.getState().clearAll() + useLiveTransforms.getState().clearAll() + useScene.setState(savedScene) + useEditor.setState(savedEditor) + useViewer.setState(savedViewer) + if (savedWindow) Object.defineProperty(globalThis, 'window', savedWindow) + else Reflect.deleteProperty(globalThis, 'window') + globalThis.document = savedDocument + globalThis.requestAnimationFrame = savedRaf + globalThis.cancelAnimationFrame = savedCancelRaf +}) + +function wallEvent(wallId: AnyNodeId, localX: number, localY: number) { + return { + node: current(wallId), + normal: [0, 0, 1], + localPosition: [localX, localY, 0.1], + position: [localX, localY, 0.1], + nativeEvent: { timeStamp: localX }, + stopPropagation() {}, + } as never +} + +async function drag3d(kind: 'door' | 'window', wallId: AnyNodeId, toLocalX: number) { + const node = seedScene(kind) + const y = node.position[1] + const Tool = kind === 'door' ? MoveDoorTool : MoveWindowTool + const renderer = await create( + false, + sceneApi: undefined as never, + selectNode: () => {}, + unit: 'metric', + }} + > + + , + ) + await act(async () => { + emitter.emit('wall:enter', wallEvent(WALL_A_ID, node.position[0], y)) + emitter.emit('wall:move', wallEvent(wallId, toLocalX, y)) + emitter.emit('wall:click', wallEvent(wallId, toLocalX, y)) + }) + await act(async () => renderer.unmount()) + return current(node.id) as DoorNode | WindowNode +} + +function drag2d(kind: 'door' | 'window', planPoint: [number, number]) { + const node = seedScene(kind) + const nodes = useScene.getState().nodes + const session = + kind === 'door' + ? doorFloorplanMoveTarget({ node: node as DoorNode, nodes }) + : windowFloorplanMoveTarget({ node: node as WindowNode, nodes }) + session.apply({ + planPoint, + modifiers: { shiftKey: false, altKey: false, ctrlKey: false, metaKey: false }, + }) + expect(session.canCommit()).toBe(true) + session.commit() + return current(node.id) as DoorNode | WindowNode +} + +const casingOf = (node: Pick) => ({ + casingFaceA: node.casingFaceA, + casingFaceB: node.casingFaceB, +}) + +describe('movedOpeningCasingFaces', () => { + const sceneOf = (hosts: AnyNode[]) => + Object.fromEntries(hosts.map((host) => [host.id, host])) as Record + const onA = (rotation = 0) => ({ + parentId: WALL_A_ID, + rotation: [0, rotation, 0] as [number, number, number], + ...ON_A, + }) + + test('outside walls: each face goes to the face on its side, outside or in', () => { + const nodes = sceneOf(OUTSIDE_WALLS) + expect(movedOpeningCasingFaces(onA(), WALL_B_ID, [0, 0, 0], nodes)).toEqual({ + casingFaceA: true, + casingFaceB: false, + }) + // Whichever way the unit is turned on its new wall. + expect(movedOpeningCasingFaces(onA(), WALL_B_ID, [0, Math.PI, 0], nodes)).toEqual({ + casingFaceA: true, + casingFaceB: false, + }) + const alike = sceneOf( + walls([ + { a: 'interior', b: 'exterior' }, + { a: 'interior', b: 'exterior' }, + ]), + ) + expect(movedOpeningCasingFaces(onA(), WALL_B_ID, [0, 0, 0], alike)).toEqual(ON_A) + }) + + test('walls that do not know their outside: the faces follow the way the unit faces', () => { + const nodes = sceneOf( + walls([ + { a: 'interior', b: 'interior' }, + { a: 'unknown', b: 'unknown' }, + ]), + ) + expect(movedOpeningCasingFaces(onA(), WALL_B_ID, [0, 0, 0], nodes)).toEqual(ON_A) + expect(movedOpeningCasingFaces(onA(), WALL_B_ID, [0, Math.PI, 0], nodes)).toEqual({ + casingFaceA: true, + casingFaceB: false, + }) + expect(movedOpeningCasingFaces(onA(Math.PI), WALL_B_ID, [0, Math.PI, 0], nodes)).toEqual(ON_A) + }) + + test("a roof face's `a` is its outside", () => { + const roofFace = { id: 'rseg_casing-move', type: 'roof-segment' } as unknown as AnyNode + const nodes = sceneOf([...OUTSIDE_WALLS, roofFace]) + // Wall A's outside is its `b`: on the gable it is the `a`. + expect(movedOpeningCasingFaces(onA(), roofFace.id, [0, 0, 0], nodes)).toEqual({ + casingFaceA: true, + casingFaceB: false, + }) + }) + + test('a slide along its own wall, or a host without cased faces, keeps them as they are', () => { + const nodes = sceneOf(OUTSIDE_WALLS) + expect(movedOpeningCasingFaces(onA(), WALL_A_ID, [0, Math.PI, 0], nodes)).toEqual(ON_A) + expect(movedOpeningCasingFaces(onA(), LEVEL_ID, [0, Math.PI, 0], nodes)).toEqual(ON_A) + const fromLevel = { ...onA(), parentId: LEVEL_ID } + expect(movedOpeningCasingFaces(fromLevel, WALL_B_ID, [0, Math.PI, 0], nodes)).toEqual(ON_A) + }) +}) + +describe('a moved opening keeps its casing on its side of the wall', () => { + for (const kind of ['door', 'window'] as const) { + test(`3D ${kind} moved to a wall drawn the other way swaps its casing faces`, async () => { + const moved = await drag3d(kind, WALL_B_ID, 3.5) + expect(moved.wallId).toBe(WALL_B_ID) + expect(casingOf(moved)).toEqual({ casingFaceA: true, casingFaceB: false }) + }) + + test(`3D ${kind} slid along its own wall keeps its casing faces`, async () => { + const moved = await drag3d(kind, WALL_A_ID, 3.5) + expect(moved.wallId).toBe(WALL_A_ID) + expect(casingOf(moved)).toEqual(ON_A) + }) + + test(`2D ${kind} moved to a wall drawn the other way swaps its casing faces`, () => { + const moved = drag2d(kind, [4, 3.95]) + expect(moved.wallId).toBe(WALL_B_ID) + expect(casingOf(moved)).toEqual({ casingFaceA: true, casingFaceB: false }) + }) + + test(`2D ${kind} slid along its own wall keeps its casing faces`, () => { + const moved = drag2d(kind, [4, 0.05]) + expect(moved.wallId).toBe(WALL_A_ID) + expect(casingOf(moved)).toEqual(ON_A) + }) + } +}) diff --git a/packages/nodes/src/shared/opening-casing-move.ts b/packages/nodes/src/shared/opening-casing-move.ts new file mode 100644 index 0000000000..aa733111b2 --- /dev/null +++ b/packages/nodes/src/shared/opening-casing-move.ts @@ -0,0 +1,50 @@ +import { + type AnyNode, + type DoorNode, + openingHostFacing, + resolveWallExteriorSide, + type WindowNode, +} from '@pascal-app/core' + +type MovedOpening = Pick< + DoorNode | WindowNode, + 'parentId' | 'roofSegmentId' | 'rotation' | 'casingFaceA' | 'casingFaceB' +> +type CasingFaces = Pick + +/** The face of a host that looks outdoors: +1 for `a`, -1 for `b`, null when it cannot tell. */ +function hostOutside(host: AnyNode): 1 | -1 | null { + if (host.type === 'wall') return resolveWallExteriorSide(host) + // A roof face's `a` is its outside, as its casing has it. + return host.type === 'roof-segment' ? 1 : null +} + +/** + * The casing faces a door or window keeps when a move takes it from its host to `hostId`, the + * wall or roof face it lands on turned to `rotation`. Casing is kept per host face, and two hosts + * need not name their faces alike: a wall drawn the other way round has its `a` where the first + * has its `b`. So each face's casing goes to the matching face of the new host: outside to + * outside where both hosts know their outside (an outside wall, as its rooms give it, or a roof + * face), else the face the unit's front looks at to the face it looks at there. A slide along its + * own host, or a host with no cased faces on either end (a dormer, open floor), keeps them as they + * are. + */ +export function movedOpeningCasingFaces( + opening: MovedOpening, + hostId: string, + rotation: DoorNode['rotation'], + nodes: Readonly>, +): CasingFaces { + const kept = { casingFaceA: opening.casingFaceA, casingFaceB: opening.casingFaceB } + const fromId = opening.roofSegmentId ?? opening.parentId + const [from, to] = [nodes[fromId ?? ''], nodes[hostId]] + if (fromId === hostId || !from || !to) return kept + const cased = (host: AnyNode) => host.type === 'wall' || host.type === 'roof-segment' + if (!(cased(from) && cased(to))) return kept + const [fromOutside, toOutside] = [hostOutside(from), hostOutside(to)] + const swapped = + fromOutside !== null && toOutside !== null + ? fromOutside !== toOutside + : openingHostFacing(opening) !== openingHostFacing({ rotation }) + return swapped ? { casingFaceA: kept.casingFaceB, casingFaceB: kept.casingFaceA } : kept +} diff --git a/packages/nodes/src/shared/opening-casing-section.tsx b/packages/nodes/src/shared/opening-casing-section.tsx new file mode 100644 index 0000000000..ebef07d4ca --- /dev/null +++ b/packages/nodes/src/shared/opening-casing-section.tsx @@ -0,0 +1,85 @@ +'use client' + +import { + type DoorNode, + openingCasingWidth, + resolveOpeningCasingHost, + usePascalI18n, + useScene, + type WindowNode, +} from '@pascal-app/core' +import { PanelSection, SliderControl, ToggleControl } from '@pascal-app/editor' +import { useViewer } from '@pascal-app/viewer' +import { useMemo } from 'react' +import { openingCasingFaceLabels } from './opening-casing' + +const INCH = 0.0254 +const MIN_CASING_WIDTH = 0.5 * INCH +const MAX_CASING_WIDTH = 8 * INCH + +type CasingPatch = Partial> + +/** + * The door and window panels' Casing section: casing on or off for each face + * of the host wall (Exterior and Interior on an outside wall), and the boards' + * face width, in inches on an imperial plan (feet would show 2 in as 0.17). + * Nothing where the opening takes no casing (a curtain wall, a dormer face, a + * unit built from a script). + */ +export function OpeningCasingSection({ + node, + onUpdate, +}: { + node: DoorNode | WindowNode + onUpdate: (patch: CasingPatch) => void +}) { + const i18n = usePascalI18n() + // Its own component, so the whole scene it reads for the face names + // re-renders this section alone, not the panel around it. + const nodes = useScene((state) => state.nodes) + const cased = useMemo(() => resolveOpeningCasingHost(node, nodes) !== null, [node, nodes]) + const { parentId, roofSegmentId } = node + const labels = useMemo( + () => openingCasingFaceLabels(nodes, { parentId, roofSegmentId }), + [nodes, parentId, roofSegmentId], + ) + const imperial = useViewer((state) => state.unit) === 'imperial' + if (!cased) return null + const faceA = node.casingFaceA === true + const faceB = node.casingFaceB === true + const toShown = (meters: number) => (imperial ? meters / INCH : meters) + + return ( + + onUpdate({ casingFaceA: checked })} + /> + onUpdate({ casingFaceB: checked })} + /> + {(faceA || faceB) && ( + { + const meters = imperial ? value * INCH : value + onUpdate({ + casingWidth: Math.min(Math.max(meters, MIN_CASING_WIDTH), MAX_CASING_WIDTH), + }) + }} + precision={imperial ? 2 : 3} + step={imperial ? 0.25 : 0.005} + unit={imperial ? 'in' : 'm'} + value={toShown(openingCasingWidth(node))} + /> + )} + + ) +} diff --git a/packages/nodes/src/shared/opening-casing.test.ts b/packages/nodes/src/shared/opening-casing.test.ts new file mode 100644 index 0000000000..ea3a6db467 --- /dev/null +++ b/packages/nodes/src/shared/opening-casing.test.ts @@ -0,0 +1,310 @@ +import { describe, expect, test } from 'bun:test' +import { + type AnyNode, + DoorNode, + type FloorplanGeometry, + type GeometryContext, + LevelNode, + OPENING_CASING_PROUD, + sceneRegistry, + slotPaintMaterial, + useScene, + WallNode, + WindowNode, +} from '@pascal-app/core' +import { DOOR_STYLES } from '@pascal-app/core/building' +import { buildDoorPreviewMesh, buildWindowPreviewMesh } from '@pascal-app/viewer' +import { type Material, type Mesh, Ray, Vector3 } from 'three' +import { doorDefinition } from '../door/definition' +import { buildDoorFloorplan } from '../door/floorplan' +import { doorPaint } from '../door/paint' +import { doorTypeOptions, placedDoorFields, useDoorPlacement } from '../door/placement' +import { windowDefinition } from '../window/definition' +import { buildWindowFloorplan } from '../window/floorplan' +import { windowPaint } from '../window/paint' +import { placedWindowFields } from '../window/placement' +import { openingCasingFaceLabels } from './opening-casing' + +const INCH = 0.0254 +const CASING = 2 * INCH +const wall = WallNode.parse({ id: 'wall_casing-plan', start: [0, 0], end: [4, 0], thickness: 0.2 }) +const context = { children: [], parent: wall, resolve: () => undefined, siblings: [] } + +/** + * The casing legs a plan draws, as along / across spans: the polygons of its nested group of + * polygons (the opening's mark is a group too, of a line, a tag and its text). + */ +function casingLegs(geometry: FloorplanGeometry | null) { + const children = geometry?.kind === 'group' ? geometry.children : [] + const casing = children.find( + (child) => child.kind === 'group' && child.children.every((leg) => leg.kind === 'polygon'), + ) + const legs = casing?.kind === 'group' ? casing.children : [] + return legs.flatMap((leg) => { + if (leg.kind !== 'polygon') return [] + const xs = leg.points.map((point) => point[0]) + const zs = leg.points.map((point) => point[1]) + return [ + { along: [Math.min(...xs), Math.max(...xs)], across: [Math.min(...zs), Math.max(...zs)] }, + ] + }) +} + +const windowPlan = (values: Partial = {}) => + buildWindowFloorplan( + WindowNode.parse({ + id: 'window_casing-plan', + parentId: wall.id, + wallId: wall.id, + position: [2, 1.2, 0], + width: 1.2, + height: 1, + casingFaceA: true, + casingFaceB: true, + ...values, + }), + context as GeometryContext, + ) + +const doorPlan = (values: Partial = {}) => + buildDoorFloorplan( + DoorNode.parse({ + id: 'door_casing-plan', + parentId: wall.id, + wallId: wall.id, + position: [2, 1.05, 0], + width: 0.9, + casingFaceA: true, + casingFaceB: true, + ...values, + }), + context as GeometryContext, + ) + +describe('opening casing in plan', () => { + test('a window shows its legs beside the cutout, standing proud of both faces', () => { + const legs = casingLegs(windowPlan()) + expect(legs).toHaveLength(4) + for (const leg of legs) { + const besideStart = Math.abs(leg.along[1]! - 1.4) < 1e-9 + const besideEnd = Math.abs(leg.along[0]! - 2.6) < 1e-9 + expect(besideStart || besideEnd).toBe(true) + expect(leg.along[1]! - leg.along[0]!).toBeCloseTo(CASING, 9) + const onA = Math.abs(leg.across[0]! - 0.1) < 1e-9 + const onB = Math.abs(leg.across[1]! + 0.1) < 1e-9 + expect(onA || onB).toBe(true) + expect(leg.across[1]! - leg.across[0]!).toBeCloseTo(OPENING_CASING_PROUD, 9) + } + }) + + test('a door shows its legs too, and a face turned off shows none', () => { + expect(casingLegs(doorPlan())).toHaveLength(4) + const legs = casingLegs(doorPlan({ casingFaceA: false })) + expect(legs).toHaveLength(2) + for (const leg of legs) expect(leg.across[1]).toBeCloseTo(-0.1, 9) + expect(casingLegs(doorPlan({ casingFaceA: false, casingFaceB: false }))).toHaveLength(0) + }) + + test('a wider casing draws wider legs', () => { + for (const leg of casingLegs(windowPlan({ casingWidth: 3.5 * INCH }))) + expect(leg.along[1]! - leg.along[0]!).toBeCloseTo(3.5 * INCH, 9) + }) +}) + +describe('opening casing face names', () => { + const grid: [number, number][] = [ + [0, 0], + [4, 0], + [4, 3], + [0, 3], + ] + const level = LevelNode.parse({ id: 'level_casing' }) + const walls = grid.map((start, i) => + WallNode.parse({ + id: `wall_casing${i}`, + parentId: level.id, + thickness: 0.2, + start, + end: grid[(i + 1) % 4]!, + }), + ) + const nodes: Record = Object.fromEntries( + [level, ...walls].map((node) => [node.id, node]), + ) + + test('an outside wall names its faces Exterior and Interior', () => { + // Drawn anticlockwise, the room is on each wall's face a. + expect(openingCasingFaceLabels(nodes, { parentId: walls[0]!.id })).toEqual({ + a: 'Interior', + b: 'Exterior', + }) + }) + + test('a gable end is outside on face a; a lone wall keeps Side A and Side B', () => { + expect(openingCasingFaceLabels(nodes, { parentId: 'rseg_x', roofSegmentId: 'rseg_x' })).toEqual( + { a: 'Exterior', b: 'Interior' }, + ) + expect(openingCasingFaceLabels({ [wall.id]: wall }, { parentId: wall.id })).toEqual({ + a: 'Side A', + b: 'Side B', + }) + }) +}) + +test('tools and preset defaults create cased openings while legacy openings stay uncased', () => { + for (const [schema, fields, definition] of [ + [DoorNode, placedDoorFields(), doorDefinition], + [WindowNode, placedWindowFields(), windowDefinition], + ] as const) { + const placed = schema.parse(fields) + expect(placed.casingFaceA).toBe(true) + expect(placed.casingFaceB).toBe(true) + const preset = definition.defaults?.() + expect(preset?.casingFaceA).toBe(true) + expect(preset?.casingFaceB).toBe(true) + expect(placed.frameThickness).toBe(0.02) + expect(preset?.frameThickness).toBe(0.02) + const legacy = schema.parse({}) + expect(legacy.frameThickness).toBe(0.05) + expect(schema.parse({ frameThickness: 0.035 }).frameThickness).toBe(0.035) + const geometry = + legacy.type === 'door' + ? buildDoorFloorplan(legacy, context as GeometryContext) + : buildWindowFloorplan(legacy, context as GeometryContext) + expect(casingLegs(geometry)).toEqual([]) + } +}) + +test('the door tool writes 20 mm frames for every type and style', () => { + const previous = useDoorPlacement.getState() + try { + for (const { value: type } of doorTypeOptions) { + for (const style of DOOR_STYLES) { + useDoorPlacement.setState({ type, style }) + expect(DoorNode.parse(placedDoorFields()).frameThickness).toBe(0.02) + } + } + } finally { + useDoorPlacement.setState(previous) + } +}) + +test('casing paint targets each host side, inherits the frame, and previews and erases independently', () => { + const previous = useScene.getState() + try { + useScene.setState({ nodes: { [wall.id]: wall }, materials: {} }) + for (const kind of ['door', 'window'] as const) { + const paint = kind === 'door' ? doorPaint : windowPaint + for (const openingShape of ['rectangle', 'arch', 'rounded'] as const) { + for (const rotationY of [0, Math.PI]) { + const frameRef = rotationY === 0 ? 'library:preset-metal' : '#123456' + const fields = { + parentId: wall.id, + position: [2, 1.2, 0], + rotation: [0, rotationY, 0], + casingFaceA: true, + casingFaceB: true, + openingShape, + slots: { frame: frameRef }, + } + const node = kind === 'door' ? DoorNode.parse(fields) : WindowNode.parse(fields) + const mesh = + node.type === 'door' ? buildDoorPreviewMesh(node) : buildWindowPreviewMesh(node) + mesh.updateMatrixWorld(true) + sceneRegistry.nodes.set(node.id, mesh) + try { + const frame = mesh.children.find((part) => part.userData.slotId === 'frame') as Mesh + const parts = mesh.children.filter( + (part) => part.userData.slotId === 'casing-a' || part.userData.slotId === 'casing-b', + ) as Mesh[] + expect(parts.length).toBeGreaterThan(0) + for (const part of parts) { + expect(part.material).toBe(frame.material) + const side = part.userData.slotId === 'casing-a' ? 1 : -1 + part.geometry.computeBoundingBox() + const local = part.geometry.boundingBox!.getCenter(new Vector3()) + if (part.geometry.type === 'ExtrudeGeometry') { + local.x = node.width / 2 + node.casingWidth / 2 + local.y = 0 + } + const center = local.applyMatrix4(mesh.matrixWorld) + expect((center.z - node.position[2]) * side).toBeGreaterThan(0) + const ray = new Ray( + new Vector3(center.x, center.y, center.z + side), + new Vector3(0, 0, -side), + ) + expect(paint.resolveRole({ node, materialIndex: null, ray })).toBe( + part.userData.slotId, + ) + expect(paint.resolveRole({ node, materialIndex: null, hitObject: part })).toBe( + part.userData.slotId, + ) + } + expect(paint.roleLabel?.(node, 'casing-a')).toBe('Casing A') + expect(paint.roleLabel?.(node, 'casing-b')).toBe('Casing B') + expect(paint.getEffectiveMaterial?.({ node, role: 'casing-a', nodes: {} })).toEqual( + slotPaintMaterial(frameRef, {}), + ) + const original = parts.map((part) => part.material) + const restore = paint.applyPreview({ + node, + role: 'casing-a', + root: mesh, + material: undefined, + materialPreset: 'library:preset-softwhite', + }) + expect(restore).not.toBeNull() + parts.forEach((part, i) => { + if (part.userData.slotId === 'casing-a') expect(part.material).not.toBe(original[i]) + else expect(part.material).toBe(original[i]) + }) + restore?.() + parts.forEach((part, i) => { + expect(part.material).toBe(original[i]) + }) + const patch = paint.buildPatch({ + node, + role: 'casing-a', + material: undefined, + materialPreset: 'library:preset-softwhite', + }) + expect(patch).toMatchObject({ + slots: { frame: frameRef, 'casing-a': 'library:preset-softwhite' }, + }) + const painted = { ...node, ...patch } as typeof node + const rebuilt = + painted.type === 'door' + ? buildDoorPreviewMesh(painted) + : buildWindowPreviewMesh(painted) + const a = rebuilt.children.find((part) => part.userData.slotId === 'casing-a') as Mesh + const b = rebuilt.children.find((part) => part.userData.slotId === 'casing-b') as Mesh + expect(a.material).not.toBe(b.material) + expect(b.material).toBe(frame.material) + const erasePreview = paint.applyPreview({ + node: painted, + role: 'casing-a', + root: rebuilt, + material: undefined, + materialPreset: undefined, + }) + expect(erasePreview).not.toBeNull() + expect(a.material).toBe(b.material as Material) + erasePreview?.() + expect( + paint.buildPatch({ + node: painted, + role: 'casing-a', + material: undefined, + materialPreset: undefined, + }), + ).toMatchObject({ slots: { frame: frameRef } }) + } finally { + sceneRegistry.nodes.delete(node.id) + } + } + } + } + } finally { + useScene.setState(previous) + } +}) diff --git a/packages/nodes/src/shared/opening-casing.ts b/packages/nodes/src/shared/opening-casing.ts new file mode 100644 index 0000000000..ed92863f97 --- /dev/null +++ b/packages/nodes/src/shared/opening-casing.ts @@ -0,0 +1,111 @@ +import { + type AnyNode, + type DoorNode, + defaultI18n, + type FloorplanGeometry, + type FloorplanPoint, + getWallBodyCenterOffset, + type OpeningCasingHost, + openingCasingBoards, + roomSideFaces, + type WallFace, + type WallNode, + type WindowNode, +} from '@pascal-app/core' + +type CasingPlanStyle = { + fill: string + stroke: string + strokeWidth: number + /** Screen-pixel strokes in the editor; plan-metre ink on a drafted sheet. */ + vectorEffect?: 'non-scaling-stroke' +} + +/** + * The casing a door's or window's plan shows: the legs beside the cutout on + * each face of the wall it is cased on, each a short rectangle standing proud + * of the finished face, as plans draw trim. Null when there is none to draw (a + * curtain wall, a railing, a script-built unit, both faces turned off). + * `cornerEnd` is the wall end a corner window runs to, where it has no leg. + */ +export function buildOpeningCasingPlan( + opening: DoorNode | WindowNode, + wall: WallNode, + style: CasingPlanStyle, + cornerEnd?: OpeningCasingHost['cornerEnd'], +): FloorplanGeometry | null { + if (opening.source || wall.wallType === 'curtain' || wall.wallType === 'railing') return null + const [x1, z1] = wall.start + const dx = wall.end[0] - x1 + const dz = wall.end[1] - z1 + const length = Math.hypot(dx, dz) + if (length < 1e-9) return null + const dir = [dx / length, dz / length] as const + const perp = [-dir[1], dir[0]] as const + const plan = (along: number, across: number): FloorplanPoint => [ + x1 + dir[0] * along + perp[0] * across, + z1 + dir[1] * along + perp[1] * across, + ] + // Boards are measured from the opening's centre plane, which a justified wall + // sets off its reference line and a plane offset sets off the wall's body. + const centreAcross = getWallBodyCenterOffset(wall) + (opening.position[2] ?? 0) + const host: OpeningCasingHost = { + thickness: wall.thickness ?? 0.1, + ...(cornerEnd ? { cornerEnd } : {}), + } + const children: FloorplanGeometry[] = openingCasingBoards(opening, host) + .filter((board) => board.part === 'leg') + .map(({ center, size }): FloorplanGeometry => { + const along = opening.position[0] + center[0] + const across = centreAcross + center[2] + const [halfAlong, halfAcross] = [size[0] / 2, size[2] / 2] + return { + kind: 'polygon', + points: [ + plan(along - halfAlong, across + halfAcross), + plan(along + halfAlong, across + halfAcross), + plan(along + halfAlong, across - halfAcross), + plan(along - halfAlong, across - halfAcross), + ], + ...style, + strokeLinejoin: 'miter', + } + }) + return children.length ? { kind: 'group', children } : null +} + +/** + * What the door and window panels call the faces an opening can be cased on. A + * wall with rooms on one side only (an outside wall, as the wall panel's paint + * regions tell it) names them Exterior and Interior, as does a roof face, whose + * `a` is its outside; any other wall keeps the wall panel's Side A and Side B. + */ +export function openingCasingFaceLabels( + nodes: Readonly>, + opening: Pick, +): Record { + if (opening.roofSegmentId) return { a: 'Exterior', b: 'Interior' } + const wallId = opening.parentId + if (wallId && nodes[wallId]?.type === 'wall') { + try { + const { inside, outside } = roomSideFaces( + nodes as Parameters[0], + wallId, + ) + if (inside && outside) { + return { [outside]: 'Exterior', [inside]: 'Interior' } as Record + } + } catch { + // Not a wall (any more): fall through to the neutral labels. + } + } + return { a: 'Side A', b: 'Side B' } +} + +export function openingCasingPaintLabel(role: string): string | null { + if (role === 'casing-a') + return defaultI18n._({ id: 'node.shared.openingCasing.faceA', message: 'Casing A' }) + if (role === 'casing-b') + return defaultI18n._({ id: 'node.shared.openingCasing.faceB', message: 'Casing B' }) + return null +} diff --git a/packages/nodes/src/shared/opening-plane-offset.ts b/packages/nodes/src/shared/opening-plane-offset.ts index 856ce92d3c..66229e4432 100644 --- a/packages/nodes/src/shared/opening-plane-offset.ts +++ b/packages/nodes/src/shared/opening-plane-offset.ts @@ -18,7 +18,7 @@ export function openingPlaneOffsetOnWall(opening: PlanarOpening, targetWallId: s * Where an opening's plan symbol sits across its wall. A centred opening keeps * the long-standing symbol: centred in the cutout, as deep as the wall. An * opening offset from the centre plane draws its frame at that offset with its - * frame depth (explicit, or the wall's thickness plus the lip), like the 3D + * resolved frame depth, like the 3D * renderer; the builder then also draws the cutout, because the wall is still * cut through its whole thickness. */ diff --git a/packages/nodes/src/shared/opening-swap.test.ts b/packages/nodes/src/shared/opening-swap.test.ts new file mode 100644 index 0000000000..0791dde11e --- /dev/null +++ b/packages/nodes/src/shared/opening-swap.test.ts @@ -0,0 +1,77 @@ +import { afterEach, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + DoorNode, + useInteractive, + useScene, + WindowNode, +} from '@pascal-app/core' +import { doorMechanism } from '../door/mechanism' +import { swapDoorSwingPatch } from '../door/swing' +import { windowMechanism } from '../window/mechanism' +import { canSwapWindowHinge, swapWindowHingePatch } from '../window/swing' +import { applyOpeningSwap } from './opening-swap' + +const OPEN_ANGLE = Math.PI / 2 +const originalScene = useScene.getState() +const originalInteractive = useInteractive.getState() +afterEach(() => { + useScene.setState(originalScene) + useInteractive.setState(originalInteractive) +}) + +function load(node: AnyNode) { + useScene.setState({ nodes: { [node.id]: node } as Record, rootNodeIds: [] }) + useScene.temporal.getState().clear() + useScene.temporal.getState().resume() +} + +test('swapping a closed door commits one undo step and opens it; an open door is left open', () => { + const door = DoorNode.parse({ id: 'door_swap', swingDirection: 'inward' }) + load(door) + applyOpeningSwap(door, swapDoorSwingPatch(door), doorMechanism) + expect(useScene.getState().nodes[door.id]).toMatchObject({ swingDirection: 'outward' }) + expect(useScene.temporal.getState().pastStates).toHaveLength(1) + expect(useInteractive.getState().doorAnimations[door.id]).toMatchObject({ + field: 'swingAngle', + to: OPEN_ANGLE, + persist: false, + }) + + useInteractive.setState({ + doors: { [door.id]: { swingAngle: OPEN_ANGLE } }, + doorAnimations: {}, + }) + const swapped = useScene.getState().nodes[door.id] as DoorNode + applyOpeningSwap(swapped, swapDoorSwingPatch(swapped), doorMechanism) + expect(useScene.getState().nodes[door.id]).toMatchObject({ swingDirection: 'inward' }) + expect(useScene.temporal.getState().pastStates).toHaveLength(2) + expect(useInteractive.getState().doorAnimations).toEqual({}) +}) + +test("only a single casement's hinge swaps; the swap opens the closed sash", () => { + expect(canSwapWindowHinge(WindowNode.parse({ windowType: 'casement' }))).toBe(true) + for (const values of [ + { windowType: 'casement', casementStyle: 'french' }, + { windowType: 'awning' }, + { windowType: 'sliding' }, + { windowType: 'casement', openingKind: 'opening' }, + ] as const) { + expect(canSwapWindowHinge(WindowNode.parse(values))).toBe(false) + } + + const casement = WindowNode.parse({ + id: 'window_swap', + windowType: 'casement', + hingesSide: 'left', + }) + load(casement) + applyOpeningSwap(casement, swapWindowHingePatch(casement), windowMechanism) + expect(useScene.getState().nodes[casement.id]).toMatchObject({ hingesSide: 'right' }) + expect(useScene.temporal.getState().pastStates).toHaveLength(1) + expect(useInteractive.getState().windowAnimations[casement.id]).toMatchObject({ + to: 1, + persist: false, + }) +}) diff --git a/packages/nodes/src/shared/opening-swap.ts b/packages/nodes/src/shared/opening-swap.ts new file mode 100644 index 0000000000..6d70eee6d2 --- /dev/null +++ b/packages/nodes/src/shared/opening-swap.ts @@ -0,0 +1,28 @@ +import { + type AnyNodeId, + type DoorNode, + type MechanismCapability, + useInteractive, + useScene, + type WindowNode, +} from '@pascal-app/core' +import { triggerSFX } from '@pascal-app/editor' + +/** + * Commits a hinge or swing swap of a door or window as one undo step, then opens it through its + * kind's mechanism when it is closed, so the new side is visible. The opening is the mechanism's + * preview (the action menu's Open): it leaves the saved open state and the undo history alone. + */ +export function applyOpeningSwap( + node: N, + patch: Partial, + mechanism: MechanismCapability, +) { + const scene = useScene.getState() + scene.updateNode(node.id, patch) + scene.dirtyNodes.add(node.id as AnyNodeId) + if (node.parentId) scene.dirtyNodes.add(node.parentId as AnyNodeId) + triggerSFX('sfx:item-rotate') + const swapped = useScene.getState().nodes[node.id as AnyNodeId] + if (swapped && !mechanism.isOn(swapped, useInteractive.getState())) mechanism.set(swapped, true) +} diff --git a/packages/nodes/src/shared/polygon-vertex-affordance.ts b/packages/nodes/src/shared/polygon-vertex-affordance.ts index 34fca1ca10..406f086c35 100644 --- a/packages/nodes/src/shared/polygon-vertex-affordance.ts +++ b/packages/nodes/src/shared/polygon-vertex-affordance.ts @@ -60,6 +60,12 @@ export type PolygonAffordanceSnapContext + vertexIndex?: number } export type PolygonEdgeSnapContext = { @@ -84,6 +90,13 @@ export type PolygonAffordanceOptions * translated edge, or `null` to keep the candidate. */ snapEdge?: (context: PolygonEdgeSnapContext) => [[number, number], [number, number]] | null + /** + * `move-edge`: the sides beside the dragged one keep their own angle, running on to meet it + * where it goes; a side in line with it (a side split in two) gets a square jog instead, so + * pulling out part of a side makes a bump-out. Off, both ends of the side translate square to + * it and its neighbours pivot on their far ends. + */ + keepNeighbourAngles?: boolean } type PolygonShape = { @@ -177,6 +190,8 @@ export function createPolygonVertexAffordance i === vertexIndex ? [snapped[0], snapped[1]] : p, @@ -261,6 +276,8 @@ export function createPolygonAddVertexAffordance i === newVertexIndex ? [snapped[0], snapped[1]] : p, @@ -325,6 +342,61 @@ export function createPolygonDeleteVertexAffordance, + edgeIndex: number, + normal: readonly [number, number], + distance: number, +): [number, number][] { + const copy = ring.map(([x, y]) => [x, y] as [number, number]) + const count = ring.length + // Under a millimetre the side has not moved: no jog a hair long. + if (count < 3 || Math.abs(distance) < 1e-3) return copy + const startIndex = edgeIndex + const endIndex = (edgeIndex + 1) % count + const start = ring[startIndex]! + const end = ring[endIndex]! + const moved = (p: readonly [number, number]): [number, number] => [ + p[0] + normal[0] * distance, + p[1] + normal[1] * distance, + ] + /** Where the side from `neighbour` to `vertex` meets the moved edge; `null` in line with it. */ + const meet = (vertex: readonly [number, number], neighbour: readonly [number, number]) => { + const dx = vertex[0] - neighbour[0] + const dy = vertex[1] - neighbour[1] + const length = Math.hypot(dx, dy) + if (length < 1e-9) return null + const along = (dx * normal[0] + dy * normal[1]) / length + if (Math.abs(along) < IN_LINE_SINE) return null + const target = moved(start) + const t = + ((target[0] - neighbour[0]) * normal[0] + (target[1] - neighbour[1]) * normal[1]) / + (along * length) + return [neighbour[0] + dx * t, neighbour[1] + dy * t] as [number, number] + } + const startMeet = meet(start, ring[(startIndex - 1 + count) % count]!) + const endMeet = meet(end, ring[(endIndex + 1) % count]!) + const startPoints: [number, number][] = startMeet + ? [startMeet] + : [[start[0], start[1]], moved(start)] + const endPoints: [number, number][] = endMeet ? [endMeet] : [moved(end), [end[0], end[1]]] + const out: [number, number][] = [] + for (let i = 0; i < count; i++) { + if (i === startIndex) out.push(...startPoints) + else if (i === endIndex) out.push(...endPoints) + else out.push(copy[i]!) + } + return out +} + /** * Edge-drag: move a whole edge perpendicular to itself. Both endpoints * translate by `edgeNormal * projectedDelta`. The other vertices of @@ -437,12 +509,19 @@ export function createPolygonMoveEdgeAffordance { - if (i === edgeStartIndex || i === edgeEndIndex) { - return [p[0] + normalX * normalDistance, p[1] + normalY * normalDistance] - } - return [p[0], p[1]] as [number, number] - }) + const nextRing: [number, number][] = options?.keepNeighbourAngles + ? movedEdgeKeepingNeighbours( + originalRing, + edgeIndex, + [normalX, normalY], + normalDistance, + ) + : originalRing.map((p, i) => { + if (i === edgeStartIndex || i === edgeEndIndex) { + return [p[0] + normalX * normalDistance, p[1] + normalY * normalDistance] + } + return [p[0], p[1]] as [number, number] + }) const patch = buildRingPatch(node, holeIndex, nextRing, options?.boundaryCommitData) commitRingPatch(node.id, holeIndex, patch) }, diff --git a/packages/nodes/src/slab/__tests__/geometry.test.ts b/packages/nodes/src/slab/__tests__/geometry.test.ts index 826fc112b2..63f8fdfad6 100644 --- a/packages/nodes/src/slab/__tests__/geometry.test.ts +++ b/packages/nodes/src/slab/__tests__/geometry.test.ts @@ -11,6 +11,7 @@ import { SlabNode, slabPolygonContextFromGeometry, WallNode, + ZoneNode, } from '@pascal-app/core' import { type Group, Mesh, type MeshStandardMaterial } from 'three' import { buildSlabGeometry } from '../geometry' @@ -105,7 +106,10 @@ function thresholdStrip(): SlabNode { }) } -function geometryContext(site: ReturnType): GeometryContext { +function geometryContext( + site: ReturnType, + extra: AnyNode[] = [], +): GeometryContext { const building = BuildingNode.parse({ id: 'building_test', parentId: site.id, @@ -118,7 +122,12 @@ function geometryContext(site: ReturnType): GeometryConte height: 2.5, children: [], }) - const nodes = { [site.id]: site, [building.id]: building, [level.id]: level } + const nodes: Record = { + [site.id]: site, + [building.id]: building, + [level.id]: level, + ...Object.fromEntries(extra.map((node) => [node.id, node])), + } return { resolve: (id) => nodes[id as keyof typeof nodes], children: [], @@ -240,6 +249,48 @@ describe('buildSlabGeometry', () => { expect(fill.geometry.boundingBox?.min.y).toBeCloseTo(0) expect(fill.geometry.boundingBox?.max.y).toBeCloseTo(0.3) }) + + test('a porch or patio slab outside the house runs its concrete edge down to the ground', () => { + const site = SiteNode.parse({ id: 'site_test', children: ['building_test'] }) + const porch = SlabNode.parse({ + plateRole: 'sunken', + boundary: 'auto', + elevation: 0.4, + thickness: 0.1, + zoneIds: ['zone_outdoor'], + polygon: [ + [0, 0], + [2, 0], + [2, 1], + [0, 1], + ], + }) + const zone = ZoneNode.parse({ + id: 'zone_outdoor', + name: 'Porch', + polygon: porch.polygon, + roomType: 'porch', + }) + const skirt = meshesOf( + buildSlabGeometry(porch, geometryContext(site, [zone]), 'solid', false), + ).find((mesh) => mesh.userData.slotId === 'foundation')! + expect(skirt).toBeDefined() + skirt.geometry.computeBoundingBox() + expect(skirt.geometry.boundingBox?.min.y).toBeCloseTo(0) + expect(skirt.geometry.boundingBox?.max.y).toBeCloseTo(0.3) + // A plate a step down inside the house stays as it is. + const sunken = { ...porch, metadata: { floor: 'porch-slab' } } + expect( + meshesOf( + buildSlabGeometry( + sunken, + geometryContext(site, [{ ...zone, roomType: undefined }]), + 'solid', + false, + ), + ).some((mesh) => mesh.userData.slotId === 'foundation'), + ).toBe(false) + }) }) describe('buildSlabGeometry on empty and collapsed polygons', () => { diff --git a/packages/nodes/src/slab/deck-geometry.test.ts b/packages/nodes/src/slab/deck-geometry.test.ts new file mode 100644 index 0000000000..e0d9f3573c --- /dev/null +++ b/packages/nodes/src/slab/deck-geometry.test.ts @@ -0,0 +1,201 @@ +import { beforeEach, describe, expect, test } from 'bun:test' +import { + type AnyNode, + type AnyNodeId, + BuildingNode, + clearPlateSurfaceCaches, + type GeometryContext, + LevelNode, + SiteNode, + SlabNode, + WallNode, + ZoneNode, +} from '@pascal-app/core' +import { Box3, type Group, Mesh, type MeshStandardMaterial } from 'three' +import { buildSlabGeometry } from './geometry' + +const IN = 0.0254 +const FT = 12 * IN +const TOP = 0.6 +const WOOD = 'library:wood-woodplank48' + +/** A 16 × 12 ft deck room off the house's rear wall (z = 0, 0.2 thick), its plate 1 in down. */ +function deckScene(decking?: ZoneNode['decking'], buildingY = 0, painted?: string) { + const wall = WallNode.parse({ + id: 'wall_rear', + parentId: 'level_1', + start: [-2, 0], + end: [8, 0], + thickness: 0.2, + height: 2.7, + }) + const outline: Array<[number, number]> = [ + [0, 0.1], + [16 * FT, 0.1], + [16 * FT, 0.1 + 12 * FT], + [0, 0.1 + 12 * FT], + ] + const zone = ZoneNode.parse({ + id: 'zone_deck', + parentId: 'level_1', + name: 'Deck', + polygon: outline, + spaceRole: 'room', + roomType: 'deck', + floor: { + finish: WOOD, + drop: IN, + ...(painted + ? { + regions: [ + { + id: 'region_1', + finish: painted, + polygon: [ + [1, 1], + [3, 1], + [3, 2.5], + [1, 2.5], + ], + }, + ], + } + : {}), + }, + ...(decking ? { decking } : {}), + }) + const plate = SlabNode.parse({ + id: 'slab_deck', + parentId: 'level_1', + boundary: 'auto', + autoFromWalls: true, + plateRole: 'sunken', + zoneIds: [zone.id], + elevation: TOP, + thickness: 0.15, + polygon: outline, + }) + const site = SiteNode.parse({ id: 'site_1', children: ['building_1'] }) + const building = BuildingNode.parse({ + id: 'building_1', + parentId: site.id, + children: ['level_1'], + position: [0, buildingY, 0], + }) + const level = LevelNode.parse({ + id: 'level_1', + parentId: building.id, + level: 0, + height: 2.7, + children: [wall.id, zone.id, plate.id], + }) + const nodes: Record = { + [site.id]: site, + [building.id]: building, + [level.id]: level, + [wall.id]: wall, + [zone.id]: zone, + [plate.id]: plate, + } + const ctx: GeometryContext = { + resolve: (id: AnyNodeId) => nodes[id] as N | undefined, + children: [], + siblings: [], + parent: level, + } + return { plate, ctx } +} + +const meshes = (group: Group) => + group.children.filter((child): child is Mesh => child instanceof Mesh) +const boxOf = (mesh: Mesh) => + new Box3().setFromBufferAttribute(mesh.geometry.getAttribute('position') as never) +/** The plan area the upward faces at `y` cover. */ +function topArea(mesh: Mesh, y: number): number { + const position = mesh.geometry.getAttribute('position') + const index = mesh.geometry.getIndex()! + let total = 0 + for (let i = 0; i < index.count; i += 3) { + const [a, b, c] = [index.getX(i), index.getX(i + 1), index.getX(i + 2)] + if ([a, b, c].some((v) => Math.abs(position.getY(v) - y) > 1e-6)) continue + const twice = + (position.getX(b) - position.getX(a)) * (position.getZ(c) - position.getZ(a)) - + (position.getX(c) - position.getX(a)) * (position.getZ(b) - position.getZ(a)) + if (twice < 0) total += -twice / 2 + } + return total +} + +describe('a deck room draws boards on a frame, not a slab', () => { + beforeEach(() => clearPlateSurfaceCaches()) + + test('its boards: the room finish and paint role, their top the floor top, gaps between them', () => { + const { plate, ctx } = deckScene() + const group = buildSlabGeometry(plate, ctx, 'rendered', true) + const boards = meshes(group).filter((mesh) => typeof mesh.userData.paintRole === 'string') + expect(boards).toHaveLength(1) + const [deck] = boards as [Mesh] + expect(deck.userData.paintRole).toBe('room:zone_deck') + const box = boxOf(deck) + expect(box.max.y).toBeCloseTo(TOP, 6) + expect(box.min.y).toBeCloseTo(TOP - IN, 6) + const full = 16 * FT * 12 * FT + const covered = topArea(deck, TOP) / full + expect(covered).toBeGreaterThan(0.94) + expect(covered).toBeLessThan(0.97) + }) + + test('its frame: treated wood under the boards down to the ground on posts, a concrete pier under each, never the framing plugin’s green', () => { + const { plate, ctx } = deckScene() + const group = buildSlabGeometry(plate, ctx, 'rendered', true) + const frame = meshes(group).filter((mesh) => mesh.userData.paintRole === undefined) + expect(frame).toHaveLength(2) + const [lumber, piers] = frame as [Mesh, Mesh] + const wood = boxOf(lumber) + expect(wood.max.y).toBeCloseTo(TOP - IN, 6) + expect(wood.min.y).toBeCloseTo(0, 6) + // the boards overhang the rims an inch on the free edges, none past the deck + expect(wood.min.x).toBeCloseTo(IN, 6) + expect(wood.max.x).toBeCloseTo(16 * FT - IN, 6) + expect(wood.min.z).toBeCloseTo(0.1, 6) + const concrete = boxOf(piers) + expect(concrete.min.y).toBeLessThan(0) + expect(concrete.max.y).toBeGreaterThan(0) + for (const mesh of frame) { + const color = (mesh.material as MeshStandardMaterial).color?.getHexString() + expect(color).not.toBe('7d9d6a') + } + }) + + test('its posts reach the ground wherever the house stands', () => { + const { plate, ctx } = deckScene(undefined, 0.3) + const group = buildSlabGeometry(plate, ctx, 'rendered', true) + const lumber = meshes(group).find((mesh) => mesh.userData.paintRole === undefined)! + expect(boxOf(lumber).min.y).toBeCloseTo(-0.3, 6) + }) + + test('the room’s boards: 2x6 stock 1 1/2 in thick, run out from the house', () => { + const { plate, ctx } = deckScene({ boardSize: '2x6', direction: 'perpendicular' }) + const group = buildSlabGeometry(plate, ctx, 'rendered', true) + const deck = meshes(group).find((mesh) => mesh.userData.paintRole === 'room:zone_deck')! + expect(boxOf(deck).min.y).toBeCloseTo(TOP - 1.5 * IN, 6) + const lumber = meshes(group).find((mesh) => mesh.userData.paintRole === undefined)! + expect(boxOf(lumber).max.y).toBeCloseTo(TOP - 1.5 * IN, 6) + }) + + test('a painted part of the floor is its own boards, cut from the same rows', () => { + const plain = buildSlabGeometry(deckScene().plate, deckScene().ctx, 'rendered', true) + const { plate, ctx } = deckScene(undefined, 0, 'library:wood-woodfine2') + const group = buildSlabGeometry(plate, ctx, 'rendered', true) + const boards = meshes(group).filter((mesh) => typeof mesh.userData.paintRole === 'string') + expect(boards.map((mesh) => mesh.userData.paintRole).sort()).toEqual([ + 'room:zone_deck', + 'room:zone_deck/region_1', + ]) + const total = boards.reduce((sum, mesh) => sum + topArea(mesh, TOP), 0) + const before = meshes(plain) + .filter((mesh) => typeof mesh.userData.paintRole === 'string') + .reduce((sum, mesh) => sum + topArea(mesh, TOP), 0) + expect(total).toBeCloseTo(before, 3) + }) +}) diff --git a/packages/nodes/src/slab/deck-geometry.ts b/packages/nodes/src/slab/deck-geometry.ts new file mode 100644 index 0000000000..b7ea9103b1 --- /dev/null +++ b/packages/nodes/src/slab/deck-geometry.ts @@ -0,0 +1,411 @@ +import { + type AnyNode, + type AnyNodeId, + area, + BEAM_MATERIAL_LIBRARY_REFS, + type BuildingNode, + type DeckFramingPlan, + type DeckPiece, + type DeckWall, + deckBoardRun, + deckBoardThickness, + deckSlabBoards, + type GeometryContext, + getLevelElevations, + intersection, + type LevelNode, + layoutDeckBoards, + type MultiPolygon, + type PlateSurfacePartition, + type PlateTopCell, + type Polygon, + planDeckFraming, + plateLevelContext, + SITE_DATUM_Y, + type SiteNode, + type SlabNode, + surfaceHeightAt, + terrainFieldOf, + type ZoneNode, +} from '@pascal-app/core' +import { + type ColorPreset, + createSurfaceRoleMaterial, + type RenderShading, + resolveSlotDefaultMaterial, +} from '@pascal-app/viewer' +import { + BufferGeometry, + Float32BufferAttribute, + FrontSide, + Group, + type Material, + Mesh, + ShapeUtils, + Vector2, +} from 'three' + +/** + * A deck's floor (`isDeckSlab`: a deck room's floor plate, a generated deck) drawn as a deck is + * built, never as a solid slab: its boards (`layoutDeckBoards`), the room's finish on them, each + * painted part of the floor its own boards with its own paint role, over its frame + * (`planDeckFraming`), the same plan the framing plugin books: ledger, joists, rims, beams and + * posts in treated wood, a concrete pier under each post at the ground. The boards' top is the + * slab's top, so items, the room label and clicks find the floor where they did. Each material is + * one merged mesh, so the deck batches like any slab. + */ + +const IN = 0.0254 +/** A post's pier: 12 in square, standing 2 in out of the ground, 10 in into it. */ +const PIER_SIDE = 12 * IN +const PIER_ABOVE = 2 * IN +const PIER_BELOW = 10 * IN + +export type DeckLook = { + shading: RenderShading + textures: boolean + colorPreset: ColorPreset + sceneTheme?: string +} + +export type DeckGeometryOptions = { + /** The deck's outline: the slab's renderable polygon. */ + polygon: Array<[number, number]> + /** The plate's top partition: one set of boards per cell. Null for a drawn slab. */ + partition: PlateSurfacePartition | null + /** A cell's finish as a material; `null` asks for the slab's own surface finish. */ + boardMaterial: (cell: PlateTopCell | null) => Material + look: DeckLook +} + +/** The level-local ground under a plan point: the site's terrain, or the datum, wherever the storey stands. */ +function groundUnder(ctx: GeometryContext | undefined): (x: number, z: number) => number { + const level = ctx?.parent + if (!ctx || level?.type !== 'level' || !level.parentId) return () => 0 + const building = ctx.resolve(level.parentId as AnyNodeId) + if (building?.type !== 'building') return () => 0 + const site = building.parentId ? ctx.resolve(building.parentId as AnyNodeId) : undefined + const nodes: Record = { [building.id]: building, [level.id]: level as LevelNode } + if (site?.type === 'site') nodes[site.id] = site + for (const childId of building.children) { + const child = ctx.resolve(childId as AnyNodeId) + if (child) nodes[child.id] = child + } + const elevation = getLevelElevations(nodes).get(level.id) + if (!elevation) return () => 0 + const baseWorldY = (building.position?.[1] ?? 0) + elevation.baseY + const field = site?.type === 'site' ? terrainFieldOf(site) : null + if (!field) return () => SITE_DATUM_Y - baseWorldY + const angle = building.rotation?.[1] ?? 0 + const cos = Math.cos(angle) + const sin = Math.sin(angle) + const [px, , pz] = building.position ?? [0, 0, 0] + return (x, z) => + surfaceHeightAt(field, cos * x + sin * z + px, -sin * x + cos * z + pz) - baseWorldY +} + +/** The house walls a deck edge may hang its ledger on: no railing, no hidden wall. */ +function ledgerWalls(ctx: GeometryContext | undefined): DeckWall[] { + if (!ctx) return [] + return plateLevelContext(ctx.parent, ctx.resolve) + .walls.filter( + (wall) => wall.visible !== false && (wall as { wallType?: string }).wallType !== 'railing', + ) + .map((wall) => ({ + start: wall.start, + end: wall.end, + thickness: wall.thickness ?? 0.1, + curved: Math.abs(wall.curveOffset ?? 0) > 1e-6, + })) +} + +/** + * Posts already standing on the ground by the deck (a generated porch's, hosted on the ground and + * passing through the deck): a beam two of them stand on is theirs to carry. + */ +function carriersBy(node: SlabNode, ctx: GeometryContext | undefined): Array<[number, number]> { + const level = ctx?.parent + if (!ctx || !level || !('children' in level)) return [] + const out: Array<[number, number]> = [] + for (const id of level.children) { + const column = ctx.resolve(id as AnyNodeId) + if (column?.type !== 'column' || column.visible === false || column.supportSlabId === node.id) + continue + const support = column.supportSlabId + ? ctx.resolve(column.supportSlabId as AnyNodeId) + : undefined + const base = column.position[1] + (support?.type === 'slab' ? support.elevation : 0) + if (base < node.elevation - 0.3) out.push([column.position[0], column.position[2]]) + } + return out +} + +/** A material's surface: the treated wood of the frame, the piers' concrete. */ +function frameMaterial(ref: string, role: 'wall' | 'floor', look: DeckLook): Material { + return look.textures + ? resolveSlotDefaultMaterial(ref, look.shading) + : createSurfaceRoleMaterial(role, look.colorPreset, FrontSide, look.sceneTheme) +} + +type Buffers = { positions: number[]; normals: number[]; uvs: number[]; indices: number[] } +const buffers = (): Buffers => ({ positions: [], normals: [], uvs: [], indices: [] }) + +function toGeometry({ positions, normals, uvs, indices }: Buffers): BufferGeometry { + const geometry = new BufferGeometry() + geometry.setAttribute('position', new Float32BufferAttribute(positions, 3)) + geometry.setAttribute('normal', new Float32BufferAttribute(normals, 3)) + geometry.setAttribute('uv', new Float32BufferAttribute(uvs, 2)) + geometry.setIndex(indices) + return geometry +} + +/** A box (centre, [run, height, across], yaw), flat-shaded with metre UVs on every face. */ +function pushBox(out: Buffers, piece: Pick) { + const [cx, cy, cz] = piece.position + const [hx, hy, hz] = piece.dims.map((value) => value / 2) as [number, number, number] + const cos = Math.cos(piece.yaw) + const sin = Math.sin(piece.yaw) + // three.js Y rotation: local +x → (cos, 0, −sin), local +z → (sin, 0, cos) + const world = (x: number, y: number, z: number): [number, number, number] => [ + cx + x * cos + z * sin, + cy + y, + cz - x * sin + z * cos, + ] + const turn = (x: number, z: number): [number, number, number] => [ + x * cos + z * sin, + 0, + -x * sin + z * cos, + ] + // each face: its normal (local), and two edge axes (local) with their half lengths + const faces: Array<{ + n: [number, number, number] + a: [number, number, number] + b: [number, number, number] + }> = [ + { n: [1, 0, 0], a: [0, 0, -1], b: [0, 1, 0] }, + { n: [-1, 0, 0], a: [0, 0, 1], b: [0, 1, 0] }, + { n: [0, 1, 0], a: [1, 0, 0], b: [0, 0, -1] }, + { n: [0, -1, 0], a: [1, 0, 0], b: [0, 0, 1] }, + { n: [0, 0, 1], a: [1, 0, 0], b: [0, 1, 0] }, + { n: [0, 0, -1], a: [-1, 0, 0], b: [0, 1, 0] }, + ] + const half = [hx, hy, hz] + for (const { n, a, b } of faces) { + const base = out.positions.length / 3 + const span = (axis: [number, number, number]) => + Math.abs(axis[0]) * half[0]! + Math.abs(axis[1]) * half[1]! + Math.abs(axis[2]) * half[2]! + const ha = span(a) + const hb = span(b) + const normal = n[1] !== 0 ? ([0, n[1], 0] as [number, number, number]) : turn(n[0], n[2]) + for (const [sa, sb] of [ + [-1, -1], + [1, -1], + [1, 1], + [-1, 1], + ] as const) { + const x = n[0] * half[0]! + a[0] * ha * sa + b[0] * hb * sb + const y = n[1] * half[1]! + a[1] * ha * sa + b[1] * hb * sb + const z = n[2] * half[2]! + a[2] * ha * sa + b[2] * hb * sb + out.positions.push(...world(x, y, z)) + out.normals.push(...normal) + out.uvs.push(ha * (sa + 1), hb * (sb + 1)) + } + out.indices.push(base, base + 1, base + 2, base, base + 2, base + 3) + } +} + +function signedArea2(ring: ReadonlyArray): number { + let twice = 0 + for (let i = 0; i < ring.length; i++) { + const [ax, az] = ring[i]! + const [bx, bz] = ring[(i + 1) % ring.length]! + twice += ax * bz - bx * az + } + return twice +} + +/** + * One board: its top at `top`, its bottom `thickness` under, its sides; the top's grain along + * the board (`along`), shifted by `shift` so neighbouring boards read as boards. + */ +function pushBoard( + out: Buffers, + board: Polygon, + top: number, + thickness: number, + along: readonly [number, number], + shift: number, +) { + const outer = signedArea2(board.outer) < 0 ? [...board.outer].reverse() : board.outer + const holes = board.holes.filter((hole) => hole.length >= 3) + const contour = outer.map(([x, z]) => new Vector2(x, z)) + const holeRings = holes.map((hole) => hole.map(([x, z]) => new Vector2(x, z))) + const bottom = top - thickness + const grain = (x: number, z: number): [number, number] => [ + x * along[0] + z * along[1] + shift, + -x * along[1] + z * along[0], + ] + const cap = [...contour, ...holeRings.flat()] + const topBase = out.positions.length / 3 + for (const p of cap) { + out.positions.push(p.x, top, p.y) + out.normals.push(0, 1, 0) + out.uvs.push(...grain(p.x, p.y)) + } + const bottomBase = out.positions.length / 3 + for (const p of cap) { + out.positions.push(p.x, bottom, p.y) + out.normals.push(0, -1, 0) + out.uvs.push(...grain(p.x, p.y)) + } + for (const [a, b, c] of ShapeUtils.triangulateShape(contour, holeRings)) { + out.indices.push(topBase + a!, topBase + c!, topBase + b!) + out.indices.push(bottomBase + a!, bottomBase + b!, bottomBase + c!) + } + // the board's edges, outward on the outline; a hole's both ways + const side = (a: Vector2, b: Vector2, flipped: boolean) => { + const length = Math.hypot(b.x - a.x, b.y - a.y) + if (length < 1e-9) return + const nx = (b.y - a.y) / length + const nz = -(b.x - a.x) / length + const base = out.positions.length / 3 + for (const [p, y, u, v] of [ + [a, bottom, 0, 0], + [b, bottom, length, 0], + [b, top, length, thickness], + [a, top, 0, thickness], + ] as const) { + out.positions.push(p.x, y, p.y) + out.normals.push(flipped ? -nx : nx, 0, flipped ? -nz : nz) + out.uvs.push(u, v) + } + if (flipped) out.indices.push(base, base + 1, base + 2, base, base + 2, base + 3) + else out.indices.push(base, base + 2, base + 1, base, base + 3, base + 2) + } + for (let i = 0; i < contour.length; i++) + side(contour[i]!, contour[(i + 1) % contour.length]!, false) + for (const ring of holeRings) + for (let i = 0; i < ring.length; i++) { + side(ring[i]!, ring[(i + 1) % ring.length]!, false) + side(ring[i]!, ring[(i + 1) % ring.length]!, true) + } +} + +/** A board's own shift along its grain, the same every build. */ +const shiftOf = (index: number) => { + const x = Math.sin(index * 12.9898 + 78.233) * 43758.5453 + return (x - Math.floor(x)) * 3 +} + +/** The deck's frame as the engine draws it: a joist a side rim stands in for is the rim. */ +export function deckFramePieces(plan: DeckFramingPlan): DeckPiece[] { + return [ + ...(plan.ledger ? [plan.ledger] : []), + ...plan.rims, + ...plan.joists.filter((joist) => !joist.atRim), + ...plan.beams, + ...plan.posts, + ] +} + +/** The deck's frame plan and boards, as drawn for `node`. */ +export function planDeck( + node: SlabNode, + ctx: GeometryContext | undefined, + polygon: Array<[number, number]>, +) { + const boards = deckSlabBoards(node, (id) => { + const zone = ctx?.resolve(id as AnyNodeId) + return zone?.type === 'zone' ? (zone as ZoneNode) : undefined + }) + const thickness = deckBoardThickness(boards) + const ground = groundUnder(ctx) + let cx = 0 + let cz = 0 + for (const [x, z] of polygon) { + cx += x + cz += z + } + const n = Math.max(polygon.length, 1) + const plan = planDeckFraming({ + polygon, + top: node.elevation, + decking: thickness, + walls: ledgerWalls(ctx), + boards, + gradeY: ground(cx / n, cz / n), + gradeAt: ground, + carriers: carriersBy(node, ctx), + }) + return { boards, thickness, plan } +} + +export function buildDeckGeometry( + node: SlabNode, + ctx: GeometryContext | undefined, + options: DeckGeometryOptions, +): Group { + const group = new Group() + const { polygon, partition, look } = options + if (polygon.length < 3) return group + const { boards, thickness, plan } = planDeck(node, ctx, polygon) + const addMesh = (geometry: BufferGeometry, material: Material, role?: string) => { + if (geometry.getAttribute('position').count === 0) { + geometry.dispose() + return + } + const mesh = new Mesh(geometry, material) + mesh.castShadow = true + mesh.receiveShadow = true + if (role) { + mesh.userData.slotId = role + mesh.userData.paintRole = role + } + group.add(mesh) + } + + // ---- the boards: a set for each painted part of the floor, cut along it ---- + const axes = plan.axes ?? { + origin: polygon[0]!, + u: [1, 0] as [number, number], + v: [0, 1] as [number, number], + } + const joists = + plan.stationAxis && plan.axes + ? { origin: plan.axes.origin, axis: plan.stationAxis, stations: plan.stations } + : undefined + // One set of rows over the whole deck, so a painted part's boards line up with the rest. + const top: MultiPolygon = [{ outer: polygon, holes: node.holes ?? [] }] + const laid = layoutDeckBoards(top, axes, boards, joists) + const cells: Array<{ cell: PlateTopCell | null; role: string; outline: MultiPolygon }> = partition + ? partition.cells.map((cell) => ({ cell, role: cell.role, outline: cell.polygons })) + : [{ cell: null, role: 'surface', outline: top }] + const whole = area(top) + const { along } = deckBoardRun(axes, boards.direction) + for (const { cell, role, outline } of cells) { + const out = buffers() + const all = cells.length === 1 && Math.abs(area(outline) - whole) < 1e-4 + laid.forEach((board, index) => { + for (const part of all ? [board] : intersection(board, outline)) + pushBoard(out, part, node.elevation, thickness, along, shiftOf(index)) + }) + addMesh(toGeometry(out), options.boardMaterial(cell), role) + } + + // ---- the frame, and a pier under each post ---- + const frame = buffers() + for (const piece of deckFramePieces(plan)) pushBox(frame, piece) + addMesh( + toGeometry(frame), + frameMaterial(BEAM_MATERIAL_LIBRARY_REFS['pressure-treated'], 'wall', look), + ) + const piers = buffers() + for (const post of plan.posts) + pushBox(piers, { + position: [post.position[0], post.bottom + (PIER_ABOVE - PIER_BELOW) / 2, post.position[2]], + dims: [PIER_SIDE, PIER_ABOVE + PIER_BELOW, PIER_SIDE], + yaw: post.yaw, + }) + addMesh(toGeometry(piers), frameMaterial('library:concrete-raw', 'floor', look)) + return group +} diff --git a/packages/nodes/src/slab/dependency-tracker.test.ts b/packages/nodes/src/slab/dependency-tracker.test.ts index 741b18aa4a..3a7236333f 100644 --- a/packages/nodes/src/slab/dependency-tracker.test.ts +++ b/packages/nodes/src/slab/dependency-tracker.test.ts @@ -28,6 +28,7 @@ for (const [field, value] of [ ['floorStepFinish', 'library:preset-white'], ['floorEdgeFinish', 'library:preset-white'], ['floorStepOverrides', [{ key: 'door_1', finish: 'library:preset-white' }]], + ['decking', { direction: 'diagonal' }], ] as const) test(`${field} changes invalidate the room plate without changing floor intent`, async () => { const { LevelNode, ZoneNode } = await import('@pascal-app/core') diff --git a/packages/nodes/src/slab/dependency-tracker.ts b/packages/nodes/src/slab/dependency-tracker.ts index 096d09e159..16c0405353 100644 --- a/packages/nodes/src/slab/dependency-tracker.ts +++ b/packages/nodes/src/slab/dependency-tracker.ts @@ -83,6 +83,9 @@ export function createSlabDependencyTracker(initialNodes: Record ctx?.resolve(id))?.roomType + return ( + isFloorPlate(node) && node.support !== 'open' && (roomType === 'porch' || roomType === 'patio') + ) +} + function terrainFillContext(ctx: GeometryContext | undefined, foundation: boolean) { if (!ctx) return null const level = ctx.parent @@ -207,8 +226,9 @@ function buildSlabTerrainFillGeometry( polygon: Array<[number, number]>, ctx: GeometryContext | undefined, partition: PlateSurfacePartition | null, + outdoor = false, ): BufferGeometry | null { - const terrain = terrainFillContext(ctx, node.plateRole === 'base') + const terrain = terrainFillContext(ctx, node.plateRole === 'base' || outdoor) if (!terrain || polygon.length < 3) return null let area2 = 0 @@ -356,6 +376,48 @@ export function buildSlabGeometry( return false }), ) + // A deck is its boards on its frame (`buildDeckGeometry`), never a solid slab. + if (isDeckSlab(node, (id) => ctx?.resolve(id))) + return buildDeckGeometry(node, ctx, { + polygon, + partition: platePartitionOf(node, ctx, node.plateRole === 'platform'), + boardMaterial: (cell) => + (cell ? cell.finish : (node.slots?.surface ?? node.materialPreset)) === LEGACY_DECK_FINISH + ? getPlateCellMaterial( + node, + { + role: cell?.role ?? 'surface', + finish: OUTDOOR_ROOM_DEFAULTS.deck.finish, + materialKey: plateFinishKey(OUTDOOR_ROOM_DEFAULTS.deck.finish), + polygons: cell?.polygons ?? [], + }, + shading, + textures, + colorPreset, + sceneTheme, + ctx?.materials, + ) + : cell + ? getPlateCellMaterial( + node, + cell, + shading, + textures, + colorPreset, + sceneTheme, + ctx?.materials, + ) + : getSlabSlotMaterial( + node, + 'surface', + shading, + textures, + colorPreset, + sceneTheme, + ctx?.materials, + ), + look: { shading, textures, colorPreset, sceneTheme }, + }) const merged = generateSlabGeometry(node, polygonContext, platform ? levelBaseAt : undefined) const elevation = node.elevation ?? 0.05 const partition = platePartitionOf(node, ctx, platform || node.plateRole === 'platform') @@ -474,8 +536,10 @@ export function buildSlabGeometry( merged.dispose() const foundation = node.plateRole === 'base' && node.foundation?.type === 'solid' + // A porch or patio slab runs down into the ground beside the house, whatever stands under it. + const outdoor = isOutdoorGroundSlab(node, ctx) if ( - (foundation || (!node.plateRole && node.fillToTerrain)) && + (foundation || outdoor || (!node.plateRole && node.fillToTerrain)) && !node.recessed && !platform && group.children.length > 0 @@ -485,10 +549,11 @@ export function buildSlabGeometry( getRenderableSlabPolygon(node, polygonContext), ctx, partition, + outdoor, ) if (terrainFill) { - // The skirt hangs below the plate perimeter and always faces out. - const slotId: SlabSlotId = foundation ? 'foundation' : partition ? 'edge' : 'side' + // The skirt hangs below the plate perimeter and always faces out: the slab's concrete. + const slotId: SlabSlotId = foundation || outdoor ? 'foundation' : partition ? 'edge' : 'side' addMesh( terrainFill, slotId, diff --git a/packages/nodes/src/slab/panel.tsx b/packages/nodes/src/slab/panel.tsx index 5d8174d218..607145dd0a 100644 --- a/packages/nodes/src/slab/panel.tsx +++ b/packages/nodes/src/slab/panel.tsx @@ -14,6 +14,8 @@ import { ActionButton, ActionGroup, FloorFoundationPanel, + formatAreaLabel, + getAreaUnitLabel, holeEditScope, PanelSection, PanelWrapper, @@ -21,6 +23,7 @@ import { SegmentedControl, ShapeChoice, SliderControl, + squareMetersToAreaUnit, startOpeningDraft, triggerSFX, useEditingHole, @@ -433,7 +436,9 @@ export function SlabPanel() {
{i18n._({ id: 'node.slab.panel.area', message: 'Area' })} - {area.toFixed(2)} m² + + {formatAreaLabel(area, unit, 2)} +
@@ -486,9 +491,14 @@ export function SlabPanel() { {i18n._({ id: 'node.holeSummary', message: - '{area} m² · {count, plural, one {{points} pt} other {{points} pts}} · {source}', + '{area} {unit} · {count, plural, one {{points} pt} other {{points} pts}} · {source}', values: { - area: formatFixed(holeArea, 2, i18n.getLocale()), + area: formatFixed( + squareMetersToAreaUnit(holeArea, unit), + 2, + i18n.getLocale(), + ), + unit: getAreaUnitLabel(unit), count: hole.length, points: String(hole.length), source: isAutoHole diff --git a/packages/nodes/src/slab/system.tsx b/packages/nodes/src/slab/system.tsx index d2aec6ac1e..25de55ad45 100644 --- a/packages/nodes/src/slab/system.tsx +++ b/packages/nodes/src/slab/system.tsx @@ -1,6 +1,7 @@ 'use client' -import { useScene } from '@pascal-app/core' +import { isDeckSlab, useScene } from '@pascal-app/core' +import { useViewer } from '@pascal-app/viewer' import { useEffect } from 'react' import { createSlabDependencyTracker } from './dependency-tracker' @@ -13,6 +14,20 @@ const SlabSystems = () => { }) }, []) + // "Framing only" hides the shell, a deck's boards and frame with it, and draws the frame on its + // own: a deck rebuilds when it flips, so no batched copy of it stays drawn over the frame. + useEffect( + () => + useViewer.subscribe((state, previous) => { + if (state.framingOnly === previous.framingOnly) return + const scene = useScene.getState() + for (const node of Object.values(scene.nodes)) + if (node.type === 'slab' && isDeckSlab(node, (id) => scene.nodes[id])) + scene.markDirty(node.id) + }), + [], + ) + return null } diff --git a/packages/nodes/src/stair/construction-controls.tsx b/packages/nodes/src/stair/construction-controls.tsx index b359b5667e..19db246658 100644 --- a/packages/nodes/src/stair/construction-controls.tsx +++ b/packages/nodes/src/stair/construction-controls.tsx @@ -46,10 +46,13 @@ const OPTIONS = [ export function StairConstructionControls({ node, inherited, + structured = false, onChange, }: { node: StairNode | StairSegmentNode inherited?: StairConstruction + /** The stair has a structure: without a body of its own it draws the structure's. */ + structured?: boolean onChange: (construction: StairConstruction | undefined) => void }) { const i18n = usePascalI18n() @@ -62,13 +65,18 @@ export function StairConstructionControls({ label={i18n._({ id: 'node.stair.constructionControls.body', message: 'Body' })} value={node.construction?.mode ?? 'original'} options={OPTIONS.map((option) => - option.value === 'original' && inherited + option.value === 'original' && (inherited || structured) ? { ...option, - label: i18n._({ - id: 'node.stair.constructionControls.inherit', - message: 'Inherit', - }), + label: inherited + ? i18n._({ + id: 'node.stair.constructionControls.inherit', + message: 'Inherit', + }) + : i18n._({ + id: 'node.stair.constructionControls.fromStructure', + message: 'From structure', + }), } : { ...option, label: i18n._(option.label) }, )} @@ -197,6 +205,7 @@ export function StairConstructionField({ return ( onUpdate({ construction })} /> ) @@ -213,10 +222,15 @@ export function StairSegmentConstructionField({ const parent = node.parentId ? state.nodes[node.parentId as AnyNodeId] : undefined return parent?.type === 'stair' ? parent.construction : undefined }) + const structured = useScene((state) => { + const parent = node.parentId ? state.nodes[node.parentId as AnyNodeId] : undefined + return parent?.type === 'stair' && Boolean(parent.structure) + }) return ( onUpdate({ construction })} /> ) diff --git a/packages/nodes/src/stair/panel.tsx b/packages/nodes/src/stair/panel.tsx index b378c5c649..790b3b91f9 100644 --- a/packages/nodes/src/stair/panel.tsx +++ b/packages/nodes/src/stair/panel.tsx @@ -56,6 +56,7 @@ import { StairConstructionControls } from './construction-controls' import { getStairDestinationUpdates } from './destination' import { StairRailingControls } from './railing-controls' import { getStairTypeChange } from './stair-type' +import { StairStructureControls } from './structure-controls' /** Core's stair diagnostics in the UI language; codes without fixed text show core's message. */ const STAIR_DIAGNOSTIC_MESSAGES: Partial> = { @@ -1073,8 +1074,12 @@ export default function StairPanel() { + {node.stairType === 'straight' ? ( + + ) : null} handleUpdate({ construction })} /> diff --git a/packages/nodes/src/stair/parametrics.ts b/packages/nodes/src/stair/parametrics.ts index e01d18be43..e41353ce29 100644 --- a/packages/nodes/src/stair/parametrics.ts +++ b/packages/nodes/src/stair/parametrics.ts @@ -1,12 +1,19 @@ import { type ParametricDescriptor, planStairRiseEdit, type StairNode } from '@pascal-app/core' import { StairConstructionField } from './construction-controls' import { StairRailingField } from './railing-controls' +import { StairStructureField } from './structure-controls' export const stairParametrics: ParametricDescriptor = { groups: [ { label: 'Construction', fields: [ + { + key: 'structure', + kind: 'custom', + component: StairStructureField, + visibleIf: (node) => node.stairType === 'straight', + }, { key: 'construction', kind: 'custom', diff --git a/packages/nodes/src/stair/placement-defaults.test.ts b/packages/nodes/src/stair/placement-defaults.test.ts new file mode 100644 index 0000000000..529a04b9d7 --- /dev/null +++ b/packages/nodes/src/stair/placement-defaults.test.ts @@ -0,0 +1,41 @@ +import { describe, expect, test } from 'bun:test' +import { resolveStairStringerLayout, resolveStairStructure, StairNode } from '@pascal-app/core' +import { + newStairStructure, + pickedStairRailingMode, + surfaceFlightRailingMode, +} from './placement-defaults' + +const IN = 0.0254 + +describe('a new stair', () => { + test('is built on standard wood stringers unless the tool asks for another structure', () => { + const structure = newStairStructure() + expect(structure).toMatchObject({ + type: 'wood-stringers', + stringerStock: '2x12', + stringerType: 'cut', + }) + expect(structure.stringerSpacing).toBeCloseTo(16 * IN, 9) + // a 1 m stair on it carries four stringers, under 16 in apart + const layout = resolveStairStringerLayout( + 1, + resolveStairStructure(StairNode.parse({ structure }))!, + ) + expect(layout.count).toBe(4) + expect(layout.spacing).toBeLessThan(16 * IN) + expect(newStairStructure({ type: 'concrete' }).type).toBe('concrete') + expect(newStairStructure({ type: 'bamboo' }).type).toBe('wood-stringers') + }) + + test('fitted to a deck or porch, takes railings from four risers or a 30 in drop, unless the tool picks one', () => { + expect(surfaceFlightRailingMode({ stepCount: 3, totalRise: 21 * IN })).toBe('none') + expect(surfaceFlightRailingMode({ stepCount: 4, totalRise: 28 * IN })).toBe('both') + expect(surfaceFlightRailingMode({ stepCount: 3, totalRise: 31 * IN })).toBe('both') + expect(surfaceFlightRailingMode({ stepCount: 6, totalRise: 42 * IN }, 'left')).toBe('left') + expect(surfaceFlightRailingMode({ stepCount: 2, totalRise: 14 * IN }, 'both')).toBe('both') + expect(pickedStairRailingMode('right')).toBe('right') + expect(pickedStairRailingMode('sideways')).toBeNull() + expect(pickedStairRailingMode(undefined)).toBeNull() + }) +}) diff --git a/packages/nodes/src/stair/placement-defaults.ts b/packages/nodes/src/stair/placement-defaults.ts new file mode 100644 index 0000000000..930de5e2a0 --- /dev/null +++ b/packages/nodes/src/stair/placement-defaults.ts @@ -0,0 +1,32 @@ +import { STAIR_CODE, type StairNode, StairStructure } from '@pascal-app/core' + +/** A railing mode picked for the stair tool, or null when none (or an unknown one) is. */ +export function pickedStairRailingMode(value: unknown): StairNode['railingMode'] | null { + return value === 'none' || value === 'left' || value === 'right' || value === 'both' + ? value + : null +} + +/** + * The railing a flight fitted to a deck, porch or patio edge takes: both sides once it has four + * risers (the IRC R311.7.8 handrail) or its open side drops more than 30 in (the R312.1.1 guard), + * none on a shorter step. A railing mode picked for the tool still wins. + */ +export function surfaceFlightRailingMode( + flight: { stepCount: number; totalRise: number }, + picked: StairNode['railingMode'] | null = null, +): StairNode['railingMode'] { + if (picked) return picked + return flight.stepCount >= STAIR_CODE.handrailRisers || flight.totalRise > STAIR_CODE.guardDrop + ? 'both' + : 'none' +} + +/** + * The structure a new stair is built with: the tool's when one is set, else standard wood + * stringers — 2x12 cut stringers at 16 in o.c. at most (IRC R311.7, DCA 6). + */ +export function newStairStructure(picked?: unknown): StairStructure { + const parsed = picked === undefined ? null : StairStructure.safeParse(picked) + return parsed?.success ? parsed.data : StairStructure.parse({}) +} diff --git a/packages/nodes/src/stair/renderer.tsx b/packages/nodes/src/stair/renderer.tsx index 88f38fd4c3..0cde5f90a2 100644 --- a/packages/nodes/src/stair/renderer.tsx +++ b/packages/nodes/src/stair/renderer.tsx @@ -14,6 +14,7 @@ import { type StairSegmentNode, type StairSlotId, stairArcSliceCount, + stairStructureConstructionOf, useLiveNodeOverrides, useRegistry, useScene, @@ -115,7 +116,7 @@ export const StairRenderer = ({ node: rawNode }: { node: StairNode }) => { const { segments, totalRise } = renderData useLayoutEffect(() => { for (const id of node.children) useScene.getState().markDirty(id) - }, [node.children, node.construction]) + }, [node.children, node.construction, node.structure]) const detail = useMemo(() => measureStairDetail(node, segments), [node, segments]) const mergedMaterials = useMemo( () => @@ -262,16 +263,20 @@ function StairSurfaceTransition({ (flight as StairSegmentNode | undefined)?.length ?? 0 const segment = flight as StairSegmentNode | undefined - const fillToFloor = - (flightOverride?.fillToFloor as boolean | undefined) ?? - segment?.fillToFloor ?? - stair.fillToFloor ?? - true - const thickness = - (flightOverride?.thickness as number | undefined) ?? - segment?.thickness ?? - stair.thickness ?? - 0.25 + // a structure fills to the floor when it is poured, and is a tread thick when it is framed + const structureBody = stair.construction ? null : stairStructureConstructionOf(stair) + const fillToFloor = structureBody + ? structureBody.mode === 'solid' + : ((flightOverride?.fillToFloor as boolean | undefined) ?? + segment?.fillToFloor ?? + stair.fillToFloor ?? + true) + const thickness = structureBody + ? structureBody.treadThickness + structureBody.finishThickness + : ((flightOverride?.thickness as number | undefined) ?? + segment?.thickness ?? + stair.thickness ?? + 0.25) const segmentHeight = (flightOverride?.height as number | undefined) ?? segment?.height ?? 0 const profile = useMemo( () => diff --git a/packages/nodes/src/stair/structure-controls.tsx b/packages/nodes/src/stair/structure-controls.tsx new file mode 100644 index 0000000000..564b2cb786 --- /dev/null +++ b/packages/nodes/src/stair/structure-controls.tsx @@ -0,0 +1,428 @@ +'use client' + +import { + type AnyNodeId, + type MessageDescriptor, + type PascalI18n, + resolveStairStringerLayout, + resolveStairStructure, + STAIR_STRINGER_SPACINGS_IN, + type StairNode, + type StairSegmentNode, + StairStructure, + type StairStructureType, + type StairTreadStock, + usePascalI18n, + useScene, +} from '@pascal-app/core' +import { formatLinearMeasurement, MetricControl, SelectControl } from '@pascal-app/editor' +import { useViewer } from '@pascal-app/viewer' +import { useShallow } from 'zustand/react/shallow' + +const IN = 0.0254 +/** The concrete a poured flight is painted when it carries no paint of its own. */ +const CONCRETE_PRESET = 'library:concrete-raw' + +const STRUCTURE_OPTIONS: { label: MessageDescriptor; value: StairStructureType | 'none' }[] = [ + { + label: /* i18n */ { id: 'node.stair.structureControls.originalBody', message: 'Original body' }, + value: 'none', + }, + { + label: /* i18n */ { + id: 'node.stair.structureControls.woodStringers', + message: 'Wood stringers', + }, + value: 'wood-stringers', + }, + { + label: /* i18n */ { id: 'node.stair.structureControls.concrete', message: 'Concrete' }, + value: 'concrete', + }, + { + label: /* i18n */ { + id: 'node.stair.structureControls.steelStringers', + message: 'Steel stringers', + }, + value: 'steel-stringers', + }, +] + +/** The lumber a tread is cut from; the trade size is a value, not copy. */ +const TREAD_LABELS: Record = { + '2x6-pair': /* i18n */ { + id: 'node.stair.structureControls.twoStock', + message: 'Two {stock}', + values: { stock: '2x6' }, + }, + '5/4x6-pair': /* i18n */ { + id: 'node.stair.structureControls.twoStock', + message: 'Two {stock}', + values: { stock: '5/4x6' }, + }, + '2x12': /* i18n */ { + id: 'node.stair.structureControls.oneStock', + message: 'One {stock}', + values: { stock: '2x12' }, + }, + 'plywood-finish': /* i18n */ { + id: 'node.stair.structureControls.plywoodFinish', + message: 'Plywood + finish', + }, +} + +type Choice = 'auto' | 'yes' | 'no' +const choiceOf = (value: boolean | undefined): Choice => + value === undefined ? 'auto' : value ? 'yes' : 'no' +const choiceValue = (choice: Choice): boolean | undefined => + choice === 'auto' ? undefined : choice === 'yes' + +/** A flight's stringers as the status line reads them: `3 stringers at 1' 4" o.c. (auto)`. */ +function stringerLayoutLine( + layout: { count: number; steel: boolean; auto: boolean }, + spacing: string, + i18n: PascalI18n, +): string { + const values = { count: layout.count, spacing } + let line: string + if (layout.steel) + line = + layout.count > 1 + ? i18n._({ + id: 'node.stair.structureControls.countSteelChannelsAtSpacing', + message: + '{count, plural, one {# steel channel at {spacing} o.c.} other {# steel channels at {spacing} o.c.}}', + values, + }) + : i18n._({ + id: 'node.stair.structureControls.countSteelChannels', + message: '{count, plural, one {# steel channel} other {# steel channels}}', + values, + }) + else + line = + layout.count > 1 + ? i18n._({ + id: 'node.stair.structureControls.countStringersAtSpacing', + message: + '{count, plural, one {# stringer at {spacing} o.c.} other {# stringers at {spacing} o.c.}}', + values, + }) + : i18n._({ + id: 'node.stair.structureControls.countStringers', + message: '{count, plural, one {# stringer} other {# stringers}}', + values, + }) + if (!layout.auto) return line + return i18n._({ + id: 'node.stair.structureControls.layoutAuto', + message: '{layout} (auto)', + comment: 'The stringer count was chosen automatically, not set by hand.', + values: { layout: line }, + }) +} + +/** + * How the stair is built (its stringers, with the code's numbers behind them): + * wood stringers — stock, cut or housed, a maximum spacing that sets the count (or a count by + * hand), treads, risers and treated lumber — a poured concrete flight, or steel channels. The + * count it lands on shows under the controls. + */ +export function StairStructureControls({ + node, + segments, + onUpdate, +}: { + node: StairNode + segments: readonly StairSegmentNode[] + onUpdate: (patch: Partial) => void +}) { + const i18n = usePascalI18n() + const unit = useViewer((state) => state.unit) + const metricNotation = useViewer((state) => state.metricNotation) + const resolved = resolveStairStructure(node) + const stored = node.structure ? StairStructure.safeParse(node.structure) : null + const structure = stored?.success ? stored.data : null + const update = (patch: Partial) => + onUpdate({ structure: StairStructure.parse({ ...structure, ...patch }) }) + + const setType = (value: StairStructureType | 'none') => { + if (value === 'none') { + onUpdate({ + structure: undefined, + ...(node.materialPreset === CONCRETE_PRESET ? { materialPreset: undefined } : {}), + }) + return + } + const painted = node.material !== undefined || typeof node.materialPreset === 'string' + onUpdate({ + structure: StairStructure.parse({ ...structure, type: value }), + // a poured flight reads as concrete until it is painted otherwise; leaving concrete takes + // that paint back off + ...(value === 'concrete' && !painted ? { materialPreset: CONCRETE_PRESET } : {}), + ...(value !== 'concrete' && node.materialPreset === CONCRETE_PRESET + ? { materialPreset: undefined } + : {}), + }) + } + + const flights = segments.filter((segment) => segment.segmentType === 'stair') + const widths = flights.length ? flights.map((flight) => flight.width) : [node.width] + const layouts = + resolved && resolved.type !== 'concrete' + ? widths.map((width) => ({ width, layout: resolveStairStringerLayout(width, resolved) })) + : [] + const first = layouts[0]?.layout + const autoCount = + resolved && first + ? resolveStairStringerLayout(widths[0]!, { ...resolved, stringerCount: undefined }).count + : 0 + const wood = resolved?.type === 'wood-stringers' + const spacingIn = structure ? Math.round((structure.stringerSpacing / IN) * 100) / 100 : 16 + const spacings: number[] = STAIR_STRINGER_SPACINGS_IN.includes( + spacingIn as (typeof STAIR_STRINGER_SPACINGS_IN)[number], + ) + ? [...STAIR_STRINGER_SPACINGS_IN] + : [...STAIR_STRINGER_SPACINGS_IN, spacingIn].sort((a, b) => a - b) + + return ( +
+ ({ ...option, label: i18n._(option.label) }))} + onChange={setType} + /> + {resolved && structure ? ( + <> + {wood ? ( + <> + update({ stringerStock })} + /> + update({ stringerType })} + /> + ({ + label: i18n._({ + id: 'node.stair.structureControls.inchesInOC', + message: '{inches} in o.c.', + values: { inches }, + }), + value: String(inches), + }))} + onChange={(value) => update({ stringerSpacing: Number(value) * IN })} + /> + + ) : null} + {resolved.type !== 'concrete' && first ? ( + <> + ({ + label: String(count), + value: String(count), + })), + ]} + onChange={(value) => + update({ stringerCount: value === 'auto' ? undefined : Number(value) }) + } + /> + ({ + label: i18n._(TREAD_LABELS[stock]), + value: stock, + })), + ]} + onChange={(value) => + update({ treadStock: value === 'auto' ? undefined : (value as StairTreadStock) }) + } + /> + update({ closedRisers: choiceValue(value as Choice) })} + /> + {wood ? ( + update({ treated: choiceValue(value as Choice) })} + /> + ) : null} + + ) : null} + update({ nosing })} + unit="m" + step={0.005} + precision={3} + /> +
+ {resolved.type === 'concrete' ? ( +
+ {i18n._({ + id: 'node.stair.structureControls.aSolidPouredFlightOnA', + message: 'A solid poured flight on a footing; risers closed, no stringers.', + })} +
+ ) : ( + layouts.map(({ width, layout }, index) => { + const line = stringerLayoutLine( + layout, + formatLinearMeasurement(layout.spacing, unit, metricNotation), + i18n, + ) + return ( +
+ {layouts.length > 1 + ? i18n._({ + id: 'node.stair.structureControls.flightLayout', + message: 'Flight {number}: {layout}', + values: { number: index + 1, layout: line }, + }) + : line} +
+ ) + }) + )} +
+ + ) : null} +
+ ) +} + +/** The structure controls in the parametric inspector, over the stair's own flights. */ +export function StairStructureField({ + node, + onUpdate, +}: { + node: StairNode + onUpdate: (patch: Partial) => void +}) { + const segments = useScene( + useShallow((state) => + (node.children ?? []) + .map((id) => state.nodes[id as AnyNodeId]) + .filter((child): child is StairSegmentNode => child?.type === 'stair-segment'), + ), + ) + return +} diff --git a/packages/nodes/src/stair/tool.tsx b/packages/nodes/src/stair/tool.tsx index 3225ac9462..955a741666 100644 --- a/packages/nodes/src/stair/tool.tsx +++ b/packages/nodes/src/stair/tool.tsx @@ -61,6 +61,11 @@ import { useViewer } from '@pascal-app/viewer' import { useThree } from '@react-three/fiber' import { useEffect, useMemo, useRef } from 'react' import * as THREE from 'three' +import { + newStairStructure, + pickedStairRailingMode, + surfaceFlightRailingMode, +} from './placement-defaults' import { createStairCommitGate, swallowFollowUpBrowserClick } from './stair-click-guard' const GRID_OFFSET = 0.02 @@ -144,6 +149,16 @@ function createSeedStairSegment(rise: number) { }) } +/** The railing mode picked for the stair tool, when one is. */ +function pickedRailingMode(): StairNode['railingMode'] | null { + return pickedStairRailingMode(useEditor.getState().toolDefaults.stair?.railingMode) +} + +/** A deck, porch or patio flight's railing (`surfaceFlightRailingMode`), the tool's pick first. */ +function surfaceSnapRailingMode(snap: StairSurfaceSnap): StairNode['railingMode'] { + return surfaceFlightRailingMode(snap, pickedRailingMode()) +} + function createDefaultStairNode({ name, levelId, @@ -159,7 +174,6 @@ function createDefaultStairNode({ rotation: number segmentId: StairSegmentNode['id'] }) { - const railingMode = useEditor.getState().toolDefaults.stair?.railingMode return StairNode.parse({ name, parentId: levelId, @@ -181,13 +195,8 @@ function createDefaultStairNode({ showCenterColumn: DEFAULT_SPIRAL_SHOW_CENTER_COLUMN, showStepSupports: DEFAULT_SPIRAL_SHOW_STEP_SUPPORTS, railingHeight: DEFAULT_STAIR_RAILING_HEIGHT, - railingMode: - railingMode === 'none' || - railingMode === 'left' || - railingMode === 'right' || - railingMode === 'both' - ? railingMode - : DEFAULT_STAIR_RAILING_MODE, + railingMode: pickedRailingMode() ?? DEFAULT_STAIR_RAILING_MODE, + structure: newStairStructure(useEditor.getState().toolDefaults.stair?.structure), children: [segmentId], }) } @@ -241,7 +250,7 @@ function commitStairPlacement( stepCount: surfaceSnap.stepCount, slabOpeningMode: 'none' as const, destinationSurfaceId: surfaceSnap.surfaceId, - railingMode: 'none' as const, + railingMode: surfaceSnapRailingMode(surfaceSnap), } : {}), }) @@ -419,7 +428,7 @@ export default function StairTool() { stair.totalRise = surfaceSnap.totalRise stair.destinationSurfaceId = surfaceSnap.surfaceId stair.slabOpeningMode = 'none' - stair.railingMode = 'none' + stair.railingMode = surfaceSnapRailingMode(surfaceSnap) segment = { ...segment, height: surfaceSnap.totalRise, diff --git a/packages/nodes/src/wall/actions.tsx b/packages/nodes/src/wall/actions.tsx index c2ae39cae7..c63d17b7ff 100644 --- a/packages/nodes/src/wall/actions.tsx +++ b/packages/nodes/src/wall/actions.tsx @@ -7,11 +7,9 @@ import { useScene, } from '@pascal-app/core' import { + ActionMenuButton, captureElementActionOrigin, completeElementAction, - Tooltip, - TooltipContent, - TooltipTrigger, triggerSFX, } from '@pascal-app/editor' import { useViewer } from '@pascal-app/viewer' @@ -19,10 +17,7 @@ import { FoldHorizontal, Scissors } from 'lucide-react' import { useMemo } from 'react' import { openWallSplit } from './split-session' -const BUTTON = - 'tooltip-trigger rounded-md p-1.5 text-muted-foreground hover:bg-accent hover:text-foreground disabled:pointer-events-none disabled:opacity-50' - -/** The wall's action-menu contributions: Split (one wall) and Merge (several). */ +/** The wall's action-menu contributions: Split (one wall), Merge (several). */ export default function WallActions() { return ( <> @@ -41,19 +36,16 @@ function SplitWallAction() { const readOnly = useScene((s) => s.readOnly) if (wall?.type !== 'wall') return null return ( - + ) } @@ -63,27 +55,31 @@ function MergeWallsAction() { const selected = useViewer((s) => s.selection.selectedIds) as AnyNodeId[] const nodes = useScene((s) => s.nodes) const readOnly = useScene((s) => s.readOnly) - // null: not a wall selection (render nothing); otherwise why it can't merge, or null. + // null: not a wall selection (render nothing); otherwise why it can't merge (undefined when the + // plan gave no reason of its own), or null. const merge = useMemo(() => { if (selected.length < 2 || selected.some((id) => nodes[id]?.type !== 'wall')) return null try { planWallMerge(nodes, selected) return { reason: null } } catch (error) { - return { reason: error instanceof Error ? error.message : 'These walls cannot be merged.' } + return { reason: error instanceof Error ? error.message : undefined } } }, [nodes, selected]) if (!merge) return null - const { reason } = merge - const button = ( - - ) - if (!reason) return button - // A disabled button gets no hover events, so the reason hangs off a wrapper. - return ( - - - {button} - - {reason} - + ) } diff --git a/packages/nodes/src/wall/construction-dimension-reference-policy.test.ts b/packages/nodes/src/wall/construction-dimension-reference-policy.test.ts index 37e7cddb81..2a58697454 100644 --- a/packages/nodes/src/wall/construction-dimension-reference-policy.test.ts +++ b/packages/nodes/src/wall/construction-dimension-reference-policy.test.ts @@ -1,12 +1,21 @@ import { describe, expect, test } from 'bun:test' -import { type AnyNode, WallNode, type WallNode as WallNodeType } from '@pascal-app/core' +import { + type AnyNode, + type FloorplanGeometry, + WallNode, + type WallNode as WallNodeType, +} from '@pascal-app/core' +import { + createFloorplanContextExtensions, + type FloorplanWallDimensionFaces, +} from '@pascal-app/editor' import { constructionDimensionStandard } from '../shared/construction-dimension-standards' import { buildLevelWallConstructionDimensionPlan, type PlannedConstructionDimension, renderPlannedConstructionDimensions, } from './construction-dimensions' -import { computeWallFloorplanLevelData } from './floorplan' +import { buildWallFloorplan, computeWallFloorplanLevelData } from './floorplan' function wall(overrides: Partial): WallNodeType { return WallNode.parse({ @@ -89,6 +98,13 @@ function topFacadePlan( ) } +function dimensionTexts(geometry: FloorplanGeometry): string[] { + if (geometry.kind === 'group') return geometry.children.flatMap(dimensionTexts) + return geometry.kind === 'dimension-string' + ? geometry.segments.map((segment) => segment.text ?? '') + : [] +} + function tierEntries( plan: readonly PlannedConstructionDimension[], tier: PlannedConstructionDimension['tier'], @@ -119,29 +135,32 @@ describe('automatic wall dimension reference policy', () => { expect(intersection('structural-face')).toBeCloseTo(3.94) }) - test('keeps centerline distinct while all face modes use the wall face', () => { - const { nodes, top, walls } = topFacadeFixture(true) + test('Measure walls picks the face chains of the finished-face strings', () => { + const { nodes, walls } = topFacadeFixture(false, true) const levelData = computeWallFloorplanLevelData({ siblings: walls, nodes }) - const renderedSegments = (reference: 'finished-faces' | 'centerline' | 'stud-faces') => { - const partitionChain = tierEntries( - levelData.constructionDimensionsByReference[reference].get(top.id) ?? [], - 'partitions', - ) - const rendered = renderPlannedConstructionDimensions(partitionChain, 'metric') - const dimensionString = rendered[0] - return dimensionString?.kind === 'dimension-string' ? dimensionString.segments : [] - } + const texts = (wallDimensionFaces: FloorplanWallDimensionFaces) => + walls.flatMap((candidate) => { + const geometry = buildWallFloorplan(candidate, { + resolve: () => undefined, + children: [], + siblings: walls.filter((sibling) => sibling.id !== candidate.id), + parent: null, + levelData, + extensions: createFloorplanContextExtensions({ wallDimensionFaces }), + }) + return geometry ? dimensionTexts(geometry) : [] + }) + + // Outside: the facade strings (top and bottom: the partition located on + // the facade, then the overall size; left and right: the overall size). + const facade = ['4.04m', '0.12m', '6.04m', '10.2m'] + const outside = [...facade, '6.2m', ...facade, '6.2m'] + // Inside: the partition's clear span, inside face to inside face. + const inside = ['5.8m'] - expect(renderedSegments('finished-faces').map((segment) => segment.text)).toEqual([ - '4.04m', - '0.12m', - '6.04m', - ]) - expect(renderedSegments('centerline').map((segment) => segment.text)).toEqual(['4.1m', '6.1m']) - expect(renderedSegments('stud-faces').map((segment) => segment.text)).toEqual([ - '4.04m', - '6.16m', - ]) + expect(texts('exterior').sort()).toEqual(outside.sort()) + expect(texts('interior')).toEqual(inside) + expect(texts('both').sort()).toEqual([...outside, ...inside].sort()) }) test('renders a face-of-stud partition chain with one shared witness', () => { diff --git a/packages/nodes/src/wall/construction-dimensions.ts b/packages/nodes/src/wall/construction-dimensions.ts index cad66e8465..ef83cea26b 100644 --- a/packages/nodes/src/wall/construction-dimensions.ts +++ b/packages/nodes/src/wall/construction-dimensions.ts @@ -47,6 +47,17 @@ export type ConstructionDimensionTier = | 'interior' | 'interior-overall' +/** + * Which face chain a tier belongs to: the clear spans drawn inside the rooms + * are interior (ID); the facade strings — openings, partitions, columns, jogs + * and the overall sizes — are measured outside the building (OD). + */ +export function constructionDimensionFace( + tier: ConstructionDimensionTier, +): 'interior' | 'exterior' { + return tier === 'interior' || tier === 'interior-overall' ? 'interior' : 'exterior' +} + const TIER_ORDER: readonly ConstructionDimensionTier[] = [ 'opening-widths', 'openings', diff --git a/packages/nodes/src/wall/contextual-dimensions.ts b/packages/nodes/src/wall/contextual-dimensions.ts index 12faaa993a..3d253a2671 100644 --- a/packages/nodes/src/wall/contextual-dimensions.ts +++ b/packages/nodes/src/wall/contextual-dimensions.ts @@ -8,7 +8,11 @@ import { isCurvedWall, type WallNode, } from '@pascal-app/core' -import { formatLinearMeasurement, readFloorplanMetricNotationOverride } from '@pascal-app/editor' +import { + formatLinearMeasurement, + readFloorplanContext, + readFloorplanMetricNotationOverride, +} from '@pascal-app/editor' type WallHostedOpening = { position: readonly [number, number, number] @@ -90,6 +94,7 @@ function pointSegmentDistance( } function structuralFaceProjections( + /** A point on the measured line (the centerline or one face) at the wall's start. */ wallStart: FloorplanPoint, wallTangent: FloorplanPoint, connectedWall: WallNode, @@ -161,6 +166,92 @@ function wallStudFaceSpan( return { start, end, length: Math.max(0, endProjection - startProjection) } } +type FaceSpan = { end: FloorplanPoint; length: number; start: FloorplanPoint } + +function nearPlanPoint(left: FloorplanPoint, right: FloorplanPoint): boolean { + return Math.hypot(left[0] - right[0], left[1] - right[1]) <= WALL_CONNECTION_TOLERANCE +} + +/** + * One face of a straight wall, from end to end. `inner` stops at the near + * face of each connected wall (an interior face, the room size); `outer` + * runs on to the far face of a wall that turns the corner with it (an + * exterior face, the outside size). A wall that only abuts another (a T) + * stops at its near face either way, and a free end at the end cap. + */ +function wallFaceSpan( + wall: WallNode, + side: 'a' | 'b', + siblings: GeometryContext['siblings'], + reach: 'inner' | 'outer', +): FaceSpan | null { + const dx = wall.end[0] - wall.start[0] + const dy = wall.end[1] - wall.start[1] + const length = Math.hypot(dx, dy) + if (length <= 1e-6) return null + const tangent: FloorplanPoint = [dx / length, dy / length] + const offset = getWallFaceOffsets(wall)[side] + const origin: FloorplanPoint = [ + wall.start[0] - tangent[1] * offset, + wall.start[1] + tangent[0] * offset, + ] + + const resolveEnd = (endpoint: FloorplanPoint, atStart: boolean): number => { + const rest = atStart ? 0 : length + let near: number | null = null + let far: number | null = null + for (const sibling of siblings) { + if (sibling.type !== 'wall' || sibling.id === wall.id) continue + if (pointSegmentDistance(endpoint, sibling.start, sibling.end) > WALL_CONNECTION_TOLERANCE) { + continue + } + const corner = nearPlanPoint(endpoint, sibling.start) || nearPlanPoint(endpoint, sibling.end) + for (const projection of structuralFaceProjections(origin, tangent, sibling)) { + const inward = atStart ? projection : length - projection + if (inward > 0 && inward < length) { + if (near === null || inward > (atStart ? near : length - near)) near = projection + } else if (corner && inward < 0 && inward > -length) { + if (far === null || inward < (atStart ? far : length - far)) far = projection + } + } + } + if (reach === 'outer' && far !== null) return far + return near ?? rest + } + + const startProjection = resolveEnd(wall.start, true) + const endProjection = resolveEnd(wall.end, false) + if (endProjection - startProjection <= 1e-6) return null + return { + start: [origin[0] + tangent[0] * startProjection, origin[1] + tangent[1] * startProjection], + end: [origin[0] + tangent[0] * endProjection, origin[1] + tangent[1] * endProjection], + length: endProjection - startProjection, + } +} + +function faceDimension( + span: FaceSpan, + offsetNormal: FloorplanPoint, + ctx: GeometryContext, +): FloorplanGeometry { + return { + kind: 'dimension', + start: span.start, + end: span.end, + offsetNormal, + offsetDistance: 0.34, + extensionOvershoot: 0.08, + text: formatLength(span.length, ctx), + stroke: selectedStroke(ctx), + } +} + +/** + * A selected wall's length, to its faces rather than its centerline: the + * interior face (ID) on the room side and the exterior face (OD) outside, as + * the dimension-faces preference asks. An interior partition has no outside, + * so it shows its clear span between the walls it runs to. + */ export function buildWallContextualDimensions( node: WallNode, ctx: GeometryContext, @@ -189,27 +280,30 @@ export function buildWallContextualDimensions( const dy = node.end[1] - node.start[1] const chordLength = Math.hypot(dx, dy) if (chordLength <= 1e-6) return null - const offsetNormal = contextualWallDimensionNormal( - node, - [-dy / chordLength, dx / chordLength], - ctx.siblings, - ) - const span = - node.frontSide === 'interior' && node.backSide === 'interior' - ? wallStudFaceSpan(node, ctx.siblings) - : { start: node.start, end: node.end, length: chordLength } - if (span.length <= 1e-6) return null + const front: FloorplanPoint = [-dy / chordLength, dx / chordLength] + const offsetNormal = contextualWallDimensionNormal(node, front, ctx.siblings) + if (node.frontSide === 'interior' && node.backSide === 'interior') { + const span = wallStudFaceSpan(node, ctx.siblings) + return span.length <= 1e-6 ? null : faceDimension(span, offsetNormal, ctx) + } - return { - kind: 'dimension', - start: span.start, - end: span.end, - offsetNormal, - offsetDistance: 0.34, - extensionOvershoot: 0.08, - text: formatLength(span.length, ctx), - stroke: selectedStroke(ctx), + // `offsetNormal` points out of the wall's exterior (or its best guess at it). + const exteriorSide = offsetNormal[0] * front[0] + offsetNormal[1] * front[1] > 0 ? 'a' : 'b' + const interiorNormal: FloorplanPoint = [cleanZero(-offsetNormal[0]), cleanZero(-offsetNormal[1])] + const faces = readFloorplanContext(ctx).wallDimensionFaces + const inner = wallFaceSpan(node, exteriorSide === 'a' ? 'b' : 'a', ctx.siblings, 'inner') + const outer = wallFaceSpan(node, exteriorSide, ctx.siblings, 'outer') + const interior = faces === 'exterior' ? null : inner + const exterior = faces === 'interior' ? null : outer + if (interior && exterior && Math.abs(interior.length - exterior.length) < 0.001) { + return faceDimension(exterior, offsetNormal, ctx) } + const children = [ + ...(interior ? [faceDimension(interior, interiorNormal, ctx)] : []), + ...(exterior ? [faceDimension(exterior, offsetNormal, ctx)] : []), + ] + if (children.length === 0) return null + return children.length === 1 ? children[0]! : { kind: 'group', children } } export function buildWallHostedOpeningContextualDimensions( diff --git a/packages/nodes/src/wall/curtain-wall-materials.ts b/packages/nodes/src/wall/curtain-wall-materials.ts index 9d7473e773..b89e874d81 100644 --- a/packages/nodes/src/wall/curtain-wall-materials.ts +++ b/packages/nodes/src/wall/curtain-wall-materials.ts @@ -14,6 +14,7 @@ import { } from '@pascal-app/viewer' import type { Material } from 'three' import { MeshLambertNodeMaterial, MeshStandardNodeMaterial } from 'three/webgpu' +import { createRailingWallMaterials } from './railing-wall-materials' export function createCurtainWallMaterials( wall: WallNode, @@ -76,10 +77,13 @@ export function getCurtainAwareWallMaterials( materials?: Record, finishRefs: readonly string[] = [], ): WallMaterials { - const override = - textures && wall.wallType === 'curtain' + const override = !textures + ? undefined + : wall.wallType === 'curtain' ? createCurtainWallMaterials(wall, shading, materials) - : undefined + : wall.wallType === 'railing' + ? createRailingWallMaterials(wall, shading, materials) + : undefined return getMaterialsForWall( wall, shading, diff --git a/packages/nodes/src/wall/curve-tool.tsx b/packages/nodes/src/wall/curve-tool.tsx index efc3a7c2e1..e185b9c0b6 100644 --- a/packages/nodes/src/wall/curve-tool.tsx +++ b/packages/nodes/src/wall/curve-tool.tsx @@ -93,9 +93,8 @@ export const CurveWallTool: React.FC<{ node: WallNode }> = ({ node }) => { // nothing clears any more. if (wasFinalized) return const snapStep = getSegmentGridStep() - // Snap the cursor on the WORLD XZ grid (still in building-local - // coords for the rest of the math) so a rotated building doesn't - // pull the curve handle off the visible grid lines. + // Snap the cursor on the building's own grid lattice, the one the + // wall tool drafts on (it turns with a turned building). const [snappedLocalX, snappedLocalZ] = snapBuildingLocalToWorldGrid( [event.localPosition[0], event.localPosition[2]], snapStep, diff --git a/packages/nodes/src/wall/definition.test.ts b/packages/nodes/src/wall/definition.test.ts index ccc8eb3c95..6727b6fc0f 100644 --- a/packages/nodes/src/wall/definition.test.ts +++ b/packages/nodes/src/wall/definition.test.ts @@ -91,6 +91,19 @@ describe('wallDefinition floor-plan extension', () => { const canCurve = getFloorplanNodeExtension(wallDefinition)?.actionMenu?.canCurve expect(canCurve?.({ node: wall, nodes })).toBe(false) }) + test('takes its own plan hits and shows typeable dimensions only between rooms', () => { + const extension = getFloorplanNodeExtension(wallDefinition) + expect(extension?.planHitSelectsNode).toBe(true) + const wall = wallDefinition.schema.parse({ + id: 'wall_lone', + parentId: 'level_lone', + start: [0, 0], + end: [4, 0], + }) + const nodes = { [wall.id]: wall } as Record + // A wall bounding no room has no room widths to show. + expect(extension?.selectionDimensions?.({ node: wall, nodes, faces: 'both' })).toEqual([]) + }) }) test('wall top surface follows the effective level-bound height', () => { diff --git a/packages/nodes/src/wall/definition.ts b/packages/nodes/src/wall/definition.ts index 00a3333302..b7a92fb0ff 100644 --- a/packages/nodes/src/wall/definition.ts +++ b/packages/nodes/src/wall/definition.ts @@ -3,6 +3,7 @@ import { DEFAULT_WALL_THICKNESS, getWallBaseElevationForNodes, getWallEffectiveHeightForNodes, + isRailingWall, type NodeDefinition, type WallNode as WallNodeType, wallSlots, @@ -14,6 +15,7 @@ import { getWallDrawVariant, type NodePanelModel, PANEL_MODEL_EXTENSION, + selectedWallDimensions, useEditor, type WallDrawVariant, } from '@pascal-app/editor' @@ -34,7 +36,12 @@ import { wallMeasurementFeatures, } from './measurement' import { wallPaint } from './paint' -import { type WallReferenceValue, wallReferenceModel, wallSettings } from './panel-model' +import { + type WallReferenceValue, + wallAssemblyMultiControls, + wallReferenceModel, + wallSettings, +} from './panel-model' import { wallParametrics } from './parametrics' import { wallQuickMeasurement } from './quick-measurement' import { WallNode } from './schema' @@ -89,6 +96,7 @@ export const wallDefinition: NodeDefinition = { value: reference.value, onChange: (value) => reference.apply(value as WallReferenceValue), }, + ...wallAssemblyMultiControls(selection), ] }, } satisfies NodePanelModel, @@ -112,6 +120,8 @@ export const wallDefinition: NodeDefinition = { tool: () => import('./floorplan-tool'), reshapeLayers: { split: () => import('./split-floorplan-layer') }, contextualDimensions: buildWallContextualDimensions, + planHitSelectsNode: true, + selectionDimensions: ({ node, nodes, faces }) => selectedWallDimensions(nodes, node, faces), actionMenu: { actions: () => import('./actions'), canCurve: ({ node, nodes }) => @@ -141,13 +151,23 @@ export const wallDefinition: NodeDefinition = { reveal: { phase: 'structure', style: 'rise' }, exterior: wallSeenFromOutside, revealLayout: { line: (node) => (node.type === 'wall' ? [node.start, node.end] : null) }, - revealOnEdit: ['start', 'end', 'curveOffset', 'height', 'thickness', 'wallType', 'curtainWall'], + revealOnEdit: [ + 'start', + 'end', + 'curveOffset', + 'height', + 'thickness', + 'wallType', + 'curtainWall', + 'railing', + ], // Wall move is bespoke (endpoint drag, linked-wall corner cascade, // ALT-detach). Omitting `movable` keeps the legacy MoveWallTool via // capability-driven dispatch. selectable: { hitVolume: 'bbox' }, // Front + back faces host items (paintings, shelves, switches). surfaces: { + renderOpeningContent: (node) => !isRailingWall(node), hosting: false, top: { height: (node, { nodes }) => { @@ -253,6 +273,8 @@ export const wallDefinition: NodeDefinition = { visible: whenWallVariant('polygon'), }, { key: 'Left click', label: 'Set wall start / end', visible: whenWallVariant('walls') }, + // A started Polygon room holds square; Alt lets it go. + { key: 'Alt', label: 'Free angle', visible: whenWallVariant('polygon') }, { key: 'Esc', label: 'Cancel' }, ], // The split session (`split-session.ts`) is the wall's own reshape; the HUD @@ -304,6 +326,6 @@ export const wallDefinition: NodeDefinition = { mcp: { description: - 'A wall defined by endpoints and optional curve sagitta. wallType selects standard or curtain. curtainWall configures construction, framing, grids, glazing, spandrels, and zero-based panel overrides. Thickness is frame depth for curtain walls.', + 'A wall defined by endpoints and optional curve sagitta. wallType selects standard, curtain or railing. curtainWall configures construction, framing, grids, glazing, spandrels, and zero-based panel overrides. Thickness is frame depth for curtain walls. A railing is an open guard (railing: style, postSpacing, postSize, infillSize, infillGap, bottomClearance, cap) that closes rooms like a wall; its height is its own (36 in by default), its thickness its posts, and a door on it is a gap in the guard.', }, } diff --git a/packages/nodes/src/wall/floorplan-affordances.test.ts b/packages/nodes/src/wall/floorplan-affordances.test.ts index 0d5bb94576..ef3199a256 100644 --- a/packages/nodes/src/wall/floorplan-affordances.test.ts +++ b/packages/nodes/src/wall/floorplan-affordances.test.ts @@ -127,6 +127,44 @@ describe('wall endpoint floorplan affordance', () => { expect((useScene.getState().nodes[lower.id] as typeof lower).start).toEqual([0, 1]) expect((useScene.getState().nodes[upper.id] as typeof upper).start).toEqual([0, 0]) }) + + test('a wall T-joined on another does not fold onto its line when dragged into its body', () => { + // `wall_stem` stands on `wall_host`'s line at [2, 0]; its free end is + // dragged down into the host's body, 8 cm off the line. + const host = WallNode.parse({ + id: 'wall_host', + parentId: 'level_main', + start: [0, 0], + end: [4, 0], + thickness: 0.2, + }) + const stem = WallNode.parse({ + id: 'wall_stem', + parentId: 'level_main', + start: [2, 0], + end: [2, 3], + }) + useScene.setState({ nodes: { [host.id]: host, [stem.id]: stem } as never }) + + const session = wallMoveEndpointAffordance.start({ + node: stem, + payload: { wallId: stem.id, endpoint: 'end' }, + nodes: useScene.getState().nodes, + initialPlanPoint: [2, 3], + gridSnapStep: 0.1, + }) + session.apply({ planPoint: [2.5, 0.08], modifiers }) + + // As in 3D, the fixed corner is the segment's start: a segment that runs + // alongside the host isn't captured into its body. + expect(useLiveNodeOverrides.getState().get(stem.id as AnyNodeId)?.end).toEqual([2.5, 0.08]) + expect(session.canCommit()).toBe(true) + session.commit?.() + const committed = useScene.getState().nodes[stem.id] as typeof stem + expect(committed.start).toEqual([2, 0]) + expect(committed.end).toEqual([2.5, 0.08]) + expect(Object.keys(useScene.getState().nodes).sort()).toEqual(['wall_host', 'wall_stem']) + }) }) describe('wall thickness floorplan affordance', () => { diff --git a/packages/nodes/src/wall/floorplan-affordances.ts b/packages/nodes/src/wall/floorplan-affordances.ts index a3cfb5d8dd..fe1ea047fa 100644 --- a/packages/nodes/src/wall/floorplan-affordances.ts +++ b/packages/nodes/src/wall/floorplan-affordances.ts @@ -131,8 +131,8 @@ export const wallCurveAffordance: FloorplanAffordance = { affectedIds: [node.id], apply({ planPoint }) { const snapStep = getSegmentGridStep() - // World-grid snap so a rotated building doesn't drag the curve - // handle off the visible grid. + // Building-grid snap, the lattice the plan draws (it turns with the + // building). const [x, y] = snapBuildingLocalToWorldGrid([planPoint[0], planPoint[1]], snapStep) // Signed projection of (snappedPoint - chord midpoint) onto the @@ -263,16 +263,19 @@ export const wallMoveEndpointAffordance: FloorplanAffordance = { // is 0 outside grid mode), so `'lines' / 'angles' / 'off'` no longer // force a grid snap the mode chip says is inactive. In `'angles'` mode // the endpoint angle-locks off the fixed corner (free length), matching - // the draft tool — the angle path ignores the `gridSnap` override. - const angleLocked = isAngleSnapActive() + // the draft tool — the angle path ignores the `gridSnap` override. The + // fixed corner is the segment's start in every mode, as in the 3D tool: + // the body capture slides the end along it, so a wall whose fixed end + // is T-joined on another wall can't fold onto that wall's line. const snapped = snapWallDraftPoint({ point: planPoint as WallPlanPoint, walls, ignoreWallIds: staleWallIds, - start: angleLocked ? fixedPoint : undefined, - angleSnap: angleLocked, + start: fixedPoint, + angleSnap: isAngleSnapActive(), magnetic: isMagneticSnapActive(), gridSnap: (p) => snapBuildingLocalToWorldGrid(p, getSegmentGridStep()), + captureWallBodies: true, }) // Figma-style alignment on the dragged corner — snaps it onto another // object's edge / wall face and publishes a guide. The guide is diff --git a/packages/nodes/src/wall/floorplan-move.test.ts b/packages/nodes/src/wall/floorplan-move.test.ts index 70e9ff9d59..d2dc9cf748 100644 --- a/packages/nodes/src/wall/floorplan-move.test.ts +++ b/packages/nodes/src/wall/floorplan-move.test.ts @@ -3,6 +3,8 @@ import { CeilingNode, initSpaceDetectionSync, LevelNode, + nodeRegistry, + registerNode, SlabNode, useLiveNodeOverrides, useScene, @@ -10,6 +12,8 @@ import { type ZoneNode, } from '@pascal-app/core' import { migrateCeilingRoomLinks, migrateRoomZones } from '@pascal-app/core/scene-migrations' +import { getActiveSnappingMode, useAlignmentGuides, useInteractionScope } from '@pascal-app/editor' +import { wallDefinition } from './definition' import { wallFloorplanMoveTarget } from './floorplan-move' const square = [ @@ -25,7 +29,12 @@ beforeEach(() => { globalThis.requestAnimationFrame = () => 0 globalThis.cancelAnimationFrame = () => {} }) +// The parallel-wall tests register the wall kind; put the registry back after. +let restoreRegistry: (() => void) | null = null afterEach(() => { + restoreRegistry?.() + restoreRegistry = null + useInteractionScope.getState().end() useLiveNodeOverrides.getState().clearAll() globalThis.requestAnimationFrame = originalRaf globalThis.cancelAnimationFrame = originalCancelRaf @@ -125,3 +134,77 @@ test('whole-wall floorplan move previews and commits automatic slab and ceiling stop() } }) + +// Two outside walls in line but apart, as when partitions break the outside up. +function outsideStep() { + const level = LevelNode.parse({ id: 'level_parallel', level: 0, height: 3, children: [] }) + const outside = { frontSide: 'exterior', backSide: 'interior', thickness: 0.15 } as const + const top = WallNode.parse({ + id: 'wall_parallel-top', + parentId: level.id, + start: [0, 0.07], + end: [4, 0.07], + ...outside, + }) + const step = WallNode.parse({ + id: 'wall_parallel-step', + parentId: level.id, + start: [5, 0.6], + end: [8, 0.6], + ...outside, + }) + useScene.setState({ + nodes: { + [level.id]: { ...level, children: [top.id, step.id] }, + [top.id]: top, + [step.id]: step, + }, + } as never) + // Snapping follows the move's own context, as in the editor. + restoreRegistry = nodeRegistry._snapshot() + if (!nodeRegistry.has(wallDefinition.kind)) registerNode(wallDefinition) + useInteractionScope.getState().begin({ + kind: 'moving', + node: step, + nodeId: step.id, + nodeType: step.type, + view: '2d', + }) + const session = wallFloorplanMoveTarget({ + node: step, + nodes: useScene.getState().nodes, + sceneApi: {} as never, + }) + return { step, session } +} + +const plain = { shiftKey: false, altKey: false, ctrlKey: false, metaKey: false } + +test('a wall moved near a parallel outside wall lines up with it, off the grid', () => { + const { step, session } = outsideStep() + expect(getActiveSnappingMode()).not.toBe('off') + session.apply({ planPoint: [6.5, 0.6], modifiers: plain }) + session.apply({ planPoint: [6.5, 0.12], modifiers: plain }) + + const preview = useLiveNodeOverrides.getState().get(step.id) as Pick + expect(preview.start[0]).toBe(5) + expect(preview.start[1]).toBeCloseTo(0.07, 10) + expect(preview.end[1]).toBeCloseTo(0.07, 10) + expect(useAlignmentGuides.getState().draft?.lines).toHaveLength(1) + + session.commit?.() + const moved = useScene.getState().nodes[step.id] as WallNode + expect(moved.start[1]).toBeCloseTo(0.07, 10) + expect(useAlignmentGuides.getState().draft).toBeNull() +}) + +test('Alt moves a wall exactly with the pointer', () => { + const { step, session } = outsideStep() + const free = { ...plain, altKey: true } + session.apply({ planPoint: [6.5, 0.6], modifiers: free }) + session.apply({ planPoint: [6.5, 0.6 - 0.0254], modifiers: free }) + session.commit?.() + const moved = useScene.getState().nodes[step.id] as WallNode + expect(moved.start[1]).toBeCloseTo(0.6 - 0.0254, 10) + expect(moved.end[1]).toBeCloseTo(0.6 - 0.0254, 10) +}) diff --git a/packages/nodes/src/wall/floorplan-move.ts b/packages/nodes/src/wall/floorplan-move.ts index 3e927dd364..d570d905aa 100644 --- a/packages/nodes/src/wall/floorplan-move.ts +++ b/packages/nodes/src/wall/floorplan-move.ts @@ -4,8 +4,12 @@ import { createLevelStructurePreview, type FloorplanMoveTarget, type FloorplanMoveTargetSession, + finishWallEdit, + generateId, getPerpendicularWallMoveAxis, getPlannedLinkedWallUpdates, + planAttachedWallChanges, + planAttachedWallUpdates, planWallEndRejoins, planWallMoveJunctions, useLiveNodeOverrides, @@ -17,10 +21,15 @@ import { getFloorplanWallThickness, getSegmentGridStep, isSegmentLongEnough, + isWallRunFree, + nearestWallParallelTarget, + publishWallParallelGuide, snapScalarToGrid, useWallMoveGhosts, WALL_CONNECT_SNAP_RADIUS, type WallMoveGhostBridge, + type WallParallelTarget, + wallParallelTargets, } from '@pascal-app/editor' import { useViewer } from '@pascal-app/viewer' import { @@ -112,7 +121,35 @@ export const wallFloorplanMoveTarget: FloorplanMoveTarget = ({ node }) .filter((node) => node.parentId === levelId) .map((node) => [node.id, node]), ) - const affectedIds: AnyNodeId[] = [wallId, ...linkedOriginals.map((wall) => wall.id as AnyNodeId)] + // Lines up with the parallel walls on the level: an outside wall's faces + // with the rest of the outside, any other wall's with every wall. + const parallelTargets = moveAxis + ? wallParallelTargets( + node, + moveAxis, + Object.values(dragNodes).filter((entry): entry is WallNode => entry.type === 'wall'), + ) + : [] + let lastLineUp: WallParallelTarget | null = null + // Walls T'd into this one stay on it, stretched along their own line. + const linkedIds = new Set(linkedOriginals.map((wall) => wall.id)) + const attachedWalls = isNew + ? [] + : planAttachedWallUpdates( + Object.values(dragNodes).filter( + (entry): entry is WallNode => + entry.type === 'wall' && entry.id !== wallId && !linkedIds.has(entry.id), + ), + originalStart, + originalEnd, + originalStart, + originalEnd, + ).map(({ id }) => dragNodes[id] as WallNode) + const affectedIds: AnyNodeId[] = [ + wallId, + ...linkedOriginals.map((wall) => wall.id as AnyNodeId), + ...attachedWalls.map((wall) => wall.id as AnyNodeId), + ] const affectedIdSet = new Set(affectedIds) const touchedSurfaceIds = new Set() @@ -160,7 +197,7 @@ export const wallFloorplanMoveTarget: FloorplanMoveTarget = ({ node }) const session: FloorplanMoveTargetSession = { affectedIds, - apply({ planPoint }) { + apply({ planPoint, modifiers }) { if (!rawAnchor) { rawAnchor = [planPoint[0], planPoint[1]] return @@ -168,19 +205,24 @@ export const wallFloorplanMoveTarget: FloorplanMoveTarget = ({ node }) const rawDx = planPoint[0] - rawAnchor[0] const rawDz = planPoint[1] - rawAnchor[1] - const step = getSegmentGridStep() + // Alt (or snapping off) moves the wall exactly with the pointer. + const free = isWallRunFree(modifiers) + const step = free ? 0 : getSegmentGridStep() // Axis-lock the move to the wall's perpendicular (normal). Project // the original centre + raw cursor delta onto the axis, snap the - // absolute projection to a grid multiple, then translate the wall - // by `axis * perpDelta`. Matches `MoveWallTool` so 2D and 3D drag - // produce identical wall topology. + // absolute projection to a parallel wall it lines up with, else to a + // grid multiple, then translate the wall by `axis * perpDelta`. + // Matches `MoveWallTool` so 2D and 3D drag produce identical wall + // topology. let dx: number let dz: number + let lineUp: WallParallelTarget | null = null if (moveAxis) { const originalProj = originalCenter[0] * moveAxis[0] + originalCenter[1] * moveAxis[1] const rawProj = originalProj + rawDx * moveAxis[0] + rawDz * moveAxis[1] - const snappedProj = snapScalarToGrid(rawProj, step) + lineUp = free ? null : nearestWallParallelTarget(parallelTargets, rawProj) + const snappedProj = lineUp ? lineUp.position : snapScalarToGrid(rawProj, step) const perpDelta = snappedProj - originalProj dx = moveAxis[0] * perpDelta dz = moveAxis[1] * perpDelta @@ -188,6 +230,10 @@ export const wallFloorplanMoveTarget: FloorplanMoveTarget = ({ node }) dx = snapScalarToGrid(rawDx, step) dz = snapScalarToGrid(rawDz, step) } + if (lineUp !== lastLineUp) { + lastLineUp = lineUp + publishWallParallelGuide(lineUp) + } if (dx === lastDelta[0] && dz === lastDelta[1]) return lastDelta = [dx, dz] @@ -242,11 +288,20 @@ export const wallFloorplanMoveTarget: FloorplanMoveTarget = ({ node }) // until the user commits. Batched into a single zustand // notification — otherwise each per-wall `.set` would re-render // every override subscriber once per linked wall per tick. + const attachedById = new Map( + planAttachedWallUpdates(attachedWalls, originalStart, originalEnd, nextStart, nextEnd).map( + (update) => [update.id, update], + ), + ) + // A wall the move carries off this one's ends lets go: back where it was. + const attachedUpdates = attachedWalls.map( + (wall) => attachedById.get(wall.id) ?? { id: wall.id, start: wall.start, end: wall.end }, + ) useLiveNodeOverrides .getState() .setMany([ [wallId, { start: nextStart, end: nextEnd }], - ...linkedUpdates.map( + ...[...linkedUpdates, ...attachedUpdates].map( (upd) => [upd.id, { start: upd.start, end: upd.end }] as [string, Record], ), @@ -260,7 +315,10 @@ export const wallFloorplanMoveTarget: FloorplanMoveTarget = ({ node }) // overrides we just published (zustand is still on baseline). const previewSceneWalls = getWallsAfterUpdates(dragNodes, [ { id: wallId, data: { start: nextStart, end: nextEnd } }, - ...linkedUpdates.map((u) => ({ id: u.id, data: { start: u.start, end: u.end } })), + ...[...linkedUpdates, ...attachedUpdates].map((u) => ({ + id: u.id, + data: { start: u.start, end: u.end }, + })), ]).filter((wall) => !collapsedIds.has(wall.id)) const bridgePreviews = buildBridgeWallPreviews({ bridgePlans: plan.bridgePlans, @@ -285,8 +343,8 @@ export const wallFloorplanMoveTarget: FloorplanMoveTarget = ({ node }) // (override-merged) so the mesh follows the cursor. const sceneState = useScene.getState() sceneState.markDirty(wallId) - for (const upd of linkedUpdates) { - sceneState.markDirty(upd.id) + for (const upd of [...linkedUpdates, ...attachedUpdates]) { + sceneState.markDirty(upd.id as AnyNodeId) } }, @@ -298,13 +356,16 @@ export const wallFloorplanMoveTarget: FloorplanMoveTarget = ({ node }) }, commit() { + publishWallParallelGuide(null) const sceneState = useScene.getState() const liveWall = sceneState.nodes[wallId] as WallNode | undefined if (liveWall?.type !== 'wall') { // Bail without leaving stale overrides behind. const overrides = useLiveNodeOverrides.getState() overrides.clear(wallId) - for (const wall of linkedOriginals) overrides.clear(wall.id as AnyNodeId) + for (const wall of [...linkedOriginals, ...attachedWalls]) { + overrides.clear(wall.id as AnyNodeId) + } clearSurfacePreviews() return } @@ -362,15 +423,46 @@ export const wallFloorplanMoveTarget: FloorplanMoveTarget = ({ node }) wallCount: Object.values(sceneState.nodes).filter((entry) => entry?.type === 'wall').length, }) + // Walls T'd into this one follow it, what hangs on them staying put. + const attachedChanges = planAttachedWallChanges( + sceneState.nodes, + wallId, + originalStart, + originalEnd, + lastNextStart, + lastNextEnd, + new Set([...linkedIds, ...collapsedLinkedWallIds]), + ) + const attachedWallIds = attachedChanges.flatMap(({ id }) => + sceneState.nodes[id]?.type === 'wall' ? [id] : [], + ) + // The moved and stretched walls and the jogs take over any stretch of a + // parallel wall they now run along; jogs on the outline are outside walls. sceneState.applyNodeChanges( - planWallEndRejoins( + finishWallEdit( sceneState.nodes, - commitUpdates.map(({ id }) => id), - WALL_CONNECT_SNAP_RADIUS, + planWallEndRejoins( + sceneState.nodes, + commitUpdates.map(({ id }) => id), + WALL_CONNECT_SNAP_RADIUS, + { + update: [ + ...(commitUpdates as Array<{ id: AnyNodeId; data: Partial }>), + ...attachedChanges, + ], + create: bridgeCreates, + delete: Array.from(collapsedLinkedWallIds), + }, + ), { - update: commitUpdates as Array<{ id: AnyNodeId; data: Partial }>, - create: bridgeCreates, - delete: Array.from(collapsedLinkedWallIds), + winnerIds: [ + ...commitUpdates.map(({ id }) => id), + ...attachedWallIds, + ...bridgeCreates.map(({ node }) => node.id), + ], + movedWallId: wallId, + bridgeIds: bridgeCreates.map(({ node }) => node.id), + mintId: () => generateId('wall'), }, ), ) @@ -382,7 +474,9 @@ export const wallFloorplanMoveTarget: FloorplanMoveTarget = ({ node }) // next frame reads the new scene state directly. const overrides = useLiveNodeOverrides.getState() overrides.clear(wallId) - for (const wall of linkedOriginals) overrides.clear(wall.id as AnyNodeId) + for (const wall of [...linkedOriginals, ...attachedWalls]) { + overrides.clear(wall.id as AnyNodeId) + } clearSurfacePreviews() // Swap ghosts → real walls: the bridges we just created render diff --git a/packages/nodes/src/wall/floorplan.test.ts b/packages/nodes/src/wall/floorplan.test.ts index 88471444ed..556191c9ec 100644 --- a/packages/nodes/src/wall/floorplan.test.ts +++ b/packages/nodes/src/wall/floorplan.test.ts @@ -10,6 +10,7 @@ import { import { createFloorplanContextExtensions, readFloorplanGeometryMetadata, + WALL_PULL_AFFORDANCE, WALL_PUSH_AFFORDANCE, } from '@pascal-app/editor' import { buildWallFloorplan } from './floorplan' @@ -36,7 +37,7 @@ function context( purpose: 'edit' | 'document', selected = false, metricNotation: 'meters' | 'millimeters' = 'meters', - wallDimensionReference: 'finished-faces' | 'centerline' | 'stud-faces' = 'finished-faces', + wallDimensionFaces: 'interior' | 'exterior' | 'both' = 'both', automaticDimensions = true, ): GeometryContext { return { @@ -56,7 +57,7 @@ function context( automaticDimensions, metricNotation, purpose, - wallDimensionReference, + wallDimensionFaces, }), } } @@ -171,10 +172,7 @@ describe('buildWallFloorplan render purpose', () => { }) test('does not construct automatic wall dimensions when presentation disables them', () => { - const geometry = buildWallFloorplan( - wall, - context('edit', false, 'meters', 'finished-faces', false), - ) + const geometry = buildWallFloorplan(wall, context('edit', false, 'meters', 'both', false)) const entries = geometry ? flatten(geometry) : [] expect( @@ -188,22 +186,22 @@ describe('buildWallFloorplan render purpose', () => { expect(entries.some((entry) => entry.kind === 'polygon')).toBe(true) }) - test('keeps standalone wall witnesses on the wall face in every intersection mode', () => { + test("keeps a standalone wall's outside string on its face, and drops it for Inside", () => { const plainWall = WallNode.parse({ ...wall, thickness: 0.1, }) - const witnessY = (reference: 'finished-faces' | 'centerline' | 'stud-faces') => { - const geometry = buildWallFloorplan(plainWall, context('edit', false, 'meters', reference)) + const witnessY = (faces: 'interior' | 'exterior' | 'both') => { + const geometry = buildWallFloorplan(plainWall, context('edit', false, 'meters', faces)) const dimension = geometry ? flatten(geometry).find((entry) => entry.kind === 'dimension-string') : undefined return dimension?.kind === 'dimension-string' ? dimension.segments[0]?.start[1] : undefined } - expect(witnessY('finished-faces')).toBeCloseTo(0.065) - expect(witnessY('centerline')).toBeCloseTo(0.065) - expect(witnessY('stud-faces')).toBeCloseTo(0.065) + expect(witnessY('both')).toBeCloseTo(0.065) + expect(witnessY('exterior')).toBeCloseTo(0.065) + expect(witnessY('interior')).toBeUndefined() }) test('shows an orthogonal depth dimension for a curved wall without a radius leader', () => { @@ -221,7 +219,11 @@ describe('buildWallFloorplan render purpose', () => { test('places selected push arrows on the curved wall midpoint', () => { const curved = WallNode.parse({ ...wall, curveOffset: 1 }) const geometry = buildWallFloorplan(curved, context('edit', true)) - const arrows = geometry ? flatten(geometry).filter((entry) => entry.kind === 'move-arrow') : [] + const arrows = geometry + ? flatten(geometry).filter( + (entry) => entry.kind === 'move-arrow' && entry.affordance === WALL_PUSH_AFFORDANCE, + ) + : [] expect(arrows).toHaveLength(2) // Each arrow is the 3D side arrow's push for its face, not a free move. @@ -244,6 +246,39 @@ describe('buildWallFloorplan render purpose', () => { expect(arrows[1].point[1]).toBeCloseTo(-1.115) }) + test('a selected wall carries a pull grip at each end, pointing out along the wall', () => { + const unselected = buildWallFloorplan(wall, context('edit', false)) + const pullsOf = (geometry: FloorplanGeometry | null) => + geometry + ? flatten(geometry).filter( + (entry) => entry.kind === 'move-arrow' && entry.affordance === WALL_PULL_AFFORDANCE, + ) + : [] + expect(pullsOf(unselected)).toHaveLength(0) + + const grips = pullsOf(buildWallFloorplan(wall, context('edit', true))) + expect(grips).toHaveLength(2) + expect(grips[0]).toMatchObject({ + kind: 'move-arrow', + variant: 'pull', + point: wall.start, + affordance: WALL_PULL_AFFORDANCE, + payload: { wallId: wall.id, endpoint: 'start' }, + title: 'Drag to draw the next wall', + }) + expect(grips[1]).toMatchObject({ + kind: 'move-arrow', + variant: 'pull', + point: wall.end, + payload: { wallId: wall.id, endpoint: 'end' }, + }) + if (grips[0]?.kind !== 'move-arrow' || grips[1]?.kind !== 'move-arrow') return + // Out of the wall: back along it from the start, on along it from the end. + const along = Math.atan2(wall.end[1] - wall.start[1], wall.end[0] - wall.start[0]) + expect(Math.cos(grips[1].angle - along)).toBeCloseTo(1) + expect(Math.cos(grips[0].angle - along)).toBeCloseTo(-1) + }) + test('places thickness handles on both visible faces of a curved wall', () => { const curved = WallNode.parse({ ...wall, curveOffset: 1 }) const geometry = buildWallFloorplan(curved, context('edit', true)) diff --git a/packages/nodes/src/wall/floorplan.ts b/packages/nodes/src/wall/floorplan.ts index 1be8ec9d0a..74723034a8 100644 --- a/packages/nodes/src/wall/floorplan.ts +++ b/packages/nodes/src/wall/floorplan.ts @@ -16,6 +16,7 @@ import { getWallPlanFootprint, getWallThickness, isCurvedWall, + isRailingWall, type WallLayerMiterData, type WallLayerPolyline, type WallMiterData, @@ -23,21 +24,28 @@ import { wallLayerBoundaryOffsets, } from '@pascal-app/core' import { + type FloorplanWallDimensionFaces, floorplanGeometryMetadata, readFloorplanContext, + WALL_PULL_AFFORDANCE, + WALL_PULL_GRIP_TITLE, WALL_PUSH_AFFORDANCE, + type WallPullGripPayload, type WallPushArrowPayload, + wallPullSeed, } from '@pascal-app/editor' import { constructionDimensionStandard } from '../shared/construction-dimension-standards' import { buildCurvedWallConstructionDimensions, buildLevelWallConstructionDimensionPlan, buildWallConstructionDimensions, + constructionDimensionFace, renderPlannedConstructionDimensions, type WallConstructionDimensionPlan, } from './construction-dimensions' import { buildCurtainWallFloorplan } from './curtain-wall-floorplan' import { hasWallCurveBlockingChildren } from './curve-eligibility' +import { buildRailingWallFloorplan } from './railing-wall-floorplan' // Same constants the legacy `getFloorplanWall` uses (editor/lib/floorplan/walls.ts). // Slightly exaggerates thin walls so the 2D plan stays legible without @@ -47,13 +55,19 @@ const FLOORPLAN_MIN_VISIBLE_WALL_THICKNESS = 0.13 const FLOORPLAN_MAX_EXTRA_THICKNESS = 0.035 const FLOORPLAN_SELECTION_HATCH_SPACING = 0.12 const FLOORPLAN_SELECTED_WALL_STROKE_WIDTH = 0.03 +const FLOORPLAN_RAILING_STROKE_WIDTH = 0.01 const FLOORPLAN_SELECTION_HATCH_STROKE_WIDTH = 0.02 -const WALL_DIMENSION_REFERENCES = ['finished-faces', 'centerline', 'stud-faces'] as const - -type WallDimensionReference = (typeof WALL_DIMENSION_REFERENCES)[number] +// The automatic strings measure finished faces; a partition meeting a facade +// is dimensioned to both of its faces. +const FINISHED_FACE_DIMENSIONS = { + datumPolicy: 'wall-face', + intersectionReferencePolicy: 'both-faces', +} as const function floorplanWallThickness(wall: WallNode): number { const baseThickness = getWallThickness(wall) + // A railing draws as thin as its posts. + if (isRailingWall(wall)) return baseThickness const scaledThickness = baseThickness * FLOORPLAN_WALL_THICKNESS_SCALE return Math.min( baseThickness + FLOORPLAN_MAX_EXTRA_THICKNESS, @@ -77,7 +91,8 @@ export type WallFloorplanLevelData = { documentMiters: WallMiterData layerMiters: WallLayerMiterData documentLayerMiters: WallLayerMiterData - constructionDimensionsByReference: Record + /** Built on first read: a level whose plan shows no automatic dimensions never pays for it. */ + readonly constructionDimensions: WallConstructionDimensionPlan } // --- Assembly layer lines --------------------------------------------------- @@ -235,45 +250,23 @@ export function computeWallFloorplanLevelData({ nodes: Record }): WallFloorplanLevelData { const walls = siblings.map(exaggerateWallThickness) - const constructionDimensionsByReference = {} as Record< - WallDimensionReference, - WallConstructionDimensionPlan - > - for (const reference of WALL_DIMENSION_REFERENCES) { - let cached: WallConstructionDimensionPlan | undefined - Object.defineProperty(constructionDimensionsByReference, reference, { - enumerable: true, - get: () => { - if (cached) return cached - const datumPolicy = - reference === 'finished-faces' - ? 'wall-face' - : reference === 'stud-faces' - ? 'structural-face' - : 'centerline' - cached = buildLevelWallConstructionDimensionPlan( - siblings, - nodes, - constructionDimensionStandard({ - datumPolicy, - ...(reference === 'finished-faces' - ? { intersectionReferencePolicy: 'both-faces' as const } - : {}), - }), - ) - return cached - }, - }) - } const documentWalls = [...siblings] const miters = calculateLevelMiters(walls) const documentMiters = calculateLevelMiters(documentWalls) + let constructionDimensions: WallConstructionDimensionPlan | undefined return { miters, documentMiters, layerMiters: calculateLevelLayerMiters(walls, miters, wallLayerOffsets), documentLayerMiters: calculateLevelLayerMiters(documentWalls, documentMiters, wallLayerOffsets), - constructionDimensionsByReference, + get constructionDimensions() { + constructionDimensions ??= buildLevelWallConstructionDimensionPlan( + siblings, + nodes, + constructionDimensionStandard(FINISHED_FACE_DIMENSIONS), + ) + return constructionDimensions + }, } } @@ -286,7 +279,8 @@ export function computeWallFloorplanLevelData({ * 3. A transparent hit-line on the centerline so the user can grab the * wall body easily. * 4. Two endpoint handles (start + end) when selected — the registry - * layer hosts the 5-circle stack + hover transitions + 2D drag. + * layer hosts the 5-circle stack + hover transitions + 2D drag — and, + * just past each, a "pull to continue" grip that draws the next wall. * 5. Exterior facade strings plus interior wall spans and hosted-opening widths. * * `ctx.levelData` provides the shared level miter graph when the floor-plan @@ -294,7 +288,7 @@ export function computeWallFloorplanLevelData({ * direct builder callers. */ export function buildWallFloorplan(node: WallNode, ctx: GeometryContext): FloorplanGeometry | null { - const { automaticDimensions, metricNotation, purpose, wallDimensionReference } = + const { automaticDimensions, metricNotation, purpose, wallDimensionFaces } = readFloorplanContext(ctx) const documentMode = purpose === 'document' const wallForPurpose = (wall: WallNode) => (documentMode ? wall : exaggerateWallThickness(wall)) @@ -342,8 +336,14 @@ export function buildWallFloorplan(node: WallNode, ctx: GeometryContext): Floorp : isHovered && palette ? palette.wallHoverStroke : '#1f2937' + // A railing is an outline round its posts, with no poché. + const railing = isRailingWall(node) const fill = - node.wallType === 'curtain' ? 'transparent' : showSelectedChrome ? '#ffffff' : '#374151' + node.wallType === 'curtain' || railing + ? 'transparent' + : showSelectedChrome + ? '#ffffff' + : '#374151' const children: FloorplanGeometry[] = [ { @@ -351,7 +351,11 @@ export function buildWallFloorplan(node: WallNode, ctx: GeometryContext): Floorp points, fill, stroke, - strokeWidth: showSelectedChrome ? FLOORPLAN_SELECTED_WALL_STROKE_WIDTH : 0.02, + strokeWidth: showSelectedChrome + ? FLOORPLAN_SELECTED_WALL_STROKE_WIDTH + : railing + ? FLOORPLAN_RAILING_STROKE_WIDTH + : 0.02, opacity: 0.92, metadata: floorplanGeometryMetadata({ annotationObstacle: 'outline' }), // Once the wall is selected, the body keeps catching the pointer @@ -372,6 +376,15 @@ export function buildWallFloorplan(node: WallNode, ctx: GeometryContext): Floorp ctx.children, ), ) + } else if (railing) { + children.push( + ...buildRailingWallFloorplan( + node, + ctx.children, + ctx.siblings.filter((sibling): sibling is AnyNode & WallNode => sibling.type === 'wall'), + stroke, + ), + ) } else if (node.assembly) { // Assembly layer lines + framing poché, drawn inside the footprint. children.push( @@ -383,7 +396,7 @@ export function buildWallFloorplan(node: WallNode, ctx: GeometryContext): Floorp const dimensionStroke = isSelected && palette ? palette.selectedStroke : (palette?.measurementStroke ?? '#334155') const dimensionStandard = constructionDimensionStandard({ - datumPolicy: wallDimensionDatumPolicy(wallDimensionReference), + ...FINISHED_FACE_DIMENSIONS, metricNotation, }) const exteriorCornerDimensionStandard = constructionDimensionStandard({ @@ -403,20 +416,21 @@ export function buildWallFloorplan(node: WallNode, ctx: GeometryContext): Floorp }), ) } else { - const planned = levelData?.constructionDimensionsByReference[wallDimensionReference].get( - node.id, - ) + const planned = levelData?.constructionDimensions.get(node.id) if (planned) { children.push( ...renderPlannedConstructionDimensions( - planned, + planned.filter((entry) => + measuresFace(wallDimensionFaces, constructionDimensionFace(entry.tier)), + ), view?.unit ?? 'metric', dimensionStroke, documentMode ? 'document' : 'editor', dimensionStandard, ), ) - } else if (!levelData) { + } else if (!levelData && measuresFace(wallDimensionFaces, 'exterior')) { + // Without the level plan, only the exterior strings are drawn. children.push( ...buildWallConstructionDimensions(self, ctx, { unit: view?.unit ?? 'metric', @@ -467,9 +481,25 @@ export function buildWallFloorplan(node: WallNode, ctx: GeometryContext): Floorp affordance: 'move-endpoint', payload: { wallId: node.id, endpoint: 'end' as const }, }) + // Pull grips — an arrow just past each end, pointing out along the wall: + // drag one to draw the next wall from that end (`startWallPull`). + for (const endpoint of ['start', 'end'] as const) { + const seed = wallPullSeed(node, endpoint) + if (!seed) continue + children.push({ + kind: 'move-arrow', + variant: 'pull', + point: seed.start, + angle: Math.atan2(seed.reference[1], seed.reference[0]), + affordance: WALL_PULL_AFFORDANCE, + payload: { wallId: node.id, endpoint } satisfies WallPullGripPayload, + title: WALL_PULL_GRIP_TITLE, + }) + } const thicknessFrame = getWallCurveFrameAt(self, 0.5) - for (const side of [1, -1] as const) { + // A railing's posts set its thickness (the panel's Post size): it has no thickness handles. + for (const side of railing ? [] : ([1, -1] as const)) { const halfVisibleThickness = getWallLocalFaceZ(self, side > 0 ? 'a' : 'b') * side children.push({ kind: 'endpoint-handle', @@ -564,13 +594,9 @@ function buildSelectedWallHatchLines(wall: WallNode, stroke: string): FloorplanG return lines } -function wallDimensionDatumPolicy(reference: WallDimensionReference) { - switch (reference) { - case 'centerline': - return 'centerline' as const - case 'stud-faces': - return 'structural-face' as const - case 'finished-faces': - return 'wall-face' as const - } +function measuresFace( + faces: FloorplanWallDimensionFaces, + face: Exclude, +): boolean { + return faces === 'both' || faces === face } diff --git a/packages/nodes/src/wall/justification.test.ts b/packages/nodes/src/wall/justification.test.ts index d41b0b5833..33b4890455 100644 --- a/packages/nodes/src/wall/justification.test.ts +++ b/packages/nodes/src/wall/justification.test.ts @@ -87,7 +87,9 @@ test('floorplan wall body, hover polygon, face dots and side arrows follow justi (child) => child.kind === 'endpoint-handle' && child.affordance === 'thickness', ) expect(dots.map((dot) => dot.kind === 'endpoint-handle' && dot.point[1])).toEqual([0.2, 0]) - const arrows = geometry.children.filter((child) => child.kind === 'move-arrow') + const arrows = geometry.children.filter( + (child) => child.kind === 'move-arrow' && child.variant !== 'pull', + ) expect(arrows).toHaveLength(2) expect(arrows[0]).toMatchObject({ point: [2, 0.28500000000000003] }) expect(arrows[1]).toMatchObject({ point: [2, -0.05] }) diff --git a/packages/nodes/src/wall/move-endpoint-tool.tsx b/packages/nodes/src/wall/move-endpoint-tool.tsx index d8c96a761e..c6e00ccaf9 100644 --- a/packages/nodes/src/wall/move-endpoint-tool.tsx +++ b/packages/nodes/src/wall/move-endpoint-tool.tsx @@ -405,6 +405,7 @@ export const MoveWallEndpointTool: React.FC<{ target: MovingWallEndpoint }> = ({ start: fixedPoint, angleSnap: isAngleSnapActive(), magnetic: isMagneticSnapActive(), + captureWallBodies: true, }) const snappedPoint = snapResult.point diff --git a/packages/nodes/src/wall/move-tool.test.tsx b/packages/nodes/src/wall/move-tool.test.tsx index 6cc27bebd6..59f359be7e 100644 --- a/packages/nodes/src/wall/move-tool.test.tsx +++ b/packages/nodes/src/wall/move-tool.test.tsx @@ -300,10 +300,12 @@ describe('3D wall move', () => { }) test('drop rejoins a moved endpoint within the connect radius in one reversible step', async () => { + // Slanted, so the move's line-up with parallel walls leaves the drop at 2.5 + // and only the rejoin carries the endpoint onto it. const target = WallNode.parse({ id: 'wall_drop_target', parentId: LEVEL_ID, - start: [2.53, -2], + start: [3.53, -2], end: [2.53, 0.04], }) useScene.getState().applyNodeChanges({ diff --git a/packages/nodes/src/wall/move-tool.tsx b/packages/nodes/src/wall/move-tool.tsx index 87be189b3f..9548913457 100644 --- a/packages/nodes/src/wall/move-tool.tsx +++ b/packages/nodes/src/wall/move-tool.tsx @@ -6,9 +6,13 @@ import { beginSceneHistoryPauseSession, createLevelStructurePreview, emitter, + finishWallEdit, type GridEvent, + generateId, getPerpendicularWallMoveAxis, getPlannedLinkedWallUpdates, + planAttachedWallChanges, + planAttachedWallUpdates, planWallEndRejoins, planWallMoveJunctions, resolveMovedWallSupportSlabPatch, @@ -24,12 +28,17 @@ import { getSegmentGridStep, isSegmentLongEnough, isTypingTarget, + isWallRunFree, markToolCancelConsumed, + nearestWallParallelTarget, + publishWallParallelGuide, snapBuildingLocalToWorldGrid, snapScalarToGrid, triggerSFX, useEditor, WALL_CONNECT_SNAP_RADIUS, + type WallParallelTarget, + wallParallelTargets, } from '@pascal-app/editor' import { useViewer } from '@pascal-app/viewer' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' @@ -328,6 +337,33 @@ export const MoveWallTool: React.FC<{ node: WallNode }> = ({ node }) => { return { start: nextStart, end: nextEnd } } + // The level's other walls, which the moving wall lines up with when parallel + // (`wallParallelTargets`). Recomputed when R / T turns the wall. + const levelWalls = Object.values(useScene.getState().nodes).filter( + (entry): entry is WallNode => entry?.type === 'wall' && (entry.parentId ?? null) === levelId, + ) + const movingWall = levelWalls.find((entry) => entry.id === nodeId) + let parallelTargets: { rotation: number; targets: WallParallelTarget[] } | null = null + const getParallelTargets = (axis: WallMoveAxis) => { + const rotation = pendingRotationRef.current + if (parallelTargets?.rotation !== rotation) { + const turned = buildWallFromCenter(originalCenter) + parallelTargets = { + rotation, + targets: movingWall + ? wallParallelTargets({ ...movingWall, ...turned }, axis, levelWalls) + : [], + } + } + return parallelTargets.targets + } + let lastLineUp: WallParallelTarget | null = null + // Alt moves the wall exactly with the pointer, as in the floor plan. + let altHeld = false + const onPointerMove = (event: PointerEvent) => { + altHeld = event.altKey + } + const getMovePlan = (nextStart: [number, number], nextEnd: [number, number]) => planWallMoveJunctions( linkedOriginalsRef.current, @@ -350,10 +386,27 @@ export const MoveWallTool: React.FC<{ node: WallNode }> = ({ node }) => { nextEnd, ) const movedById = new Map(movedUpdates.map((entry) => [entry.id, entry])) - - return linkedOriginalsRef.current.map( - (wall) => movedById.get(wall.id) ?? { id: wall.id, start: wall.start, end: wall.end }, - ) + const linkedIds = new Set(linkedOriginalsRef.current.map((wall) => wall.id)) + // Walls T'd into this one stay on it, stretched along their own line. + const attached = isNew + ? [] + : planAttachedWallUpdates( + Object.values(dragNodes).filter( + (entry): entry is WallNode => + entry.type === 'wall' && entry.id !== nodeId && !linkedIds.has(entry.id), + ), + originalStart, + originalEnd, + nextStart, + nextEnd, + ) + + return [ + ...linkedOriginalsRef.current.map( + (wall) => movedById.get(wall.id) ?? { id: wall.id, start: wall.start, end: wall.end }, + ), + ...attached, + ] } const applyPreview = (nextStart: [number, number], nextEnd: [number, number]) => { @@ -432,6 +485,7 @@ export const MoveWallTool: React.FC<{ node: WallNode }> = ({ node }) => { const rawDeltaX = rawX - anchor[0] const rawDeltaZ = rawZ - anchor[1] if (!hasDraggedRef.current && Math.hypot(rawDeltaX, rawDeltaZ) < 1e-6) return + const free = isWallRunFree({ altKey: altHeld }) // When the move is axis-locked (side-handle drag), snap the wall // center's absolute perpendicular offset to a multiple of @@ -444,30 +498,40 @@ export const MoveWallTool: React.FC<{ node: WallNode }> = ({ node }) => { // the displacement alone preserves any pre-existing off-grid // offset, so the wall could only ever sit at `originalCentre ± // k·snapStep` — never on actual grid lines. Snapping the wall's - // own perpendicular coordinate fixes that. + // own perpendicular coordinate fixes that. A parallel wall the wall + // lines up with wins over the grid. const axis = moveAxisRef.current let deltaX: number let deltaZ: number + let lineUp: WallParallelTarget | null = null if (axis) { const originalProj = originalCenter[0] * axis[0] + originalCenter[1] * axis[1] const rawProj = originalProj + rawDeltaX * axis[0] + rawDeltaZ * axis[1] - const snappedProj = snapScalarToGrid(rawProj, snapStep) + lineUp = free ? null : nearestWallParallelTarget(getParallelTargets(axis), rawProj) + const snappedProj = lineUp + ? lineUp.position + : snapScalarToGrid(rawProj, free ? 0 : snapStep) const perpDelta = snappedProj - originalProj deltaX = axis[0] * perpDelta deltaZ = axis[1] * perpDelta } else { - // Snap the resulting wall center to the WORLD XZ grid (projected - // back into building-local), then express the result as a delta - // from the original centre. Without this, a rotated building - // dragged the wall along its local axes instead of world ones. + // Snap the resulting wall center to the building's own grid lattice + // (the one the wall tool drafts on, square to a turned house), then + // express the result as a delta from the original centre. const targetLocal: [number, number] = [ originalCenter[0] + rawDeltaX, originalCenter[1] + rawDeltaZ, ] - const snappedLocal = snapBuildingLocalToWorldGrid(targetLocal, snapStep) + const snappedLocal = free + ? targetLocal + : snapBuildingLocalToWorldGrid(targetLocal, snapStep) deltaX = snappedLocal[0] - originalCenter[0] deltaZ = snappedLocal[1] - originalCenter[1] } + if (lineUp !== lastLineUp) { + lastLineUp = lineUp + publishWallParallelGuide(lineUp) + } const constrainedGridPos: [number, number] = [anchor[0] + deltaX, anchor[1] + deltaZ] @@ -564,14 +628,46 @@ export const MoveWallTool: React.FC<{ node: WallNode }> = ({ node }) => { // The drag writes nothing to the store (the preview is live overrides), so history is // paused only for this drop. Keyed by the moving wall: in split view the 2D move overlay // co-owns the gesture, and commitStep lifts its pause too. - const changes = planWallEndRejoins( + // The moved and stretched walls and the jogs take over any stretch of a + // parallel wall they now run along; jogs on the outline are outside walls. + // Walls T'd into this one follow it, what hangs on them staying put. + const attachedChanges = isNew + ? [] + : planAttachedWallChanges( + sceneState.nodes, + nodeId, + originalStart, + originalEnd, + preview.start, + preview.end, + new Set([ + ...linkedOriginalsRef.current.map((wall) => wall.id), + ...collapsedLinkedWallIds, + ]), + ) + const changes = finishWallEdit( sceneState.nodes, - commitUpdates.map(({ id }) => id), - WALL_CONNECT_SNAP_RADIUS, + planWallEndRejoins( + sceneState.nodes, + commitUpdates.map(({ id }) => id), + WALL_CONNECT_SNAP_RADIUS, + { + update: [...wallUpdates, ...attachedChanges], + create: wallCreates, + delete: Array.from(collapsedLinkedWallIds), + }, + ), { - update: wallUpdates, - create: wallCreates, - delete: Array.from(collapsedLinkedWallIds), + winnerIds: [ + ...commitUpdates.map(({ id }) => id), + ...attachedChanges.flatMap(({ id }) => + sceneState.nodes[id]?.type === 'wall' ? [id] : [], + ), + ...wallCreates.map(({ node }) => node.id), + ], + movedWallId: nodeId, + bridgeIds: wallCreates.map(({ node }) => node.id), + mintId: () => generateId('wall'), }, ) const drop = beginSceneHistoryPauseSession(useScene, { gesture: nodeId }) @@ -650,10 +746,12 @@ export const MoveWallTool: React.FC<{ node: WallNode }> = ({ node }) => { emitter.on('grid:move', onGridMove) emitter.on('tool:cancel', onCancel) + window.addEventListener('pointermove', onPointerMove) window.addEventListener('pointerup', onPointerUp) window.addEventListener('keydown', onKeyDown) return () => { + if (lastLineUp) publishWallParallelGuide(null) if (shouldRestoreOnCleanup) { // `shouldRestoreOnCleanup` is only true if neither `onPointerUp` // (commit branch) nor `onCancel` ran — i.e., the unmount came @@ -668,6 +766,7 @@ export const MoveWallTool: React.FC<{ node: WallNode }> = ({ node }) => { } emitter.off('grid:move', onGridMove) emitter.off('tool:cancel', onCancel) + window.removeEventListener('pointermove', onPointerMove) window.removeEventListener('pointerup', onPointerUp) window.removeEventListener('keydown', onKeyDown) } diff --git a/packages/nodes/src/wall/multi-reference.test.ts b/packages/nodes/src/wall/multi-reference.test.ts index 01a71745ef..740deded02 100644 --- a/packages/nodes/src/wall/multi-reference.test.ts +++ b/packages/nodes/src/wall/multi-reference.test.ts @@ -1,6 +1,18 @@ import { afterEach, expect, test } from 'bun:test' -import { type AnyNode, type AnyNodeId, useScene, WallNode } from '@pascal-app/core' -import { getNodePanelModel } from '@pascal-app/editor' +import { + type AnyNode, + type AnyNodeId, + GYPSUM_HALF, + getWallAssemblyPreset, + SiteNode, + STUCCO_3_COAT, + STUD_2X8, + useScene, + WallNode, + wallAssemblyPatch, + wallTypeAssembly, +} from '@pascal-app/core' +import { getNodePanelModel, type MultiPanelControl } from '@pascal-app/editor' import { wallDefinition } from './definition' globalThis.requestAnimationFrame ??= () => 0 @@ -21,18 +33,113 @@ const room = () => { ) } +type Choice = Extract +const controls = (selection: WallNode[]) => + getNodePanelModel(wallDefinition)!.multiControls!({ + selection, + nodes: useScene.getState().nodes, + }) +const choices = (selection: WallNode[]) => + controls(selection).filter((control): control is Choice => control.kind !== 'readout') +const control = (selection: WallNode[], id: string) => + controls(selection).find((entry) => entry.id === id) + +const load = (walls: WallNode[]) => { + const nodes = Object.fromEntries(walls.map((w) => [w.id, w])) as Record + useScene.setState({ nodes, rootNodeIds: [] }) + useScene.temporal.getState().clear() + useScene.temporal.getState().resume() +} +const current = (walls: WallNode[]) => + walls.map((w) => useScene.getState().nodes[w.id as AnyNodeId] as WallNode) + +test('multi-select Preset and Exterior apply to every wall in one step, mixed reads as mixed', () => { + const walls = room() + load(walls) + const preset = control(walls, 'wall-assembly-preset') as Choice + expect(preset).toMatchObject({ kind: 'select', section: 'Assembly', value: 'none' }) + preset.onChange('exterior-2x6-siding') + expect(useScene.temporal.getState().pastStates).toHaveLength(1) + const sided = current(walls) + const total = wallAssemblyPatch(getWallAssemblyPreset('exterior-2x6-siding')!.assembly).thickness + for (const wall of sided) { + expect(wall.assembly?.presetId).toBe('exterior-2x6-siding') + expect(wall.thickness).toBeCloseTo(total, 9) + } + // The assembly owns the thickness: a readout, not a field to type over. + expect(control(sided, 'wall-thickness-assembly')).toMatchObject({ + kind: 'readout', + detail: 'from assembly', + }) + const exterior = control(sided, 'wall-assembly-exterior') as Choice + expect(exterior.value).toBe('siding') + exterior.onChange('stucco') + expect(useScene.temporal.getState().pastStates).toHaveLength(2) + const stucco = current(walls) + expect((control(stucco, 'wall-assembly-exterior') as Choice).value).toBe('stucco') + for (const wall of stucco) + expect(wall.assembly?.layers.find((layer) => layer.role === 'finish')?.material).toBe('stucco') + expect(stucco[0]!.assembly?.presetId).toBeUndefined() + // One wall back to a plain single layer: the selection's preset is mixed. + const mixed = [{ ...stucco[0]!, assembly: undefined }, ...stucco.slice(1)] as WallNode[] + expect((control(mixed, 'wall-assembly-preset') as Choice).value).toBeNull() + expect(control(mixed, 'wall-assembly-exterior')).toBeUndefined() + // The readout covers only the assembly walls; the plain one keeps its Thickness field. + expect(control(mixed, 'wall-thickness-assembly')).toMatchObject({ + label: 'Assembly walls', + detail: '3 of 4, from assembly', + }) + const thickness = wallDefinition.parametrics!.groups[0]!.fields.find( + (field) => field.key === 'thickness', + ) as { appliesTo?: (wall: WallNode) => boolean } + expect(mixed.map((wall) => thickness.appliesTo!(wall))).toEqual([true, false, false, false]) + // A curtain wall is neither in the readout nor given a preset. + const curtain = [{ ...stucco[0]!, wallType: 'curtain' }, ...stucco.slice(1)] as WallNode[] + expect(control(curtain, 'wall-thickness-assembly')).toMatchObject({ + detail: '3 of 4, from assembly', + }) +}) + +test("the Preset lists the project's own wall types by name and applies one like a preset", () => { + const walls = room() + const type = { + id: 'custom-deep', + label: '2x8 stucco', + assembly: wallTypeAssembly('custom-deep', [ + { role: 'finish', material: 'stucco', thickness: STUCCO_3_COAT }, + { role: 'structure', core: true, material: 'wood', thickness: STUD_2X8 }, + { role: 'lining', material: 'drywall', thickness: GYPSUM_HALF }, + ]), + } + const site = SiteNode.parse({ id: 'site_lot', wallTypes: [type] }) + const nodes = Object.fromEntries([site, ...walls].map((n) => [n.id, n])) as Record< + AnyNodeId, + AnyNode + > + useScene.setState({ nodes, rootNodeIds: [site.id as AnyNodeId] }) + useScene.temporal.getState().clear() + useScene.temporal.getState().resume() + const preset = control(walls, 'wall-assembly-preset') as Choice + expect(preset.options.at(-1)).toEqual({ value: 'custom-deep', label: '2x8 stucco' }) + preset.onChange('custom-deep') + const applied = current(walls) + for (const wall of applied) { + expect(wall.assembly?.presetId).toBe('custom-deep') + expect(wall.thickness).toBeCloseTo(STUCCO_3_COAT + STUD_2X8 + GYPSUM_HALF, 9) + } + expect((control(applied, 'wall-assembly-preset') as Choice).value).toBe('custom-deep') + // A type this project does not have reads as a custom stack. + useScene.setState({ rootNodeIds: [] }) + expect((control(applied, 'wall-assembly-preset') as Choice).value).toBe('custom') +}) + test('multi-select Reference: room labels, mixed shows no option, one step for every wall', () => { const walls = room() const nodes = Object.fromEntries(walls.map((w) => [w.id, w])) as Record useScene.setState({ nodes, rootNodeIds: [] }) useScene.temporal.getState().clear() useScene.temporal.getState().resume() - const controls = (selection: WallNode[]) => - getNodePanelModel(wallDefinition)!.multiControls!({ - selection, - nodes: useScene.getState().nodes, - }) - const [reference] = controls(walls) + const [reference] = choices(walls) expect(reference).toMatchObject({ id: 'wall-reference', section: 'Dimensions', @@ -47,8 +154,8 @@ test('multi-select Reference: room labels, mixed shows no option, one step for e reference!.onChange('outside') expect(useScene.temporal.getState().pastStates).toHaveLength(1) const after = walls.map((w) => useScene.getState().nodes[w.id as AnyNodeId] as WallNode) - expect(controls(after)[0]!.value).toBe('outside') + expect(choices(after)[0]!.value).toBe('outside') // Mixed: one wall back to centre. const mixed = [{ ...after[0]!, justification: undefined }, ...after.slice(1)] as WallNode[] - expect(controls(mixed)[0]!.value).toBeNull() + expect(choices(mixed)[0]!.value).toBeNull() }) diff --git a/packages/nodes/src/wall/paint-plan.test.ts b/packages/nodes/src/wall/paint-plan.test.ts index d9a948821a..e9300b029c 100644 --- a/packages/nodes/src/wall/paint-plan.test.ts +++ b/packages/nodes/src/wall/paint-plan.test.ts @@ -135,7 +135,7 @@ describe('wall paint plan', () => { 'stripe_b', ]) expect(after[room.id].wallOverrides).toEqual([ - { wallId: WALL_ID, face: 'a', finish: 'library:concrete-drywall' }, + { wallId: WALL_ID, face: 'a', finish: 'library:preset-seattlegrey' }, ]) expect(after[room.id].wallMaterial).toBe('library:room') expect(after[other.id]).toEqual(other) diff --git a/packages/nodes/src/wall/paint.test.ts b/packages/nodes/src/wall/paint.test.ts index 41f87987cf..9d938b6e78 100644 --- a/packages/nodes/src/wall/paint.test.ts +++ b/packages/nodes/src/wall/paint.test.ts @@ -287,7 +287,7 @@ describe('wall paint roles', () => { expect(nodes()[wall.id].slots?.a).toBeUndefined() expect(nodes()[wall.id].faceRegions).toBeUndefined() expect(nodes().zone_room.wallOverrides).toEqual([ - { wallId: wall.id, face: 'a', finish: 'library:concrete-drywall' }, + { wallId: wall.id, face: 'a', finish: 'library:preset-seattlegrey' }, ]) expect(nodes().zone_room.wallMaterial).toBe('library:new-room') expect( diff --git a/packages/nodes/src/wall/paint.ts b/packages/nodes/src/wall/paint.ts index f2773c39b8..82b7d54bf3 100644 --- a/packages/nodes/src/wall/paint.ts +++ b/packages/nodes/src/wall/paint.ts @@ -15,6 +15,7 @@ import { parseMaterialRef, plannedWallIds, planWallPaint, + type RailingWallSlotId, resolveWallFaceChain, resolveWallFinish, type SceneMaterialId, @@ -55,6 +56,7 @@ import { resolveSlotPaintMaterialRef, } from '../shared/slot-paint' import { swapPreviewMaterial } from '../shared/swap-preview-material' +import { RAILING_WALL_SLOTS } from './railing-wall-materials' // Roles (see `parseWallPaintRole` in core): face / trim slots write // `node.slots`, `region:` a paint region, `room:/` this face @@ -63,7 +65,7 @@ import { swapPreviewMaterial } from '../shared/swap-preview-material' // shows there: a region, else the room's finish on that face, else the face slot. type ResolvedWallPaintRole = - | { kind: 'slot'; slotId: WallSurfaceSlotId | CurtainWallRole } + | { kind: 'slot'; slotId: WallSurfaceSlotId | CurtainWallRole | RailingWallSlotId } | Exclude const WALL_SLOT_IDS = new Set(Object.keys(WALL_SURFACE_SLOT_DEFAULTS)) @@ -72,6 +74,9 @@ const CURTAIN_WALL_ROLES = ['curtain-frame', 'curtain-glass', 'curtain-solid'] a type CurtainWallRole = (typeof CURTAIN_WALL_ROLES)[number] const isCurtainWallRole = (role: string): role is CurtainWallRole => (CURTAIN_WALL_ROLES as readonly string[]).includes(role) +// A railing paints its posts and rails, and its infill (palette 0..1). +const isRailingWallRole = (role: string): role is RailingWallSlotId => + (RAILING_WALL_SLOTS as readonly string[]).includes(role) const FACE_MATERIAL_INDEX: Record = { a: 1, b: 2 } @@ -80,7 +85,7 @@ export { wallRegionRole, wallRoomFaceRole, wallRoomFinishRole } export function parseWallPaintRole(role: string): ResolvedWallPaintRole | null { return parseCoreWallPaintRole( role, - (slotId) => WALL_SLOT_IDS.has(slotId) || isCurtainWallRole(slotId), + (slotId) => WALL_SLOT_IDS.has(slotId) || isCurtainWallRole(slotId) || isRailingWallRole(slotId), ) as ResolvedWallPaintRole | null } @@ -126,12 +131,13 @@ export function resolveWallRole(args: { nodes?: Readonly> }): string | null { const { node, hitObject, localPosition, ray } = args - if (node.wallType === 'curtain') { + if (node.wallType === 'curtain' || node.wallType === 'railing') { const root = sceneRegistry.nodes.get(node.id) if (!(root && ray && hasMaterialsForGroups(root))) return null wallSlotRaycaster.ray.copy(ray) const hit = wallSlotRaycaster.intersectObject(root, false)[0] - return CURTAIN_WALL_ROLES[hit?.face?.materialIndex ?? -1] ?? null + const roles = node.wallType === 'curtain' ? CURTAIN_WALL_ROLES : RAILING_WALL_SLOTS + return roles[hit?.face?.materialIndex ?? -1] ?? null } const directSlotId = hitObject?.userData?.slotId if (typeof directSlotId === 'string' && WALL_SLOT_IDS.has(directSlotId)) { @@ -205,10 +211,12 @@ function refToEffective(ref: string | undefined) { /** * The wall mesh's palette entry a non-face slot draws with, when it is part of * the wall body rather than its own mesh: a curtain wall's frame / glass / - * solid panels (0..2), or the underpinning's stemwall (a finish ref, 3..). + * solid panels (0..2), a railing's frame / infill (0..1), or the underpinning's + * stemwall (a finish ref, 3..). */ function wallPaletteSlotIndex(wall: WallNode, slotId: string, mesh: Mesh): number | null { if (isCurtainWallRole(slotId)) return CURTAIN_WALL_ROLES.indexOf(slotId) + if (isRailingWallRole(slotId)) return RAILING_WALL_SLOTS.indexOf(slotId) if (slotId !== 'foundation' || !wall.underpinning) return null const ref = wall.slots?.foundation ?? WALL_SURFACE_SLOT_DEFAULTS.foundation const at = getWallFinishRefs(mesh.geometry).indexOf(ref) diff --git a/packages/nodes/src/wall/panel-model.ts b/packages/nodes/src/wall/panel-model.ts index d034889a61..ef7221c7ee 100644 --- a/packages/nodes/src/wall/panel-model.ts +++ b/packages/nodes/src/wall/panel-model.ts @@ -1,6 +1,11 @@ import { type AnyNode, type AnyNodeId, + type Assembly, + BRICK_AIR_SPACE, + BRICK_VENEER, + DEFAULT_WALL_THICKNESS, + FIBER_CEMENT, faceOnLine, GROUND_SUPPORT_ID, getClampedWallCurveOffset, @@ -9,18 +14,30 @@ import { justificationForFaceOnLine, normalizeWallCurveOffset, planWallJustification, + projectWallTypes, roomSideFaces, + runAsSingleSceneHistoryStep, + SIDING_LAP, + STONE_VENEER_UNVERIFIED, + STUCCO_3_COAT, terrainSupportLift, useScene, + WALL_ASSEMBLY_PRESETS, WALL_CHAIR_RAIL_DEFAULT, WALL_CROWN_DEFAULT, WALL_SKIRTING_DEFAULT, + type WallAssemblyExteriorFinish, type WallNode, type WallTrimProfile, + wallAssemblyFromLegacy, + wallAssemblyPatch, + wallAssemblyToLegacy, wallTrimPatch, } from '@pascal-app/core' import { curveReshapeScope, + formatLinearMeasurement, + type MultiPanelControl, type PanelRow, triggerSFX, useInteractionScope, @@ -29,6 +46,7 @@ import { useViewer } from '@pascal-app/viewer' import { resolveWallOpeningCeiling } from '../shared/wall-opening-ceiling' import { hasWallCurveBlockingChildren } from './curve-eligibility' import { buildWallLengthPatch } from './length-patch' +import { railingWallRows } from './railing-wall-panel-model' type TrimKey = 'skirting' | 'crown' | 'chairRail' const profiles: Record = { @@ -196,46 +214,51 @@ export function wallSettings( number('Dimensions', 'wall-length', 'Length', length, 0.1, 1000, 0.05, (next) => { update(buildWallLengthPatch(node, next)) }) - choice( - 'Dimensions', - 'wall-top', - 'Top', - node.height == null ? 'Follows level' : 'Custom height', - () => - update( - node.height == null - ? { height: Math.max(0.1, height) } - : { height: undefined, ...repairBase() }, - ), - ) - if (node.height == null) - choice('Dimensions', 'wall-height-auto', 'Current height', `${Number(height.toFixed(3))} m`) - else - number('Dimensions', 'height', 'Height', node.height, 0.1, 1000, 0.05, (height) => - update({ height }), + // A railing keeps its own height and its posts set its thickness: its rows say so instead. + const railing = node.wallType === 'railing' + if (railing) rows.push(...railingWallRows(node, update)) + else { + choice( + 'Dimensions', + 'wall-top', + 'Top', + node.height == null ? 'Follows level' : 'Custom height', + () => + update( + node.height == null + ? { height: Math.max(0.1, height) } + : { height: undefined, ...repairBase() }, + ), ) - choice( - 'Dimensions', - 'wall-bottom', - 'Bottom', - node.fillToTerrain ? 'Fill to terrain' : 'Auto', - () => - update( - node.fillToTerrain - ? { fillToTerrain: undefined, ...repairBase() } - : { fillToTerrain: true }, - ), - ) - number( - 'Dimensions', - 'thickness', - 'Thickness', - node.thickness ?? 0.1, - 0.05, - 1000, - 0.01, - (thickness) => update({ thickness }), - ) + if (node.height == null) + choice('Dimensions', 'wall-height-auto', 'Current height', `${Number(height.toFixed(3))} m`) + else + number('Dimensions', 'height', 'Height', node.height, 0.1, 1000, 0.05, (height) => + update({ height }), + ) + choice( + 'Dimensions', + 'wall-bottom', + 'Bottom', + node.fillToTerrain ? 'Fill to terrain' : 'Auto', + () => + update( + node.fillToTerrain + ? { fillToTerrain: undefined, ...repairBase() } + : { fillToTerrain: true }, + ), + ) + number( + 'Dimensions', + 'thickness', + 'Thickness', + node.thickness ?? 0.1, + 0.05, + 1000, + 0.01, + (thickness) => update({ thickness }), + ) + } const blockedCurve = hasWallCurveBlockingChildren( (node.children ?? []).flatMap((id) => nodes[id as AnyNodeId] ? [nodes[id as AnyNodeId]!] : [], @@ -262,11 +285,15 @@ export function wallSettings( onSelect: reshape, }) } - for (const [key, title, defaults] of [ - ['skirting', 'Skirting', WALL_SKIRTING_DEFAULT], - ['crown', 'Crown molding', WALL_CROWN_DEFAULT], - ['chairRail', 'Chair rail', WALL_CHAIR_RAIL_DEFAULT], - ] as const) { + // A railing has no faces to trim. + const trims = railing + ? [] + : ([ + ['skirting', 'Skirting', WALL_SKIRTING_DEFAULT], + ['crown', 'Crown molding', WALL_CROWN_DEFAULT], + ['chairRail', 'Chair rail', WALL_CHAIR_RAIL_DEFAULT], + ] as const) + for (const [key, title, defaults] of trims) { const trim = { ...defaults, ...node[key] } const patch = (value: Partial) => update(wallTrimPatch(node, key, value)) choice(title, `${key}-enabled`, title, trim.enabled ? 'On' : 'Off', () => @@ -307,3 +334,148 @@ export function wallSettings( } return rows } + +export const EXTERIOR_FINISH_OPTIONS: Array<{ value: WallAssemblyExteriorFinish; label: string }> = + [ + { value: 'none', label: 'None' }, + { value: 'siding', label: 'Lap siding' }, + { value: 'fiber-cement', label: 'Fiber cement' }, + { value: 'stucco', label: 'Stucco' }, + { value: 'brick', label: 'Brick veneer' }, + { value: 'stone', label: 'Stone veneer' }, + ] + +/** Cited default thickness for a finish the user just switched to. */ +export const EXTERIOR_FINISH_DEFAULT: Record = { + none: 0, + siding: SIDING_LAP, + 'fiber-cement': FIBER_CEMENT, + stucco: STUCCO_3_COAT, + brick: BRICK_VENEER + BRICK_AIR_SPACE, + stone: STONE_VENEER_UNVERIFIED, +} + +const PLAIN_PRESET = 'none' +const CUSTOM_PRESET = 'custom' + +/** + * The wall types a wall's Preset can be: the cited presets, then the project's own + * (`SiteNode.wallTypes`, by label), each applied the same way (`wallAssemblyPatch`). + */ +function wallPresetChoices(): Array<{ id: string; label: string; assembly: Assembly }> { + const { nodes, rootNodeIds } = useScene.getState() + return [...WALL_ASSEMBLY_PRESETS, ...projectWallTypes(nodes, rootNodeIds)] +} + +/** + * The assembly preset a wall shows: its preset or project type, a custom stack + * (also one from a project type this project does not have), or none (a single layer). + */ +function wallPresetValue(wall: WallNode, known: ReadonlySet): string { + const presetId = wall.assembly?.presetId + if (presetId && known.has(presetId)) return presetId + return wall.assembly ? CUSTOM_PRESET : PLAIN_PRESET +} + +function shared(values: readonly T[]): T | null { + return values.length > 0 && values.every((value) => value === values[0]) ? values[0]! : null +} + +function writeWalls(updates: Array<{ id: AnyNodeId; data: Partial }>) { + if (updates.length === 0) return + runAsSingleSceneHistoryStep(useScene, () => useScene.getState().updateNodes(updates)) +} + +/** + * The wall's assembly and thickness controls for a multi-selection, as the + * single panel offers them: the Preset (wall type) and the Exterior cladding, + * each applied to every selected standard wall in one undo step, and the + * thickness of the walls whose assembly sets it, which the selection reads but + * cannot type over (the Thickness field edits the others). Curtain walls and + * railings take no assembly and are left out of all three. + */ +export function wallAssemblyMultiControls(selection: readonly WallNode[]): MultiPanelControl[] { + const walls = selection.filter( + (wall) => wall.wallType !== 'curtain' && wall.wallType !== 'railing', + ) + if (walls.length === 0) return [] + const controls: MultiPanelControl[] = [] + const withAssembly = walls.filter((wall) => wall.assembly) + if (withAssembly.length > 0) { + const { unit, metricNotation } = useViewer.getState() + const thickness = shared( + withAssembly.map((wall) => Math.round((wall.thickness ?? DEFAULT_WALL_THICKNESS) * 1e6)), + ) + // Only the walls with an assembly: the Thickness field edits the rest. + const every = withAssembly.length === selection.length + controls.push({ + id: 'wall-thickness-assembly', + kind: 'readout', + section: 'Dimensions', + label: every ? 'Thickness' : 'Assembly walls', + value: + thickness === null + ? 'Mixed' + : formatLinearMeasurement(thickness / 1e6, unit, metricNotation), + detail: every + ? 'from assembly' + : `${withAssembly.length} of ${selection.length}, from assembly`, + }) + } + const choices = wallPresetChoices() + const known = new Set(choices.map((choice) => choice.id)) + const preset = shared(walls.map((wall) => wallPresetValue(wall, known))) + controls.push({ + id: 'wall-assembly-preset', + kind: 'select', + section: 'Assembly', + label: 'Preset', + options: [ + { value: PLAIN_PRESET, label: 'None (single layer)' }, + ...(preset === CUSTOM_PRESET ? [{ value: CUSTOM_PRESET, label: 'Custom' }] : []), + ...choices.map((entry) => ({ value: entry.id, label: entry.label })), + ], + value: preset, + onChange: (value) => { + if (value === CUSTOM_PRESET) return + const chosen = choices.find((entry) => entry.id === value) + writeWalls( + walls.map((wall) => ({ + id: wall.id as AnyNodeId, + data: chosen + ? wallAssemblyPatch(structuredClone(chosen.assembly)) + : { assembly: undefined }, + })), + ) + }, + }) + // The cladding edit works on the WS5 view of each stack, as the single panel's + // Exterior row does; it shows only when every wall has one. + const legacy = walls.map((wall) => (wall.assembly ? wallAssemblyToLegacy(wall.assembly) : null)) + if (legacy.every((entry) => entry !== null)) { + controls.push({ + id: 'wall-assembly-exterior', + kind: 'select', + section: 'Assembly', + label: 'Exterior', + options: EXTERIOR_FINISH_OPTIONS, + value: shared(legacy.map((entry) => entry!.exterior?.finish ?? 'none')), + onChange: (value) => { + const finish = value as WallAssemblyExteriorFinish + writeWalls( + walls.map((wall, index) => ({ + id: wall.id as AnyNodeId, + data: wallAssemblyPatch( + wallAssemblyFromLegacy({ + ...legacy[index]!, + exterior: { finish, thickness: EXTERIOR_FINISH_DEFAULT[finish] }, + preset: undefined, + }), + ), + })), + ) + }, + }) + } + return controls +} diff --git a/packages/nodes/src/wall/panel.test.ts b/packages/nodes/src/wall/panel.test.ts new file mode 100644 index 0000000000..59da32202f --- /dev/null +++ b/packages/nodes/src/wall/panel.test.ts @@ -0,0 +1,20 @@ +import { expect, test } from 'bun:test' +import { createI18n, FRAMING_SPACINGS } from '@pascal-app/core' +import { formatSpacing } from '../shared/build-up-controls' +import { studSpacingChoices } from './panel' + +const INCH = 0.0254 + +// Walls offered 12/16/24 "in on centre" while roofs and ceilings offered 12/16/19.2/24 `" o.c.`. +test('wall studs offer the framing spacings roofs and ceilings do, keeping one off the list', () => { + expect(studSpacingChoices(undefined)).toEqual({ sizes: FRAMING_SPACINGS, current: null }) + expect(studSpacingChoices(16 * INCH + 1e-9).current).toBe(FRAMING_SPACINGS[1]) + expect(studSpacingChoices(0.6)).toEqual({ sizes: [0.6, ...FRAMING_SPACINGS], current: 0.6 }) + const english = createI18n() + expect(FRAMING_SPACINGS.map((size) => formatSpacing(size, 'imperial', english))).toEqual([ + '12" o.c.', + '16" o.c.', + '19.2" o.c.', + '24" o.c.', + ]) +}) diff --git a/packages/nodes/src/wall/panel.tsx b/packages/nodes/src/wall/panel.tsx index 7aab6e4e4c..4e293b8ba5 100644 --- a/packages/nodes/src/wall/panel.tsx +++ b/packages/nodes/src/wall/panel.tsx @@ -4,9 +4,7 @@ import { type AnyNode, type AnyNodeId, assemblyThickness, - BRICK_AIR_SPACE, - BRICK_VENEER, - FIBER_CEMENT, + FRAMING_SPACINGS, GROUND_SUPPORT_ID, GYPSUM_HALF, GYPSUM_SHEATHING, @@ -18,9 +16,6 @@ import { normalizeWallCurveOffset, resolveWallAssembly, runAsSingleSceneHistoryStep, - SIDING_LAP, - STONE_VENEER_UNVERIFIED, - STUCCO_3_COAT, terrainSupportLift, useLiveNodeOverrides, usePascalI18n, @@ -60,18 +55,29 @@ import { SliderControl, triggerSFX, useInteractionScope, + useProjectWallTypes, WallPaintRegionList, + WallTypeMenu, } from '@pascal-app/editor' import { useViewer } from '@pascal-app/viewer' import { Spline } from 'lucide-react' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useShallow } from 'zustand/react/shallow' +import { formatSpacing } from '../shared/build-up-controls' +import { formatLayerThickness, parseLayerThickness } from '../shared/layer-thickness' import { resolveWallOpeningCeiling } from '../shared/wall-opening-ceiling' import { CurtainWallPanel } from './curtain-wall-panel' import { hasWallCurveBlockingChildren } from './curve-eligibility' import { buildWallLengthPatch } from './length-patch' -import { type WallReferenceValue, wallReferenceModel } from './panel-model' +import { + EXTERIOR_FINISH_DEFAULT, + EXTERIOR_FINISH_OPTIONS, + type WallReferenceValue, + wallReferenceModel, +} from './panel-model' import { createWallPropertyPreview } from './property-preview' +import { RailingWallPanel } from './railing-wall-panel' +import { railingWallTypePatch } from './railing-wall-panel-model' /** * Base half of the plane-bound repair: a stamped draft offset goes, and a @@ -296,6 +302,9 @@ export default function WallPanel() { const skirting = { ...WALL_SKIRTING_DEFAULT, ...(node.skirting ?? {}) } const crown = { ...WALL_CROWN_DEFAULT, ...(node.crown ?? {}) } const chairRail = { ...WALL_CHAIR_RAIL_DEFAULT, ...(node.chairRail ?? {}) } + // A railing keeps its own height, its posts set its thickness, and it has no assembly or faces: + // the Railing section holds its controls instead. + const railing = node.wallType === 'railing' return ( handleUpdate({ wallType })} + onChange={(wallType) => + handleUpdate(wallType === 'railing' ? railingWallTypePatch(node) : { wallType }) + } options={[ { label: i18n._({ id: 'node.wall.panel.standard', message: 'Standard' }), @@ -316,10 +327,17 @@ export default function WallPanel() { label: i18n._({ id: 'node.wall.panel.curtainWall', message: 'Curtain wall' }), value: 'curtain', }, + { + label: i18n._({ id: 'node.wall.panel.railing', message: 'Railing' }), + value: 'railing', + }, ]} value={node.wallType ?? 'standard'} /> + {node.wallType !== 'curtain' && !railing && ( + + )} -
- {i18n._({ id: 'node.wall.panel.top', message: 'Top' })} -
- - {isPlaneBound ? ( -
- {i18n._({ - id: 'node.panel.currently', - message: 'Currently {value}', - values: { value: formatLinearMeasurement(height, unit) }, - })} -
- ) : ( - - handlePreview({ - height: linearControlValueToMeters(v, unit, { maxMeters: 1000, minMeters: 0.1 }), - }) - } - precision={2} - step={0.1} - unit={unitLabel} - value={Math.round(displayHeight * 100) / 100} - /> - )} -
- {i18n._({ id: 'node.wall.panel.bottom', message: 'Bottom' })} -
- - {followsTerrain && ( -
- {i18n._({ - id: 'node.wall.panel.extendsDownwardToMeetTheTerrain', - message: 'Extends downward to meet the terrain. Height and top stay unchanged.', - })} -
- )} - {node.assembly && node.wallType !== 'curtain' ? ( - // The assembly owns the total. Editing `thickness` here would put the - // two out of sync, so the slider becomes a readout and the Assembly - // section is the only place thickness changes. -
- - {i18n._({ id: 'node.wall.panel.thickness', message: 'Thickness' })} - - - {i18n._({ - id: 'node.wall.panel.thicknessFromAssembly', - message: '{thickness} · from assembly', - values: { thickness: formatLinearMeasurement(thickness, unit) }, - })} - -
- ) : ( - - handlePreview({ - thickness: linearControlValueToMeters(v, unit, { - maxMeters: 1000, - minMeters: 0.05, - }), - }) - } - precision={3} - step={0.01} - unit={unitLabel} - value={Math.round(displayThickness * 1000) / 1000} - /> + {!railing && ( + <> +
+ {i18n._({ id: 'node.wall.panel.top', message: 'Top' })} +
+ + {isPlaneBound ? ( +
+ {i18n._({ + id: 'node.panel.currently', + message: 'Currently {value}', + values: { value: formatLinearMeasurement(height, unit) }, + })} +
+ ) : ( + + handlePreview({ + height: linearControlValueToMeters(v, unit, { + maxMeters: 1000, + minMeters: 0.1, + }), + }) + } + precision={2} + step={0.1} + unit={unitLabel} + value={Math.round(displayHeight * 100) / 100} + /> + )} +
+ {i18n._({ id: 'node.wall.panel.bottom', message: 'Bottom' })} +
+ + {followsTerrain && ( +
+ {i18n._({ + id: 'node.wall.panel.extendsDownwardToMeetTheTerrain', + message: 'Extends downward to meet the terrain. Height and top stay unchanged.', + })} +
+ )} + {node.assembly && node.wallType !== 'curtain' ? ( + // The assembly owns the total. Editing `thickness` here would put the + // two out of sync, so the slider becomes a readout and the Assembly + // section is the only place thickness changes. +
+ + {i18n._({ id: 'node.wall.panel.thickness', message: 'Thickness' })} + + + {i18n._({ + id: 'node.wall.panel.thicknessFromAssembly', + message: '{thickness} · from assembly', + values: { thickness: formatLinearMeasurement(thickness, unit) }, + })} + +
+ ) : ( + + handlePreview({ + thickness: linearControlValueToMeters(v, unit, { + maxMeters: 1000, + minMeters: 0.05, + }), + }) + } + precision={3} + step={0.01} + unit={unitLabel} + value={Math.round(displayThickness * 1000) / 1000} + /> + )} + )}
{i18n._({ id: 'node.wall.panel.reference', message: 'Reference' })} @@ -502,10 +530,18 @@ export default function WallPanel() { onCancel={handleCancel} unit={unit} /> + ) : railing ? ( + ) : ( <> - - @@ -791,68 +827,6 @@ function WallTrimSection({ // re-derived total in one `updateNode` call, so the 2D plan and the 3D wall // both move on the same store tick. -const METRES_PER_INCH = 0.0254 - -/** - * Imperial-friendly thickness input. Accepts `5/8`, `5/8"`, `7/16 in`, - * `1-1/4"`, `1 1/2"`, `12mm`, `0.012m`. A bare number means INCHES in imperial - * display and MILLIMETRES in metric — wall layers are millimetre-scale and - * typing `0.0127` for half-inch board is nobody's idea of usable. - */ -function parseLayerThickness(raw: string, unit: 'metric' | 'imperial'): number | null { - const text = raw.trim().toLowerCase().replace(/["”]/g, ' in ') - if (!text) return null - const explicit = /(mm|cm|m|in|ft|')\s*$/.exec(text) - const suffix = explicit?.[1] - const body = (suffix ? text.slice(0, explicit?.index) : text).trim() - - // `1-1/4` / `1 1/2` / `5/8` / `0.4375` - const mixed = /^(\d+(?:\.\d+)?)[\s-]+(\d+)\s*\/\s*(\d+)$/.exec(body) - const fraction = /^(\d+)\s*\/\s*(\d+)$/.exec(body) - let value: number - if (mixed) { - value = Number(mixed[1]) + Number(mixed[2]) / Number(mixed[3]) - } else if (fraction) { - value = Number(fraction[1]) / Number(fraction[2]) - } else { - value = Number(body) - } - if (!Number.isFinite(value) || value < 0) return null - - switch (suffix) { - case 'mm': - return value / 1000 - case 'cm': - return value / 100 - case 'm': - return value - case 'in': - return value * METRES_PER_INCH - case 'ft': - case "'": - return value * 12 * METRES_PER_INCH - default: - return unit === 'imperial' ? value * METRES_PER_INCH : value / 1000 - } -} - -/** Nearest common fraction of an inch, so 0.0111 m reads back as `7/16"`. */ -function formatLayerThickness(metres: number, unit: 'metric' | 'imperial'): string { - if (unit !== 'imperial') return `${Math.round(metres * 1000 * 10) / 10} mm` - const inchValue = metres / METRES_PER_INCH - const sixteenths = Math.round(inchValue * 16) - if (Math.abs(inchValue * 16 - sixteenths) > 1e-6) return `${Math.round(inchValue * 1000) / 1000}"` - const whole = Math.floor(sixteenths / 16) - let numerator = sixteenths % 16 - let denominator = 16 - while (numerator % 2 === 0 && numerator > 0) { - numerator /= 2 - denominator /= 2 - } - if (numerator === 0) return `${whole}"` - return whole > 0 ? `${whole}-${numerator}/${denominator}"` : `${numerator}/${denominator}"` -} - const SELECT_CLASS = 'h-7 w-full rounded border border-border bg-background px-2 text-[11px] text-foreground outline-none focus:border-primary' const INPUT_CLASS = @@ -904,26 +878,18 @@ function ThicknessInput({ ) } -const EXTERIOR_FINISH_OPTIONS: Array<{ - value: WallAssemblyExteriorFinish - label: MessageDescriptor -}> = [ - { value: 'none', label: /* i18n */ { id: 'node.wall.panel.none', message: 'None' } }, - { value: 'siding', label: /* i18n */ { id: 'node.wall.panel.lapSiding', message: 'Lap siding' } }, - { - value: 'fiber-cement', - label: /* i18n */ { id: 'node.wall.panel.fiberCement', message: 'Fiber cement' }, - }, - { value: 'stucco', label: /* i18n */ { id: 'node.wall.panel.stucco', message: 'Stucco' } }, - { - value: 'brick', - label: /* i18n */ { id: 'node.wall.panel.brickVeneer', message: 'Brick veneer' }, - }, - { - value: 'stone', - label: /* i18n */ { id: 'node.wall.panel.stoneVeneer', message: 'Stone veneer' }, - }, -] +/** + * The Exterior select's names for the finishes of the list it shares with the + * multi-selection controls (`EXTERIOR_FINISH_OPTIONS`, in `panel-model`). + */ +const EXTERIOR_FINISH_LABELS: Record = { + none: /* i18n */ { id: 'node.wall.panel.none', message: 'None' }, + siding: /* i18n */ { id: 'node.wall.panel.lapSiding', message: 'Lap siding' }, + 'fiber-cement': /* i18n */ { id: 'node.wall.panel.fiberCement', message: 'Fiber cement' }, + stucco: /* i18n */ { id: 'node.wall.panel.stucco', message: 'Stucco' }, + brick: /* i18n */ { id: 'node.wall.panel.brickVeneer', message: 'Brick veneer' }, + stone: /* i18n */ { id: 'node.wall.panel.stoneVeneer', message: 'Stone veneer' }, +} const SHEATHING_OPTIONS: Array<{ value: WallAssemblySheathingMaterial; label: MessageDescriptor }> = [ @@ -940,6 +906,24 @@ const FRAMING_OPTIONS: Array<{ value: WallAssemblyFramingKind; label: MessageDes { value: 'icf', label: /* i18n */ { id: 'node.wall.panel.icf', message: 'ICF' } }, ] +const spacingKey = (metres: number) => metres.toFixed(6) + +/** + * The stud spacings to pick from, the framing list roofs and ceilings use, keeping a stored one + * off the list; and the one stored (null for the framer's default). + */ +export function studSpacingChoices(stored: number | undefined) { + const listed = FRAMING_SPACINGS.find( + (size) => stored !== undefined && Math.abs(size - stored) < 1e-6, + ) + const current = stored === undefined ? null : (listed ?? stored) + return { + sizes: + current === null || listed !== undefined ? FRAMING_SPACINGS : [current, ...FRAMING_SPACINGS], + current, + } +} + const INTERIOR_FINISH_OPTIONS: Array<{ value: WallAssemblyInteriorFinish label: MessageDescriptor @@ -949,16 +933,6 @@ const INTERIOR_FINISH_OPTIONS: Array<{ { value: 'plaster', label: /* i18n */ { id: 'node.wall.panel.plaster', message: 'Plaster' } }, ] -/** Cited default thickness for a finish the user just switched to. */ -const EXTERIOR_FINISH_DEFAULT: Record = { - none: 0, - siding: SIDING_LAP, - 'fiber-cement': FIBER_CEMENT, - stucco: STUCCO_3_COAT, - brick: BRICK_VENEER + BRICK_AIR_SPACE, - stone: STONE_VENEER_UNVERIFIED, -} - function WallAssemblySection({ node, onUpdate, @@ -973,8 +947,15 @@ function WallAssemblySection({ // The cladding / sheathing / framing / interior editor works on the WS5 view // of the F2 stack; a stack it cannot express is listed read-only. const assembly = stack ? (wallAssemblyToLegacy(stack) ?? undefined) : undefined + const studSpacing = studSpacingChoices(assembly?.framing.spacing) const resolved = resolveWallAssembly(node) const presetNote = wallAssemblyUnverifiedNote(node) + // The project's own wall types sit beside the presets and apply the same way. + const projectTypes = useProjectWallTypes() + const presetId = stack?.presetId + const knownPreset = + !!presetId && + (!!getWallAssemblyPreset(presetId) || projectTypes.some((type) => type.id === presetId)) // Every write goes through wallAssemblyPatch so `thickness` is re-derived. // Changing any layer clears `preset` — the stack is no longer that preset. @@ -996,10 +977,10 @@ function WallAssemblySection({ onUpdate({ assembly: undefined }) return } - const preset = getWallAssemblyPreset(id) - if (preset) onUpdate(wallAssemblyPatch(preset.assembly)) + const preset = getWallAssemblyPreset(id) ?? projectTypes.find((type) => type.id === id) + if (preset) onUpdate(wallAssemblyPatch(structuredClone(preset.assembly))) }} - value={stack?.presetId ?? ''} + value={knownPreset ? presetId : ''} > ))} + {projectTypes.length > 0 ? ( + + {projectTypes.map((type) => ( + + ))} + + ) : null} + onUpdate(wallAssemblyPatch(structuredClone(type.assembly)))} + placement={ + node.frontSide === 'exterior' || node.backSide === 'exterior' ? 'exterior' : 'interior' + } + /> {assembly && ( @@ -1030,7 +1029,7 @@ function WallAssemblySection({ > {EXTERIOR_FINISH_OPTIONS.map((option) => ( ))} @@ -1092,13 +1091,16 @@ function WallAssemblySection({ { + const spacing = studSpacing.sizes.find( + (size) => spacingKey(size) === event.target.value, + ) + edit((draft) => ({ + ...draft, + framing: { + kind: draft.framing.kind, + depth: draft.framing.depth, + ...(spacing !== undefined ? { spacing } : {}), + }, + })) + }} + value={studSpacing.current === null ? '' : spacingKey(studSpacing.current)} + > + + {studSpacing.sizes.map((spacing) => ( + + ))} + + + )} +